golly-2.7-src/0000755000175000017500000000000012536111546010302 500000000000000golly-2.7-src/gui-wx/0000755000175000017500000000000012536111546011522 500000000000000golly-2.7-src/gui-wx/Info.plist.in0000644000175000017500000000404012536111364014013 00000000000000 CFBundleInfoDictionaryVersion 6.0 CFBundleIdentifier net.sourceforge.golly CFBundleDevelopmentRegion English CFBundleExecutable Golly CFBundleName Golly CFBundlePackageType APPL CFBundleSignature GoLy CFBundleIconFile app.icns CFBundleVersion VERSION CFBundleShortVersionString VERSION CFBundleGetInfoString Golly version VERSION, Copyright 2015 The Golly Gang LSRequiresCarbon CFBundleDocumentTypes CFBundleTypeName Golly Run Length Encoded File CFBundleTypeIconFile file-rle.icns CFBundleTypeExtensions rle CFBundleTypeOSTypes GoLR CFBundleTypeRole Editor LSIsAppleDefaultForType CFBundleTypeName Golly Macrocell File CFBundleTypeIconFile file-mc.icns CFBundleTypeExtensions mc CFBundleTypeOSTypes GoLM CFBundleTypeRole Editor LSIsAppleDefaultForType CFBundleTypeName Pattern File CFBundleTypeOSTypes **** CFBundleTypeRole Viewer golly-2.7-src/gui-wx/wxpython.cpp0000644000175000017500000031500512536111364014050 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /* Golly uses an embedded Python interpreter to execute scripts. Here is the official Python copyright notice: Copyright (c) 2001-2005 Python Software Foundation. All Rights Reserved. Copyright (c) 2000 BeOpen.com. All Rights Reserved. Copyright (c) 1995-2001 Corporation for National Research Initiatives. All Rights Reserved. Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All Rights Reserved. */ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/filename.h" // for wxFileName #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "readpattern.h" #include "writepattern.h" #include "wxgolly.h" // for wxGetApp, mainptr, viewptr, statusptr #include "wxmain.h" // for mainptr->... #include "wxselect.h" // for Selection #include "wxview.h" // for viewptr->... #include "wxstatus.h" // for statusptr->... #include "wxutils.h" // for Warning, Note, GetString, etc #include "wxprefs.h" // for pythonlib, gollydir, etc #include "wxinfo.h" // for ShowInfo #include "wxhelp.h" // for ShowHelp #include "wxundo.h" // for currlayer->undoredo->... #include "wxalgos.h" // for *_ALGO, CreateNewUniverse, etc #include "wxlayer.h" // for AddLayer, currlayer, currindex, etc #include "wxscript.h" // for inscript, abortmsg, GSF_*, etc #include "wxpython.h" // ============================================================================= // On Windows and Linux we need to load the Python library at runtime // so Golly will start up even if Python isn't installed. // Based on code from Mahogany (mahogany.sourceforge.net) and Vim (www.vim.org). #ifdef __WXMAC__ // avoid warnings (only if using CMake, for some unknown reason) #undef SIZEOF_LONG #undef SIZEOF_SIZE_T #undef SIZEOF_VOID_P #else // load Python lib at runtime #define USE_PYTHON_DYNAMIC #ifdef __UNIX__ // avoid warning on Linux #undef _POSIX_C_SOURCE #undef _XOPEN_SOURCE #endif #ifdef __WXMSW__ // avoid warning on Windows #undef HAVE_SSIZE_T #endif // prevent Python.h from adding Python library to link settings #define USE_DL_EXPORT #endif // workaround for hard-linking to missing python_d.lib #ifdef _DEBUG #undef _DEBUG #include #define _DEBUG #else #include #endif #ifdef USE_PYTHON_DYNAMIC #ifndef __WXMAC__ // avoid warning on Windows/Linux #undef PyRun_SimpleString #endif #include "wx/dynlib.h" // for wxDynamicLibrary // declare G_* wrappers for the functions we want to use from Python lib extern "C" { // startup/shutdown void(*G_Py_Initialize)(void) = NULL; #if defined(__LP64__) || defined(__amd64__) || defined(_WIN64) PyObject*(*G_Py_InitModule4_64)(char*, struct PyMethodDef*, char*, PyObject*, int) = NULL; #else PyObject*(*G_Py_InitModule4)(char*, struct PyMethodDef*, char*, PyObject*, int) = NULL; #endif void(*G_Py_Finalize)(void) = NULL; // errors PyObject*(*G_PyErr_Occurred)(void) = NULL; void(*G_PyErr_SetString)(PyObject*, const char*) = NULL; // ints long(*G_PyInt_AsLong)(PyObject*) = NULL; PyObject*(*G_PyInt_FromLong)(long) = NULL; PyTypeObject* G_PyInt_Type = NULL; // lists PyObject*(*G_PyList_New)(int size) = NULL; int(*G_PyList_Append)(PyObject*, PyObject*) = NULL; PyObject*(*G_PyList_GetItem)(PyObject*, int) = NULL; int(*G_PyList_SetItem)(PyObject*, int, PyObject*) = NULL; int(*G_PyList_Size)(PyObject*) = NULL; PyTypeObject* G_PyList_Type = NULL; // tuples PyObject*(*G_PyTuple_New)(int) = NULL; int(*G_PyTuple_SetItem)(PyObject*, int, PyObject*) = NULL; PyObject*(*G_PyTuple_GetItem)(PyObject*, int) = NULL; // misc int(*G_PyArg_Parse)(PyObject*, char*, ...) = NULL; int(*G_PyArg_ParseTuple)(PyObject*, char*, ...) = NULL; PyObject*(*G_PyImport_ImportModule)(const char*) = NULL; PyObject*(*G_PyDict_GetItemString)(PyObject*, const char*) = NULL; PyObject*(*G_PyModule_GetDict)(PyObject*) = NULL; PyObject*(*G_Py_BuildValue)(char*, ...) = NULL; PyObject*(*G_Py_FindMethod)(PyMethodDef[], PyObject*, char*) = NULL; int(*G_PyRun_SimpleString)(const char*) = NULL; PyObject* G__Py_NoneStruct = NULL; // used by Py_None } // redefine the Py* functions to their equivalent G_* wrappers #define Py_Initialize G_Py_Initialize #if defined(__LP64__) || defined(__amd64__) || defined(_WIN64) #define Py_InitModule4_64 G_Py_InitModule4_64 #else #define Py_InitModule4 G_Py_InitModule4 #endif #define Py_Finalize G_Py_Finalize #define PyErr_Occurred G_PyErr_Occurred #define PyErr_SetString G_PyErr_SetString #define PyInt_AsLong G_PyInt_AsLong #define PyInt_FromLong G_PyInt_FromLong #define PyInt_Type (*G_PyInt_Type) #define PyList_New G_PyList_New #define PyList_Append G_PyList_Append #define PyList_GetItem G_PyList_GetItem #define PyList_SetItem G_PyList_SetItem #define PyList_Size G_PyList_Size #define PyList_Type (*G_PyList_Type) #define PyTuple_New G_PyTuple_New #define PyTuple_SetItem G_PyTuple_SetItem #define PyTuple_GetItem G_PyTuple_GetItem #define Py_BuildValue G_Py_BuildValue #define PyArg_Parse G_PyArg_Parse #define PyArg_ParseTuple G_PyArg_ParseTuple #define PyDict_GetItemString G_PyDict_GetItemString #define PyImport_ImportModule G_PyImport_ImportModule #define PyModule_GetDict G_PyModule_GetDict #define PyRun_SimpleString G_PyRun_SimpleString #define _Py_NoneStruct (*G__Py_NoneStruct) #ifdef __WXMSW__ #define PYTHON_PROC FARPROC #else #define PYTHON_PROC void * #endif #define PYTHON_FUNC(func) { _T(#func), (PYTHON_PROC*)&G_ ## func }, // store function names and their addresses in Python lib static struct PythonFunc { const wxChar* name; // function name PYTHON_PROC* ptr; // function pointer } pythonFuncs[] = { PYTHON_FUNC(Py_Initialize) #if defined(__LP64__) || defined(__amd64__) || defined(_WIN64) PYTHON_FUNC(Py_InitModule4_64) #else PYTHON_FUNC(Py_InitModule4) #endif PYTHON_FUNC(Py_Finalize) PYTHON_FUNC(PyErr_Occurred) PYTHON_FUNC(PyErr_SetString) PYTHON_FUNC(PyInt_AsLong) PYTHON_FUNC(PyInt_FromLong) PYTHON_FUNC(PyInt_Type) PYTHON_FUNC(PyList_New) PYTHON_FUNC(PyList_Append) PYTHON_FUNC(PyList_GetItem) PYTHON_FUNC(PyList_SetItem) PYTHON_FUNC(PyList_Size) PYTHON_FUNC(PyList_Type) PYTHON_FUNC(PyTuple_New) PYTHON_FUNC(PyTuple_SetItem) PYTHON_FUNC(PyTuple_GetItem) PYTHON_FUNC(Py_BuildValue) PYTHON_FUNC(PyArg_Parse) PYTHON_FUNC(PyArg_ParseTuple) PYTHON_FUNC(PyDict_GetItemString) PYTHON_FUNC(PyImport_ImportModule) PYTHON_FUNC(PyModule_GetDict) PYTHON_FUNC(PyRun_SimpleString) PYTHON_FUNC(_Py_NoneStruct) { _T(""), NULL } }; // imported exception objects -- we can't import the symbols from the // lib as this can cause errors (importing data symbols is not reliable) static PyObject* imp_PyExc_RuntimeError = NULL; static PyObject* imp_PyExc_KeyboardInterrupt = NULL; #define PyExc_RuntimeError imp_PyExc_RuntimeError #define PyExc_KeyboardInterrupt imp_PyExc_KeyboardInterrupt static void GetPythonExceptions() { PyObject* exmod = PyImport_ImportModule("exceptions"); PyObject* exdict = PyModule_GetDict(exmod); PyExc_RuntimeError = PyDict_GetItemString(exdict, "RuntimeError"); PyExc_KeyboardInterrupt = PyDict_GetItemString(exdict, "KeyboardInterrupt"); Py_XINCREF(PyExc_RuntimeError); Py_XINCREF(PyExc_KeyboardInterrupt); Py_XDECREF(exmod); } // handle for Python lib static wxDllType pythondll = NULL; static void FreePythonLib() { if ( pythondll ) { wxDynamicLibrary::Unload(pythondll); pythondll = NULL; } } static bool LoadPythonLib() { // load the Python library wxDynamicLibrary dynlib; // don't log errors in here wxLogNull noLog; // wxDL_GLOBAL corresponds to RTLD_GLOBAL on Linux (ignored on Windows) and // is needed to avoid an ImportError when importing some modules (eg. time) while ( !dynlib.Load(pythonlib, wxDL_NOW | wxDL_VERBATIM | wxDL_GLOBAL) ) { // prompt user for a different Python library; // on Windows pythonlib should be something like "python27.dll" // and on Linux it should be something like "libpython2.7.so" Beep(); wxString str = _("If Python isn't installed then you'll have to Cancel,"); str += _("\notherwise change the version numbers to match the"); str += _("\nversion installed on your system and try again."); #ifdef __WXMSW__ str += _("\n\nIf that fails, search your system for a python*.dll"); str += _("\nfile and enter the full path to that file."); #endif wxTextEntryDialog dialog( wxGetActiveWindow(), str, _("Could not load the Python library"), pythonlib, wxOK | wxCANCEL ); if (dialog.ShowModal() == wxID_OK) { pythonlib = dialog.GetValue(); } else { return false; } } if ( dynlib.IsLoaded() ) { // load all functions named in pythonFuncs void* funcptr; PythonFunc* pf = pythonFuncs; while ( pf->name[0] ) { funcptr = dynlib.GetSymbol(pf->name); if ( !funcptr ) { wxString err = _("The Python library does not have this symbol:\n"); err += pf->name; Warning(err); return false; } *(pf++->ptr) = (PYTHON_PROC)funcptr; } pythondll = dynlib.Detach(); } if ( pythondll == NULL ) { // should never happen Warning(_("Oh dear, the Python library is not loaded!")); } return pythondll != NULL; } #endif // USE_PYTHON_DYNAMIC // ============================================================================= // some useful macros #define RETURN_NONE Py_INCREF(Py_None); return Py_None #define PYTHON_ERROR(msg) { PyErr_SetString(PyExc_RuntimeError, msg); return NULL; } #define CheckRGB(r,g,b,cmd) \ if (r < 0 || r > 255 || g < 0 || g > 255 || g < 0 || g > 255) { \ char msg[128]; \ sprintf(msg, "Bad rgb value in %s: %d,%d,%d", cmd, r, g, b); \ PYTHON_ERROR(msg); \ } #ifdef __WXMAC__ // use decomposed UTF8 so fopen will work #define FILENAME wxString(filename,wxConvLocal).fn_str() #else #define FILENAME filename #endif // ----------------------------------------------------------------------------- void AbortPythonScript() { // raise an exception with a special message PyErr_SetString(PyExc_KeyboardInterrupt, abortmsg); } // ----------------------------------------------------------------------------- bool PythonScriptAborted() { if (allowcheck) wxGetApp().Poller()->checkevents(); // if user hit escape key then AbortPythonScript has raised an exception // and PyErr_Occurred will be true; if so, caller must return NULL // otherwise Python can abort app with this message: // Fatal Python error: unexpected exception during garbage collection return PyErr_Occurred() != NULL; } // ----------------------------------------------------------------------------- static void AddTwoInts(PyObject* list, long x, long y) { // append two ints to the given list -- these ints can be: // the x,y coords of a live cell in a one-state cell list, // or the x,y location of a rect, or the wd,ht of a rect PyObject* xo = PyInt_FromLong(x); PyObject* yo = PyInt_FromLong(y); PyList_Append(list, xo); PyList_Append(list, yo); // must decrement references to avoid Python memory leak Py_DECREF(xo); Py_DECREF(yo); } // ----------------------------------------------------------------------------- static void AddState(PyObject* list, long s) { // append cell state (possibly dead) to a multi-state cell list PyObject* so = PyInt_FromLong(s); PyList_Append(list, so); Py_DECREF(so); } // ----------------------------------------------------------------------------- static void AddPadding(PyObject* list) { // assume list is multi-state and add an extra int if necessary so the list // has an odd number of ints (this is how we distinguish multi-state lists // from one-state lists -- the latter always have an even number of ints) int len = PyList_Size(list); if (len == 0) return; // always return [] rather than [0] if ((len & 1) == 0) { PyObject* padding = PyInt_FromLong(0L); PyList_Append(list, padding); Py_DECREF(padding); } } // ----------------------------------------------------------------------------- static void AddCellColor(PyObject* list, long s, long r, long g, long b) { // append state,r,g,b values to given list PyObject* so = PyInt_FromLong(s); PyObject* ro = PyInt_FromLong(r); PyObject* go = PyInt_FromLong(g); PyObject* bo = PyInt_FromLong(b); PyList_Append(list, so); PyList_Append(list, ro); PyList_Append(list, go); PyList_Append(list, bo); // must decrement references to avoid Python memory leak Py_DECREF(so); Py_DECREF(ro); Py_DECREF(go); Py_DECREF(bo); } // ----------------------------------------------------------------------------- static bool ExtractCellList(PyObject* list, lifealgo* universe, bool shift = false) { // extract cell list from given universe if ( !universe->isEmpty() ) { bigint top, left, bottom, right; universe->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { PyErr_SetString(PyExc_RuntimeError, "Universe is too big to extract all cells!"); return false; } bool multistate = universe->NumCellStates() > 2; int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int cx, cy; int v = 0; int cntr = 0; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = universe->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (shift) { // shift cells so that top left cell of bounding box is at 0,0 AddTwoInts(list, cx - ileft, cy - itop); } else { AddTwoInts(list, cx, cy); } if (multistate) AddState(list, v); } else { cx = iright; // done this row } cntr++; if ((cntr % 4096) == 0 && PythonScriptAborted()) return false; } } if (multistate) AddPadding(list); } return true; } // ============================================================================= // The following py_* routines can be called from Python scripts; some are // based on code in PLife's lifeint.cc (see http://plife.sourceforge.net/). static PyObject* py_open(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* filename; int remember = 0; if (!PyArg_ParseTuple(args, (char*)"s|i", &filename, &remember)) return NULL; const char* err = GSF_open(filename, remember); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_save(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* filename; char* format; int remember = 0; if (!PyArg_ParseTuple(args, (char*)"ss|i", &filename, &format, &remember)) return NULL; const char* err = GSF_save(filename, format, remember); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_opendialog(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); const char* title = "Choose a file"; const char* filetypes = "All files (*)|*"; const char* initialdir = ""; const char* initialfname = ""; int mustexist = 1; if (!PyArg_ParseTuple(args, (char*)"|ssssi", &title, &filetypes, &initialdir, &initialfname, &mustexist)) return NULL; wxString wxs_title(title, wxConvLocal); wxString wxs_filetypes(filetypes, wxConvLocal); wxString wxs_initialdir(initialdir, wxConvLocal); wxString wxs_initialfname(initialfname, wxConvLocal); wxString wxs_result = wxEmptyString; if (wxs_initialdir.IsEmpty()) wxs_initialdir = wxFileName::GetCwd(); if (wxs_filetypes == wxT("dir")) { // let user choose a directory wxDirDialog dirdlg(NULL, wxs_title, wxs_initialdir, wxDD_NEW_DIR_BUTTON); if (dirdlg.ShowModal() == wxID_OK) { wxs_result = dirdlg.GetPath(); if (wxs_result.Last() != wxFILE_SEP_PATH) wxs_result += wxFILE_SEP_PATH; } } else { // let user choose a file wxFileDialog opendlg(NULL, wxs_title, wxs_initialdir, wxs_initialfname, wxs_filetypes, wxFD_OPEN | (mustexist == 0 ? 0 : wxFD_FILE_MUST_EXIST) ); #ifdef __WXGTK__ // wxs_initialdir is ignored above (bug in wxGTK 2.8.0???) opendlg.SetDirectory(wxs_initialdir); #endif if (opendlg.ShowModal() == wxID_OK) wxs_result = opendlg.GetPath(); } return Py_BuildValue((char*)"s", (const char*)wxs_result.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- static PyObject* py_savedialog(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); const char* title = "Choose a save location and filename"; const char* filetypes = "All files (*)|*"; const char* initialdir = ""; const char* initialfname = ""; int suppressprompt = 0; if (!PyArg_ParseTuple(args, (char*)"|ssssi", &title, &filetypes, &initialdir, &initialfname, &suppressprompt)) return NULL; wxString wxs_title(title, wxConvLocal); wxString wxs_filetypes(filetypes, wxConvLocal); wxString wxs_initialdir(initialdir, wxConvLocal); wxString wxs_initialfname(initialfname, wxConvLocal); if (wxs_initialdir.IsEmpty()) wxs_initialdir = wxFileName::GetCwd(); wxFileDialog savedlg( NULL, wxs_title, wxs_initialdir, wxs_initialfname, wxs_filetypes, wxFD_SAVE | (suppressprompt == 0 ? wxFD_OVERWRITE_PROMPT : 0) ); #ifdef __WXGTK__ savedlg.SetDirectory(wxs_initialdir); #endif wxString wxs_savefname = wxEmptyString; if ( savedlg.ShowModal() == wxID_OK ) wxs_savefname = savedlg.GetPath(); return Py_BuildValue((char*)"s", (const char*)wxs_savefname.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- static PyObject* py_load(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* filename; if (!PyArg_ParseTuple(args, (char*)"s", &filename)) return NULL; // create temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, allowcheck); // readpattern will call setrule // read pattern into temporary universe const char* err = readpattern(FILENAME, *tempalgo); if (err) { // try all other algos until readpattern succeeds for (int i = 0; i < NumAlgos(); i++) { if (i != currlayer->algtype) { delete tempalgo; tempalgo = CreateNewUniverse(i, allowcheck); err = readpattern(FILENAME, *tempalgo); if (!err) break; } } } if (err) { delete tempalgo; PYTHON_ERROR(err); } // convert pattern into a cell list, shifting cell coords so that the // bounding box's top left cell is at 0,0 PyObject* outlist = PyList_New(0); bool done = ExtractCellList(outlist, tempalgo, true); delete tempalgo; if (!done) { Py_DECREF(outlist); return NULL; } return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_store(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* inlist; char* filename; if (!PyArg_ParseTuple(args, (char*)"O!s|s", &PyList_Type, &inlist, &filename)) return NULL; // create temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, allowcheck); const char* err = tempalgo->setrule(currlayer->algo->getrule()); if (err) tempalgo->setrule(tempalgo->DefaultRule()); // copy cell list into temporary universe bool multistate = (PyList_Size(inlist) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = PyList_Size(inlist) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; long x = PyInt_AsLong( PyList_GetItem(inlist, item) ); long y = PyInt_AsLong( PyList_GetItem(inlist, item + 1) ); // check if x,y is outside bounded grid const char* err = GSF_checkpos(tempalgo, x, y); if (err) { delete tempalgo; PYTHON_ERROR(err); } if (multistate) { long state = PyInt_AsLong( PyList_GetItem(inlist, item + 2) ); if (tempalgo->setcell(x, y, state) < 0) { tempalgo->endofpattern(); delete tempalgo; PYTHON_ERROR("store error: state value is out of range."); } } else { tempalgo->setcell(x, y, 1); } if ((n % 4096) == 0 && PythonScriptAborted()) { tempalgo->endofpattern(); delete tempalgo; return NULL; } } tempalgo->endofpattern(); // write pattern to given file in RLE/XRLE format bigint top, left, bottom, right; tempalgo->findedges(&top, &left, &bottom, &right); pattern_format format = savexrle ? XRLE_format : RLE_format; // if grid is bounded then force XRLE_format so that position info is recorded if (tempalgo->gridwd > 0 || tempalgo->gridht > 0) format = XRLE_format; err = writepattern(FILENAME, *tempalgo, format, no_compression, top.toint(), left.toint(), bottom.toint(), right.toint()); delete tempalgo; if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- // deprecated (use py_getdir) static PyObject* py_appdir(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"s", (const char*)gollydir.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- // deprecated (use py_getdir) static PyObject* py_datadir(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"s", (const char*)datadir.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- static PyObject* py_setdir(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* dirname; char* newdir; if (!PyArg_ParseTuple(args, (char*)"ss", &dirname, &newdir)) return NULL; const char* err = GSF_setdir(dirname, newdir); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getdir(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* dirname; if (!PyArg_ParseTuple(args, (char*)"s", &dirname)) return NULL; const char* dirstring = GSF_getdir(dirname); if (dirstring == NULL) PYTHON_ERROR("getdir error: unknown directory name."); return Py_BuildValue((char*)"s", dirstring); } // ----------------------------------------------------------------------------- static PyObject* py_new(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* title; if (!PyArg_ParseTuple(args, (char*)"s", &title)) return NULL; mainptr->NewPattern(wxString(title,wxConvLocal)); DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_cut(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (viewptr->SelectionExists()) { viewptr->CutSelection(); DoAutoUpdate(); } else { PYTHON_ERROR("cut error: no selection."); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_copy(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (viewptr->SelectionExists()) { viewptr->CopySelection(); DoAutoUpdate(); } else { PYTHON_ERROR("copy error: no selection."); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_clear(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int where; if (!PyArg_ParseTuple(args, (char*)"i", &where)) return NULL; if (viewptr->SelectionExists()) { if (where == 0) viewptr->ClearSelection(); else viewptr->ClearOutsideSelection(); DoAutoUpdate(); } else { PYTHON_ERROR("clear error: no selection."); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_paste(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int x, y; char* mode; if (!PyArg_ParseTuple(args, (char*)"iis", &x, &y, &mode)) return NULL; const char* err = GSF_paste(x, y, mode); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_shrink(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (viewptr->SelectionExists()) { viewptr->ShrinkSelection(false); // false == don't fit in viewport DoAutoUpdate(); } else { PYTHON_ERROR("shrink error: no selection."); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_randfill(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int perc; if (!PyArg_ParseTuple(args, (char*)"i", &perc)) return NULL; if (perc < 1 || perc > 100) { PYTHON_ERROR("randfill error: percentage must be from 1 to 100."); } if (viewptr->SelectionExists()) { int oldperc = randomfill; randomfill = perc; viewptr->RandomFill(); randomfill = oldperc; DoAutoUpdate(); } else { PYTHON_ERROR("randfill error: no selection."); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_flip(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int direction; if (!PyArg_ParseTuple(args, (char*)"i", &direction)) return NULL; if (viewptr->SelectionExists()) { viewptr->FlipSelection(direction != 0); // 1 = top-bottom DoAutoUpdate(); } else { PYTHON_ERROR("flip error: no selection."); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_rotate(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int direction; if (!PyArg_ParseTuple(args, (char*)"i", &direction)) return NULL; if (viewptr->SelectionExists()) { viewptr->RotateSelection(direction == 0); // 0 = clockwise DoAutoUpdate(); } else { PYTHON_ERROR("rotate error: no selection."); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_parse(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* s; // defaults for optional params long x0 = 0; long y0 = 0; long axx = 1; long axy = 0; long ayx = 0; long ayy = 1; if (!PyArg_ParseTuple(args, (char*)"s|llllll", &s, &x0, &y0, &axx, &axy, &ayx, &ayy)) return NULL; PyObject* outlist = PyList_New(0); long x = 0, y = 0; if (strchr(s, '*')) { // parsing 'visual' format int c = *s++; while (c) { switch (c) { case '\n': if (x) { x = 0; y++; } break; case '.': x++; break; case '*': AddTwoInts(outlist, x0 + x * axx + y * axy, y0 + x * ayx + y * ayy); x++; break; } c = *s++; } } else { // parsing RLE format; first check if multi-state data is present bool multistate = false; char* p = s; while (*p) { char c = *p++; if ((c == '.') || ('p' <= c && c <= 'y') || ('A' <= c && c <= 'X')) { multistate = true; break; } } int prefix = 0; bool done = false; int c = *s++; while (c && !done) { if (isdigit(c)) prefix = 10 * prefix + (c - '0'); else { prefix += (prefix == 0); switch (c) { case '!': done = true; break; case '$': x = 0; y += prefix; break; case 'b': x += prefix; break; case '.': x += prefix; break; case 'o': for (int k = 0; k < prefix; k++, x++) { AddTwoInts(outlist, x0 + x * axx + y * axy, y0 + x * ayx + y * ayy); if (multistate) AddState(outlist, 1); } break; default: if (('p' <= c && c <= 'y') || ('A' <= c && c <= 'X')) { // multistate must be true int state; if (c < 'p') { state = c - 'A' + 1; } else { state = 24 * (c - 'p' + 1); c = *s++; if ('A' <= c && c <= 'X') { state = state + c - 'A' + 1; } else { // Py_DECREF(outlist); // PYTHON_ERROR("parse error: illegal multi-char state."); // be more forgiving and treat 'p'..'y' like 'o' state = 1; s--; } } for (int k = 0; k < prefix; k++, x++) { AddTwoInts(outlist, x0 + x * axx + y * axy, y0 + x * ayx + y * ayy); AddState(outlist, state); } } } prefix = 0; } c = *s++; } if (multistate) AddPadding(outlist); } return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_transform(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* inlist; long x0, y0; // defaults for optional params long axx = 1; long axy = 0; long ayx = 0; long ayy = 1; if (!PyArg_ParseTuple(args, (char*)"O!ll|llll", &PyList_Type, &inlist, &x0, &y0, &axx, &axy, &ayx, &ayy)) return NULL; PyObject* outlist = PyList_New(0); bool multistate = (PyList_Size(inlist) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = PyList_Size(inlist) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; long x = PyInt_AsLong( PyList_GetItem(inlist, item) ); long y = PyInt_AsLong( PyList_GetItem(inlist, item + 1) ); AddTwoInts(outlist, x0 + x * axx + y * axy, y0 + x * ayx + y * ayy); if (multistate) { long state = PyInt_AsLong( PyList_GetItem(inlist, item + 2) ); AddState(outlist, state); } if ((n % 4096) == 0 && PythonScriptAborted()) { Py_DECREF(outlist); return NULL; } } if (multistate) AddPadding(outlist); return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_evolve(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int ngens = 0; PyObject* inlist; if (!PyArg_ParseTuple(args, (char*)"O!i", &PyList_Type, &inlist, &ngens)) return NULL; if (ngens < 0) { PYTHON_ERROR("evolve error: number of generations is negative."); } // create a temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, allowcheck); const char* err = tempalgo->setrule(currlayer->algo->getrule()); if (err) tempalgo->setrule(tempalgo->DefaultRule()); // copy cell list into temporary universe bool multistate = (PyList_Size(inlist) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = PyList_Size(inlist) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; long x = PyInt_AsLong( PyList_GetItem(inlist, item) ); long y = PyInt_AsLong( PyList_GetItem(inlist, item + 1) ); // check if x,y is outside bounded grid const char* err = GSF_checkpos(tempalgo, x, y); if (err) { delete tempalgo; PYTHON_ERROR(err); } if (multistate) { long state = PyInt_AsLong( PyList_GetItem(inlist, item + 2) ); if (tempalgo->setcell(x, y, state) < 0) { tempalgo->endofpattern(); delete tempalgo; PYTHON_ERROR("evolve error: state value is out of range."); } } else { tempalgo->setcell(x, y, 1); } if ((n % 4096) == 0 && PythonScriptAborted()) { tempalgo->endofpattern(); delete tempalgo; return NULL; } } tempalgo->endofpattern(); // advance pattern by ngens mainptr->generating = true; if (tempalgo->gridwd > 0 || tempalgo->gridht > 0) { // a bounded grid must use an increment of 1 so we can call // CreateBorderCells and DeleteBorderCells around each step() tempalgo->setIncrement(1); while (ngens > 0) { if (PythonScriptAborted()) { mainptr->generating = false; delete tempalgo; return NULL; } if (!mainptr->CreateBorderCells(tempalgo)) break; tempalgo->step(); if (!mainptr->DeleteBorderCells(tempalgo)) break; ngens--; } } else { tempalgo->setIncrement(ngens); tempalgo->step(); } mainptr->generating = false; // convert new pattern into a new cell list PyObject* outlist = PyList_New(0); bool done = ExtractCellList(outlist, tempalgo); delete tempalgo; if (!done) { Py_DECREF(outlist); return NULL; } return outlist; } // ----------------------------------------------------------------------------- static const char* BAD_STATE = "putcells error: state value is out of range."; static PyObject* py_putcells(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* list; // defaults for optional params long x0 = 0; long y0 = 0; long axx = 1; long axy = 0; long ayx = 0; long ayy = 1; // default for mode is 'or'; 'xor' mode is also supported; // for a one-state list 'copy' mode currently has the same effect as 'or' mode // because there is no bounding box to set dead cells, but a multi-state list can // have dead cells so in that case 'copy' mode is not the same as 'or' mode const char* mode = "or"; if (!PyArg_ParseTuple(args, (char*)"O!|lllllls", &PyList_Type, &list, &x0, &y0, &axx, &axy, &ayx, &ayy, &mode)) return NULL; wxString modestr = wxString(mode, wxConvLocal); if ( !( modestr.IsSameAs(wxT("or"), false) || modestr.IsSameAs(wxT("xor"), false) || modestr.IsSameAs(wxT("copy"), false) || modestr.IsSameAs(wxT("and"), false) || modestr.IsSameAs(wxT("not"), false)) ) { PYTHON_ERROR("putcells error: unknown mode."); } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; // use ChangeCell below and combine all changes due to consecutive setcell/putcells // if (savecells) SavePendingChanges(); bool multistate = (PyList_Size(list) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = PyList_Size(list) / ints_per_cell; bool abort = false; const char* err = NULL; bool pattchanged = false; lifealgo* curralgo = currlayer->algo; if (modestr.IsSameAs(wxT("copy"), false)) { // TODO: find bounds of cell list and call ClearRect here (to be added to wxedit.cpp) } if (modestr.IsSameAs(wxT("and"), false)) { if (!curralgo->isEmpty()) { int newstate = 1; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; long x = PyInt_AsLong( PyList_GetItem(list, item) ); long y = PyInt_AsLong( PyList_GetItem(list, item + 1) ); int newx = x0 + x * axx + y * axy; int newy = y0 + x * ayx + y * ayy; // check if newx,newy is outside bounded grid err = GSF_checkpos(curralgo, newx, newy); if (err) break; int oldstate = curralgo->getcell(newx, newy); if (multistate) { // multi-state lists can contain dead cells so newstate might be 0 newstate = PyInt_AsLong( PyList_GetItem(list, item + 2) ); } if (newstate != oldstate && oldstate > 0) { curralgo->setcell(newx, newy, 0); if (savecells) ChangeCell(newx, newy, oldstate, 0); pattchanged = true; } if ((n % 4096) == 0 && PythonScriptAborted()) { abort = true; break; } } } } else if (modestr.IsSameAs(wxT("xor"), false)) { // loop code is duplicated here to allow 'or' case to execute faster int numstates = curralgo->NumCellStates(); for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; long x = PyInt_AsLong( PyList_GetItem(list, item) ); long y = PyInt_AsLong( PyList_GetItem(list, item + 1) ); int newx = x0 + x * axx + y * axy; int newy = y0 + x * ayx + y * ayy; // check if newx,newy is outside bounded grid err = GSF_checkpos(curralgo, newx, newy); if (err) break; int oldstate = curralgo->getcell(newx, newy); int newstate; if (multistate) { // multi-state lists can contain dead cells so newstate might be 0 newstate = PyInt_AsLong( PyList_GetItem(list, item + 2) ); if (newstate == oldstate) { if (oldstate != 0) newstate = 0; } else { newstate = newstate ^ oldstate; // if xor overflows then don't change current state if (newstate >= numstates) newstate = oldstate; } if (newstate != oldstate) { // paste (possibly transformed) cell into current universe if (curralgo->setcell(newx, newy, newstate) < 0) { PyErr_SetString(PyExc_RuntimeError, BAD_STATE); abort = true; break; } if (savecells) ChangeCell(newx, newy, oldstate, newstate); pattchanged = true; } } else { // one-state lists only contain live cells newstate = 1 - oldstate; // paste (possibly transformed) cell into current universe if (curralgo->setcell(newx, newy, newstate) < 0) { PyErr_SetString(PyExc_RuntimeError, BAD_STATE); abort = true; break; } if (savecells) ChangeCell(newx, newy, oldstate, newstate); pattchanged = true; } if ((n % 4096) == 0 && PythonScriptAborted()) { abort = true; break; } } } else { bool notmode = modestr.IsSameAs(wxT("not"), false); bool ormode = modestr.IsSameAs(wxT("or"), false); int newstate = notmode ? 0 : 1; int maxstate = curralgo->NumCellStates() - 1; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; long x = PyInt_AsLong( PyList_GetItem(list, item) ); long y = PyInt_AsLong( PyList_GetItem(list, item + 1) ); int newx = x0 + x * axx + y * axy; int newy = y0 + x * ayx + y * ayy; // check if newx,newy is outside bounded grid err = GSF_checkpos(curralgo, newx, newy); if (err) break; int oldstate = curralgo->getcell(newx, newy); if (multistate) { // multi-state lists can contain dead cells so newstate might be 0 newstate = PyInt_AsLong( PyList_GetItem(list, item + 2) ); if (notmode) newstate = maxstate - newstate; if (ormode && newstate == 0) newstate = oldstate; } if (newstate != oldstate) { // paste (possibly transformed) cell into current universe if (curralgo->setcell(newx, newy, newstate) < 0) { PyErr_SetString(PyExc_RuntimeError, BAD_STATE); abort = true; break; } if (savecells) ChangeCell(newx, newy, oldstate, newstate); pattchanged = true; } if ((n % 4096) == 0 && PythonScriptAborted()) { abort = true; break; } } } if (pattchanged) { curralgo->endofpattern(); MarkLayerDirty(); DoAutoUpdate(); } if (err) PYTHON_ERROR(err); if (abort) return NULL; RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getcells(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* rect_list; if (!PyArg_ParseTuple(args, (char*)"O!", &PyList_Type, &rect_list)) return NULL; // convert pattern in given rect into a cell list PyObject* outlist = PyList_New(0); int numitems = PyList_Size(rect_list); if (numitems == 0) { // return empty cell list } else if (numitems == 4) { int ileft = PyInt_AsLong( PyList_GetItem(rect_list, 0) ); int itop = PyInt_AsLong( PyList_GetItem(rect_list, 1) ); int wd = PyInt_AsLong( PyList_GetItem(rect_list, 2) ); int ht = PyInt_AsLong( PyList_GetItem(rect_list, 3) ); const char* err = GSF_checkrect(ileft, itop, wd, ht); if (err) { Py_DECREF(outlist); PYTHON_ERROR(err); } int iright = ileft + wd - 1; int ibottom = itop + ht - 1; int cx, cy; int v = 0; int cntr = 0; lifealgo* curralgo = currlayer->algo; bool multistate = curralgo->NumCellStates() > 2; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (cx <= iright) { AddTwoInts(outlist, cx, cy); if (multistate) AddState(outlist, v); } } else { cx = iright; // done this row } cntr++; if ((cntr % 4096) == 0 && PythonScriptAborted()) { Py_DECREF(outlist); return NULL; } } } if (multistate) AddPadding(outlist); } else { Py_DECREF(outlist); PYTHON_ERROR("getcells error: arg must be [] or [x,y,wd,ht]."); } return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_join(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* inlist1; PyObject* inlist2; if (!PyArg_ParseTuple(args, (char*)"O!O!", &PyList_Type, &inlist1, &PyList_Type, &inlist2)) return NULL; bool multi1 = (PyList_Size(inlist1) & 1) == 1; bool multi2 = (PyList_Size(inlist2) & 1) == 1; bool multiout = multi1 || multi2; int ints_per_cell, num_cells; long x, y, state; PyObject* outlist = PyList_New(0); // append 1st list ints_per_cell = multi1 ? 3 : 2; num_cells = PyList_Size(inlist1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; x = PyInt_AsLong( PyList_GetItem(inlist1, item) ); y = PyInt_AsLong( PyList_GetItem(inlist1, item + 1) ); if (multi1) { state = PyInt_AsLong( PyList_GetItem(inlist1, item + 2) ); } else { state = 1; } AddTwoInts(outlist, x, y); if (multiout) AddState(outlist, state); if ((n % 4096) == 0 && PythonScriptAborted()) { Py_DECREF(outlist); return NULL; } } // append 2nd list ints_per_cell = multi2 ? 3 : 2; num_cells = PyList_Size(inlist2) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; x = PyInt_AsLong( PyList_GetItem(inlist2, item) ); y = PyInt_AsLong( PyList_GetItem(inlist2, item + 1) ); if (multi2) { state = PyInt_AsLong( PyList_GetItem(inlist2, item + 2) ); } else { state = 1; } AddTwoInts(outlist, x, y); if (multiout) AddState(outlist, state); if ((n % 4096) == 0 && PythonScriptAborted()) { Py_DECREF(outlist); return NULL; } } if (multiout) AddPadding(outlist); return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_hash(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* rect_list; if (!PyArg_ParseTuple(args, (char*)"O!", &PyList_Type, &rect_list)) return NULL; int numitems = PyList_Size(rect_list); if (numitems != 4) { PYTHON_ERROR("hash error: arg must be [x,y,wd,ht]."); } int x = PyInt_AsLong( PyList_GetItem(rect_list, 0) ); int y = PyInt_AsLong( PyList_GetItem(rect_list, 1) ); int wd = PyInt_AsLong( PyList_GetItem(rect_list, 2) ); int ht = PyInt_AsLong( PyList_GetItem(rect_list, 3) ); const char* err = GSF_checkrect(x, y, wd, ht); if (err) PYTHON_ERROR(err); int hash = GSF_hash(x, y, wd, ht); return Py_BuildValue((char*)"i", hash); } // ----------------------------------------------------------------------------- static PyObject* py_getclip(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (!mainptr->ClipboardHasText()) { PYTHON_ERROR("getclip error: no pattern in clipboard."); } // convert pattern in clipboard into a cell list, but where the first 2 items // are the pattern's width and height (not necessarily the minimal bounding box // because the pattern might have empty borders, or it might even be empty) PyObject* outlist = PyList_New(0); // create a temporary universe for storing clipboard pattern; // GetClipboardPattern assumes it is same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, allowcheck); const char* err = tempalgo->setrule(currlayer->algo->getrule()); if (err) tempalgo->setrule(tempalgo->DefaultRule()); // read clipboard pattern into temporary universe and set edges // (not a minimal bounding box if pattern is empty or has empty borders) bigint top, left, bottom, right; if ( viewptr->GetClipboardPattern(&tempalgo, &top, &left, &bottom, &right) ) { if ( viewptr->OutsideLimits(top, left, bottom, right) ) { delete tempalgo; Py_DECREF(outlist); PYTHON_ERROR("getclip error: pattern is too big."); } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; AddTwoInts(outlist, wd, ht); // extract cells from tempalgo bool multistate = tempalgo->NumCellStates() > 2; int cx, cy; int cntr = 0; int v = 0; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = tempalgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; // shift cells so that top left cell of bounding box is at 0,0 AddTwoInts(outlist, cx - ileft, cy - itop); if (multistate) AddState(outlist, v); } else { cx = iright; // done this row } cntr++; if ((cntr % 4096) == 0 && PythonScriptAborted()) { delete tempalgo; Py_DECREF(outlist); return NULL; } } } // if no live cells then return [wd,ht] rather than [wd,ht,0] if (multistate && PyList_Size(outlist) > 2) { AddPadding(outlist); } delete tempalgo; } else { // assume error message has been displayed delete tempalgo; Py_DECREF(outlist); return NULL; } return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_select(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* rect_list; if (!PyArg_ParseTuple(args, (char*)"O!", &PyList_Type, &rect_list)) return NULL; int numitems = PyList_Size(rect_list); if (numitems == 0) { // remove any existing selection GSF_select(0, 0, 0, 0); } else if (numitems == 4) { int x = PyInt_AsLong( PyList_GetItem(rect_list, 0) ); int y = PyInt_AsLong( PyList_GetItem(rect_list, 1) ); int wd = PyInt_AsLong( PyList_GetItem(rect_list, 2) ); int ht = PyInt_AsLong( PyList_GetItem(rect_list, 3) ); const char* err = GSF_checkrect(x, y, wd, ht); if (err) PYTHON_ERROR(err); // set selection rect GSF_select(x, y, wd, ht); } else { PYTHON_ERROR("select error: arg must be [] or [x,y,wd,ht]."); } DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getrect(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; PyObject* outlist = PyList_New(0); if (!currlayer->algo->isEmpty()) { bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { Py_DECREF(outlist); PYTHON_ERROR("getrect error: pattern is too big."); } long x = left.toint(); long y = top.toint(); long wd = right.toint() - x + 1; long ht = bottom.toint() - y + 1; AddTwoInts(outlist, x, y); AddTwoInts(outlist, wd, ht); } return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_getselrect(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; PyObject* outlist = PyList_New(0); if (viewptr->SelectionExists()) { if (currlayer->currsel.TooBig()) { Py_DECREF(outlist); PYTHON_ERROR("getselrect error: selection is too big."); } int x, y, wd, ht; currlayer->currsel.GetRect(&x, &y, &wd, &ht); AddTwoInts(outlist, x, y); AddTwoInts(outlist, wd, ht); } return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_setcell(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int x, y, state; if (!PyArg_ParseTuple(args, (char*)"iii", &x, &y, &state)) return NULL; const char* err = GSF_setcell(x, y, state); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getcell(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int x, y; if (!PyArg_ParseTuple(args, (char*)"ii", &x, &y)) return NULL; // check if x,y is outside bounded grid const char* err = GSF_checkpos(currlayer->algo, x, y); if (err) PYTHON_ERROR(err); return Py_BuildValue((char*)"i", currlayer->algo->getcell(x, y)); } // ----------------------------------------------------------------------------- static PyObject* py_setcursor(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); const char* newcursor; if (!PyArg_ParseTuple(args, (char*)"s", &newcursor)) return NULL; const char* oldcursor = CursorToString(currlayer->curs); wxCursor* cursptr = StringToCursor(newcursor); if (cursptr) { viewptr->SetCursorMode(cursptr); // see the cursor change, including button in edit bar mainptr->UpdateUserInterface(); } else { PYTHON_ERROR("setcursor error: unknown cursor string."); } // return old cursor (simplifies saving and restoring cursor) return Py_BuildValue((char*)"s", oldcursor); } // ----------------------------------------------------------------------------- static PyObject* py_getcursor(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"s", CursorToString(currlayer->curs)); } // ----------------------------------------------------------------------------- static PyObject* py_empty(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", currlayer->algo->isEmpty() ? 1 : 0); } // ----------------------------------------------------------------------------- static PyObject* py_run(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int ngens; if (!PyArg_ParseTuple(args, (char*)"i", &ngens)) return NULL; if (ngens > 0 && !currlayer->algo->isEmpty()) { if (ngens > 1) { bigint saveinc = currlayer->algo->getIncrement(); currlayer->algo->setIncrement(ngens); mainptr->NextGeneration(true); // step by ngens currlayer->algo->setIncrement(saveinc); } else { mainptr->NextGeneration(false); // step 1 gen } DoAutoUpdate(); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_step(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (!currlayer->algo->isEmpty()) { mainptr->NextGeneration(true); // step by current increment DoAutoUpdate(); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_setstep(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int exp; if (!PyArg_ParseTuple(args, (char*)"i", &exp)) return NULL; mainptr->SetStepExponent(exp); DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getstep(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", currlayer->currexpo); } // ----------------------------------------------------------------------------- static PyObject* py_setbase(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int base; if (!PyArg_ParseTuple(args, (char*)"i", &base)) return NULL; if (base < 2) base = 2; if (base > MAX_BASESTEP) base = MAX_BASESTEP; currlayer->currbase = base; mainptr->SetGenIncrement(); DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getbase(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", currlayer->currbase); } // ----------------------------------------------------------------------------- static PyObject* py_advance(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int where, ngens; if (!PyArg_ParseTuple(args, (char*)"ii", &where, &ngens)) return NULL; if (ngens > 0) { if (viewptr->SelectionExists()) { while (ngens > 0) { ngens--; if (where == 0) currlayer->currsel.Advance(); else currlayer->currsel.AdvanceOutside(); } DoAutoUpdate(); } else { PYTHON_ERROR("advance error: no selection."); } } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_reset(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (currlayer->algo->getGeneration() != currlayer->startgen) { mainptr->ResetPattern(); DoAutoUpdate(); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_setgen(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* genstring = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &genstring)) return NULL; const char* err = GSF_setgen(genstring); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getgen(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char sepchar = '\0'; if (!PyArg_ParseTuple(args, (char*)"|c", &sepchar)) return NULL; return Py_BuildValue((char*)"s", currlayer->algo->getGeneration().tostring(sepchar)); } // ----------------------------------------------------------------------------- static PyObject* py_getpop(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char sepchar = '\0'; if (!PyArg_ParseTuple(args, (char*)"|c", &sepchar)) return NULL; return Py_BuildValue((char*)"s", currlayer->algo->getPopulation().tostring(sepchar)); } // ----------------------------------------------------------------------------- static PyObject* py_setalgo(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* algostring = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &algostring)) return NULL; const char* err = GSF_setalgo(algostring); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getalgo(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int index = currlayer->algtype; if (!PyArg_ParseTuple(args, (char*)"|i", &index)) return NULL; if (index < 0 || index >= NumAlgos()) { char msg[64]; sprintf(msg, "Bad getalgo index: %d", index); PYTHON_ERROR(msg); } return Py_BuildValue((char*)"s", GetAlgoName(index)); } // ----------------------------------------------------------------------------- static PyObject* py_setrule(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* rulestring = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &rulestring)) return NULL; const char* err = GSF_setrule(rulestring); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getrule(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"s", currlayer->algo->getrule()); } // ----------------------------------------------------------------------------- static PyObject* py_getwidth(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", currlayer->algo->gridwd); } // ----------------------------------------------------------------------------- static PyObject* py_getheight(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", currlayer->algo->gridht); } // ----------------------------------------------------------------------------- static PyObject* py_numstates(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", currlayer->algo->NumCellStates()); } // ----------------------------------------------------------------------------- static PyObject* py_numalgos(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", NumAlgos()); } // ----------------------------------------------------------------------------- static PyObject* py_setpos(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* x; char* y; if (!PyArg_ParseTuple(args, (char*)"ss", &x, &y)) return NULL; const char* err = GSF_setpos(x, y); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getpos(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char sepchar = '\0'; if (!PyArg_ParseTuple(args, (char*)"|c", &sepchar)) return NULL; bigint bigx, bigy; viewptr->GetPos(bigx, bigy); // return position as x,y tuple PyObject* xytuple = PyTuple_New(2); PyTuple_SetItem(xytuple, 0, Py_BuildValue((char*)"s",bigx.tostring(sepchar))); PyTuple_SetItem(xytuple, 1, Py_BuildValue((char*)"s",bigy.tostring(sepchar))); return xytuple; } // ----------------------------------------------------------------------------- static PyObject* py_setmag(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int mag; if (!PyArg_ParseTuple(args, (char*)"i", &mag)) return NULL; viewptr->SetMag(mag); DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getmag(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", viewptr->GetMag()); } // ----------------------------------------------------------------------------- static PyObject* py_fit(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; viewptr->FitPattern(); DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_fitsel(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (viewptr->SelectionExists()) { viewptr->FitSelection(); DoAutoUpdate(); } else { PYTHON_ERROR("fitsel error: no selection."); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_visrect(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* rect_list; if (!PyArg_ParseTuple(args, (char*)"O!", &PyList_Type, &rect_list)) return NULL; int numitems = PyList_Size(rect_list); if (numitems != 4) { PYTHON_ERROR("visrect error: arg must be [x,y,wd,ht]."); } int x = PyInt_AsLong( PyList_GetItem(rect_list, 0) ); int y = PyInt_AsLong( PyList_GetItem(rect_list, 1) ); int wd = PyInt_AsLong( PyList_GetItem(rect_list, 2) ); int ht = PyInt_AsLong( PyList_GetItem(rect_list, 3) ); const char* err = GSF_checkrect(x, y, wd, ht); if (err) PYTHON_ERROR(err); bigint left = x; bigint top = y; bigint right = x + wd - 1; bigint bottom = y + ht - 1; int visible = viewptr->CellVisible(left, top) && viewptr->CellVisible(right, bottom); return Py_BuildValue((char*)"i", visible); } // ----------------------------------------------------------------------------- static PyObject* py_update(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; GSF_update(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_autoupdate(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int flag; if (!PyArg_ParseTuple(args, (char*)"i", &flag)) return NULL; autoupdate = (flag != 0); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_addlayer(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (numlayers >= MAX_LAYERS) { PYTHON_ERROR("addlayer error: no more layers can be added."); } else { AddLayer(); DoAutoUpdate(); } // return index of new layer return Py_BuildValue((char*)"i", currindex); } // ----------------------------------------------------------------------------- static PyObject* py_clone(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (numlayers >= MAX_LAYERS) { PYTHON_ERROR("clone error: no more layers can be added."); } else { CloneLayer(); DoAutoUpdate(); } // return index of new layer return Py_BuildValue((char*)"i", currindex); } // ----------------------------------------------------------------------------- static PyObject* py_duplicate(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (numlayers >= MAX_LAYERS) { PYTHON_ERROR("duplicate error: no more layers can be added."); } else { DuplicateLayer(); DoAutoUpdate(); } // return index of new layer return Py_BuildValue((char*)"i", currindex); } // ----------------------------------------------------------------------------- static PyObject* py_dellayer(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; if (numlayers <= 1) { PYTHON_ERROR("dellayer error: there is only one layer."); } else { DeleteLayer(); DoAutoUpdate(); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_movelayer(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int fromindex, toindex; if (!PyArg_ParseTuple(args, (char*)"ii", &fromindex, &toindex)) return NULL; if (fromindex < 0 || fromindex >= numlayers) { char msg[64]; sprintf(msg, "Bad movelayer fromindex: %d", fromindex); PYTHON_ERROR(msg); } if (toindex < 0 || toindex >= numlayers) { char msg[64]; sprintf(msg, "Bad movelayer toindex: %d", toindex); PYTHON_ERROR(msg); } MoveLayer(fromindex, toindex); DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_setlayer(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int index; if (!PyArg_ParseTuple(args, (char*)"i", &index)) return NULL; if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "Bad setlayer index: %d", index); PYTHON_ERROR(msg); } SetLayer(index); DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getlayer(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", currindex); } // ----------------------------------------------------------------------------- static PyObject* py_numlayers(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", numlayers); } // ----------------------------------------------------------------------------- static PyObject* py_maxlayers(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; return Py_BuildValue((char*)"i", MAX_LAYERS); } // ----------------------------------------------------------------------------- static PyObject* py_setname(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* name; int index = currindex; if (!PyArg_ParseTuple(args, (char*)"s|i", &name, &index)) return NULL; if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "Bad setname index: %d", index); PYTHON_ERROR(msg); } GSF_setname(name, index); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getname(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int index = currindex; if (!PyArg_ParseTuple(args, (char*)"|i", &index)) return NULL; if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "Bad getname index: %d", index); PYTHON_ERROR(msg); } return Py_BuildValue((char*)"s", (const char*)GetLayer(index)->currname.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- static PyObject* py_setcolors(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); PyObject* color_list; if (!PyArg_ParseTuple(args, (char*)"O!", &PyList_Type, &color_list)) return NULL; int len = PyList_Size(color_list); if (len == 0) { // restore default colors in current layer and its clones UpdateLayerColors(); } else if (len == 6) { // create gradient from r1,g1,b1 to r2,g2,b2 int r1 = PyInt_AsLong( PyList_GetItem(color_list, 0) ); int g1 = PyInt_AsLong( PyList_GetItem(color_list, 1) ); int b1 = PyInt_AsLong( PyList_GetItem(color_list, 2) ); int r2 = PyInt_AsLong( PyList_GetItem(color_list, 3) ); int g2 = PyInt_AsLong( PyList_GetItem(color_list, 4) ); int b2 = PyInt_AsLong( PyList_GetItem(color_list, 5) ); CheckRGB(r1, g1, b1, "setcolors"); CheckRGB(r2, g2, b2, "setcolors"); currlayer->fromrgb.Set(r1, g1, b1); currlayer->torgb.Set(r2, g2, b2); CreateColorGradient(); UpdateCloneColors(); } else if (len % 4 == 0) { int i = 0; while (i < len) { int s = PyInt_AsLong( PyList_GetItem(color_list, i) ); i++; int r = PyInt_AsLong( PyList_GetItem(color_list, i) ); i++; int g = PyInt_AsLong( PyList_GetItem(color_list, i) ); i++; int b = PyInt_AsLong( PyList_GetItem(color_list, i) ); i++; CheckRGB(r, g, b, "setcolors"); if (s == -1) { // set all LIVE states to r,g,b (best not to alter state 0) for (s = 1; s < currlayer->algo->NumCellStates(); s++) { currlayer->cellr[s] = r; currlayer->cellg[s] = g; currlayer->cellb[s] = b; } } else { if (s < 0 || s >= currlayer->algo->NumCellStates()) { char msg[64]; sprintf(msg, "Bad state in setcolors: %d", s); PYTHON_ERROR(msg); } else { currlayer->cellr[s] = r; currlayer->cellg[s] = g; currlayer->cellb[s] = b; } } } UpdateCloneColors(); } else { PYTHON_ERROR("setcolors error: list length is not a multiple of 4."); } DoAutoUpdate(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getcolors(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int state = -1; if (!PyArg_ParseTuple(args, (char*)"|i", &state)) return NULL; PyObject* outlist = PyList_New(0); if (state == -1) { // return colors for ALL states, including state 0 for (state = 0; state < currlayer->algo->NumCellStates(); state++) { AddCellColor(outlist, state, currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state]); } } else if (state >= 0 && state < currlayer->algo->NumCellStates()) { AddCellColor(outlist, state, currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state]); } else { char msg[64]; sprintf(msg, "Bad getcolors state: %d", state); PYTHON_ERROR(msg); } return outlist; } // ----------------------------------------------------------------------------- static PyObject* py_setoption(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* optname; int oldval, newval; if (!PyArg_ParseTuple(args, (char*)"si", &optname, &newval)) return NULL; if (!GSF_setoption(optname, newval, &oldval)) { PYTHON_ERROR("setoption error: unknown option."); } // return old value (simplifies saving and restoring settings) return Py_BuildValue((char*)"i", oldval); } // ----------------------------------------------------------------------------- static PyObject* py_getoption(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* optname; int optval; if (!PyArg_ParseTuple(args, (char*)"s", &optname)) return NULL; if (!GSF_getoption(optname, &optval)) { PYTHON_ERROR("getoption error: unknown option."); } return Py_BuildValue((char*)"i", optval); } // ----------------------------------------------------------------------------- static PyObject* py_setcolor(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* colname; int r, g, b; if (!PyArg_ParseTuple(args, (char*)"siii", &colname, &r, &g, &b)) return NULL; wxColor newcol(r, g, b); wxColor oldcol; if (!GSF_setcolor(colname, newcol, oldcol)) { PYTHON_ERROR("setcolor error: unknown color."); } // return old r,g,b values (simplifies saving and restoring colors) PyObject* rgbtuple = PyTuple_New(3); PyTuple_SetItem(rgbtuple, 0, Py_BuildValue((char*)"i",oldcol.Red())); PyTuple_SetItem(rgbtuple, 1, Py_BuildValue((char*)"i",oldcol.Green())); PyTuple_SetItem(rgbtuple, 2, Py_BuildValue((char*)"i",oldcol.Blue())); return rgbtuple; } // ----------------------------------------------------------------------------- static PyObject* py_getcolor(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* colname; wxColor color; if (!PyArg_ParseTuple(args, (char*)"s", &colname)) return NULL; if (!GSF_getcolor(colname, color)) { PYTHON_ERROR("getcolor error: unknown color."); } // return r,g,b tuple PyObject* rgbtuple = PyTuple_New(3); PyTuple_SetItem(rgbtuple, 0, Py_BuildValue((char*)"i",color.Red())); PyTuple_SetItem(rgbtuple, 1, Py_BuildValue((char*)"i",color.Green())); PyTuple_SetItem(rgbtuple, 2, Py_BuildValue((char*)"i",color.Blue())); return rgbtuple; } // ----------------------------------------------------------------------------- static PyObject* py_setclipstr(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* clipstr; if (!PyArg_ParseTuple(args, (char*)"s", &clipstr)) return NULL; wxString wxs_clip(clipstr, wxConvLocal); mainptr->CopyTextToClipboard(wxs_clip); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getclipstr(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; wxTextDataObject data; if ( !mainptr->GetTextFromClipboard(&data) ) return NULL; wxString wxs_clipstr = data.GetText(); return Py_BuildValue((char*)"s", (const char*)wxs_clipstr.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- static PyObject* py_getstring(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* prompt; const char* initial = ""; const char* title = ""; if (!PyArg_ParseTuple(args, (char*)"s|ss", &prompt, &initial, &title)) return NULL; wxString result; if ( !GetString(wxString(title,wxConvLocal), wxString(prompt,wxConvLocal), wxString(initial,wxConvLocal), result) ) { // user hit Cancel button AbortPythonScript(); return NULL; } return Py_BuildValue((char*)"s", (const char*)result.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- static PyObject* py_getxy(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; statusptr->CheckMouseLocation(mainptr->infront); // sets mousepos if (viewptr->showcontrols) mousepos = wxEmptyString; return Py_BuildValue((char*)"s", (const char*)mousepos.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- static PyObject* py_getevent(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int get = 1; if (!PyArg_ParseTuple(args, (char*)"|i", &get)) return NULL; wxString event; GSF_getevent(event, get); return Py_BuildValue((char*)"s", (const char*)event.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- static PyObject* py_doevent(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* event; if (!PyArg_ParseTuple(args, (char*)"s", &event)) return NULL; if (event[0]) { const char* err = GSF_doevent(wxString(event,wxConvLocal)); if (err) PYTHON_ERROR(err); } RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getkey(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; char s[2]; // room for char + NULL GSF_getkey(s); return Py_BuildValue((char*)"s", s); } // ----------------------------------------------------------------------------- static PyObject* py_dokey(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* ascii; if (!PyArg_ParseTuple(args, (char*)"s", &ascii)) return NULL; GSF_dokey(ascii); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_show(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* s = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &s)) return NULL; inscript = false; statusptr->DisplayMessage(wxString(s,wxConvLocal)); inscript = true; // make sure status bar is visible if (!showstatus) mainptr->ToggleStatusBar(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_error(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* s = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &s)) return NULL; inscript = false; statusptr->ErrorMessage(wxString(s,wxConvLocal)); inscript = true; // make sure status bar is visible if (!showstatus) mainptr->ToggleStatusBar(); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_warn(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* s = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &s)) return NULL; Warning(wxString(s,wxConvLocal)); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_note(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* s = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &s)) return NULL; Note(wxString(s,wxConvLocal)); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_help(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* htmlfile = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &htmlfile)) return NULL; ShowHelp(wxString(htmlfile,wxConvLocal)); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_check(PyObject* self, PyObject* args) { // if (PythonScriptAborted()) return NULL; // don't call checkevents() here otherwise we can't safely write code like // if g.getlayer() == target: // g.check(0) // ... do stuff to target layer ... // g.check(1) wxUnusedVar(self); int flag; if (!PyArg_ParseTuple(args, (char*)"i", &flag)) return NULL; allowcheck = (flag != 0); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_exit(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* err = NULL; if (!PyArg_ParseTuple(args, (char*)"|s", &err)) return NULL; GSF_exit(err); AbortPythonScript(); // exception raised so must return NULL return NULL; } // ----------------------------------------------------------------------------- static PyObject* py_stderr(PyObject* self, PyObject* args) { // probably safer not to call checkevents here // if (PythonScriptAborted()) return NULL; wxUnusedVar(self); char* s = NULL; if (!PyArg_ParseTuple(args, (char*)"s", &s)) return NULL; // accumulate stderr messages in global string (shown after script finishes) scripterr = wxString(s, wxConvLocal); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyMethodDef py_methods[] = { // filing { "open", py_open, METH_VARARGS, "open given pattern file" }, { "save", py_save, METH_VARARGS, "save pattern in given file using given format" }, { "opendialog", py_opendialog, METH_VARARGS, "return input path and filename chosen by user" }, { "savedialog", py_savedialog, METH_VARARGS, "return output path and filename chosen by user" }, { "load", py_load, METH_VARARGS, "read pattern file and return cell list" }, { "store", py_store, METH_VARARGS, "write cell list to a file (in RLE format)" }, { "setdir", py_setdir, METH_VARARGS, "set location of specified directory" }, { "getdir", py_getdir, METH_VARARGS, "return location of specified directory" }, // next two are deprecated (use getdir) { "appdir", py_appdir, METH_VARARGS, "return location of Golly app" }, { "datadir", py_datadir, METH_VARARGS, "return location of user-specific data" }, // editing { "new", py_new, METH_VARARGS, "create new universe and set window title" }, { "cut", py_cut, METH_VARARGS, "cut selection to clipboard" }, { "copy", py_copy, METH_VARARGS, "copy selection to clipboard" }, { "clear", py_clear, METH_VARARGS, "clear inside/outside selection" }, { "paste", py_paste, METH_VARARGS, "paste clipboard pattern at x,y using given mode" }, { "shrink", py_shrink, METH_VARARGS, "shrink selection" }, { "randfill", py_randfill, METH_VARARGS, "randomly fill selection to given percentage" }, { "flip", py_flip, METH_VARARGS, "flip selection top-bottom or left-right" }, { "rotate", py_rotate, METH_VARARGS, "rotate selection 90 deg clockwise or anticlockwise" }, { "parse", py_parse, METH_VARARGS, "parse RLE or Life 1.05 string and return cell list" }, { "transform", py_transform, METH_VARARGS, "apply an affine transformation to cell list" }, { "evolve", py_evolve, METH_VARARGS, "generate pattern contained in given cell list" }, { "putcells", py_putcells, METH_VARARGS, "paste given cell list into current universe" }, { "getcells", py_getcells, METH_VARARGS, "return cell list in given rectangle" }, { "join", py_join, METH_VARARGS, "return concatenation of given cell lists" }, { "hash", py_hash, METH_VARARGS, "return hash value for pattern in given rectangle" }, { "getclip", py_getclip, METH_VARARGS, "return pattern in clipboard (as cell list)" }, { "select", py_select, METH_VARARGS, "select [x, y, wd, ht] rectangle or remove if []" }, { "getrect", py_getrect, METH_VARARGS, "return pattern rectangle as [] or [x, y, wd, ht]" }, { "getselrect", py_getselrect, METH_VARARGS, "return selection rectangle as [] or [x, y, wd, ht]" }, { "setcell", py_setcell, METH_VARARGS, "set given cell to given state" }, { "getcell", py_getcell, METH_VARARGS, "get state of given cell" }, { "setcursor", py_setcursor, METH_VARARGS, "set cursor (returns old cursor)" }, { "getcursor", py_getcursor, METH_VARARGS, "return current cursor" }, // control { "empty", py_empty, METH_VARARGS, "return true if universe is empty" }, { "run", py_run, METH_VARARGS, "run current pattern for given number of gens" }, { "step", py_step, METH_VARARGS, "run current pattern for current step" }, { "setstep", py_setstep, METH_VARARGS, "set step exponent" }, { "getstep", py_getstep, METH_VARARGS, "return current step exponent" }, { "setbase", py_setbase, METH_VARARGS, "set base step" }, { "getbase", py_getbase, METH_VARARGS, "return current base step" }, { "advance", py_advance, METH_VARARGS, "advance inside/outside selection by given gens" }, { "reset", py_reset, METH_VARARGS, "restore starting pattern" }, { "setgen", py_setgen, METH_VARARGS, "set current generation to given string" }, { "getgen", py_getgen, METH_VARARGS, "return current generation as string" }, { "getpop", py_getpop, METH_VARARGS, "return current population as string" }, { "numstates", py_numstates, METH_VARARGS, "return number of cell states in current universe" }, { "numalgos", py_numalgos, METH_VARARGS, "return number of algorithms" }, { "setalgo", py_setalgo, METH_VARARGS, "set current algorithm using given string" }, { "getalgo", py_getalgo, METH_VARARGS, "return name of given or current algorithm" }, { "setrule", py_setrule, METH_VARARGS, "set current rule using given string" }, { "getrule", py_getrule, METH_VARARGS, "return current rule" }, { "getwidth", py_getwidth, METH_VARARGS, "return width of universe (0 if unbounded)" }, { "getheight", py_getheight, METH_VARARGS, "return height of universe (0 if unbounded)" }, // viewing { "setpos", py_setpos, METH_VARARGS, "move given cell to middle of viewport" }, { "getpos", py_getpos, METH_VARARGS, "return x,y position of cell in middle of viewport" }, { "setmag", py_setmag, METH_VARARGS, "set magnification (0=1:1, 1=1:2, -1=2:1, etc)" }, { "getmag", py_getmag, METH_VARARGS, "return current magnification" }, { "fit", py_fit, METH_VARARGS, "fit entire pattern in viewport" }, { "fitsel", py_fitsel, METH_VARARGS, "fit selection in viewport" }, { "visrect", py_visrect, METH_VARARGS, "return true if given rect is completely visible" }, { "update", py_update, METH_VARARGS, "update display (viewport and status bar)" }, { "autoupdate", py_autoupdate, METH_VARARGS, "update display after each change to universe?" }, // layers { "addlayer", py_addlayer, METH_VARARGS, "add a new layer" }, { "clone", py_clone, METH_VARARGS, "add a cloned layer (shares universe)" }, { "duplicate", py_duplicate, METH_VARARGS, "add a duplicate layer (copies universe)" }, { "dellayer", py_dellayer, METH_VARARGS, "delete current layer" }, { "movelayer", py_movelayer, METH_VARARGS, "move given layer to new index" }, { "setlayer", py_setlayer, METH_VARARGS, "switch to given layer" }, { "getlayer", py_getlayer, METH_VARARGS, "return index of current layer" }, { "numlayers", py_numlayers, METH_VARARGS, "return current number of layers" }, { "maxlayers", py_maxlayers, METH_VARARGS, "return maximum number of layers" }, { "setname", py_setname, METH_VARARGS, "set name of given layer" }, { "getname", py_getname, METH_VARARGS, "get name of given layer" }, { "setcolors", py_setcolors, METH_VARARGS, "set color(s) used in current layer" }, { "getcolors", py_getcolors, METH_VARARGS, "get color(s) used in current layer" }, // miscellaneous { "setoption", py_setoption, METH_VARARGS, "set given option to new value (returns old value)" }, { "getoption", py_getoption, METH_VARARGS, "return current value of given option" }, { "setcolor", py_setcolor, METH_VARARGS, "set given color to new r,g,b (returns old r,g,b)" }, { "getcolor", py_getcolor, METH_VARARGS, "return r,g,b values of given color" }, { "setclipstr", py_setclipstr, METH_VARARGS, "set the clipboard contents to a given string value" }, { "getclipstr", py_getclipstr, METH_VARARGS, "retrieve the contents of the clipboard as a string" }, { "getstring", py_getstring, METH_VARARGS, "display dialog box to get string from user" }, { "getxy", py_getxy, METH_VARARGS, "return current grid location of mouse" }, { "getevent", py_getevent, METH_VARARGS, "return keyboard/mouse event or empty string if none" }, { "doevent", py_doevent, METH_VARARGS, "pass given keyboard/mouse event to Golly to handle" }, // next two are deprecated (use getevent and doevent) { "getkey", py_getkey, METH_VARARGS, "return key hit by user or empty string if none" }, { "dokey", py_dokey, METH_VARARGS, "pass given key to Golly's standard key handler" }, { "show", py_show, METH_VARARGS, "show given string in status bar" }, { "error", py_error, METH_VARARGS, "beep and show given string in status bar" }, { "warn", py_warn, METH_VARARGS, "show given string in warning dialog" }, { "note", py_note, METH_VARARGS, "show given string in note dialog" }, { "help", py_help, METH_VARARGS, "show given HTML file in help window" }, { "check", py_check, METH_VARARGS, "allow event checking?" }, { "exit", py_exit, METH_VARARGS, "exit script with optional error message" }, // for internal use (don't document) { "stderr", py_stderr, METH_VARARGS, "save Python error message" }, { NULL, NULL, 0, NULL } }; // ============================================================================= bool pyinited = false; // InitPython has been successfully called? bool InitPython() { if (!pyinited) { #ifdef USE_PYTHON_DYNAMIC // try to load Python library if ( !LoadPythonLib() ) return false; #endif // only initialize the Python interpreter once, mainly because multiple // Py_Initialize/Py_Finalize calls cause leaks of about 12K each time! Py_Initialize(); #ifdef USE_PYTHON_DYNAMIC GetPythonExceptions(); #endif // allow Python to call the above py_* routines Py_InitModule((char*)"golly", py_methods); // catch Python messages sent to stderr and pass them to py_stderr if ( PyRun_SimpleString( "import golly\n" "import sys\n" "class StderrCatcher:\n" " def __init__(self):\n" " self.data = ''\n" " def write(self, stuff):\n" " self.data += stuff\n" " golly.stderr(self.data)\n" "sys.stderr = StderrCatcher()\n" // also create dummy sys.argv so scripts can import Tkinter "sys.argv = ['golly-app']\n" // works, but Golly's menus get permanently changed on Mac ) < 0 ) Warning(_("StderrCatcher code failed!")); // build absolute path to Scripts/Python folder and add to Python's // import search list so scripts can import glife from anywhere wxString scriptsdir = gollydir + _("Scripts"); scriptsdir += wxFILE_SEP_PATH; scriptsdir += _("Python"); // convert any \ to \\ and then convert any ' to \' scriptsdir.Replace(wxT("\\"), wxT("\\\\")); scriptsdir.Replace(wxT("'"), wxT("\\'")); wxString command = wxT("import sys ; sys.path.append('") + scriptsdir + wxT("')"); // also insert script's current directory at start of sys.path // since that's what most Python interpreter's do (thanks to Joel Snyder) command += wxT(" ; sys.path.insert(0,'')"); if ( PyRun_SimpleString(command.mb_str(wxConvLocal)) < 0 ) Warning(_("Failed to append Scripts path!")); pyinited = true; } else { // Py_Initialize has already been successfully called; // Py_Finalize is not used to close stderr so reset it here if ( PyRun_SimpleString("sys.stderr.data = ''\n") < 0 ) Warning(_("PyRun_SimpleString failed!")); } return true; } // ----------------------------------------------------------------------------- void RunPythonScript(const wxString& filepath) { if (!InitPython()) return; // we must convert any backslashes to "\\" to avoid "\a" being treated as // escape char, then we must escape any apostrophes wxString fpath = filepath; fpath.Replace(wxT("\\"), wxT("\\\\")); fpath.Replace(wxT("'"), wxT("\\'")); // execute the given script; note that we pass an empty dictionary // for the global namespace so that this script cannot change the // globals of a caller script (which is possible now that RunScript // is re-entrant) wxString command = wxT("execfile('") + fpath + wxT("',{})"); PyRun_SimpleString(command.mb_str(wxConvLocal)); // note that PyRun_SimpleString returns -1 if an exception occurred; // the error message (in scripterr) is checked at the end of RunScript } // ----------------------------------------------------------------------------- void FinishPythonScripting() { // Py_Finalize can cause an obvious delay, so best not to call it // if (pyinited) Py_Finalize(); // probably don't really need this either #ifdef USE_PYTHON_DYNAMIC FreePythonLib(); #endif } golly-2.7-src/gui-wx/wxselect.h0000644000175000017500000001477012536111364013460 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXSELECT_H_ #define _WXSELECT_H_ #include "bigint.h" // for bigint #include "lifealgo.h" // for lifealgo // Most editing functions operate on the current selection. // The Selection class encapsulates all selection-related operations. class Selection { public: Selection(); Selection(int t, int l, int b, int r); ~Selection(); bool operator==(const Selection& sel) const; bool operator!=(const Selection& sel) const; bool Exists(); // return true if the selection exists void Deselect(); // remove the selection bool TooBig(); // return true if any selection edge is outside the editable limits void DisplaySize(); // display the selection's size in the status bar void SetRect(int x, int y, int wd, int ht); // set the selection to the given rectangle void GetRect(int* x, int* y, int* wd, int* ht); // return the selection rectangle void SetEdges(bigint& t, bigint& l, bigint& b, bigint& r); // set the selection using the given rectangle edges void CheckGridEdges(); // change selection edges if necessary to ensure they are inside a bounded grid bool Contains(bigint& t, bigint& l, bigint& b, bigint& r); // return true if the selection encloses the given rectangle bool Outside(bigint& t, bigint& l, bigint& b, bigint& r); // return true if the selection is completely outside the given rectangle bool ContainsCell(int x, int y); // return true if the given cell is within the selection void Advance(); // advance the pattern inside the selection by one generation void AdvanceOutside(); // advance the pattern outside the selection by one generation void Modify(const bigint& xclick, const bigint& yclick, bigint& anchorx, bigint& anchory, bool* forceh, bool* forcev); // modify the existing selection based on where the user clicked void SetLeftRight(const bigint& x, const bigint& anchorx); // set the selection's left and right edges void SetTopBottom(const bigint& y, const bigint& anchory); // set the selection's top and bottom edges void Fit(); // fit the selection inside the current viewport void Shrink(bool fit); // shrink the selection so it just encloses all the live cells // and optionally fit the new selection inside the current viewport bool Visible(wxRect* visrect); // return true if the selection is visible in the current viewport // and, if visrect is not NULL, set it to the visible rectangle void Clear(); // kill all cells inside the selection void ClearOutside(); // kill all cells outside the selection void CopyToClipboard(bool cut); // copy the selection to the clipboard (using RLE format) and // optionally clear the selection if cut is true bool CanPaste(const bigint& wd, const bigint& ht, bigint& top, bigint& left); // return true if the selection fits inside a rectangle of size ht x wd; // if so then top and left are set to the selection's top left corner void RandomFill(); // randomly fill the selection bool Flip(bool topbottom, bool inundoredo); // return true if selection was successfully flipped bool Rotate(bool clockwise, bool inundoredo); // return true if selection was successfully rotated private: bool SaveOutside(bigint& t, bigint& l, bigint& b, bigint& r); // remember live cells outside the selection void EmptyUniverse(); // kill all cells by creating a new, empty universe void AddRun(int state, int multistate, unsigned int &run, unsigned int &linelen, char* &chptr); void AddEOL(char* &chptr); // these routines are used by CopyToClipboard to create RLE data bool SaveDifferences(lifealgo* oldalgo, lifealgo* newalgo, int itop, int ileft, int ibottom, int iright); // compare same rectangle in the given universes and remember the differences // in cell states; return false only if user aborts lengthy comparison bool FlipRect(bool topbottom, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, int top, int left, int bottom, int right); // called by Flip to flip given rectangle from source universe to // destination universe and optionally kill cells in the source rectangle; // return false only if user aborts lengthy flip bool RotateRect(bool clockwise, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, int itop, int ileft, int ibottom, int iright, int ntop, int nleft, int nbottom, int nright); // called by Rotate to rotate given rectangle from source universe to // destination universe and optionally kill cells in the source rectangle; // return false only if user aborts lengthy rotation bool RotatePattern(bool clockwise, bigint& newtop, bigint& newbottom, bigint& newleft, bigint& newright, bool inundoredo); // called by Rotate when the selection encloses the entire pattern; // return false only if user aborts lengthy rotation bigint seltop, selleft, selbottom, selright; // currently we only support a single rectangular selection // which is represented by these edges; eventually we might // support arbitrarily complex selection shapes by maintaining // a list or dynamic array of non-overlapping rectangles bool exists; // does the selection exist? }; #endif golly-2.7-src/gui-wx/wxundo.cpp0000644000175000017500000017107212536111364013500 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/filename.h" // for wxFileName #include "bigint.h" #include "lifealgo.h" #include "writepattern.h" // for MC_format, XRLE_format #include "wxgolly.h" // for mainptr, viewptr #include "wxmain.h" // for mainptr->... #include "wxselect.h" // for Selection #include "wxview.h" // for viewptr->... #include "wxutils.h" // for Warning, Fatal #include "wxscript.h" // for inscript #include "wxalgos.h" // for algo_type #include "wxlayer.h" // for currlayer, numclones, MarkLayerDirty, etc #include "wxprefs.h" // for allowundo, GetAccelerator, etc #include "wxundo.h" // ----------------------------------------------------------------------------- const wxString lack_of_memory = _("Due to lack of memory, some changes can't be undone!"); const wxString to_gen = _("to Gen "); const wxString temp_prefix = wxT("golly_undo_"); // ----------------------------------------------------------------------------- // encapsulate change info stored in undo/redo lists typedef enum { cellstates, // one or more cell states were changed fliptb, // selection was flipped top-bottom fliplr, // selection was flipped left-right rotatecw, // selection was rotated clockwise rotateacw, // selection was rotated anticlockwise rotatepattcw, // pattern was rotated clockwise rotatepattacw, // pattern was rotated anticlockwise namechange, // layer name was changed // WARNING: code in UndoChange/RedoChange assumes only changes < selchange // can alter the layer's dirty state; ie. the olddirty/newdirty flags are // not used for all the following changes selchange, // selection was changed genchange, // pattern was generated setgen, // generation count was changed rulechange, // rule was changed algochange, // algorithm was changed scriptstart, // later changes were made by script scriptfinish // earlier changes were made by script } change_type; class ChangeNode: public wxObject { public: ChangeNode(change_type id); ~ChangeNode(); bool DoChange(bool undo); // do the undo/redo; if it returns false (eg. user has aborted a lengthy // rotate/flip operation) then cancel the undo/redo void ChangeCells(bool undo); // change cell states using cellinfo change_type changeid; // specifies the type of change wxString suffix; // action string for Undo/Redo item bool olddirty; // layer's dirty state before change bool newdirty; // layer's dirty state after change // cellstates info cell_change* cellinfo; // dynamic array of cell changes unsigned int cellcount; // number of cell changes in array // rotatecw/rotateacw/selchange info Selection oldsel, newsel; // old and new selections // genchange info wxString oldfile, newfile; // old and new pattern files bigint oldgen, newgen; // old and new generation counts bigint oldx, oldy, newx, newy; // old and new positions int oldmag, newmag; // old and new scales int oldbase, newbase; // old and new base steps int oldexpo, newexpo; // old and new step exponents bool scriptgen; // gen change was done by script? // also uses oldsel, newsel // setgen info bigint oldstartgen, newstartgen; // old and new startgen values bool oldsave, newsave; // old and new savestart states wxString oldtempstart, newtempstart; // old and new tempstart paths wxString oldstartfile, newstartfile; // old and new startfile paths wxString oldcurrfile, newcurrfile; // old and new currfile paths wxString oldclone[MAX_LAYERS]; // old starting names for cloned layers wxString newclone[MAX_LAYERS]; // new starting names for cloned layers // also uses oldgen, newgen // and oldrule, newrule // and oldx, oldy, newx, newy, oldmag, newmag // and oldbase, newbase // and oldexpo, newexpo // and oldsel, newsel // and oldalgo, newalgo // namechange info wxString oldname, newname; // old and new layer names Layer* whichlayer; // which layer was changed // also uses oldsave, newsave // and oldcurrfile, newcurrfile // rulechange info wxString oldrule, newrule; // old and new rules // also uses oldsel, newsel // algochange info algo_type oldalgo, newalgo; // old and new algorithm types // also uses oldrule, newrule // and oldsel, newsel }; // ----------------------------------------------------------------------------- ChangeNode::ChangeNode(change_type id) { changeid = id; cellinfo = NULL; cellcount = 0; oldfile = wxEmptyString; newfile = wxEmptyString; oldtempstart = wxEmptyString; newtempstart = wxEmptyString; } // ----------------------------------------------------------------------------- ChangeNode::~ChangeNode() { if (cellinfo) free(cellinfo); if (!oldfile.IsEmpty() && wxFileExists(oldfile)) { wxRemoveFile(oldfile); //printf("removed oldfile: %s\n", (const char*)oldfile.mb_str(wxConvLocal)); } if (!newfile.IsEmpty() && wxFileExists(newfile)) { wxRemoveFile(newfile); //printf("removed newfile: %s\n", (const char*)newfile.mb_str(wxConvLocal)); } // only delete oldtempstart/newtempstart if they're not being used to // store the current layer's starting pattern if ( !oldtempstart.IsEmpty() && wxFileExists(oldtempstart) && oldtempstart != currlayer->startfile && oldtempstart != currlayer->currfile ) { wxRemoveFile(oldtempstart); } if ( !newtempstart.IsEmpty() && wxFileExists(newtempstart) && newtempstart != currlayer->startfile && newtempstart != currlayer->currfile ) { wxRemoveFile(newtempstart); } } // ----------------------------------------------------------------------------- void ChangeNode::ChangeCells(bool undo) { // change state of cell(s) stored in cellinfo array if (undo) { // we must undo the cell changes in reverse order in case // a script has changed the same cell more than once unsigned int i = cellcount; while (i > 0) { i--; currlayer->algo->setcell(cellinfo[i].x, cellinfo[i].y, cellinfo[i].oldstate); } } else { unsigned int i = 0; while (i < cellcount) { currlayer->algo->setcell(cellinfo[i].x, cellinfo[i].y, cellinfo[i].newstate); i++; } } if (cellcount > 0) currlayer->algo->endofpattern(); } // ----------------------------------------------------------------------------- bool ChangeNode::DoChange(bool undo) { switch (changeid) { case cellstates: if (cellcount > 0) { ChangeCells(undo); mainptr->UpdatePatternAndStatus(); } break; case fliptb: case fliplr: // pass in true so FlipSelection won't save changes or call MarkLayerDirty if (!viewptr->FlipSelection(changeid == fliptb, true)) return false; break; case rotatepattcw: case rotatepattacw: // pass in true so RotateSelection won't save changes or call MarkLayerDirty if (!viewptr->RotateSelection(changeid == rotatepattcw ? !undo : undo, true)) return false; break; case rotatecw: case rotateacw: if (cellcount > 0) { ChangeCells(undo); } // rotate selection edges if (undo) { currlayer->currsel = oldsel; } else { currlayer->currsel = newsel; } viewptr->DisplaySelectionSize(); mainptr->UpdatePatternAndStatus(); break; case selchange: if (undo) { currlayer->currsel = oldsel; } else { currlayer->currsel = newsel; } if (viewptr->SelectionExists()) viewptr->DisplaySelectionSize(); mainptr->UpdatePatternAndStatus(); break; case genchange: if (undo) { currlayer->currsel = oldsel; mainptr->RestorePattern(oldgen, oldfile, oldx, oldy, oldmag, oldbase, oldexpo); } else { currlayer->currsel = newsel; mainptr->RestorePattern(newgen, newfile, newx, newy, newmag, newbase, newexpo); } break; case setgen: if (undo) { mainptr->ChangeGenCount(oldgen.tostring(), true); currlayer->startgen = oldstartgen; currlayer->savestart = oldsave; currlayer->tempstart = oldtempstart; currlayer->startfile = oldstartfile; currlayer->currfile = oldcurrfile; if (oldtempstart != newtempstart) { currlayer->startdirty = olddirty; currlayer->startalgo = oldalgo; currlayer->startrule = oldrule; currlayer->startx = oldx; currlayer->starty = oldy; currlayer->startmag = oldmag; currlayer->startbase = oldbase; currlayer->startexpo = oldexpo; currlayer->startsel = oldsel; currlayer->startname = oldname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->startname = oldclone[i]; } } } } } else { mainptr->ChangeGenCount(newgen.tostring(), true); currlayer->startgen = newstartgen; currlayer->savestart = newsave; currlayer->tempstart = newtempstart; currlayer->startfile = newstartfile; currlayer->currfile = newcurrfile; if (oldtempstart != newtempstart) { currlayer->startdirty = newdirty; currlayer->startalgo = newalgo; currlayer->startrule = newrule; currlayer->startx = newx; currlayer->starty = newy; currlayer->startmag = newmag; currlayer->startbase = newbase; currlayer->startexpo = newexpo; currlayer->startsel = newsel; currlayer->startname = newname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->startname = newclone[i]; } } } } } // Reset item may become enabled/disabled mainptr->UpdateMenuItems(); break; case namechange: if (whichlayer == NULL) { // the layer has been deleted so ignore name change } else { // note that if whichlayer != currlayer then we're changing the // name of a non-active cloned layer if (undo) { whichlayer->currname = oldname; currlayer->currfile = oldcurrfile; currlayer->savestart = oldsave; } else { whichlayer->currname = newname; currlayer->currfile = newcurrfile; currlayer->savestart = newsave; } if (whichlayer == currlayer) { if (olddirty == newdirty) mainptr->SetWindowTitle(currlayer->currname); // if olddirty != newdirty then UndoChange/RedoChange will call // MarkLayerClean/MarkLayerDirty (they call SetWindowTitle) } else { // whichlayer is non-active clone so only update Layer menu items for (int i = 0; i < numlayers; i++) mainptr->UpdateLayerItem(i); } } break; case rulechange: if (undo) { RestoreRule(oldrule); currlayer->currsel = oldsel; } else { RestoreRule(newrule); currlayer->currsel = newsel; } // show new rule in window title (file name doesn't change) mainptr->SetWindowTitle(wxEmptyString); if (cellcount > 0) { ChangeCells(undo); } // switch to default colors for new rule UpdateLayerColors(); mainptr->UpdateEverything(); break; case algochange: // pass in true so ChangeAlgorithm won't call RememberAlgoChange if (undo) { mainptr->ChangeAlgorithm(oldalgo, oldrule, true); currlayer->currsel = oldsel; } else { mainptr->ChangeAlgorithm(newalgo, newrule, true); currlayer->currsel = newsel; } // show new rule in window title (file name doesn't change) mainptr->SetWindowTitle(wxEmptyString); if (cellcount > 0) { ChangeCells(undo); } // ChangeAlgorithm has called UpdateLayerColors() mainptr->UpdateEverything(); break; case scriptstart: case scriptfinish: // should never happen Warning(_("Bug detected in DoChange!")); break; } return true; } // ----------------------------------------------------------------------------- UndoRedo::UndoRedo() { numchanges = 0; // for 1st SaveCellChange maxchanges = 0; // ditto badalloc = false; // true if malloc/realloc fails cellarray = NULL; // play safe savecellchanges = false; // no script cell changes are pending savegenchanges = false; // no script gen changes are pending doingscriptchanges = false; // not undoing/redoing script changes prevfile = wxEmptyString; // play safe for ClearUndoRedo startcount = 0; // unfinished RememberGenStart calls fixsetgen = false; // no setgen nodes need fixing // need to remember if script has created a new layer (not a clone) if (inscript) RememberScriptStart(); } // ----------------------------------------------------------------------------- UndoRedo::~UndoRedo() { ClearUndoRedo(); } // ----------------------------------------------------------------------------- void UndoRedo::SaveCellChange(int x, int y, int oldstate, int newstate) { if (numchanges == maxchanges) { if (numchanges == 0) { // initially allocate room for 1 cell change maxchanges = 1; cellarray = (cell_change*) malloc(maxchanges * sizeof(cell_change)); if (cellarray == NULL) { badalloc = true; return; } // ~ChangeNode or ForgetCellChanges will free cellarray } else { // double size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, maxchanges * 2 * sizeof(cell_change)); if (newptr == NULL) { badalloc = true; return; } cellarray = newptr; maxchanges *= 2; } } cellarray[numchanges].x = x; cellarray[numchanges].y = y; cellarray[numchanges].oldstate = oldstate; cellarray[numchanges].newstate = newstate; numchanges++; } // ----------------------------------------------------------------------------- void UndoRedo::ForgetCellChanges() { if (numchanges > 0) { if (cellarray) { free(cellarray); } else { Warning(_("Bug detected in ForgetCellChanges!")); } numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto badalloc = false; } } // ----------------------------------------------------------------------------- bool UndoRedo::RememberCellChanges(const wxString& action, bool olddirty) { if (numchanges > 0) { if (numchanges < maxchanges) { // reduce size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, numchanges * sizeof(cell_change)); if (newptr != NULL) cellarray = newptr; // in the unlikely event that newptr is NULL, cellarray should // still point to valid data } // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add cellstates node to head of undo list ChangeNode* change = new ChangeNode(cellstates); if (change == NULL) Fatal(_("Failed to create cellstates node!")); change->suffix = action; change->cellinfo = cellarray; change->cellcount = numchanges; change->olddirty = olddirty; change->newdirty = true; undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto if (badalloc) { Warning(lack_of_memory); badalloc = false; } return true; // at least one cell changed state } return false; // no cells changed state (SaveCellChange wasn't called) } // ----------------------------------------------------------------------------- void UndoRedo::RememberFlip(bool topbot, bool olddirty) { // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add fliptb/fliplr node to head of undo list ChangeNode* change = new ChangeNode(topbot ? fliptb : fliplr); if (change == NULL) Fatal(_("Failed to create flip node!")); change->suffix = _("Flip"); change->olddirty = olddirty; change->newdirty = true; undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::RememberRotation(bool clockwise, bool olddirty) { // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add rotatepattcw/rotatepattacw node to head of undo list ChangeNode* change = new ChangeNode(clockwise ? rotatepattcw : rotatepattacw); if (change == NULL) Fatal(_("Failed to create simple rotation node!")); change->suffix = _("Rotation"); change->olddirty = olddirty; change->newdirty = true; undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::RememberRotation(bool clockwise, Selection& oldsel, Selection& newsel, bool olddirty) { // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add rotatecw/rotateacw node to head of undo list ChangeNode* change = new ChangeNode(clockwise ? rotatecw : rotateacw); if (change == NULL) Fatal(_("Failed to create rotation node!")); change->suffix = _("Rotation"); change->oldsel = oldsel; change->newsel = newsel; change->olddirty = olddirty; change->newdirty = true; // if numchanges == 0 we still need to rotate selection edges if (numchanges > 0) { if (numchanges < maxchanges) { // reduce size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, numchanges * sizeof(cell_change)); if (newptr != NULL) cellarray = newptr; } change->cellinfo = cellarray; change->cellcount = numchanges; numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto if (badalloc) { Warning(lack_of_memory); badalloc = false; } } undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::RememberSelection(const wxString& action) { if (currlayer->savesel == currlayer->currsel) { // selection has not changed return; } if (mainptr->generating) { // don't record selection changes while a pattern is generating; // RememberGenStart and RememberGenFinish will remember the overall change return; } // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add selchange node to head of undo list ChangeNode* change = new ChangeNode(selchange); if (change == NULL) Fatal(_("Failed to create selchange node!")); if (currlayer->currsel.Exists()) { change->suffix = action; } else { change->suffix = _("Deselection"); } change->oldsel = currlayer->savesel; change->newsel = currlayer->currsel; undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::SaveCurrentPattern(const wxString& tempfile) { const char* err = NULL; //!!! need lifealgo::CanWriteFormat(MC_format) method??? if ( currlayer->algo->hyperCapable() ) { // save hlife pattern in a macrocell file err = mainptr->WritePattern(tempfile, MC_format, no_compression, 0, 0, 0, 0); } else { // can only save RLE file if edges are within getcell/setcell limits bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { err = "Pattern is too big to save."; } else { // use XRLE format so the pattern's top left location and the current // generation count are stored in the file err = mainptr->WritePattern(tempfile, XRLE_format, no_compression, top.toint(), left.toint(), bottom.toint(), right.toint()); } } if (err) Warning(wxString(err,wxConvLocal)); } // ----------------------------------------------------------------------------- void UndoRedo::RememberGenStart() { startcount++; if (startcount > 1) { // return immediately and ignore next RememberGenFinish call; // this can happen in Linux app if user holds down space bar return; } if (inscript) { if (savegenchanges) return; // ignore consecutive run/step command savegenchanges = true; // we're about to do first run/step command of a (possibly long) // sequence, so save starting info } // save current generation, selection, position, scale, speed, etc prevgen = currlayer->algo->getGeneration(); prevsel = currlayer->currsel; viewptr->GetPos(prevx, prevy); prevmag = viewptr->GetMag(); prevbase = currlayer->currbase; prevexpo = currlayer->currexpo; if (!inscript) { // make sure Undo and Redo items show correct actions while generating UpdateUndoItem(to_gen + wxString(prevgen.tostring(), wxConvLocal)); UpdateRedoItem(wxEmptyString); } if (prevgen == currlayer->startgen) { // we can just reset to starting pattern prevfile = wxEmptyString; if (fixsetgen) { // SaveStartingPattern has just been called so search undolist for setgen // node that changed tempstart and update the starting info in that node; // yuk -- is there a simpler solution??? wxList::compatibility_iterator node = undolist.GetFirst(); while (node) { ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == setgen && change->oldtempstart != change->newtempstart) { change->newdirty = currlayer->startdirty; change->newalgo = currlayer->startalgo; change->newrule = currlayer->startrule; change->newx = currlayer->startx; change->newy = currlayer->starty; change->newmag = currlayer->startmag; change->newbase = currlayer->startbase; change->newexpo = currlayer->startexpo; change->newsel = currlayer->startsel; change->newname = currlayer->startname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { change->newclone[i] = cloneptr->startname; } } } // do NOT reset fixsetgen to false here; the gen change might // be removed when clearing the redo list and so we may need // to update this setgen node again after a new gen change break; } node = node->GetNext(); } } } else { // save starting pattern in a unique temporary file prevfile = wxFileName::CreateTempFileName(tempdir + temp_prefix); // if head of undo list is a genchange node then we can copy that // change node's newfile to prevfile; this makes consecutive generating // runs faster (setting prevfile to newfile would be even faster but it's // difficult to avoid the file being deleted if the redo list is cleared) if (!undolist.IsEmpty()) { wxList::compatibility_iterator node = undolist.GetFirst(); ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == genchange) { if (wxCopyFile(change->newfile, prevfile, true)) { return; } else { Warning(_("Failed to copy temporary file!")); // continue and call SaveCurrentPattern } } } SaveCurrentPattern(prevfile); } } // ----------------------------------------------------------------------------- void UndoRedo::RememberGenFinish() { startcount--; if (startcount > 0) return; if (startcount < 0) { // this can happen if a script has pending gen changes that need // to be remembered (ie. savegenchanges is now false) so reset // startcount for the next RememberGenStart call startcount = 0; } if (inscript && savegenchanges) return; // ignore consecutive run/step command // generation count might not have changed (can happen in Linux app) if (prevgen == currlayer->algo->getGeneration()) { // delete prevfile created by RememberGenStart if (!prevfile.IsEmpty() && wxFileExists(prevfile)) { wxRemoveFile(prevfile); } prevfile = wxEmptyString; return; } wxString fpath; if (currlayer->algo->getGeneration() == currlayer->startgen) { // this can happen if script called reset() so just use starting pattern fpath = wxEmptyString; } else { // save finishing pattern in a unique temporary file fpath = wxFileName::CreateTempFileName(tempdir + temp_prefix); SaveCurrentPattern(fpath); } // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add genchange node to head of undo list ChangeNode* change = new ChangeNode(genchange); if (change == NULL) Fatal(_("Failed to create genchange node!")); change->suffix = to_gen + wxString(prevgen.tostring(), wxConvLocal); change->scriptgen = inscript; change->oldgen = prevgen; change->newgen = currlayer->algo->getGeneration(); change->oldfile = prevfile; change->newfile = fpath; change->oldx = prevx; change->oldy = prevy; viewptr->GetPos(change->newx, change->newy); change->oldmag = prevmag; change->newmag = viewptr->GetMag(); change->oldbase = prevbase; change->newbase = currlayer->currbase; change->oldexpo = prevexpo; change->newexpo = currlayer->currexpo; change->oldsel = prevsel; change->newsel = currlayer->currsel; // prevfile has been saved in change->oldfile (~ChangeNode will delete it) prevfile = wxEmptyString; undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::AddGenChange() { // add a genchange node to empty undo list if (!undolist.IsEmpty()) Warning(_("AddGenChange bug: undo list NOT empty!")); // use starting pattern info for previous state prevgen = currlayer->startgen; prevsel = currlayer->startsel; prevx = currlayer->startx; prevy = currlayer->starty; prevmag = currlayer->startmag; prevbase = currlayer->startbase; prevexpo = currlayer->startexpo; prevfile = wxEmptyString; // play safe and pretend RememberGenStart was called startcount = 1; // avoid RememberGenFinish returning early if inscript is true savegenchanges = false; RememberGenFinish(); if (undolist.IsEmpty()) Warning(_("AddGenChange bug: undo list is empty!")); } // ----------------------------------------------------------------------------- void UndoRedo::SyncUndoHistory() { // synchronize undo history due to a ResetPattern call; // wind back the undo list to just past the genchange node that // matches the current layer's starting gen count wxList::compatibility_iterator node; ChangeNode* change; while (!undolist.IsEmpty()) { node = undolist.GetFirst(); change = (ChangeNode*) node->GetData(); // remove node from head of undo list and append it to redo list undolist.Erase(node); redolist.Insert(change); if (change->changeid == genchange && change->oldgen == currlayer->startgen) { if (change->scriptgen) { // gen change was done by a script so keep winding back the undo list // to just past the scriptstart node, or until the list is empty while (!undolist.IsEmpty()) { node = undolist.GetFirst(); change = (ChangeNode*) node->GetData(); undolist.Erase(node); redolist.Insert(change); if (change->changeid == scriptstart) break; } } // update Undo/Redo items so they show the correct suffix UpdateUndoRedoItems(); return; } } // should never get here Warning(_("Bug detected in SyncUndoHistory!")); } // ----------------------------------------------------------------------------- void UndoRedo::RememberSetGen(bigint& oldgen, bigint& newgen, bigint& oldstartgen, bool oldsave) { wxString oldtempstart = currlayer->tempstart; wxString oldstartfile = currlayer->startfile; wxString oldcurrfile = currlayer->currfile; if (oldgen > oldstartgen && newgen <= oldstartgen) { // if pattern is generated then tempstart will be clobbered by // SaveStartingPattern, so change tempstart to a new temporary file currlayer->tempstart = wxFileName::CreateTempFileName(tempdir + wxT("golly_setgen_")); // also need to update startfile and currfile (currlayer->savestart is true) currlayer->startfile = currlayer->tempstart; currlayer->currfile = wxEmptyString; } // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add setgen node to head of undo list ChangeNode* change = new ChangeNode(setgen); if (change == NULL) Fatal(_("Failed to create setgen node!")); change->suffix = _("Set Generation"); change->oldgen = oldgen; change->newgen = newgen; change->oldstartgen = oldstartgen; change->newstartgen = currlayer->startgen; change->oldsave = oldsave; change->newsave = currlayer->savestart; change->oldtempstart = oldtempstart; change->newtempstart = currlayer->tempstart; change->oldstartfile = oldstartfile; change->newstartfile = currlayer->startfile; change->oldcurrfile = oldcurrfile; change->newcurrfile = currlayer->currfile; if (change->oldtempstart != change->newtempstart) { // save extra starting info set by previous SaveStartingPattern so that // Undoing this setgen change will restore the correct info for a Reset change->olddirty = currlayer->startdirty; change->oldalgo = currlayer->startalgo; change->oldrule = currlayer->startrule; change->oldx = currlayer->startx; change->oldy = currlayer->starty; change->oldmag = currlayer->startmag; change->oldbase = currlayer->startbase; change->oldexpo = currlayer->startexpo; change->oldsel = currlayer->startsel; change->oldname = currlayer->startname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { change->oldclone[i] = cloneptr->startname; } } } // following settings will be updated by next RememberGenStart call so that // Redoing this setgen change will restore the correct info for a Reset fixsetgen = true; change->newdirty = currlayer->startdirty; change->newalgo = currlayer->startalgo; change->newrule = currlayer->startrule; change->newx = currlayer->startx; change->newy = currlayer->starty; change->newmag = currlayer->startmag; change->newbase = currlayer->startbase; change->newexpo = currlayer->startexpo; change->newsel = currlayer->startsel; change->newname = currlayer->startname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { change->newclone[i] = cloneptr->startname; } } } } undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::RememberNameChange(const wxString& oldname, const wxString& oldcurrfile, bool oldsave, bool olddirty) { if (oldname == currlayer->currname && oldcurrfile == currlayer->currfile && oldsave == currlayer->savestart && olddirty == currlayer->dirty) return; // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add namechange node to head of undo list ChangeNode* change = new ChangeNode(namechange); if (change == NULL) Fatal(_("Failed to create namechange node!")); change->suffix = _("Name Change"); change->oldname = oldname; change->newname = currlayer->currname; change->oldcurrfile = oldcurrfile; change->newcurrfile = currlayer->currfile; change->oldsave = oldsave; change->newsave = currlayer->savestart; change->olddirty = olddirty; change->newdirty = currlayer->dirty; // cloned layers share the same undo/redo history but each clone can have // a different name, so we need to remember which layer was changed change->whichlayer = currlayer; undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::DeletingClone(int index) { // the given cloned layer is about to be deleted, so we need to go thru the // undo/redo lists and, for each namechange node, set a matching whichlayer // ptr to NULL so DoChange can ignore later changes involving this layer; // very ugly, but I don't see any better solution if we're going to allow // cloned layers to have different names Layer* cloneptr = GetLayer(index); wxList::compatibility_iterator node; node = undolist.GetFirst(); while (node) { ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == namechange && change->whichlayer == cloneptr) change->whichlayer = NULL; node = node->GetNext(); } node = redolist.GetFirst(); while (node) { ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == namechange && change->whichlayer == cloneptr) change->whichlayer = NULL; node = node->GetNext(); } } // ----------------------------------------------------------------------------- void UndoRedo::RememberRuleChange(const wxString& oldrule) { wxString newrule = wxString(currlayer->algo->getrule(), wxConvLocal); if (oldrule == newrule) return; // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add rulechange node to head of undo list ChangeNode* change = new ChangeNode(rulechange); if (change == NULL) Fatal(_("Failed to create rulechange node!")); change->suffix = _("Rule Change"); change->oldrule = oldrule; change->newrule = newrule; // selection might have changed if grid became smaller change->oldsel = currlayer->savesel; change->newsel = currlayer->currsel; // SaveCellChange may have been called if (numchanges > 0) { if (numchanges < maxchanges) { // reduce size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, numchanges * sizeof(cell_change)); if (newptr != NULL) cellarray = newptr; } change->cellinfo = cellarray; change->cellcount = numchanges; numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto if (badalloc) { Warning(lack_of_memory); badalloc = false; } } undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::RememberAlgoChange(algo_type oldalgo, const wxString& oldrule) { // clear the redo history WX_CLEAR_LIST(wxList, redolist); UpdateRedoItem(wxEmptyString); // add algochange node to head of undo list ChangeNode* change = new ChangeNode(algochange); if (change == NULL) Fatal(_("Failed to create algochange node!")); change->suffix = _("Algorithm Change"); change->oldalgo = oldalgo; change->newalgo = currlayer->algtype; change->oldrule = oldrule; change->newrule = wxString(currlayer->algo->getrule(), wxConvLocal); // selection might have changed if grid became smaller change->oldsel = currlayer->savesel; change->newsel = currlayer->currsel; // SaveCellChange may have been called if (numchanges > 0) { if (numchanges < maxchanges) { // reduce size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, numchanges * sizeof(cell_change)); if (newptr != NULL) cellarray = newptr; } change->cellinfo = cellarray; change->cellcount = numchanges; numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto if (badalloc) { Warning(lack_of_memory); badalloc = false; } } undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- void UndoRedo::RememberScriptStart() { if (!undolist.IsEmpty()) { wxList::compatibility_iterator node = undolist.GetFirst(); ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == scriptstart) { // ignore consecutive RememberScriptStart calls made by RunScript // due to cloned layers if (numclones == 0) Warning(_("Unexpected RememberScriptStart call!")); return; } } // add scriptstart node to head of undo list ChangeNode* change = new ChangeNode(scriptstart); if (change == NULL) Fatal(_("Failed to create scriptstart node!")); change->suffix = _("Script Changes"); undolist.Insert(change); // update Undo action and clear Redo action UpdateUndoItem(change->suffix); UpdateRedoItem(wxEmptyString); } // ----------------------------------------------------------------------------- void UndoRedo::RememberScriptFinish() { if (undolist.IsEmpty()) { // this can happen if RunScript calls RememberScriptFinish multiple times // due to cloned layers AND the script made no changes if (numclones == 0) { // there should be at least a scriptstart node (see ClearUndoRedo) Warning(_("Bug detected in RememberScriptFinish!")); } return; } // if head of undo list is a scriptstart node then simply remove it // and return (ie. the script didn't make any changes) wxList::compatibility_iterator node = undolist.GetFirst(); ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == scriptstart) { undolist.Erase(node); delete change; return; } else if (change->changeid == scriptfinish) { // ignore consecutive RememberScriptFinish calls made by RunScript // due to cloned layers if (numclones == 0) Warning(_("Unexpected RememberScriptFinish call!")); return; } // add scriptfinish node to head of undo list change = new ChangeNode(scriptfinish); if (change == NULL) Fatal(_("Failed to create scriptfinish node!")); change->suffix = _("Script Changes"); undolist.Insert(change); // update Undo item in Edit menu UpdateUndoItem(change->suffix); } // ----------------------------------------------------------------------------- bool UndoRedo::CanUndo() { // we need to allow undo if generating even though undo list might be empty // (selecting Undo will stop generating and add genchange node to undo list) if (allowundo && mainptr->generating) return true; return !undolist.IsEmpty() && !inscript && !viewptr->waitingforclick && !viewptr->drawingcells && !viewptr->selectingcells; } // ----------------------------------------------------------------------------- bool UndoRedo::CanRedo() { return !redolist.IsEmpty() && !inscript && !mainptr->generating && !viewptr->waitingforclick && !viewptr->drawingcells && !viewptr->selectingcells; } // ----------------------------------------------------------------------------- void UndoRedo::UndoChange() { if (!CanUndo()) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_UNDO); return; } // prevent re-entrancy if DoChange calls checkevents if (insideYield) return; // get change info from head of undo list and do the change wxList::compatibility_iterator node = undolist.GetFirst(); ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == scriptfinish) { // undo all changes between scriptfinish and scriptstart nodes; // first remove scriptfinish node from undo list and add it to redo list undolist.Erase(node); redolist.Insert(change); while (change->changeid != scriptstart) { // call UndoChange recursively; temporarily set doingscriptchanges so // 1) UndoChange won't return if DoChange is aborted // 2) user won't see any intermediate pattern/status updates // 3) Undo/Redo items won't be updated doingscriptchanges = true; UndoChange(); doingscriptchanges = false; node = undolist.GetFirst(); if (node == NULL) Fatal(_("Bug in UndoChange!")); change = (ChangeNode*) node->GetData(); } mainptr->UpdatePatternAndStatus(); // continue below so that scriptstart node is removed from undo list // and added to redo list } else { // user might abort the undo (eg. a lengthy rotate/flip) if (!change->DoChange(true) && !doingscriptchanges) return; } // remove node from head of undo list (doesn't delete node's data) undolist.Erase(node); if (change->changeid < selchange && change->olddirty != change->newdirty) { // change dirty flag, update window title and Layer menu items if (change->olddirty) { currlayer->dirty = false; // make sure it changes MarkLayerDirty(); } else { MarkLayerClean(currlayer->currname); } } // add change to head of redo list redolist.Insert(change); // update Undo/Redo items in Edit menu UpdateUndoRedoItems(); } // ----------------------------------------------------------------------------- void UndoRedo::RedoChange() { if (!CanRedo()) return; /* can't redo while generating -- redo list will be empty if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_REDO); return; } */ // prevent re-entrancy if DoChange calls checkevents if (insideYield) return; // get change info from head of redo list and do the change wxList::compatibility_iterator node = redolist.GetFirst(); ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == scriptstart) { // redo all changes between scriptstart and scriptfinish nodes; // first remove scriptstart node from redo list and add it to undo list redolist.Erase(node); undolist.Insert(change); while (change->changeid != scriptfinish) { // call RedoChange recursively; temporarily set doingscriptchanges so // 1) RedoChange won't return if DoChange is aborted // 2) user won't see any intermediate pattern/status updates // 3) Undo/Redo items won't be updated doingscriptchanges = true; RedoChange(); doingscriptchanges = false; node = redolist.GetFirst(); if (node == NULL) Fatal(_("Bug in RedoChange!")); change = (ChangeNode*) node->GetData(); } mainptr->UpdatePatternAndStatus(); // continue below so that scriptfinish node is removed from redo list // and added to undo list } else { // user might abort the redo (eg. a lengthy rotate/flip) if (!change->DoChange(false) && !doingscriptchanges) return; } // remove node from head of redo list (doesn't delete node's data) redolist.Erase(node); if (change->changeid < selchange && change->olddirty != change->newdirty) { // change dirty flag, update window title and Layer menu items if (change->newdirty) { currlayer->dirty = false; // make sure it changes MarkLayerDirty(); } else { MarkLayerClean(currlayer->currname); } } // add change to head of undo list undolist.Insert(change); // update Undo/Redo items in Edit menu UpdateUndoRedoItems(); } // ----------------------------------------------------------------------------- void UndoRedo::UpdateUndoRedoItems() { if (inscript) return; // update Undo/Redo items at end of script if (doingscriptchanges) return; if (undolist.IsEmpty()) { UpdateUndoItem(wxEmptyString); } else { wxList::compatibility_iterator node = undolist.GetFirst(); ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == genchange) { change->suffix = to_gen + wxString(change->oldgen.tostring(), wxConvLocal); } UpdateUndoItem(change->suffix); } if (redolist.IsEmpty()) { UpdateRedoItem(wxEmptyString); } else { wxList::compatibility_iterator node = redolist.GetFirst(); ChangeNode* change = (ChangeNode*) node->GetData(); if (change->changeid == genchange) { change->suffix = to_gen + wxString(change->newgen.tostring(), wxConvLocal); } UpdateRedoItem(change->suffix); } } // ----------------------------------------------------------------------------- void UndoRedo::UpdateUndoItem(const wxString& action) { if (inscript) return; // update Undo/Redo items at end of script wxMenuBar* mbar = mainptr->GetMenuBar(); if (mbar) { wxString label = _("Undo "); label += action; label += GetAccelerator(DO_UNDO); mbar->SetLabel(ID_UNDO, label); } } // ----------------------------------------------------------------------------- void UndoRedo::UpdateRedoItem(const wxString& action) { if (inscript) return; // update Undo/Redo items at end of script wxMenuBar* mbar = mainptr->GetMenuBar(); if (mbar) { wxString label = _("Redo "); label += action; label += GetAccelerator(DO_REDO); mbar->SetLabel(ID_REDO, label); } } // ----------------------------------------------------------------------------- void UndoRedo::ClearUndoRedo() { // free cellarray in case there were SaveCellChange calls not followed // by ForgetCellChanges or RememberCellChanges ForgetCellChanges(); if (startcount > 0) { // RememberGenStart was not followed by RememberGenFinish if (!prevfile.IsEmpty() && wxFileExists(prevfile)) { wxRemoveFile(prevfile); } prevfile = wxEmptyString; startcount = 0; } // clear the undo/redo lists (and delete each node's data) WX_CLEAR_LIST(wxList, undolist); WX_CLEAR_LIST(wxList, redolist); fixsetgen = false; if (inscript) { // script has called a command like new() so add a scriptstart node // to the undo list to match the final scriptfinish node RememberScriptStart(); // reset flags to indicate no pending cell/gen changes savecellchanges = false; savegenchanges = false; } else { UpdateUndoItem(wxEmptyString); UpdateRedoItem(wxEmptyString); } } // ----------------------------------------------------------------------------- bool CopyTempFiles(ChangeNode* srcnode, ChangeNode* destnode, const wxString& tempstart1) { // if srcnode has any existing temporary files then create new // temporary file names in the destnode and copy each file bool allcopied = true; if ( !srcnode->oldfile.IsEmpty() && wxFileExists(srcnode->oldfile) ) { destnode->oldfile = wxFileName::CreateTempFileName(tempdir + wxT("golly_dupe1_")); if ( !wxCopyFile(srcnode->oldfile, destnode->oldfile, true) ) allcopied = false; } if ( !srcnode->newfile.IsEmpty() && wxFileExists(srcnode->newfile) ) { destnode->newfile = wxFileName::CreateTempFileName(tempdir + wxT("golly_dupe2_")); if ( !wxCopyFile(srcnode->newfile, destnode->newfile, true) ) allcopied = false; } if ( !srcnode->oldtempstart.IsEmpty() && wxFileExists(srcnode->oldtempstart) ) { if (srcnode->oldtempstart == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->oldtempstart = tempstart1; } else { destnode->oldtempstart = wxFileName::CreateTempFileName(tempdir + wxT("golly_dupe3_")); if ( !wxCopyFile(srcnode->oldtempstart, destnode->oldtempstart, true) ) allcopied = false; } if (srcnode->oldstartfile == srcnode->oldtempstart) destnode->oldstartfile = destnode->oldtempstart; if (srcnode->oldcurrfile == srcnode->oldtempstart) destnode->oldcurrfile = destnode->oldtempstart; } if ( !srcnode->newtempstart.IsEmpty() && wxFileExists(srcnode->newtempstart) ) { if (srcnode->newtempstart == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->newtempstart = tempstart1; } else { destnode->newtempstart = wxFileName::CreateTempFileName(tempdir + wxT("golly_dupe4_")); if ( !wxCopyFile(srcnode->newtempstart, destnode->newtempstart, true) ) allcopied = false; } if (srcnode->newstartfile == srcnode->newtempstart) destnode->newstartfile = destnode->newtempstart; if (srcnode->newcurrfile == srcnode->newtempstart) destnode->newcurrfile = destnode->newtempstart; } return allcopied; } // ----------------------------------------------------------------------------- void UndoRedo::DuplicateHistory(Layer* oldlayer, Layer* newlayer) { UndoRedo* history = oldlayer->undoredo; // clear the undo/redo lists; note that UndoRedo::UndoRedo has added // a scriptstart node to undolist if inscript is true, but we don't // want that here because the old layer's history will already have one WX_CLEAR_LIST(wxList, undolist); WX_CLEAR_LIST(wxList, redolist); // safer to do our own shallow copy (avoids setting undolist/redolist) savecellchanges = history->savecellchanges; savegenchanges = history->savegenchanges; doingscriptchanges = history->doingscriptchanges; numchanges = history->numchanges; maxchanges = history->maxchanges; badalloc = history->badalloc; prevfile = history->prevfile; prevgen = history->prevgen; prevx = history->prevx; prevy = history->prevy; prevmag = history->prevmag; prevbase = history->prevbase; prevexpo = history->prevexpo; prevsel = history->prevsel; startcount = history->startcount; fixsetgen = history->fixsetgen; // copy existing temporary file to new name if ( !prevfile.IsEmpty() && wxFileExists(prevfile) ) { prevfile = wxFileName::CreateTempFileName(tempdir + temp_prefix); if ( !wxCopyFile(history->prevfile, prevfile, true) ) { Warning(_("Could not copy prevfile!")); return; } } // do a deep copy of dynamically allocated data cellarray = NULL; if (numchanges > 0 && history->cellarray) { cellarray = (cell_change*) malloc(maxchanges * sizeof(cell_change)); if (cellarray == NULL) { Warning(_("Could not allocate cellarray!")); return; } // copy history->cellarray data to this cellarray memcpy(cellarray, history->cellarray, numchanges * sizeof(cell_change)); } wxList::compatibility_iterator node; // build a new undolist using history->undolist node = history->undolist.GetFirst(); while (node) { ChangeNode* change = (ChangeNode*) node->GetData(); ChangeNode* newchange = new ChangeNode(change->changeid); if (newchange == NULL) { Warning(_("Failed to copy undolist!")); WX_CLEAR_LIST(wxList, undolist); return; } // shallow copy the change node *newchange = *change; // deep copy any dynamically allocated data if (change->cellinfo) { int bytes = change->cellcount * sizeof(cell_change); newchange->cellinfo = (cell_change*) malloc(bytes); if (newchange->cellinfo == NULL) { Warning(_("Could not copy undolist!")); WX_CLEAR_LIST(wxList, undolist); return; } memcpy(newchange->cellinfo, change->cellinfo, bytes); } // copy any existing temporary files to new names if (!CopyTempFiles(change, newchange, newlayer->tempstart)) { Warning(_("Failed to copy temporary file in undolist!")); WX_CLEAR_LIST(wxList, undolist); return; } // if node is a name change then update whichlayer to point to new layer if (newchange->changeid == namechange) { newchange->whichlayer = newlayer; } undolist.Append(newchange); node = node->GetNext(); } // build a new redolist using history->redolist node = history->redolist.GetFirst(); while (node) { ChangeNode* change = (ChangeNode*) node->GetData(); ChangeNode* newchange = new ChangeNode(change->changeid); if (newchange == NULL) { Warning(_("Failed to copy redolist!")); WX_CLEAR_LIST(wxList, redolist); return; } // shallow copy the change node *newchange = *change; // deep copy any dynamically allocated data if (change->cellinfo) { int bytes = change->cellcount * sizeof(cell_change); newchange->cellinfo = (cell_change*) malloc(bytes); if (newchange->cellinfo == NULL) { Warning(_("Could not copy redolist!")); WX_CLEAR_LIST(wxList, redolist); return; } memcpy(newchange->cellinfo, change->cellinfo, bytes); } // copy any existing temporary files to new names if (!CopyTempFiles(change, newchange, newlayer->tempstart)) { Warning(_("Failed to copy temporary file in redolist!")); WX_CLEAR_LIST(wxList, redolist); return; } // if node is a name change then update whichlayer to point to new layer if (newchange->changeid == namechange) { newchange->whichlayer = newlayer; } redolist.Append(newchange); node = node->GetNext(); } } golly-2.7-src/gui-wx/wxscript.h0000644000175000017500000001111712536111364013475 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXSCRIPT_H_ #define _WXSCRIPT_H_ #include "lifealgo.h" // for lifealgo class extern bool inscript; // Is a script currently running? We allow access to this flag // so clients can temporarily save and restore its setting. extern bool passkeys; extern bool passclicks; // Pass keyboard and/or mouse events to script? Both flags are initially false // at the start of a script; both become true if the script calls getevent. // If the script calls getkey (deprecated) then only passkeys becomes true. extern bool canswitch; // Can user switch layers while a script is running? extern bool stop_after_script; // Stop generating pattern after running script? void RunScript(const wxString& filename); // Run the given Perl or Python script. void PassClickToScript(const bigint& x, const bigint& y, int button, int modifiers); // Called if a script is running and user clicks mouse. void PassKeyToScript(int key, int modifiers = 0); // Called if a script is running and user hits a key. // Can also be used to abort a script by passing WXK_ESCAPE. void ShowTitleLater(); // Called if a script is running and window title has changed. void ChangeCell(int x, int y, int oldstate, int newstate); // A setcell/putcells command is changing state of cell at x,y. void SavePendingChanges(bool checkgenchanges = true); // Called to save any pending cell changes made by ChangeCell calls. // If checkgenchanges is true then it will also save any pending // generating changes. This lets us accumulate consecutive cell/gen // changes in a single undo/redo change node, which is better for // scripts like invert.py that can call setcell() many times, or // for scripts like oscar.py that can call run() many times. // Must be called BEFORE all undoredo->Remember... calls but // only if inscript && allowundo && !currlayer->stayclean. void FinishScripting(); // Called when app quits to abort a running script. // Following are used in wxperl.cpp and wxpython.cpp: extern bool autoupdate; // update display after changing current universe? extern bool allowcheck; // allow event checking? extern wxString scripterr; // Perl/Python error message extern wxString mousepos; // current mouse position const char abortmsg[] = "GOLLY: ABORT SCRIPT"; // special message used to indicate that the script was aborted void DoAutoUpdate(); // update display if autoupdate is true // The following Golly Script Functions are used to reduce code duplication. // They are called by corresponding pl_* and py_* functions in wxperl.cpp // and wxpython.cpp respectively. const char* GSF_open(char* filename, int remember); const char* GSF_save(char* filename, char* format, int remember); const char* GSF_setdir(char* dirname, char* newdir); const char* GSF_getdir(char* dirname); const char* GSF_setalgo(char* algostring); const char* GSF_setrule(char* rulestring); const char* GSF_setgen(char* genstring); const char* GSF_setpos(char* x, char* y); const char* GSF_setcell(int x, int y, int newstate); const char* GSF_paste(int x, int y, char* mode); const char* GSF_checkpos(lifealgo* algo, int x, int y); const char* GSF_checkrect(int x, int y, int wd, int ht); int GSF_hash(int x, int y, int wd, int ht); bool GSF_setoption(char* optname, int newval, int* oldval); bool GSF_getoption(char* optname, int* optval); bool GSF_setcolor(char* colname, wxColor& newcol, wxColor& oldcol); bool GSF_getcolor(char* colname, wxColor& color); void GSF_setname(char* name, int index); void GSF_select(int x, int y, int wd, int ht); void GSF_getevent(wxString& event, int get); const char* GSF_doevent(const wxString& event); void GSF_getkey(char* s); void GSF_dokey(char* ascii); void GSF_update(); void GSF_exit(char* errmsg); #endif golly-2.7-src/gui-wx/wxalgos.h0000644000175000017500000001232312536111364013276 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXALGOS_H_ #define _WXALGOS_H_ #include "lifealgo.h" // Golly supports multiple algorithms. The first algorithm // registered must *always* be qlifealgo. The second must // *always* be hlifealgo. (These are to support old scripts.) // The order of the rest do not matter and indeed should soon // be capable of being dynamic. enum { QLIFE_ALGO, // QuickLife HLIFE_ALGO // HashLife }; const int MAX_ALGOS = 50; // maximum number of algorithms typedef int algo_type; // 0..MAX_ALGOS-1 // A class for all the static info we need about a particular algorithm. class AlgoData : public staticAlgoInfo { public: AlgoData(); ~AlgoData(); virtual void setDefaultBaseStep(int v) { defbase = v; } virtual void setDefaultMaxMem(int v) { algomem = v; } static AlgoData& tick(); // static allocator // additional data bool canhash; // algo uses hashing? int algomem; // maximum memory (in MB) int defbase; // default base step wxColor statusrgb; // status bar color wxBrush* statusbrush; // corresponding brush wxBitmap** icons7x7; // icon bitmaps for scale 1:8 wxBitmap** icons15x15; // icon bitmaps for scale 1:16 wxBitmap** icons31x31; // icon bitmaps for scale 1:32 // default color scheme bool gradient; // use color gradient? wxColor fromrgb; // color at start of gradient wxColor torgb; // color at end of gradient // if gradient is false then use these colors for each cell state unsigned char algor[256]; unsigned char algog[256]; unsigned char algob[256]; }; extern AlgoData* algoinfo[MAX_ALGOS]; // static info for each algorithm extern wxMenu* algomenu; // menu of algorithm names extern wxMenu* algomenupop; // copy of algomenu for PopupMenu calls extern algo_type initalgo; // initial algorithm // the following bitmaps are grayscale icons that can be used with any rules // with any number of states extern wxBitmap** circles7x7; // circular icons for scale 1:8 extern wxBitmap** circles15x15; // circular icons for scale 1:16 extern wxBitmap** circles31x31; // circular icons for scale 1:32 extern wxBitmap** diamonds7x7; // diamond icons for scale 1:8 extern wxBitmap** diamonds15x15; // diamond icons for scale 1:16 extern wxBitmap** diamonds31x31; // diamond icons for scale 1:32 extern wxBitmap** hexagons7x7; // hexagonal icons for scale 1:8 extern wxBitmap** hexagons15x15; // hexagonal icons for scale 1:16 extern wxBitmap** hexagons31x31; // hexagonal icons for scale 1:32 // NOTE: the triangular icons are only suitable for a 4-state rule that // is emulating a triangular neighborhood with 2 triangles per cell extern wxBitmap** triangles7x7; // triangular icons for scale 1:8 extern wxBitmap** triangles15x15; // triangular icons for scale 1:16 extern wxBitmap** triangles31x31; // triangular icons for scale 1:32 void InitAlgorithms(); // Initialize above data. Must be called before reading the prefs file. void DeleteAlgorithms(); // Deallocate memory allocated in InitAlgorithms(). lifealgo* CreateNewUniverse(algo_type algotype, bool allowcheck = true); // Create a new universe of given type. If allowcheck is true then // event checking is allowed; ie. poller is set to wxGetApp().Poller(). const char* GetAlgoName(algo_type algotype); // Return name of given algorithm. This name appears in various menus // and is also stored in the prefs file. int NumAlgos(); // Return current number of algorithms. bool MultiColorImage(wxImage& image); // Return true if image contains at least one color that isn't a shade of gray. bool LoadIconFile(const wxString& path, int maxstate, wxBitmap*** out7x7, wxBitmap*** out15x15, wxBitmap*** out31x31); // Return true if we can successfully load icon bitmaps from given file. wxBitmap** CreateIconBitmaps(const char** xpmdata, int maxstates); // Create icon bitmaps using the given XPM data. wxBitmap** ScaleIconBitmaps(wxBitmap** srcicons, int size); // Create scaled versions of the given icon bitmaps. void FreeIconBitmaps(wxBitmap** icons); // Delete the given icon bitmaps. #endif golly-2.7-src/gui-wx/wxpython.h0000644000175000017500000000225212536111364013512 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXPYTHON_H_ #define _WXPYTHON_H_ void RunPythonScript(const wxString& filepath); // Run the given .py file. void AbortPythonScript(); // Abort the currently running Python script. void FinishPythonScripting(); // Called when app is quitting. #endif golly-2.7-src/gui-wx/wxutils.cpp0000644000175000017500000005507112536111364013673 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/spinctrl.h" // for wxSpinCtrl #include "wx/progdlg.h" // for wxProgressDialog #include "wx/image.h" // for wxImage #include "wxgolly.h" // for wxGetApp, viewptr, mainptr #include "wxview.h" // for viewptr->... #include "wxmain.h" // for mainptr->... #include "wxscript.h" // for inscript, PassKeyToScript #include "wxprefs.h" // for allowbeep #include "wxutils.h" #if defined(__WXMAC__) && !defined(__WXOSX_COCOA__) #include #include "wx/mac/corefoundation/cfstring.h" // for wxMacCFStringHolder #endif // ----------------------------------------------------------------------------- // need platform-specific gap after OK/Cancel buttons #ifdef __WXMAC__ const int STDHGAP = 0; #elif defined(__WXMSW__) const int STDHGAP = 6; #else const int STDHGAP = 10; #endif // ----------------------------------------------------------------------------- void Note(const wxString& msg) { wxString title = wxGetApp().GetAppName() + _(" note:"); #ifdef __WXMAC__ wxSetCursor(*wxSTANDARD_CURSOR); #endif wxMessageBox(msg, title, wxOK | wxICON_INFORMATION, wxGetActiveWindow()); } // ----------------------------------------------------------------------------- void Warning(const wxString& msg) { Beep(); wxString title = wxGetApp().GetAppName() + _(" warning:"); #ifdef __WXMAC__ wxSetCursor(*wxSTANDARD_CURSOR); #endif wxMessageBox(msg, title, wxOK | wxICON_EXCLAMATION, wxGetActiveWindow()); } // ----------------------------------------------------------------------------- void Fatal(const wxString& msg) { Beep(); wxString title = wxGetApp().GetAppName() + _(" error:"); #ifdef __WXMAC__ wxSetCursor(*wxSTANDARD_CURSOR); #endif wxMessageBox(msg, title, wxOK | wxICON_ERROR, wxGetActiveWindow()); exit(1); // safer than calling wxExit() } // ----------------------------------------------------------------------------- void Beep() { if (allowbeep) wxBell(); } // ============================================================================= // define a modal dialog for getting a string class StringDialog : public wxDialog { public: StringDialog(wxWindow* parent, const wxString& title, const wxString& prompt, const wxString& instring); virtual bool TransferDataFromWindow(); // called when user hits OK wxString GetValue() { return result; } private: wxTextCtrl* textbox; // text box for entering the string wxString result; // the resulting string }; // ----------------------------------------------------------------------------- StringDialog::StringDialog(wxWindow* parent, const wxString& title, const wxString& prompt, const wxString& instring) { Create(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize); // create the controls wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); SetSizer(topSizer); textbox = new wxTextCtrl(this, wxID_ANY, instring); wxStaticText* promptlabel = new wxStaticText(this, wxID_STATIC, prompt); wxSizer* stdbutts = CreateButtonSizer(wxOK | wxCANCEL); // position the controls wxBoxSizer* stdhbox = new wxBoxSizer(wxHORIZONTAL); stdhbox->Add(stdbutts, 1, wxGROW | wxALIGN_CENTER_VERTICAL | wxRIGHT, STDHGAP); wxSize minsize = stdhbox->GetMinSize(); if (minsize.GetWidth() < 250) { minsize.SetWidth(250); stdhbox->SetMinSize(minsize); } topSizer->AddSpacer(12); topSizer->Add(promptlabel, 0, wxLEFT | wxRIGHT, 10); topSizer->AddSpacer(10); topSizer->Add(textbox, 0, wxGROW | wxLEFT | wxRIGHT, 10); topSizer->AddSpacer(12); topSizer->Add(stdhbox, 1, wxGROW | wxTOP | wxBOTTOM, 10); GetSizer()->Fit(this); GetSizer()->SetSizeHints(this); Centre(); // select initial string (must do this last on Windows) textbox->SetFocus(); textbox->SetSelection(-1,-1); } // ----------------------------------------------------------------------------- bool StringDialog::TransferDataFromWindow() { result = textbox->GetValue(); return true; } // ----------------------------------------------------------------------------- bool GetString(const wxString& title, const wxString& prompt, const wxString& instring, wxString& outstring) { StringDialog dialog(wxGetApp().GetTopWindow(), title, prompt, instring); if ( dialog.ShowModal() == wxID_OK ) { outstring = dialog.GetValue(); return true; } else { // user hit Cancel button return false; } } // ============================================================================= // define a modal dialog for getting an integer class IntegerDialog : public wxDialog { public: IntegerDialog(wxWindow* parent, const wxString& title, const wxString& prompt, int inval, int minval, int maxval); virtual bool TransferDataFromWindow(); // called when user hits OK #ifdef __WXMAC__ void OnSpinCtrlChar(wxKeyEvent& event); #endif int GetValue() { return result; } private: enum { ID_SPIN_CTRL = wxID_HIGHEST + 1 }; wxSpinCtrl* spinctrl; // for entering the integer int minint; // minimum value int maxint; // maximum value int result; // the resulting integer }; // ----------------------------------------------------------------------------- #ifdef __WXMAC__ // override key event handler for wxSpinCtrl to allow key checking class MySpinCtrl : public wxSpinCtrl { public: MySpinCtrl(wxWindow* parent, wxWindowID id) : wxSpinCtrl(parent, id) { // create a dynamic event handler for the underlying wxTextCtrl wxTextCtrl* textctrl = GetText(); if (textctrl) { textctrl->Connect(wxID_ANY, wxEVT_CHAR, wxKeyEventHandler(IntegerDialog::OnSpinCtrlChar)); } } }; void IntegerDialog::OnSpinCtrlChar(wxKeyEvent& event) { int key = event.GetKeyCode(); if (event.CmdDown()) { // allow handling of cmd-x/v/etc event.Skip(); } else if ( key == WXK_TAB ) { wxSpinCtrl* sc = (wxSpinCtrl*) FindWindowById(ID_SPIN_CTRL); if ( sc ) { sc->SetFocus(); sc->SetSelection(-1,-1); } } else if ( key >= ' ' && key <= '~' ) { if ( (key >= '0' && key <= '9') || key == '+' || key == '-' ) { // allow digits and + or - event.Skip(); } else { // disallow any other displayable ascii char Beep(); } } else { event.Skip(); } } #else #define MySpinCtrl wxSpinCtrl #endif // __WXMAC__ // ----------------------------------------------------------------------------- IntegerDialog::IntegerDialog(wxWindow* parent, const wxString& title, const wxString& prompt, int inval, int minval, int maxval) { Create(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize); minint = minval; maxint = maxval; // create the controls wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); SetSizer(topSizer); spinctrl = new MySpinCtrl(this, ID_SPIN_CTRL); spinctrl->SetRange(minval, maxval); spinctrl->SetValue(inval); wxStaticText* promptlabel = new wxStaticText(this, wxID_STATIC, prompt); wxSizer* stdbutts = CreateButtonSizer(wxOK | wxCANCEL); // position the controls wxBoxSizer* stdhbox = new wxBoxSizer(wxHORIZONTAL); stdhbox->Add(stdbutts, 1, wxGROW | wxALIGN_CENTER_VERTICAL | wxRIGHT, STDHGAP); wxSize minsize = stdhbox->GetMinSize(); if (minsize.GetWidth() < 250) { minsize.SetWidth(250); stdhbox->SetMinSize(minsize); } topSizer->AddSpacer(12); topSizer->Add(promptlabel, 0, wxLEFT | wxRIGHT, 10); topSizer->AddSpacer(10); topSizer->Add(spinctrl, 0, wxGROW | wxLEFT | wxRIGHT, 10); topSizer->AddSpacer(12); topSizer->Add(stdhbox, 1, wxGROW | wxTOP | wxBOTTOM, 10); GetSizer()->Fit(this); GetSizer()->SetSizeHints(this); Centre(); // select initial value (must do this last on Windows) spinctrl->SetFocus(); spinctrl->SetSelection(-1,-1); } // ----------------------------------------------------------------------------- bool IntegerDialog::TransferDataFromWindow() { // spinctrl->GetValue() always returns a value within range even if // the text ctrl doesn't contain a valid number -- yuk! result = spinctrl->GetValue(); if (result < minint || result > maxint) { wxString msg; msg.Printf(_("Value must be from %d to %d."), minint, maxint); Warning(msg); spinctrl->SetFocus(); spinctrl->SetSelection(-1,-1); return false; } else { return true; } } // ----------------------------------------------------------------------------- bool GetInteger(const wxString& title, const wxString& prompt, int inval, int minval, int maxval, int* outval) { IntegerDialog dialog(wxGetApp().GetTopWindow(), title, prompt, inval, minval, maxval); if ( dialog.ShowModal() == wxID_OK ) { *outval = dialog.GetValue(); return true; } else { // user hit Cancel button return false; } } // ============================================================================= #if defined(__WXMAC__) && !defined(__WXOSX_COCOA__) // this filter is used to detect cmd-D in SaveChanges dialog Boolean SaveChangesFilter(DialogRef dlg, EventRecord* event, DialogItemIndex* item) { if (event->what == keyDown && (event->modifiers & cmdKey) && toupper(event->message & charCodeMask) == 'D') { // temporarily highlight the Don't Save button ControlRef ctrl; Rect box; GetDialogItemAsControl(dlg, kAlertStdAlertOtherButton, &ctrl); HiliteControl(ctrl, kControlButtonPart); GetControlBounds(ctrl, &box); InvalWindowRect(GetDialogWindow(dlg), &box); HIWindowFlush(GetDialogWindow(dlg)); Delay(6, NULL); HiliteControl(ctrl, 0); *item = kAlertStdAlertOtherButton; return true; } return StdFilterProc(dlg, event, item); } #endif // ----------------------------------------------------------------------------- int SaveChanges(const wxString& query, const wxString& msg) { #if defined(__WXOSX_COCOA__) // use a standard looking modal dialog on wxOSX; // sadly, positioning over center of parent window is not supported by NSAlert wxMessageDialog dialog(wxGetActiveWindow(), msg, query, wxCENTER | wxNO_DEFAULT | wxYES_NO | wxCANCEL | wxICON_INFORMATION); dialog.SetYesNoCancelLabels("Cancel", "Save", "Don't Save"); switch ( dialog.ShowModal() ) { case wxID_YES: return 0; // Cancel case wxID_NO: return 2; // Save case wxID_CANCEL: return 1; // Don't Save default: return 0; // should never happen } #elif defined(__WXMAC__) // use a standard looking modal dialog on wxMac short result; AlertStdCFStringAlertParamRec param; wxMacCFStringHolder cfSave(_("Save"), wxFONTENCODING_DEFAULT); wxMacCFStringHolder cfDontSave(_("Don't Save"), wxFONTENCODING_DEFAULT); wxMacCFStringHolder cfTitle(query, wxFONTENCODING_DEFAULT); wxMacCFStringHolder cfText(msg, wxFONTENCODING_DEFAULT); param.version = kStdCFStringAlertVersionOne; param.position = kWindowAlertPositionParentWindow; param.movable = true; param.flags = 0; param.defaultText = cfSave; param.cancelText = (CFStringRef) kAlertDefaultCancelText; param.otherText = cfDontSave; param.helpButton = false; param.defaultButton = kAlertStdAlertOKButton; param.cancelButton = kAlertStdAlertCancelButton; ModalFilterUPP filterProc = NewModalFilterUPP(SaveChangesFilter); DialogRef alertRef; CreateStandardAlert(kAlertNoteAlert, cfTitle, cfText, ¶m, &alertRef); RunStandardAlert(alertRef, filterProc, &result); DisposeModalFilterUPP(filterProc); switch (result) { case 1: return 2; // Save case 2: return 0; // Cancel case 3: return 1; // Don't Save default: return 0; } #else // Windows/Linux int answer = wxMessageBox(msg, query, wxICON_QUESTION | wxYES_NO | wxCANCEL, wxGetActiveWindow()); switch (answer) { case wxYES: return 2; case wxNO: return 1; default: return 0; // answer == wxCANCEL } #endif } // ============================================================================= // globals for showing progress wxProgressDialog* progdlg = NULL; // progress dialog const int maxprogrange = 1000000000; // maximum range (best if very large) wxStopWatch* progwatch = NULL; // stopwatch for progress dialog long prognext; // when to update progress dialog wxString progtitle; // title for progress dialog // ----------------------------------------------------------------------------- #ifdef __WXMAC__ // define a key event handler to allow escape key to cancel progress dialog class ProgressHandler : public wxEvtHandler { public: void OnKeyDown(wxKeyEvent& event); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(ProgressHandler, wxEvtHandler) EVT_KEY_DOWN (ProgressHandler::OnKeyDown) END_EVENT_TABLE() void ProgressHandler::OnKeyDown(wxKeyEvent& event) { int key = event.GetKeyCode(); if (key == WXK_ESCAPE || key == '.') { wxCommandEvent cancel(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); wxWindow* buttwin = progdlg->FindWindow(wxID_CANCEL); if (buttwin) { cancel.SetEventObject(buttwin); buttwin->GetEventHandler()->ProcessEvent(cancel); } } else { event.Skip(); } } #endif // ----------------------------------------------------------------------------- void BeginProgress(const wxString& dlgtitle) { if (progdlg) { // better do this in case of nested call delete progdlg; progdlg = NULL; } if (progwatch) { delete progwatch; } progwatch = new wxStopWatch(); progtitle = dlgtitle; // avoid cursor flickering if this is called during a script if (!inscript) { // let user know they'll have to wait #ifdef __WXMAC__ wxSetCursor(*wxHOURGLASS_CURSOR); #endif if (mainptr->infront) viewptr->SetCursor(*wxHOURGLASS_CURSOR); } } // ----------------------------------------------------------------------------- bool AbortProgress(double fraction_done, const wxString& newmsg) { long msecs = progwatch->Time(); if (progdlg) { if (msecs < prognext) return false; prognext = msecs + 100; // call Update/Pulse about 10 times per sec bool cancel; if (fraction_done < 0.0) { // show indeterminate progress gauge cancel = !progdlg->Pulse(newmsg); } else { cancel = !progdlg->Update(int((double)maxprogrange * fraction_done), newmsg); } if (cancel) { // user hit Cancel button if (inscript) PassKeyToScript(WXK_ESCAPE); // abort script return true; } else { return false; } } else { // note that fraction_done is not always an accurate estimator for how long // the task will take, especially when we use nextcell for cut/copy if ( (msecs > 1000 && fraction_done < 0.3) || msecs > 2500 ) { // task is probably going to take a while so create progress dialog progdlg = new wxProgressDialog(progtitle, wxEmptyString, maxprogrange, wxGetActiveWindow(), wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_SMOOTH | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME); #if defined(__WXMAC__) if (progdlg) { #if !defined(__WXOSX_COCOA__) // avoid user selecting Quit or bringing another window to front BeginAppModalStateForWindow( (OpaqueWindowPtr*)progdlg->MacGetWindowRef() ); #endif // install key event handler progdlg->PushEventHandler(new ProgressHandler()); } #endif } prognext = msecs + 10; // short delay until 1st Update/Pulse return false; // don't abort } } // ----------------------------------------------------------------------------- void EndProgress() { if (progdlg) { #if defined(__WXMAC__) #if !defined(__WXOSX_COCOA__) EndAppModalStateForWindow( (OpaqueWindowPtr*)progdlg->MacGetWindowRef() ); #endif // remove and delete ProgressHandler progdlg->PopEventHandler(true); #endif delete progdlg; progdlg = NULL; } if (progwatch) { delete progwatch; progwatch = NULL; } if (!inscript) { // BeginProgress changed cursor so reset it viewptr->CheckCursor(mainptr->infront); } } // ============================================================================= void FillRect(wxDC& dc, wxRect& rect, wxBrush& brush) { // set pen transparent so brush fills rect dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(brush); dc.DrawRectangle(rect); dc.SetBrush(wxNullBrush); // restore brush dc.SetPen(wxNullPen); // restore pen } // ----------------------------------------------------------------------------- void CreatePaleBitmap(const wxBitmap& inmap, wxBitmap& outmap) { wxImage oldimg = inmap.ConvertToImage(); wxImage newimg; newimg.Create(oldimg.GetWidth(), oldimg.GetHeight(), false); unsigned char* dest = newimg.GetData(); unsigned char* src = oldimg.GetData(); bool hasMask = oldimg.HasMask(); unsigned char maskRed = oldimg.GetMaskRed(); unsigned char maskGreen = oldimg.GetMaskGreen(); unsigned char maskBlue = oldimg.GetMaskBlue(); if (hasMask) newimg.SetMaskColour(maskRed, maskGreen, maskBlue); const long size = oldimg.GetWidth() * oldimg.GetHeight(); for ( long i = 0; i < size; i++, src += 3, dest += 3 ) { if ( hasMask && src[0] == maskRed && src[1] == maskGreen && src[2] == maskBlue ) { // don't modify the mask memcpy(dest, src, 3); } else { // make pixel a pale shade of gray int gray = (int) ((src[0] + src[1] + src[2]) / 3.0); gray = (int) (170.0 + (gray / 4.0)); dest[0] = dest[1] = dest[2] = gray; } } // copy the alpha channel, if any if (oldimg.HasAlpha()) { const size_t alphaSize = oldimg.GetWidth() * oldimg.GetHeight(); unsigned char* alpha = (unsigned char*) malloc(alphaSize); if (alpha) { memcpy(alpha, oldimg.GetAlpha(), alphaSize); newimg.InitAlpha(); newimg.SetAlpha(alpha); } } outmap = wxBitmap(newimg); } // ----------------------------------------------------------------------------- bool IsScriptFile(const wxString& filename) { wxString ext = filename.AfterLast('.'); // if filename has no extension then ext == filename if (ext == filename) return false; // currently we support Perl or Python scripts return ( ext.IsSameAs(wxT("pl"),false) || ext.IsSameAs(wxT("py"),false) ); } // ----------------------------------------------------------------------------- bool IsHTMLFile(const wxString& filename) { wxString ext = filename.AfterLast('.'); // if filename has no extension then ext == filename if (ext == filename) return false; return ( ext.IsSameAs(wxT("htm"),false) || ext.IsSameAs(wxT("html"),false) ); } // ----------------------------------------------------------------------------- bool IsTextFile(const wxString& filename) { if (!IsHTMLFile(filename)) { // if non-html file name contains "readme" then assume it's a text file wxString name = filename.AfterLast(wxFILE_SEP_PATH).MakeLower(); if (name.Contains(wxT("readme"))) return true; } wxString ext = filename.AfterLast('.'); // if filename has no extension then ext == filename if (ext == filename) return false; return ( ext.IsSameAs(wxT("txt"),false) || ext.IsSameAs(wxT("doc"),false) ); } // ----------------------------------------------------------------------------- bool IsZipFile(const wxString& filename) { wxString ext = filename.AfterLast('.'); // if filename has no extension then ext == filename if (ext == filename) return false; return ( ext.IsSameAs(wxT("zip"),false) || ext.IsSameAs(wxT("gar"),false) ); } // ----------------------------------------------------------------------------- bool IsRuleFile(const wxString& filename) { wxString ext = filename.AfterLast('.'); // if filename has no extension then ext == filename if (ext == filename) return false; return ( ext.IsSameAs(wxT("rule"),false) || ext.IsSameAs(wxT("table"),false) || ext.IsSameAs(wxT("tree"),false) || ext.IsSameAs(wxT("colors"),false) || ext.IsSameAs(wxT("icons"),false) ); } golly-2.7-src/gui-wx/wxstatus.cpp0000644000175000017500000005177412536111364014064 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/dcbuffer.h" // for wxBufferedPaintDC #include "bigint.h" #include "lifealgo.h" #include "wxgolly.h" // for wxGetApp, etc #include "wxutils.h" // for Fatal, Beep, FillRect #include "wxprefs.h" // for mindelay, maxdelay, etc #include "wxview.h" // for viewptr->... #include "wxmain.h" // for mainptr->... #include "wxscript.h" // for inscript #include "wxalgos.h" // for algoinfo #include "wxlayer.h" // for currlayer #include "wxtimeline.h" // for TimelineExists #include "wxstatus.h" // ----------------------------------------------------------------------------- // the following is a bit messy but gives good results on all platforms const int LINEHT = 14; // distance between each baseline const int DESCHT = 4; // descender height const int STATUS_HT = 2*LINEHT+DESCHT; // normal status bar height const int STATUS_EXHT = 7*LINEHT+DESCHT; // height when showing exact numbers const int BASELINE1 = LINEHT-2; // baseline of 1st line const int BOTGAP = 6; // to get baseline of message line // these baseline values are used when showexact is true const int GENLINE = 1*LINEHT-2; const int POPLINE = 2*LINEHT-2; const int SCALELINE = 3*LINEHT-2; const int STEPLINE = 4*LINEHT-2; const int XLINE = 5*LINEHT-2; const int YLINE = 6*LINEHT-2; // these horizontal offets are used when showexact is true int h_x_ex, h_y_ex; #ifdef __WXMAC__ // gray line at bottom of status bar (matches line at bottom of OS X title bar) wxPen linepen(wxColor(140,140,140)); #endif // ----------------------------------------------------------------------------- void StatusBar::ClearMessage() { if (inscript) return; // let script control messages if (viewptr->waitingforclick) return; // don't clobber message if (statusmsg.IsEmpty()) return; // no need to clear message statusmsg.Clear(); if (statusht > 0) { int wd, ht; GetClientSize(&wd, &ht); if (wd > 0 && ht > 0) { // update bottom line wxRect r = wxRect(wxPoint(0,statusht-BOTGAP+DESCHT-LINEHT), wxPoint(wd-1,ht-1) ); Refresh(false, &r); // nicer not to call Update() here otherwise users can see different // colored bands in status bar when changing algos } } } // ----------------------------------------------------------------------------- void StatusBar::DisplayMessage(const wxString& s) { if (inscript) return; // let script control messages statusmsg = s; if (statusht > 0) { int wd, ht; GetClientSize(&wd, &ht); if (wd > 0 && ht > 0) { // update bottom line wxRect r = wxRect( wxPoint(0,statusht-BOTGAP+DESCHT-LINEHT), wxPoint(wd-1,ht-1) ); Refresh(false, &r); // show message immediately Update(); } } } // ----------------------------------------------------------------------------- void StatusBar::ErrorMessage(const wxString& s) { if (inscript) return; // let script control messages Beep(); DisplayMessage(s); } // ----------------------------------------------------------------------------- void StatusBar::SetMessage(const wxString& s) { if (inscript) return; // let script control messages // set message string without displaying it statusmsg = s; } // ----------------------------------------------------------------------------- void StatusBar::UpdateXYLocation() { int wd, ht; GetClientSize(&wd, &ht); if (ht > 0 && (wd > h_xy || showexact)) { wxRect r; if (showexact) r = wxRect( wxPoint(0, XLINE+DESCHT-LINEHT), wxPoint(wd-1, YLINE+DESCHT) ); else r = wxRect( wxPoint(h_xy, 0), wxPoint(wd-1, BASELINE1+DESCHT) ); Refresh(false, &r); // no need to Update() immediately } } // ----------------------------------------------------------------------------- void StatusBar::CheckMouseLocation(bool active) { if (statusht == 0 && !inscript) return; if ( !active ) { // main window is not in front so clear XY location showxy = false; if (statusht > 0) UpdateXYLocation(); if (inscript) mousepos = wxEmptyString; return; } // may need to update XY location in status bar bigint xpos, ypos; if ( viewptr->GetCellPos(xpos, ypos) ) { if ( xpos != currx || ypos != curry ) { // show new XY location currx = xpos; curry = ypos; showxy = true; if (statusht > 0) UpdateXYLocation(); } else if (!showxy) { showxy = true; if (statusht > 0) UpdateXYLocation(); } if (inscript) { mousepos = wxString(xpos.tostring('\0'), wxConvLocal); mousepos += wxT(" "); mousepos += wxString(ypos.tostring('\0'), wxConvLocal); } } else { // outside viewport so clear XY location showxy = false; if (statusht > 0) UpdateXYLocation(); if (inscript) mousepos = wxEmptyString; } } // ----------------------------------------------------------------------------- void StatusBar::SetStatusFont(wxDC& dc) { dc.SetFont(*statusfont); dc.SetTextForeground(*wxBLACK); dc.SetBrush(*wxBLACK_BRUSH); dc.SetBackgroundMode(wxTRANSPARENT); } // ----------------------------------------------------------------------------- void StatusBar::DisplayText(wxDC& dc, const wxString& s, wxCoord x, wxCoord y) { // DrawText's y parameter is top of text box but we pass in baseline // so adjust by textascent which depends on platform and OS version -- yuk! dc.DrawText(s, x, y - textascent); } // ----------------------------------------------------------------------------- wxString StatusBar::Stringify(const bigint& b) { static char buf[32]; char* p = buf; double d = b.toscinot(); if ( fabs(d) < 10.0 ) { // show exact value with commas inserted for readability d = b.todouble(); if ( d < 0 ) { d = - d; *p++ = '-'; } sprintf(p, "%.f", d); int len = (int)strlen(p); int commas = ((len + 2) / 3) - 1; int dest = len + commas; int src = len; p[dest] = 0; while (commas > 0) { p[--dest] = p[--src]; p[--dest] = p[--src]; p[--dest] = p[--src]; p[--dest] = ','; commas--; } if ( p[-1] == '-' ) p--; } else { // use e notation for abs value > 10^9 (agrees with min & max_coord) const char * sign = ""; if (d < 0) { sign = "-"; d = 0.0 - d; } double exp = floor(d); d = (d - exp) * 10.0; exp = exp - 1.0; // UI has been set up to accomodate "9.999999e+999" // which is the same width as "9.9999999e+99", etc. if (exp < 100.0) { // two-digit exponent sprintf(p, "%s%9.7fe+%.0f", sign, d, exp); // 9.9999999e+99 } else if (exp < 1000.0) { sprintf(p, "%s%8.6fe+%.0f", sign, d, exp); // 9.999999e+999 } else if (exp < 10000.0) { sprintf(p, "%s%7.5fe+%.0f", sign, d, exp); // 9.99999e+9999 } else if (exp < 100000.0) { sprintf(p, "%s%6.4fe+%.0f", sign, d, exp); // 9.9999e+99999 } else { // for 6-digit exponent or larger we'll just always show a "d.ddd" // mantissa. 7-digit exponent appears unattainable at the present // time (late 2011) sprintf(p, "%s%5.3fe+%.0f", sign, d, exp); } } return wxString(p, wxConvLocal); } // ----------------------------------------------------------------------------- int StatusBar::GetCurrentDelay() { int gendelay = mindelay * (1 << (-currlayer->currexpo - 1)); if (gendelay > maxdelay) gendelay = maxdelay; return gendelay; } // ----------------------------------------------------------------------------- void StatusBar::DrawStatusBar(wxDC& dc, wxRect& updaterect) { int wd, ht; GetClientSize(&wd, &ht); if (wd < 1 || ht < 1) return; wxRect r = wxRect(0, 0, wd, ht); FillRect(dc, r, *(algoinfo[currlayer->algtype]->statusbrush)); #if defined(__WXMSW__) // draw gray lines at top and left edges dc.SetPen(*wxGREY_PEN); dc.DrawLine(0, 0, r.width, 0); dc.DrawLine(0, 0, 0, r.height); // don't draw right edge on XP // dc.DrawLine(r.GetRight(), 0, r.GetRight(), r.height); #elif defined(__WXMAC__) // draw gray line at bottom edge dc.SetPen(linepen); dc.DrawLine(0, r.GetBottom(), r.width, r.GetBottom()); #else // draw gray line at bottom edge dc.SetPen(*wxLIGHT_GREY_PEN); dc.DrawLine(0, r.GetBottom(), r.width, r.GetBottom()); #endif dc.SetPen(wxNullPen); // must be here rather than in StatusBar::OnPaint; it looks like // some call resets the font SetStatusFont(dc); wxString strbuf; if (updaterect.y >= statusht-BOTGAP+DESCHT-LINEHT) { // only show possible message in bottom line -- see below } else if (showexact) { // might only need to display X and Y lines if (updaterect.y < XLINE+DESCHT-LINEHT) { strbuf = _("Generation = "); if (viewptr->nopattupdate) { strbuf += _("0"); } else { strbuf += wxString(currlayer->algo->getGeneration().tostring(), wxConvLocal); } DisplayText(dc, strbuf, h_gen, GENLINE); strbuf = _("Population = "); if (viewptr->nopattupdate) { strbuf += _("0"); } else { bigint popcount = currlayer->algo->getPopulation(); if (popcount.sign() < 0) { // getPopulation returns -1 if it can't be calculated strbuf += _("?"); } else { strbuf += wxString(popcount.tostring(), wxConvLocal); } } DisplayText(dc, strbuf, h_gen, POPLINE); // no need to show scale as an exact number if (viewptr->GetMag() < 0) { strbuf.Printf(_("Scale = 2^%d:1"), -viewptr->GetMag()); } else { strbuf.Printf(_("Scale = 1:%d"), 1 << viewptr->GetMag()); } DisplayText(dc, strbuf, h_gen, SCALELINE); if (currlayer->currexpo < 0) { // show delay in secs strbuf.Printf(_("Delay = %gs"), (double)GetCurrentDelay() / 1000.0); } else { // no real need to show step as an exact number strbuf.Printf(_("Step = %d^%d"), currlayer->currbase, currlayer->currexpo); } DisplayText(dc, strbuf, h_gen, STEPLINE); } DisplayText(dc, _("X ="), h_gen, XLINE); DisplayText(dc, _("Y ="), h_gen, YLINE); if (showxy) { bigint xo, yo; bigint xpos = currx; xpos -= currlayer->originx; bigint ypos = curry; ypos -= currlayer->originy; if (mathcoords) { // Y values increase upwards bigint temp = 0; temp -= ypos; ypos = temp; } DisplayText(dc, wxString(xpos.tostring(), wxConvLocal), h_x_ex, XLINE); DisplayText(dc, wxString(ypos.tostring(), wxConvLocal), h_y_ex, YLINE); } } else { // showexact is false so show info in top line if (updaterect.x < h_xy) { // show all info strbuf = _("Generation="); if (viewptr->nopattupdate) { strbuf += _("0"); } else { strbuf += Stringify(currlayer->algo->getGeneration()); } DisplayText(dc, strbuf, h_gen, BASELINE1); strbuf = _("Population="); if (viewptr->nopattupdate) { strbuf += _("0"); } else { bigint popcount = currlayer->algo->getPopulation(); if (popcount.sign() < 0) { // getPopulation returns -1 if it can't be calculated strbuf += _("?"); } else { strbuf += Stringify(popcount); } } DisplayText(dc, strbuf, h_pop, BASELINE1); if (viewptr->GetMag() < 0) { strbuf.Printf(_("Scale=2^%d:1"), -viewptr->GetMag()); } else { strbuf.Printf(_("Scale=1:%d"), 1 << viewptr->GetMag()); } DisplayText(dc, strbuf, h_scale, BASELINE1); if (currlayer->currexpo < 0) { // show delay in secs strbuf.Printf(_("Delay=%gs"), (double)GetCurrentDelay() / 1000.0); } else { strbuf.Printf(_("Step=%d^%d"), currlayer->currbase, currlayer->currexpo); } DisplayText(dc, strbuf, h_step, BASELINE1); } strbuf = _("XY="); if (showxy) { bigint xo, yo; bigint xpos = currx; xpos -= currlayer->originx; bigint ypos = curry; ypos -= currlayer->originy; if (mathcoords) { // Y values increase upwards bigint temp = 0; temp -= ypos; ypos = temp; } strbuf += Stringify(xpos); strbuf += wxT(" "); strbuf += Stringify(ypos); } DisplayText(dc, strbuf, h_xy, BASELINE1); } if (!statusmsg.IsEmpty()) { // display status message on bottom line DisplayText(dc, statusmsg, h_gen, statusht - BOTGAP); } } // ----------------------------------------------------------------------------- // event table and handlers: BEGIN_EVENT_TABLE(StatusBar, wxWindow) EVT_PAINT (StatusBar::OnPaint) EVT_LEFT_DOWN (StatusBar::OnMouseDown) EVT_LEFT_DCLICK (StatusBar::OnMouseDown) EVT_ERASE_BACKGROUND (StatusBar::OnEraseBackground) END_EVENT_TABLE() // ----------------------------------------------------------------------------- void StatusBar::OnPaint(wxPaintEvent& WXUNUSED(event)) { #if defined(__WXMAC__) || defined(__WXGTK__) // windows on Mac OS X and GTK+ 2.0 are automatically buffered wxPaintDC dc(this); #else // use wxWidgets buffering to avoid flicker int wd, ht; GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; if (wd != statbitmapwd || ht != statbitmapht) { // need to create a new bitmap for status bar delete statbitmap; statbitmap = new wxBitmap(wd, ht); statbitmapwd = wd; statbitmapht = ht; } if (statbitmap == NULL) Fatal(_("Not enough memory to render status bar!")); wxBufferedPaintDC dc(this, *statbitmap); #endif wxRect updaterect = GetUpdateRegion().GetBox(); DrawStatusBar(dc, updaterect); } // ----------------------------------------------------------------------------- bool StatusBar::ClickInGenBox(int x, int y) { if (showexact) return x >= 0 && y > (GENLINE+DESCHT-LINEHT) && y <= (GENLINE+DESCHT); else return x >= h_gen && x <= h_pop - 20 && y <= (BASELINE1+DESCHT); } // ----------------------------------------------------------------------------- bool StatusBar::ClickInScaleBox(int x, int y) { if (showexact) return x >= 0 && y > (SCALELINE+DESCHT-LINEHT) && y <= (SCALELINE+DESCHT); else return x >= h_scale && x <= h_step - 20 && y <= (BASELINE1+DESCHT); } // ----------------------------------------------------------------------------- bool StatusBar::ClickInStepBox(int x, int y) { if (showexact) return x >= 0 && y > (STEPLINE+DESCHT-LINEHT) && y <= (STEPLINE+DESCHT); else return x >= h_step && x <= h_xy - 20 && y <= (BASELINE1+DESCHT); } // ----------------------------------------------------------------------------- void StatusBar::OnMouseDown(wxMouseEvent& event) { if (inscript) return; // let script control scale and step ClearMessage(); if ( ClickInGenBox(event.GetX(), event.GetY()) && !mainptr->generating ) { if (TimelineExists()) { ErrorMessage(_("You can't change the generation count if there is a timeline.")); } else { mainptr->SetGeneration(); } } else if ( ClickInScaleBox(event.GetX(), event.GetY()) ) { if (viewptr->GetMag() != 0) { // reset scale to 1:1 viewptr->SetMag(0); } } else if ( ClickInStepBox(event.GetX(), event.GetY()) ) { if (TimelineExists()) { ErrorMessage(_("You can't change the step size if there is a timeline.")); } else if (currlayer->currbase != algoinfo[currlayer->algtype]->defbase || currlayer->currexpo != 0) { // reset base step to default value and step exponent to 0 currlayer->currbase = algoinfo[currlayer->algtype]->defbase; mainptr->SetStepExponent(0); // update status bar Refresh(false); Update(); } } } // ----------------------------------------------------------------------------- void StatusBar::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { // do nothing because we'll be painting the entire status bar } // ----------------------------------------------------------------------------- // create the status bar window StatusBar::StatusBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht) : wxWindow(parent, wxID_ANY, wxPoint(xorg,yorg), wxSize(wd,ht), wxNO_BORDER | wxFULL_REPAINT_ON_RESIZE) { // avoid erasing background on GTK+ SetBackgroundStyle(wxBG_STYLE_CUSTOM); // create font for text in status bar and set textascent for use in DisplayText #ifdef __WXMSW__ // use smaller, narrower font on Windows statusfont = wxFont::New(8, wxDEFAULT, wxNORMAL, wxNORMAL); int major, minor; wxGetOsVersion(&major, &minor); if ( major > 5 || (major == 5 && minor >= 1) ) { // 5.1+ means XP or later (Vista or later if major >= 6) textascent = 11; } else { textascent = 10; } #elif defined(__WXGTK__) // use smaller font on GTK statusfont = wxFont::New(8, wxMODERN, wxNORMAL, wxNORMAL); textascent = 11; #elif defined(__WXOSX_COCOA__) // we need to specify facename to get Monaco instead of Courier statusfont = wxFont::New(10, wxMODERN, wxNORMAL, wxNORMAL, false, wxT("Monaco")); textascent = 10; #else // __WXMAC__ statusfont = wxFont::New(10, wxMODERN, wxNORMAL, wxNORMAL); textascent = 10; #endif if (statusfont == NULL) Fatal(_("Failed to create status bar font!")); // determine horizontal offsets for info in status bar wxClientDC dc(this); int textwd, textht; int mingap = 10; SetStatusFont(dc); h_gen = 6; // when showexact is false: dc.GetTextExtent(_("Generation=9.999999e+999"), &textwd, &textht); h_pop = h_gen + textwd + mingap; dc.GetTextExtent(_("Population=9.999999e+999"), &textwd, &textht); h_scale = h_pop + textwd + mingap; dc.GetTextExtent(_("Scale=2^9999:1"), &textwd, &textht); h_step = h_scale + textwd + mingap; dc.GetTextExtent(_("Step=1000000000^9"), &textwd, &textht); h_xy = h_step + textwd + mingap; // when showexact is true: dc.GetTextExtent(_("X = "), &textwd, &textht); h_x_ex = h_gen + textwd; dc.GetTextExtent(_("Y = "), &textwd, &textht); h_y_ex = h_gen + textwd; statusht = ht; showxy = false; statbitmap = NULL; statbitmapwd = -1; statbitmapht = -1; statusmsg.Clear(); } // ----------------------------------------------------------------------------- StatusBar::~StatusBar() { delete statusfont; delete statbitmap; } golly-2.7-src/gui-wx/wxgolly.h0000755000175000017500000000434312536111364013325 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXGOLLY_H_ #define _WXGOLLY_H_ // need some forward declarations class lifepoll; class MainFrame; class PatternView; class StatusBar; // Define our application class: class GollyApp : public wxApp { public: // called on application startup virtual bool OnInit(); #ifdef __WXMAC__ // called in response to an open-document event; // eg. when a file is dropped onto the app icon virtual void MacOpenFile(const wxString& fullPath); #endif // put app icon in given frame void SetFrameIcon(wxFrame* frame); // event poller is used by non-wx modules to process events lifepoll* Poller(); void PollerReset(); void PollerInterrupt(); }; DECLARE_APP(GollyApp) // so other files can use wxGetApp // At the risk of offending C++ purists, we use some globals to simplify code: // "mainptr->GetRect()" is more readable than "wxGetApp().GetMainFrame()->GetRect()". extern MainFrame* mainptr; // main window extern PatternView* viewptr; // current viewport window (possibly a tile) extern PatternView* bigview; // big viewport window (encloses all tiles) extern StatusBar* statusptr; // status bar window extern wxStopWatch* stopwatch; // global stopwatch (started in OnInit) extern bool insideYield; // processing an event via Yield()? #endif golly-2.7-src/gui-wx/wxgolly.cpp0000755000175000017500000003151312536111364013657 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ // A GUI for Golly, implemented in wxWidgets (www.wxwidgets.org). // Unfinished code is flagged by "!!!". // Uncertain code is flagged by "???". #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/image.h" // for wxImage #include "wx/stdpaths.h" // for wxStandardPaths #include "wx/sysopt.h" // for wxSystemOptions #include "wx/filename.h" // for wxFileName #include "wx/fs_inet.h" // for wxInternetFSHandler #include "wx/fs_zip.h" // for wxZipFSHandler #include "lifepoll.h" #include "util.h" // for lifeerrors #include "wxgolly.h" // defines GollyApp class #include "wxmain.h" // defines MainFrame class #include "wxstatus.h" // defines StatusBar class #include "wxview.h" // defines PatternView class #include "wxutils.h" // for Warning, Fatal, BeginProgress, etc #include "wxprefs.h" // for GetPrefs, gollydir, rulesdir, userrules #ifdef __WXMSW__ // app icons are loaded via .rc file #else #include "icons/appicon.xpm" #endif // ----------------------------------------------------------------------------- // Create a new application object: this macro will allow wxWidgets to create // the application object during program execution and also implements the // accessor function wxGetApp() which will return the reference of the correct // type (ie. GollyApp and not wxApp). IMPLEMENT_APP(GollyApp) // ----------------------------------------------------------------------------- #define STRINGIFY(arg) STR2(arg) #define STR2(arg) #arg MainFrame* mainptr = NULL; // main window PatternView* viewptr = NULL; // current viewport window (possibly a tile) PatternView* bigview = NULL; // main viewport window StatusBar* statusptr = NULL; // status bar window wxStopWatch* stopwatch; // global stopwatch bool insideYield = false; // processing an event via Yield()? // ----------------------------------------------------------------------------- // let non-wx modules call Fatal, Warning, BeginProgress, etc class wx_errors : public lifeerrors { public: virtual void fatal(const char* s) { Fatal(wxString(s,wxConvLocal)); } virtual void warning(const char* s) { Warning(wxString(s,wxConvLocal)); } virtual void status(const char* s) { statusptr->DisplayMessage(wxString(s,wxConvLocal)); } virtual void beginprogress(const char* s) { BeginProgress(wxString(s,wxConvLocal)); // init flag for isaborted() calls in non-wx modules aborted = false; } virtual bool abortprogress(double f, const char* s) { return AbortProgress(f, wxString(s,wxConvLocal)); } virtual void endprogress() { EndProgress(); } virtual const char* getuserrules() { // need to be careful converting Unicode wxString to char* #ifdef __WXMAC__ // we need to convert path to decomposed UTF8 so fopen will work dirbuff = userrules.fn_str(); #else dirbuff = userrules.mb_str(wxConvLocal); #endif return (const char*) dirbuff; } virtual const char* getrulesdir() { // need to be careful converting Unicode wxString to char* #ifdef __WXMAC__ // we need to convert path to decomposed UTF8 so fopen will work dirbuff = rulesdir.fn_str(); #else dirbuff = rulesdir.mb_str(wxConvLocal); #endif return (const char*) dirbuff; } private: wxCharBuffer dirbuff; }; wx_errors wxerrhandler; // create instance // ----------------------------------------------------------------------------- // let non-wx modules process events class wx_poll : public lifepoll { public: virtual int checkevents(); virtual void updatePop(); long nextcheck; }; void CallYield() { if (mainptr->infront) { // make sure viewport window keeps keyboard focus viewptr->SetFocus(); } insideYield = true; wxGetApp().Yield(true); insideYield = false; } int wx_poll::checkevents() { #ifdef __WXMSW__ // on Windows it seems that Time has a higher overhead than Yield CallYield(); #else // on Mac/Linux it is faster to avoid calling Yield too often long t = stopwatch->Time(); if (t > nextcheck) { nextcheck = t + 100; // call 10 times per sec CallYield(); } #endif return isInterrupted(); } void wx_poll::updatePop() { if (showstatus) { statusptr->Refresh(false); } } wx_poll wxpoller; // create instance lifepoll* GollyApp::Poller() { return &wxpoller; } void GollyApp::PollerReset() { wxpoller.resetInterrupted(); wxpoller.nextcheck = 0; } void GollyApp::PollerInterrupt() { wxpoller.setInterrupted(); wxpoller.nextcheck = 0; } // ----------------------------------------------------------------------------- void SetAppDirectory(const char* argv0) { #ifdef __WXMSW__ // on Windows we need to reset current directory to app directory if user // dropped file from somewhere else onto app to start it up (otherwise we // can't find Help files) wxString appdir = wxStandardPaths::Get().GetDataDir(); wxString currdir = wxGetCwd(); if ( currdir.CmpNoCase(appdir) != 0 ) wxSetWorkingDirectory(appdir); // avoid VC++ warning wxUnusedVar(argv0); #elif defined(__WXMAC__) // wxMac has set current directory to location of .app bundle so no need // to do anything #else // assume Unix // first, try to switch to GOLLYDIR if that is set to a sensible value: static const char *gd = STRINGIFY(GOLLYDIR); if ( *gd == '/' && wxSetWorkingDirectory(wxString(gd,wxConvLocal)) ) { return; } // otherwise, use the executable directory as the application directory. // user might have started app from a different directory so find // last "/" in argv0 and change cwd if "/" isn't part of "./" prefix unsigned int pos = strlen(argv0); while (pos > 0) { pos--; if (argv0[pos] == '/') break; } if ( pos > 0 && !(pos == 1 && argv0[0] == '.') ) { char appdir[2048]; if (pos < sizeof(appdir)) { strncpy(appdir, argv0, pos); appdir[pos] = 0; wxSetWorkingDirectory(wxString(appdir,wxConvLocal)); } } #endif } // ----------------------------------------------------------------------------- void GollyApp::SetFrameIcon(wxFrame* frame) { // set frame icon #ifdef __WXMSW__ // create a bundle with 32x32 and 16x16 icons wxIconBundle icb(wxICON(appicon0)); icb.AddIcon(wxICON(appicon1)); frame->SetIcons(icb); #else // use appicon.xpm on other platforms (ignored on Mac) frame->SetIcon(wxICON(appicon)); #endif } // ----------------------------------------------------------------------------- #ifdef __WXMAC__ // open file double-clicked or dropped onto Golly icon void GollyApp::MacOpenFile(const wxString& fullPath) { mainptr->Raise(); mainptr->OpenFile(fullPath); } #endif // ----------------------------------------------------------------------------- // app execution starts here bool GollyApp::OnInit() { SetAppName(_("Golly")); // for use in Warning/Fatal dialogs // create a stopwatch so we can use Time() to get elapsed millisecs stopwatch = new wxStopWatch(); // set variable seed for later rand() calls srand(time(0)); #if defined(__WXMAC__) && !wxCHECK_VERSION(2,7,2) // prevent rectangle animation when windows open/close wxSystemOptions::SetOption(wxMAC_WINDOW_PLAIN_TRANSITION, 1); // prevent position problem in wxTextCtrl with wxTE_DONTWRAP style // (but doesn't fix problem with I-beam cursor over scroll bars) wxSystemOptions::SetOption(wxMAC_TEXTCONTROL_USE_MLTE, 1); #endif // get current working directory before calling SetAppDirectory wxString initdir = wxFileName::GetCwd(); if (initdir.Last() != wxFILE_SEP_PATH) initdir += wxFILE_SEP_PATH; // make sure current working directory contains application otherwise // we can't open Help files SetAppDirectory( wxString(argv[0]).mb_str(wxConvLocal) ); // now set global gollydir for use in GetPrefs and elsewhere gollydir = wxFileName::GetCwd(); if (gollydir.Last() != wxFILE_SEP_PATH) gollydir += wxFILE_SEP_PATH; // let non-wx modules call Fatal, Warning, BeginProgress, etc lifeerrors::seterrorhandler(&wxerrhandler); // allow .html files to include common graphic formats, // and .icons files to be in any of these formats; // note that wxBMPHandler is always installed, so it needs not be added, // and we can assume that if HAVE_WX_BMP_HANDLER is not defined, then // the handlers have not been auto-detected (and we just install them all). #if !defined(HAVE_WX_BMP_HANDLER) || defined(HAVE_WX_GIF_HANDLER) wxImage::AddHandler(new wxGIFHandler); #endif #if !defined(HAVE_WX_BMP_HANDLER) || defined(HAVE_WX_PNG_HANDLER) wxImage::AddHandler(new wxPNGHandler); #endif #if !defined(HAVE_WX_BMP_HANDLER) || defined(HAVE_WX_TIFF_HANDLER) wxImage::AddHandler(new wxTIFFHandler); #endif // wxInternetFSHandler is needed to allow downloading files wxFileSystem::AddHandler(new wxInternetFSHandler); wxFileSystem::AddHandler(new wxZipFSHandler); // get main window location and other user preferences GetPrefs(); // create main window (also initializes viewptr, bigview, statusptr) mainptr = new MainFrame(); if (mainptr == NULL) Fatal(_("Failed to create main window!")); // initialize some stuff before showing main window mainptr->SetRandomFillPercentage(); mainptr->SetMinimumStepExponent(); wxString banner = _("This is Golly version "); banner += _(STRINGIFY(VERSION)); #ifdef GOLLY64BIT banner += _(" (64-bit)"); #else banner += _(" (32-bit)"); #endif banner += _(". Copyright 2015 The Golly Gang."); if (debuglevel == 99) { banner += _(" *** debuglevel is 99 ***"); } statusptr->SetMessage(banner); mainptr->NewPattern(); // script/pattern files are stored in the pendingfiles array for later processing // in OnIdle; this avoids a crash in Win app if a script is run before showing // the main window, and also avoids event problems in Win app with a long-running // script (eg. user can't hit escape to abort script) const wxString START_PERL = wxT("golly-start.pl"); const wxString START_PYTHON = wxT("golly-start.py"); wxString startscript = gollydir + START_PERL; if (wxFileExists(startscript)) { mainptr->pendingfiles.Add(startscript); } else { // look in user-specific data directory startscript = datadir + START_PERL; if (wxFileExists(startscript)) { mainptr->pendingfiles.Add(startscript); } } startscript = gollydir + START_PYTHON; if (wxFileExists(startscript)) { mainptr->pendingfiles.Add(startscript); } else { // look in user-specific data directory startscript = datadir + START_PYTHON; if (wxFileExists(startscript)) { mainptr->pendingfiles.Add(startscript); } } // argc is > 1 if command line has one or more script/pattern files for (int n = 1; n < argc; n++) { wxFileName filename(argv[n]); // convert given path to a full path if not one already; this allows users // to do things like "../golly bricklayer.py" from within Scripts folder if (!filename.IsAbsolute()) filename = initdir + argv[n]; mainptr->pendingfiles.Add(filename.GetFullPath()); } // show main window if (maximize) mainptr->Maximize(true); mainptr->Show(true); SetTopWindow(mainptr); // true means call wxApp::OnRun() which will enter the main event loop; // false means exit immediately return true; } golly-2.7-src/gui-wx/wxinfo.cpp0000644000175000017500000001716512536111364013470 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "readpattern.h" // for readcomments #include "wxgolly.h" // for wxGetApp, mainptr #include "wxmain.h" // for mainptr->... #include "wxutils.h" // for Warning #include "wxprefs.h" // for infox/y/wd/ht and mininfo* #include "wxinfo.h" // ----------------------------------------------------------------------------- // define a modeless window to display pattern info: class InfoFrame : public wxFrame { public: InfoFrame(char *comments); private: // event handlers void OnActivate(wxActivateEvent& event); void OnCloseButton(wxCommandEvent& event); void OnClose(wxCloseEvent& event); // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(InfoFrame, wxFrame) EVT_ACTIVATE ( InfoFrame::OnActivate) EVT_BUTTON (wxID_CLOSE, InfoFrame::OnCloseButton) EVT_CLOSE ( InfoFrame::OnClose) END_EVENT_TABLE() // ----------------------------------------------------------------------------- InfoFrame *infoptr = NULL; // pattern info window wxFrame* GetInfoFrame() { return infoptr; } // ----------------------------------------------------------------------------- // define a child window for viewing comments: class TextView : public wxTextCtrl { public: TextView(wxWindow *parent, wxWindowID id, const wxString &value, const wxPoint& pos, const wxSize& size, long style) : wxTextCtrl(parent, id, value, pos, size, style) { } private: // event handlers void OnKeyDown(wxKeyEvent& event); // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(TextView, wxTextCtrl) EVT_KEY_DOWN (TextView::OnKeyDown) END_EVENT_TABLE() // ----------------------------------------------------------------------------- void TextView::OnKeyDown(wxKeyEvent& event) { int key = event.GetKeyCode(); #ifdef __WXMAC__ // let cmd-W close info window if (event.CmdDown() && key == 'W') { infoptr->Close(true); return; } // let cmd-A select all text if (event.CmdDown() && key == 'A') { SetSelection(-1, -1); return; } #endif if ( event.CmdDown() || event.AltDown() ) { // let default handler see things like cmd-C event.Skip(); } else { // let escape/return/enter key close info window if ( key == WXK_ESCAPE || key == WXK_RETURN || key == WXK_NUMPAD_ENTER ) { infoptr->Close(true); } else { event.Skip(); } } } // ----------------------------------------------------------------------------- // create the pattern info window InfoFrame::InfoFrame(char *comments) : wxFrame(NULL, wxID_ANY, _("Pattern Info"), wxPoint(infox,infoy), wxSize(infowd,infoht)) { wxGetApp().SetFrameIcon(this); #ifdef __WXMSW__ // use current theme's background colour SetBackgroundColour(wxNullColour); #endif TextView* textctrl = new TextView(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_RICH | // needed for font changing on Windows wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP); // use a fixed-width font wxTextAttr textattr(wxNullColour, wxNullColour, #if defined(__WXOSX_COCOA__) // we need to specify facename to get Monaco instead of Courier wxFont(12, wxMODERN, wxNORMAL, wxNORMAL, false, wxT("Monaco"))); #elif defined(__WXMAC__) wxFont(11, wxMODERN, wxNORMAL, wxNORMAL)); #else wxFont(10, wxMODERN, wxNORMAL, wxNORMAL)); #endif textctrl->SetDefaultStyle(textattr); if (comments[0] == 0) { textctrl->WriteText(_("No comments found.")); } else { textctrl->WriteText(wxString(comments,wxConvLocal)); #if defined(__WXOSX_COCOA__) // sigh... wxOSX seems to ignore SetDefaultStyle textctrl->SetStyle(0, strlen(comments), textattr); #endif } textctrl->ShowPosition(0); textctrl->SetInsertionPoint(0); wxButton *closebutt = new wxButton(this, wxID_CLOSE, _("Close")); closebutt->SetDefault(); wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL); vbox->Add(textctrl, 1, wxLEFT | wxRIGHT | wxTOP | wxEXPAND | wxALIGN_TOP, 10); vbox->Add(closebutt, 0, wxALL | wxALIGN_CENTER, 10); SetMinSize(wxSize(mininfowd, mininfoht)); SetSizer(vbox); #ifdef __WXMAC__ // expand sizer now to avoid flicker vbox->SetDimension(0, 0, infowd, infoht); #endif // need this on Linux textctrl->SetFocus(); } // ----------------------------------------------------------------------------- void InfoFrame::OnActivate(wxActivateEvent& event) { if ( event.GetActive() ) { // ensure correct menu items, esp after info window // is clicked while app is in background mainptr->UpdateMenuItems(); } event.Skip(); } // ----------------------------------------------------------------------------- void InfoFrame::OnCloseButton(wxCommandEvent& WXUNUSED(event)) { Close(true); } // ----------------------------------------------------------------------------- void InfoFrame::OnClose(wxCloseEvent& WXUNUSED(event)) { #ifdef __WXMSW__ if (!IsIconized()) { #endif // save current location and size for later use in SavePrefs wxRect r = GetRect(); infox = r.x; infoy = r.y; infowd = r.width; infoht = r.height; #ifdef __WXMSW__ } #endif Destroy(); // also deletes all child windows (buttons, etc) infoptr = NULL; } // ----------------------------------------------------------------------------- #ifdef __WXMAC__ // convert path to decomposed UTF8 so fopen will work #define FILEPATH filepath.fn_str() #else #define FILEPATH filepath.mb_str(wxConvLocal) #endif void ShowInfo(const wxString& filepath) { if (infoptr) { // info window exists so just bring it to front infoptr->Raise(); return; } // buffer for receiving comment data (allocated by readcomments) char *commptr = NULL; // read and display comments in current pattern file const char *err = readcomments(FILEPATH, &commptr); if (err) { Warning(wxString(err,wxConvLocal)); } else { infoptr = new InfoFrame(commptr); if (infoptr == NULL) { Warning(_("Could not create info window!")); } else { infoptr->Show(true); } } if (commptr) free(commptr); } golly-2.7-src/gui-wx/local-win-template.mk0000644000175000017500000000132312536111364015466 00000000000000# makefile-win includes local-win.mk, so create a copy of this file # and call it local-win.mk, then make any desired changes. # Change the next 2 lines to specify where you installed wxWidgets: !include WX_DIR = C:\wxWidgets-2.8.12-64 # Change the next line to match your wxWidgets version (first two digits): WX_RELEASE = 28 # Change the next line depending on where you installed Python: PYTHON_INCLUDE = -I"C:\Python27-64\include" # Simplified output from "perl -MExtUtils::Embed -e ccopts": PERL_INCLUDE = \ -DHAVE_DES_FCRYPT -DNO_HASH_SEED -DUSE_SITECUSTOMIZE -DPERL_IMPLICIT_CONTEXT \ -DPERL_IMPLICIT_SYS -DUSE_PERLIO -DPERL_MSVCRT_READFIX -I"C:\Perl514-64\lib\CORE" golly-2.7-src/gui-wx/wxmain.cpp0000644000175000017500000032311712536111364013456 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #if wxUSE_TOOLTIPS #include "wx/tooltip.h" // for wxToolTip #endif #include "wx/dnd.h" // for wxFileDropTarget #include "wx/filename.h" // for wxFileName #include "wx/dir.h" // for wxDir #include "wx/clipbrd.h" // for wxTheClipboard #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "wxgolly.h" // for wxGetApp, statusptr, viewptr, bigview #include "wxutils.h" // for Warning, Fatal, etc #include "wxprefs.h" // for gollydir, datadir, SavePrefs, etc #include "wxinfo.h" // for ShowInfo, GetInfoFrame #include "wxhelp.h" // for ShowHelp, GetHelpFrame #include "wxstatus.h" // for statusptr->... #include "wxview.h" // for viewptr->... #include "wxrender.h" // for InitDrawingData, DestroyDrawingData, etc #include "wxedit.h" // for CreateEditBar, EditBarHeight, etc #include "wxscript.h" // for inscript, PassKeyToScript #include "wxalgos.h" // for algo_type, algomenu, algomenupop #include "wxlayer.h" // for AddLayer, MAX_LAYERS, currlayer #include "wxundo.h" // for currlayer->undoredo->... #include "wxtimeline.h" // for CreateTimelineBar, TimelineExists, etc #include "wxmain.h" #ifdef __WXMAC__ #include // for GetCurrentProcess, etc #endif #ifdef USING_VISUAL_LEAK_DETECTOR #include #endif // ----------------------------------------------------------------------------- // one-shot timer to fix problems in wxMac and wxGTK -- see OnOneTimer; // must be static global because it's used in DnDFile::OnDropFiles static wxTimer* onetimer; #ifdef __WXMSW__ static bool set_focus = false; // OnIdle needs to call SetFocus? static wxString editpath = wxEmptyString; // OnIdle calls EditFile if this isn't empty #endif static bool call_close = false; // OnIdle needs to call Close? static bool edit_file = false; // edit the clicked file? // ----------------------------------------------------------------------------- // ids for bitmap buttons in tool bar enum { START_TOOL = 0, STOP_TOOL, RESET_TOOL, ALGO_TOOL, AUTOFIT_TOOL, HYPER_TOOL, NEW_TOOL, OPEN_TOOL, SAVE_TOOL, PATTERNS_TOOL, SCRIPTS_TOOL, INFO_TOOL, HELP_TOOL, NUM_BUTTONS // must be last }; // bitmaps for tool bar buttons #include "bitmaps/play.xpm" #include "bitmaps/stop.xpm" #include "bitmaps/reset.xpm" #include "bitmaps/algo.xpm" #include "bitmaps/autofit.xpm" #include "bitmaps/hyper.xpm" #include "bitmaps/new.xpm" #include "bitmaps/open.xpm" #include "bitmaps/save.xpm" #include "bitmaps/patterns.xpm" #include "bitmaps/scripts.xpm" #include "bitmaps/info.xpm" #include "bitmaps/help.xpm" // bitmaps for down state of toggle buttons #include "bitmaps/autofit_down.xpm" #include "bitmaps/hyper_down.xpm" #include "bitmaps/patterns_down.xpm" #include "bitmaps/scripts_down.xpm" // ----------------------------------------------------------------------------- // Define our own vertical tool bar to avoid bugs and limitations in wxToolBar: // derive from wxPanel so we get current theme's background color on Windows class ToolBar : public wxPanel { public: ToolBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht); ~ToolBar() {} // add a bitmap button to tool bar void AddButton(int id, const wxString& tip); // add a vertical gap between buttons void AddSeparator(); // enable/disable button void EnableButton(int id, bool enable); // set state of start/stop button void SetStartStopButton(); // set state of a toggle button void SelectButton(int id, bool select); // detect press and release of a bitmap button void OnButtonDown(wxMouseEvent& event); void OnButtonUp(wxMouseEvent& event); void OnKillFocus(wxFocusEvent& event); private: // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() // event handlers void OnPaint(wxPaintEvent& event); void OnMouseDown(wxMouseEvent& event); void OnButton(wxCommandEvent& event); // bitmaps for normal or down state wxBitmap normtool[NUM_BUTTONS]; wxBitmap downtool[NUM_BUTTONS]; #ifdef __WXMSW__ // on Windows we need bitmaps for disabled buttons wxBitmap disnormtool[NUM_BUTTONS]; wxBitmap disdowntool[NUM_BUTTONS]; #endif // remember state of toggle buttons to avoid unnecessary drawing; // 0 = not yet initialized, 1 = selected, -1 = not selected int buttstate[NUM_BUTTONS]; // positioning data used by AddButton and AddSeparator int ypos, xpos, smallgap, biggap; }; BEGIN_EVENT_TABLE(ToolBar, wxPanel) EVT_PAINT ( ToolBar::OnPaint) EVT_LEFT_DOWN ( ToolBar::OnMouseDown) EVT_BUTTON (wxID_ANY, ToolBar::OnButton) END_EVENT_TABLE() ToolBar* toolbarptr = NULL; // global pointer to tool bar const int toolbarwd = 32; // width of (vertical) tool bar // tool bar buttons (must be global to use Connect/Disconnect on Windows) wxBitmapButton* tbbutt[NUM_BUTTONS]; // width and height of bitmap buttons #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) // note that BUTTON_WD will have to be at least 26 to avoid clipping bitmaps // if we decide to use wxBORDER_SUNKEN rather than wxBORDER_SIMPLE // (and toolbarwd will probably need to be increased to 48) const int BUTTON_WD = 24; const int BUTTON_HT = 24; #elif defined(__WXOSX_COCOA__) || defined(__WXGTK__) const int BUTTON_WD = 28; const int BUTTON_HT = 28; #else const int BUTTON_WD = 24; const int BUTTON_HT = 24; #endif // ----------------------------------------------------------------------------- ToolBar::ToolBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht) : wxPanel(parent, wxID_ANY, wxPoint(xorg,yorg), wxSize(wd,ht), wxNO_FULL_REPAINT_ON_RESIZE) { #ifdef __WXGTK__ // avoid erasing background on GTK+ SetBackgroundStyle(wxBG_STYLE_CUSTOM); #endif // init bitmaps for normal state normtool[START_TOOL] = XPM_BITMAP(play); normtool[STOP_TOOL] = XPM_BITMAP(stop); normtool[RESET_TOOL] = XPM_BITMAP(reset); normtool[ALGO_TOOL] = XPM_BITMAP(algo); normtool[AUTOFIT_TOOL] = XPM_BITMAP(autofit); normtool[HYPER_TOOL] = XPM_BITMAP(hyper); normtool[NEW_TOOL] = XPM_BITMAP(new); normtool[OPEN_TOOL] = XPM_BITMAP(open); normtool[SAVE_TOOL] = XPM_BITMAP(save); normtool[PATTERNS_TOOL] = XPM_BITMAP(patterns); normtool[SCRIPTS_TOOL] = XPM_BITMAP(scripts); normtool[INFO_TOOL] = XPM_BITMAP(info); normtool[HELP_TOOL] = XPM_BITMAP(help); // toggle buttons also have a down state downtool[AUTOFIT_TOOL] = XPM_BITMAP(autofit_down); downtool[HYPER_TOOL] = XPM_BITMAP(hyper_down); downtool[PATTERNS_TOOL] = XPM_BITMAP(patterns_down); downtool[SCRIPTS_TOOL] = XPM_BITMAP(scripts_down); #ifdef __WXMSW__ for (int i = 0; i < NUM_BUTTONS; i++) { CreatePaleBitmap(normtool[i], disnormtool[i]); } CreatePaleBitmap(downtool[AUTOFIT_TOOL], disdowntool[AUTOFIT_TOOL]); CreatePaleBitmap(downtool[HYPER_TOOL], disdowntool[HYPER_TOOL]); CreatePaleBitmap(downtool[PATTERNS_TOOL], disdowntool[PATTERNS_TOOL]); CreatePaleBitmap(downtool[SCRIPTS_TOOL], disdowntool[SCRIPTS_TOOL]); #endif for (int i = 0; i < NUM_BUTTONS; i++) { buttstate[i] = 0; } // init position variables used by AddButton and AddSeparator #ifdef __WXGTK__ // buttons are a different size in wxGTK xpos = 2; ypos = 2; smallgap = 6; #else xpos = (32 - BUTTON_WD) / 2; ypos = (32 - BUTTON_HT) / 2; smallgap = 4; #endif biggap = 16; } // ----------------------------------------------------------------------------- void ToolBar::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); int wd, ht; GetClientSize(&wd, &ht); if (wd < 1 || ht < 1 || !showtool) return; wxRect r = wxRect(0, 0, wd, ht); #ifdef __WXMSW__ dc.Clear(); // draw gray line at top edge dc.SetPen(*wxGREY_PEN); dc.DrawLine(0, 0, r.width, 0); dc.SetPen(wxNullPen); #else // draw gray line at right edge #ifdef __WXMAC__ wxBrush brush(wxColor(202,202,202)); FillRect(dc, r, brush); wxPen linepen(wxColor(140,140,140)); dc.SetPen(linepen); #else dc.SetPen(*wxLIGHT_GREY_PEN); #endif dc.DrawLine(r.GetRight(), 0, r.GetRight(), r.height); dc.SetPen(wxNullPen); #endif } // ----------------------------------------------------------------------------- void ToolBar::OnMouseDown(wxMouseEvent& WXUNUSED(event)) { // this is NOT called if user clicks a tool bar button; // on Windows we need to reset keyboard focus to viewport window viewptr->SetFocus(); } // ----------------------------------------------------------------------------- void ToolBar::OnButton(wxCommandEvent& event) { int id = event.GetId(); int cmdid; switch (id) { case START_TOOL: cmdid = ID_START; break; case RESET_TOOL: cmdid = ID_RESET; break; case ALGO_TOOL: return; // handled in OnButtonDown case AUTOFIT_TOOL: cmdid = ID_AUTO; break; case HYPER_TOOL: cmdid = ID_HYPER; break; case NEW_TOOL: cmdid = wxID_NEW; break; case OPEN_TOOL: cmdid = wxID_OPEN; break; case SAVE_TOOL: cmdid = wxID_SAVE; break; case PATTERNS_TOOL: cmdid = ID_SHOW_PATTERNS; break; case SCRIPTS_TOOL: cmdid = ID_SHOW_SCRIPTS; break; case INFO_TOOL: cmdid = ID_INFO; break; case HELP_TOOL: cmdid = ID_HELP_BUTT; break; default: Warning(_("Unexpected button id!")); return; } // call MainFrame::OnMenu after OnButton finishes; // this avoids start/stop button problem in GTK app wxCommandEvent cmdevt(wxEVT_COMMAND_MENU_SELECTED, cmdid); wxPostEvent(mainptr->GetEventHandler(), cmdevt); // avoid weird bug on Mac where all buttons can be disabled after hitting // RESET_TOOL button *and* the "All controls" option is ticked in // System Prefs > Keyboard & Mouse > Keyboard Shortcuts // (might also fix similar problem on Windows) viewptr->SetFocus(); } // ----------------------------------------------------------------------------- void ToolBar::OnKillFocus(wxFocusEvent& event) { int id = event.GetId(); tbbutt[id]->SetFocus(); // don't let button lose focus } // ----------------------------------------------------------------------------- void ToolBar::OnButtonDown(wxMouseEvent& event) { // a tool bar button has been pressed int id = event.GetId(); #ifdef __WXMSW__ // connect a handler that keeps focus with the pressed button if (id != ALGO_TOOL) tbbutt[id]->Connect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(ToolBar::OnKillFocus)); #endif #ifdef __WXMAC__ // close any open tool tip window (probably wxMac bug) wxToolTip::RemoveToolTips(); #endif // we want pop-up menu to appear as soon as ALGO_TOOL button is pressed //!!! doesn't work 100% correctly on Windows if (id == ALGO_TOOL) { // we use algomenupop here rather than algomenu to avoid assert messages in wx 2.9+ #ifdef __WXMSW__ tbbutt[id]->PopupMenu(algomenupop, 0, 25); // fix prob on Win (almost -- button-up doesn't always close menu) viewptr->SetFocus(); return; #else tbbutt[id]->PopupMenu(algomenupop, 0, 30); #endif #ifdef __WXOSX_COCOA__ viewptr->SetFocus(); // don't call event.Skip() otherwise algo button will remain selected return; #endif } event.Skip(); } // ----------------------------------------------------------------------------- void ToolBar::OnButtonUp(wxMouseEvent& event) { // a tool bar button has been released (only called in wxMSW) int id = event.GetId(); wxPoint pt = tbbutt[id]->ScreenToClient( wxGetMousePosition() ); int wd, ht; tbbutt[id]->GetClientSize(&wd, &ht); wxRect r(0, 0, wd, ht); // diconnect kill-focus handler if (id != ALGO_TOOL) tbbutt[id]->Disconnect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(ToolBar::OnKillFocus)); viewptr->SetFocus(); if ( r.Contains(pt) ) { // call OnButton wxCommandEvent buttevt(wxEVT_COMMAND_BUTTON_CLICKED, id); buttevt.SetEventObject(tbbutt[id]); tbbutt[id]->GetEventHandler()->ProcessEvent(buttevt); } } // ----------------------------------------------------------------------------- void ToolBar::AddButton(int id, const wxString& tip) { tbbutt[id] = new wxBitmapButton(this, id, normtool[id], wxPoint(xpos,ypos), #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) wxSize(BUTTON_WD, BUTTON_HT), wxBORDER_SIMPLE #else wxSize(BUTTON_WD, BUTTON_HT) #endif ); if (tbbutt[id] == NULL) { Fatal(_("Failed to create tool bar button!")); } else { ypos += BUTTON_HT + smallgap; tbbutt[id]->SetToolTip(tip); #ifdef __WXMSW__ // fix problem with tool bar buttons when generating/inscript // due to focus being changed to viewptr tbbutt[id]->Connect(id, wxEVT_LEFT_DOWN, wxMouseEventHandler(ToolBar::OnButtonDown)); tbbutt[id]->Connect(id, wxEVT_LEFT_UP, wxMouseEventHandler(ToolBar::OnButtonUp)); #else // allow pop-up menu to appear as soon as ALGO_TOOL button is pressed tbbutt[id]->Connect(id, wxEVT_LEFT_DOWN, wxMouseEventHandler(ToolBar::OnButtonDown)); #endif } } // ----------------------------------------------------------------------------- void ToolBar::AddSeparator() { ypos += biggap - smallgap; } // ----------------------------------------------------------------------------- void ToolBar::EnableButton(int id, bool enable) { if (enable == tbbutt[id]->IsEnabled()) return; #ifdef __WXMSW__ if (id == START_TOOL && (inscript || mainptr->generating)) { tbbutt[id]->SetBitmapDisabled(disnormtool[STOP_TOOL]); } else if (id == AUTOFIT_TOOL && currlayer->autofit) { tbbutt[id]->SetBitmapDisabled(disdowntool[id]); } else if (id == HYPER_TOOL && currlayer->hyperspeed) { tbbutt[id]->SetBitmapDisabled(disdowntool[id]); } else if (id == PATTERNS_TOOL && showpatterns) { tbbutt[id]->SetBitmapDisabled(disdowntool[id]); } else if (id == SCRIPTS_TOOL && showscripts) { tbbutt[id]->SetBitmapDisabled(disdowntool[id]); } else { tbbutt[id]->SetBitmapDisabled(disnormtool[id]); } #endif tbbutt[id]->Enable(enable); } // ----------------------------------------------------------------------------- void ToolBar::SetStartStopButton() { if (inscript || mainptr->generating) { // show stop bitmap if (buttstate[START_TOOL] == 1) return; buttstate[START_TOOL] = 1; tbbutt[START_TOOL]->SetBitmapLabel(normtool[STOP_TOOL]); if (inscript) tbbutt[START_TOOL]->SetToolTip(_("Stop script")); else tbbutt[START_TOOL]->SetToolTip(_("Stop generating")); } else { // show start bitmap if (buttstate[START_TOOL] == -1) return; buttstate[START_TOOL] = -1; tbbutt[START_TOOL]->SetBitmapLabel(normtool[START_TOOL]); tbbutt[START_TOOL]->SetToolTip(_("Start generating")); } tbbutt[START_TOOL]->Refresh(false); } // ----------------------------------------------------------------------------- void ToolBar::SelectButton(int id, bool select) { if (select) { if (buttstate[id] == 1) return; buttstate[id] = 1; tbbutt[id]->SetBitmapLabel(downtool[id]); } else { if (buttstate[id] == -1) return; buttstate[id] = -1; tbbutt[id]->SetBitmapLabel(normtool[id]); } tbbutt[id]->Refresh(false); } // ----------------------------------------------------------------------------- void MainFrame::CreateToolbar() { int wd, ht; GetClientSize(&wd, &ht); toolbarptr = new ToolBar(this, 0, 0, toolbarwd, ht); if (toolbarptr == NULL) Fatal(_("Failed to create tool bar!")); // add buttons to tool bar toolbarptr->AddButton(START_TOOL, _("Start generating")); toolbarptr->AddButton(RESET_TOOL, _("Reset")); toolbarptr->AddSeparator(); toolbarptr->AddButton(ALGO_TOOL, _("Set algorithm")); toolbarptr->AddButton(AUTOFIT_TOOL, _("Auto fit")); toolbarptr->AddButton(HYPER_TOOL, _("Hyperspeed")); toolbarptr->AddSeparator(); toolbarptr->AddButton(NEW_TOOL, _("New pattern")); toolbarptr->AddButton(OPEN_TOOL, _("Open pattern")); toolbarptr->AddButton(SAVE_TOOL, _("Save pattern")); toolbarptr->AddSeparator(); toolbarptr->AddButton(PATTERNS_TOOL, _("Show/hide patterns")); toolbarptr->AddButton(SCRIPTS_TOOL, _("Show/hide scripts")); toolbarptr->AddSeparator(); toolbarptr->AddButton(INFO_TOOL, _("Show pattern information")); toolbarptr->AddButton(HELP_TOOL, _("Show help window")); toolbarptr->Show(showtool); } // ----------------------------------------------------------------------------- void MainFrame::UpdateToolBar() { // update tool bar buttons according to the current state if (toolbarptr && showtool) { bool active = !viewptr->waitingforclick; bool timeline = TimelineExists(); // set state of start/stop button toolbarptr->SetStartStopButton(); // set state of toggle buttons toolbarptr->SelectButton(AUTOFIT_TOOL, currlayer->autofit); toolbarptr->SelectButton(HYPER_TOOL, currlayer->hyperspeed); toolbarptr->SelectButton(PATTERNS_TOOL, showpatterns); toolbarptr->SelectButton(SCRIPTS_TOOL, showscripts); toolbarptr->EnableButton(START_TOOL, active && !timeline); toolbarptr->EnableButton(RESET_TOOL, active && !timeline && !inscript && (generating || currlayer->algo->getGeneration() > currlayer->startgen)); toolbarptr->EnableButton(ALGO_TOOL, active && !timeline && !inscript); toolbarptr->EnableButton(AUTOFIT_TOOL, active); toolbarptr->EnableButton(HYPER_TOOL, active && !timeline); toolbarptr->EnableButton(NEW_TOOL, active && !inscript); toolbarptr->EnableButton(OPEN_TOOL, active && !inscript); toolbarptr->EnableButton(SAVE_TOOL, active && !inscript); toolbarptr->EnableButton(PATTERNS_TOOL, active); toolbarptr->EnableButton(SCRIPTS_TOOL, active); toolbarptr->EnableButton(INFO_TOOL, active && !currlayer->currfile.IsEmpty()); toolbarptr->EnableButton(HELP_TOOL, active); } } // ----------------------------------------------------------------------------- bool MainFrame::ClipboardHasText() { bool hastext = false; #ifdef __WXGTK__ // avoid re-entrancy bug in wxGTK 2.9.x if (wxTheClipboard->IsOpened()) return false; #endif if (wxTheClipboard->Open()) { hastext = wxTheClipboard->IsSupported(wxDF_TEXT); if (!hastext) { // we'll try to convert bitmap data to text pattern hastext = wxTheClipboard->IsSupported(wxDF_BITMAP); } wxTheClipboard->Close(); } return hastext; } // ----------------------------------------------------------------------------- void MainFrame::EnableAllMenus(bool enable) { #if defined(__WXMAC__) && !defined(__WXOSX_COCOA__) // enable/disable all menus, including Help menu and items in app menu if (enable) EndAppModalStateForWindow( (OpaqueWindowPtr*)this->MacGetWindowRef() ); else BeginAppModalStateForWindow( (OpaqueWindowPtr*)this->MacGetWindowRef() ); #else wxMenuBar* mbar = GetMenuBar(); if (mbar) { int count = (int)(mbar->GetMenuCount()); int i; for (i = 0; i < count; i++) { mbar->EnableTop(i, enable); } #ifdef __WXOSX_COCOA__ // enable/disable items in app menu mbar->Enable(wxID_ABOUT, enable); mbar->Enable(wxID_PREFERENCES, enable); mbar->Enable(wxID_EXIT, enable); #endif } #endif } // ----------------------------------------------------------------------------- void MainFrame::UpdateMenuItems() { // update menu bar items according to the given state wxMenuBar* mbar = GetMenuBar(); if (mbar) { // we need to disable most menu items if main window is not in front so user can // hit return key to close help/info window rather than start/stop generating bool active = infront && !viewptr->waitingforclick; bool selexists = viewptr->SelectionExists(); bool timeline = TimelineExists(); bool textinclip = ClipboardHasText(); mbar->Enable(wxID_NEW, active && !inscript); mbar->Enable(wxID_OPEN, active && !inscript); mbar->Enable(ID_OPEN_CLIP, active && !inscript && textinclip); mbar->Enable(ID_OPEN_RECENT, active && !inscript && numpatterns > 0); mbar->Enable(ID_SHOW_PATTERNS, active); mbar->Enable(ID_PATTERN_DIR, active); mbar->Enable(wxID_SAVE, active && !inscript); mbar->Enable(ID_SAVE_XRLE, active); mbar->Enable(ID_RUN_SCRIPT, active && !timeline && !inscript); mbar->Enable(ID_RUN_CLIP, active && !timeline && !inscript && textinclip); mbar->Enable(ID_RUN_RECENT, active && !timeline && !inscript && numscripts > 0); mbar->Enable(ID_SHOW_SCRIPTS, active); mbar->Enable(ID_SCRIPT_DIR, active); // safer not to allow prefs dialog while script is running??? // mbar->Enable(wxID_PREFERENCES, !inscript); bool can_undo = active && !timeline && currlayer->undoredo->CanUndo(); bool can_redo = active && !timeline && currlayer->undoredo->CanRedo(); #if defined(__WXMAC__) && !defined(__WXOSX_COCOA__) // need this stupidity to avoid wxMac bug after modal dialog closes (eg. Set Rule) // and force items to appear correctly enabled/disabled mbar->Enable(ID_UNDO, !can_undo); mbar->Enable(ID_REDO, !can_redo); #endif mbar->Enable(ID_UNDO, can_undo); mbar->Enable(ID_REDO, can_redo); mbar->Enable(ID_NO_UNDO, active && !inscript); mbar->Enable(ID_CUT, active && !timeline && !inscript && selexists); mbar->Enable(ID_COPY, active && !inscript && selexists); mbar->Enable(ID_CLEAR, active && !timeline && !inscript && selexists); mbar->Enable(ID_OUTSIDE, active && !timeline && !inscript && selexists); mbar->Enable(ID_PASTE, active && !timeline && !inscript && textinclip); mbar->Enable(ID_PASTE_SEL, active && !timeline && !inscript && textinclip && selexists); mbar->Enable(ID_PLOCATION, active); mbar->Enable(ID_PMODE, active); mbar->Enable(ID_SELECTALL, active && !inscript); mbar->Enable(ID_REMOVE, active && !inscript && selexists); mbar->Enable(ID_SHRINK, active && !inscript && selexists); mbar->Enable(ID_RANDOM, active && !timeline && !inscript && selexists); mbar->Enable(ID_FLIPTB, active && !timeline && !inscript && selexists); mbar->Enable(ID_FLIPLR, active && !timeline && !inscript && selexists); mbar->Enable(ID_ROTATEC, active && !timeline && !inscript && selexists); mbar->Enable(ID_ROTATEA, active && !timeline && !inscript && selexists); mbar->Enable(ID_CMODE, active); if (inscript) { // don't use DO_STARTSTOP key to abort a running script #ifdef __WXMAC__ // on Mac we need to clear the accelerator first because "\tEscape" doesn't really // change the accelerator (it just looks like it does!) -- this is because escape // (key code 27) is used by SetItemCmd to indicate the item has a submenu; // see UMASetMenuItemShortcut in wx/src/mac/carbon/uma.cpp mbar->SetLabel(ID_START, _("x")); #endif mbar->SetLabel(ID_START, _("Stop Script\tEscape")); } else if (generating) { mbar->SetLabel(ID_START, _("Stop Generating") + GetAccelerator(DO_STARTSTOP)); } else if (timeline && !currlayer->algo->isrecording()) { if (TimelineIsPlaying()) mbar->SetLabel(ID_START, _("Stop Playing Timeline") + GetAccelerator(DO_STARTSTOP)); else mbar->SetLabel(ID_START, _("Start Playing Timeline") + GetAccelerator(DO_STARTSTOP)); } else { mbar->SetLabel(ID_START, _("Start Generating") + GetAccelerator(DO_STARTSTOP)); } if (currlayer->algo->isrecording()) { mbar->SetLabel(ID_RECORD, _("Stop Recording") + GetAccelerator(DO_RECORD)); } else { mbar->SetLabel(ID_RECORD, _("Start Recording") + GetAccelerator(DO_RECORD)); } mbar->Enable(ID_START, active && !currlayer->algo->isrecording()); #ifdef __WXMAC__ // for some unknown reason we need to disable these menu items when generating // otherwise auto-repeating space/tab key doesn't work all the time mbar->Enable(ID_NEXT, active && !timeline && !inscript && !generating); mbar->Enable(ID_STEP, active && !timeline && !inscript && !generating); #else mbar->Enable(ID_NEXT, active && !timeline && !inscript); mbar->Enable(ID_STEP, active && !timeline && !inscript); #endif mbar->Enable(ID_RESET, active && !timeline && !inscript && (generating || currlayer->algo->getGeneration() > currlayer->startgen)); mbar->Enable(ID_SETGEN, active && !timeline && !inscript); mbar->Enable(ID_FASTER, active); mbar->Enable(ID_SLOWER, active /* && currlayer->currexpo > minexpo */); // don't do this test because Win users won't hear beep mbar->Enable(ID_SETBASE, active && !timeline && !inscript); mbar->Enable(ID_AUTO, active); mbar->Enable(ID_HYPER, active && !timeline); mbar->Enable(ID_HINFO, active); mbar->Enable(ID_RECORD, active && !inscript && currlayer->algo->hyperCapable()); mbar->Enable(ID_DELTIME, active && !inscript && timeline && !currlayer->algo->isrecording()); mbar->Enable(ID_CONVERT, active && !timeline && !inscript); mbar->Enable(ID_SETALGO, active && !timeline && !inscript); mbar->Enable(ID_SETRULE, active && !timeline && !inscript); mbar->Enable(ID_FULL, active); mbar->Enable(ID_FIT, active); mbar->Enable(ID_FIT_SEL, active && selexists); mbar->Enable(ID_MIDDLE, active); mbar->Enable(ID_RESTORE00, active && (currlayer->originx != bigint::zero || currlayer->originy != bigint::zero)); mbar->Enable(wxID_ZOOM_IN, active /* && viewptr->GetMag() < MAX_MAG */); // don't do this test because Win users won't hear beep mbar->Enable(wxID_ZOOM_OUT, active); mbar->Enable(ID_SET_SCALE, active); mbar->Enable(ID_TOOL_BAR, active); mbar->Enable(ID_LAYER_BAR, active); mbar->Enable(ID_EDIT_BAR, active); mbar->Enable(ID_ALL_STATES, active); mbar->Enable(ID_STATUS_BAR, active); mbar->Enable(ID_EXACT, active); mbar->Enable(ID_GRID, active); mbar->Enable(ID_ICONS, active); mbar->Enable(ID_INVERT, active); #if defined(__WXMAC__) || defined(__WXGTK__) // windows on Mac OS X and GTK+ 2.0 are automatically buffered mbar->Enable(ID_BUFF, false); mbar->Check(ID_BUFF, true); #else mbar->Enable(ID_BUFF, active); mbar->Check(ID_BUFF, buffered); #endif mbar->Enable(ID_TIMELINE, active); mbar->Enable(ID_INFO, !currlayer->currfile.IsEmpty()); mbar->Enable(ID_ADD_LAYER, active && !inscript && numlayers < MAX_LAYERS); mbar->Enable(ID_CLONE, active && !inscript && numlayers < MAX_LAYERS); mbar->Enable(ID_DUPLICATE, active && !inscript && numlayers < MAX_LAYERS); mbar->Enable(ID_DEL_LAYER, active && !inscript && numlayers > 1); mbar->Enable(ID_DEL_OTHERS, active && !inscript && numlayers > 1); mbar->Enable(ID_MOVE_LAYER, active && !inscript && numlayers > 1); mbar->Enable(ID_NAME_LAYER, active && !inscript); mbar->Enable(ID_SET_COLORS, active && !inscript); mbar->Enable(ID_SYNC_VIEW, active); mbar->Enable(ID_SYNC_CURS, active); mbar->Enable(ID_STACK, active); mbar->Enable(ID_TILE, active); for (int i = 0; i < numlayers; i++) mbar->Enable(ID_LAYER0 + i, active && CanSwitchLayer(i)); // tick/untick menu items created using AppendCheckItem mbar->Check(ID_SAVE_XRLE, savexrle); mbar->Check(ID_SHOW_PATTERNS, showpatterns); mbar->Check(ID_SHOW_SCRIPTS, showscripts); mbar->Check(ID_NO_UNDO, !allowundo); mbar->Check(ID_AUTO, currlayer->autofit); mbar->Check(ID_HYPER, currlayer->hyperspeed); mbar->Check(ID_HINFO, currlayer->showhashinfo); mbar->Check(ID_TOOL_BAR, showtool); mbar->Check(ID_LAYER_BAR, showlayer); mbar->Check(ID_EDIT_BAR, showedit); mbar->Check(ID_ALL_STATES, showallstates); mbar->Check(ID_STATUS_BAR, showstatus); mbar->Check(ID_EXACT, showexact); mbar->Check(ID_GRID, showgridlines); mbar->Check(ID_ICONS, showicons); mbar->Check(ID_INVERT, swapcolors); mbar->Check(ID_TIMELINE, showtimeline); mbar->Check(ID_PL_TL, plocation == TopLeft); mbar->Check(ID_PL_TR, plocation == TopRight); mbar->Check(ID_PL_BR, plocation == BottomRight); mbar->Check(ID_PL_BL, plocation == BottomLeft); mbar->Check(ID_PL_MID, plocation == Middle); mbar->Check(ID_PM_AND, pmode == And); mbar->Check(ID_PM_COPY, pmode == Copy); mbar->Check(ID_PM_OR, pmode == Or); mbar->Check(ID_PM_XOR, pmode == Xor); mbar->Check(ID_DRAW, currlayer->curs == curs_pencil); mbar->Check(ID_PICK, currlayer->curs == curs_pick); mbar->Check(ID_SELECT, currlayer->curs == curs_cross); mbar->Check(ID_MOVE, currlayer->curs == curs_hand); mbar->Check(ID_ZOOMIN, currlayer->curs == curs_zoomin); mbar->Check(ID_ZOOMOUT, currlayer->curs == curs_zoomout); mbar->Check(ID_SCALE_1, viewptr->GetMag() == 0); mbar->Check(ID_SCALE_2, viewptr->GetMag() == 1); mbar->Check(ID_SCALE_4, viewptr->GetMag() == 2); mbar->Check(ID_SCALE_8, viewptr->GetMag() == 3); mbar->Check(ID_SCALE_16, viewptr->GetMag() == 4); mbar->Check(ID_SCALE_32, viewptr->GetMag() == 5); mbar->Check(ID_SYNC_VIEW, syncviews); mbar->Check(ID_SYNC_CURS, synccursors); mbar->Check(ID_STACK, stacklayers); mbar->Check(ID_TILE, tilelayers); for (int i = 0; i < NumAlgos(); i++) { mbar->Check(ID_ALGO0 + i, currlayer->algtype == i); // keep algomenupop in sync with algomenu algomenupop->Check(ID_ALGO0 + i, currlayer->algtype == i); } for (int i = 0; i < numlayers; i++) { mbar->Check(ID_LAYER0 + i, currindex == i); } } } // ----------------------------------------------------------------------------- void MainFrame::UpdateUserInterface() { UpdateToolBar(); UpdateLayerBar(); UpdateEditBar(); UpdateTimelineBar(); UpdateMenuItems(); viewptr->CheckCursor(infront); statusptr->CheckMouseLocation(infront); #ifdef __WXMSW__ // ensure viewport window has keyboard focus if main window is active if (infront) viewptr->SetFocus(); #endif } // ----------------------------------------------------------------------------- // update everything in main window, and menu bar and cursor void MainFrame::UpdateEverything() { if (IsIconized()) { // main window has been minimized, so only update menu bar items UpdateMenuItems(); return; } // update all tool bars, menus and cursor UpdateUserInterface(); if (inscript) { // make sure scroll bars are accurate while running script bigview->UpdateScrollBars(); return; } int wd, ht; GetClientSize(&wd, &ht); // includes status bar and viewport if (wd > 0 && ht > statusptr->statusht) { bigview->Refresh(false); bigview->UpdateScrollBars(); } if (wd > 0 && ht > 0 && showstatus) { statusptr->Refresh(false); } } // ----------------------------------------------------------------------------- // only update viewport and status bar void MainFrame::UpdatePatternAndStatus() { if (inscript || currlayer->undoredo->doingscriptchanges) return; if (!IsIconized()) { bigview->Refresh(false); if (showstatus) { statusptr->CheckMouseLocation(infront); statusptr->Refresh(false); } } } // ----------------------------------------------------------------------------- // only update status bar void MainFrame::UpdateStatus() { if (inscript || currlayer->undoredo->doingscriptchanges) return; if (!IsIconized()) { if (showstatus) { statusptr->CheckMouseLocation(infront); statusptr->Refresh(false); } } } // ----------------------------------------------------------------------------- void MainFrame::SimplifyTree(wxString& indir, wxTreeCtrl* treectrl, wxTreeItemId root) { // delete old tree (except root) treectrl->DeleteChildren(root); // remove any terminating separator wxString dir = indir; if (dir.Last() == wxFILE_SEP_PATH) dir.Truncate(dir.Length()-1); // append dir as only child wxDirItemData* diritem = new wxDirItemData(dir, dir, true); wxTreeItemId id; id = treectrl->AppendItem(root, dir.AfterLast(wxFILE_SEP_PATH), 0, 0, diritem); if ( diritem->HasFiles() || diritem->HasSubDirs() ) { treectrl->SetItemHasChildren(id); treectrl->Expand(id); // nicer to expand Perl & Python subdirs inside Scripts if ( dir == gollydir + _("Scripts") ) { wxTreeItemId child; wxTreeItemIdValue cookie; child = treectrl->GetFirstChild(id, cookie); while ( child.IsOk() ) { wxString name = treectrl->GetItemText(child); if ( name == _("Perl") || name == _("Python") ) { treectrl->Expand(child); } child = treectrl->GetNextChild(id, cookie); } } #ifndef __WXMSW__ // can cause crash on Windows treectrl->ScrollTo(root); #endif } // select top folder so hitting left arrow can collapse it and won't cause an assert wxTreeItemIdValue cookie; id = treectrl->GetFirstChild(root, cookie); if (id.IsOk()) treectrl->SelectItem(id); } // ----------------------------------------------------------------------------- // Define a window for right pane of split window: class RightWindow : public wxWindow { public: RightWindow(wxWindow* parent) : wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER | // need this to avoid layer/edit/timeline bar buttons flashing on Windows wxNO_FULL_REPAINT_ON_RESIZE) { // avoid erasing background on GTK+ SetBackgroundStyle(wxBG_STYLE_CUSTOM); } ~RightWindow() {} // event handlers void OnSize(wxSizeEvent& event); void OnEraseBackground(wxEraseEvent& event); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(RightWindow, wxWindow) EVT_ERASE_BACKGROUND (RightWindow::OnEraseBackground) EVT_SIZE (RightWindow::OnSize) END_EVENT_TABLE() // ----------------------------------------------------------------------------- void RightWindow::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { // do nothing because layer/edit/timeline bars and viewport cover all of right pane } // ----------------------------------------------------------------------------- void RightWindow::OnSize(wxSizeEvent& event) { int wd, ht; GetClientSize(&wd, &ht); if (wd > 0 && ht > 0 && bigview) { // resize layer/edit/timeline bars and main viewport window ResizeLayerBar(wd); ResizeEditBar(wd); int y = 0; if (showlayer) { y += LayerBarHeight(); ht -= LayerBarHeight(); } if (showedit) { y += EditBarHeight(); ht -= EditBarHeight(); } if (showtimeline) { ht -= TimelineBarHeight(); } // timeline bar goes underneath viewport ResizeTimelineBar(y + ht, wd); bigview->SetSize(0, y, wd, ht); } event.Skip(); } // ----------------------------------------------------------------------------- RightWindow* rightpane; wxWindow* MainFrame::RightPane() { return rightpane; } // ----------------------------------------------------------------------------- void MainFrame::ResizeSplitWindow(int wd, int ht) { int x = showtool ? toolbarwd : 0; int y = statusptr->statusht; int w = showtool ? wd - toolbarwd : wd; int h = ht > statusptr->statusht ? ht - statusptr->statusht : 0; splitwin->SetSize(x, y, w, h); // RightWindow::OnSize has now been called; // wxSplitterWindow automatically resizes left and right panes } // ----------------------------------------------------------------------------- void MainFrame::ResizeStatusBar(int wd, int ht) { wxUnusedVar(ht); // assume showstatus is true statusptr->statusht = showexact ? STATUS_EXHT : STATUS_HT; statusptr->SetSize(showtool ? toolbarwd : 0, 0, showtool ? wd - toolbarwd : wd, statusptr->statusht); } // ----------------------------------------------------------------------------- void MainFrame::ToggleStatusBar() { int wd, ht; GetClientSize(&wd, &ht); showstatus = !showstatus; if (showstatus) { ResizeStatusBar(wd, ht); } else { statusptr->statusht = 0; statusptr->SetSize(0, 0, 0, 0); } ResizeSplitWindow(wd, ht); UpdateEverything(); } // ----------------------------------------------------------------------------- void MainFrame::ToggleExactNumbers() { int wd, ht; GetClientSize(&wd, &ht); showexact = !showexact; if (showstatus) { ResizeStatusBar(wd, ht); ResizeSplitWindow(wd, ht); UpdateEverything(); } else if (showexact) { // show the status bar using new size ToggleStatusBar(); } else { UpdateMenuItems(); } } // ----------------------------------------------------------------------------- void MainFrame::ToggleToolBar() { showtool = !showtool; int wd, ht; GetClientSize(&wd, &ht); if (showstatus) { ResizeStatusBar(wd, ht); } if (showtool) { // resize tool bar in case window was made larger while tool bar hidden toolbarptr->SetSize(0, 0, toolbarwd, ht); } ResizeSplitWindow(wd, ht); toolbarptr->Show(showtool); } // ----------------------------------------------------------------------------- void MainFrame::ToggleFullScreen() { static bool restorestatusbar; // restore status bar at end of full screen mode? static bool restorelayerbar; // restore layer bar? static bool restoreeditbar; // restore edit bar? static bool restoretimelinebar; // restore timeline bar? static bool restoretoolbar; // restore tool bar? static bool restorepattdir; // restore pattern directory? static bool restorescrdir; // restore script directory? if (!fullscreen) { // save current location and size for use in SavePrefs wxRect r = GetRect(); mainx = r.x; mainy = r.y; mainwd = r.width; mainht = r.height; } fullscreen = !fullscreen; ShowFullScreen(fullscreen, wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION); if (fullscreen) { // hide scroll bars bigview->SetScrollbar(wxHORIZONTAL, 0, 0, 0, true); bigview->SetScrollbar(wxVERTICAL, 0, 0, 0, true); // hide status bar if necessary restorestatusbar = showstatus; if (restorestatusbar) { showstatus = false; statusptr->statusht = 0; statusptr->SetSize(0, 0, 0, 0); } // hide layer bar if necessary restorelayerbar = showlayer; if (restorelayerbar) { ToggleLayerBar(); } // hide edit bar if necessary restoreeditbar = showedit; if (restoreeditbar) { ToggleEditBar(); } // hide timeline bar if necessary restoretimelinebar = showtimeline; if (restoretimelinebar) { ToggleTimelineBar(); } // hide tool bar if necessary restoretoolbar = showtool; if (restoretoolbar) { ToggleToolBar(); } // hide pattern/script directory if necessary restorepattdir = showpatterns; restorescrdir = showscripts; if (restorepattdir) { dirwinwd = splitwin->GetSashPosition(); splitwin->Unsplit(patternctrl); showpatterns = false; } else if (restorescrdir) { dirwinwd = splitwin->GetSashPosition(); splitwin->Unsplit(scriptctrl); showscripts = false; } } else { // first show tool bar if necessary if (restoretoolbar && !showtool) { ToggleToolBar(); if (showstatus) { // reduce width of status bar below restorestatusbar = true; } } // show status bar if necessary; // note that even if it's visible we may have to resize width if (restorestatusbar) { showstatus = true; int wd, ht; GetClientSize(&wd, &ht); ResizeStatusBar(wd, ht); } // show layer bar if necessary if (restorelayerbar && !showlayer) ToggleLayerBar(); // show edit bar if necessary if (restoreeditbar && !showedit) ToggleEditBar(); // show timeline bar if necessary if (restoretimelinebar && !showtimeline) ToggleTimelineBar(); // restore pattern/script directory if necessary if ( restorepattdir && !splitwin->IsSplit() ) { splitwin->SplitVertically(patternctrl, RightPane(), dirwinwd); showpatterns = true; } else if ( restorescrdir && !splitwin->IsSplit() ) { splitwin->SplitVertically(scriptctrl, RightPane(), dirwinwd); showscripts = true; } } if (!fullscreen) { // restore scroll bars BEFORE setting viewport size bigview->UpdateScrollBars(); } // adjust size of viewport (and pattern/script directory if visible) int wd, ht; GetClientSize(&wd, &ht); ResizeSplitWindow(wd, ht); UpdateEverything(); } // ----------------------------------------------------------------------------- void MainFrame::ToggleAllowUndo() { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_NO_UNDO); return; } allowundo = !allowundo; if (allowundo) { if (currlayer->algo->getGeneration() > currlayer->startgen) { // undo list is empty but user can Reset, so add a generating change // to undo list so user can Undo or Reset (and then Redo if they wish) currlayer->undoredo->AddGenChange(); } } else { currlayer->undoredo->ClearUndoRedo(); // don't clear undo/redo history for other layers here; only do it // if allowundo is false when user switches to another layer } } // ----------------------------------------------------------------------------- void MainFrame::ShowPatternInfo() { if (viewptr->waitingforclick || currlayer->currfile.IsEmpty()) return; ShowInfo(currlayer->currfile); } // ----------------------------------------------------------------------------- // event table and handlers for main window: BEGIN_EVENT_TABLE(MainFrame, wxFrame) EVT_MENU (wxID_ANY, MainFrame::OnMenu) EVT_SET_FOCUS ( MainFrame::OnSetFocus) EVT_ACTIVATE ( MainFrame::OnActivate) EVT_IDLE ( MainFrame::OnIdle) EVT_SIZE ( MainFrame::OnSize) EVT_TREE_SEL_CHANGED (wxID_TREECTRL, MainFrame::OnDirTreeSelection) EVT_SPLITTER_DCLICK (wxID_ANY, MainFrame::OnSashDblClick) EVT_TIMER (wxID_ANY, MainFrame::OnOneTimer) EVT_CLOSE ( MainFrame::OnClose) END_EVENT_TABLE() // ----------------------------------------------------------------------------- void MainFrame::OnMenu(wxCommandEvent& event) { if (debuglevel == 99 && insideYield) { if (generating || viewptr->waitingforclick) { // ignore this case (frequent and expected because Yield() is called in // a tight loop while generating a pattern or doing a paste) } else { // this is *possibly* an unwanted re-entrancy wxBell(); // ignore allowbeep } } showbanner = false; if (keepmessage) { // don't clear message created by script while generating a pattern keepmessage = false; } else { statusptr->ClearMessage(); } int id = event.GetId(); switch (id) { // File menu case wxID_NEW: NewPattern(); break; case wxID_OPEN: OpenPattern(); break; case ID_OPEN_CLIP: OpenClipboard(); break; case ID_SHOW_PATTERNS: ToggleShowPatterns(); break; case ID_PATTERN_DIR: ChangePatternDir(); break; case wxID_SAVE: SavePattern(); break; case ID_SAVE_XRLE: savexrle = !savexrle; break; case ID_RUN_SCRIPT: OpenScript(); break; case ID_RUN_CLIP: RunClipboard(); break; case ID_SHOW_SCRIPTS: ToggleShowScripts(); break; case ID_SCRIPT_DIR: ChangeScriptDir(); break; case wxID_PREFERENCES: ShowPrefsDialog(); break; case wxID_EXIT: QuitApp(); break; // Edit menu case ID_UNDO: currlayer->undoredo->UndoChange(); break; case ID_REDO: currlayer->undoredo->RedoChange(); break; case ID_NO_UNDO: ToggleAllowUndo(); break; case ID_CUT: viewptr->CutSelection(); break; case ID_COPY: viewptr->CopySelection(); break; case ID_CLEAR: viewptr->ClearSelection(); break; case ID_OUTSIDE: viewptr->ClearOutsideSelection(); break; case ID_PASTE: viewptr->PasteClipboard(false); break; case ID_PASTE_SEL: viewptr->PasteClipboard(true); break; case ID_PL_TL: SetPasteLocation("TopLeft"); break; case ID_PL_TR: SetPasteLocation("TopRight"); break; case ID_PL_BR: SetPasteLocation("BottomRight"); break; case ID_PL_BL: SetPasteLocation("BottomLeft"); break; case ID_PL_MID: SetPasteLocation("Middle"); break; case ID_PM_AND: SetPasteMode("And"); break; case ID_PM_COPY: SetPasteMode("Copy"); break; case ID_PM_OR: SetPasteMode("Or"); break; case ID_PM_XOR: SetPasteMode("Xor"); break; case ID_SELECTALL: viewptr->SelectAll(); break; case ID_REMOVE: viewptr->RemoveSelection(); break; case ID_SHRINK: viewptr->ShrinkSelection(false); break; case ID_SHRINKFIT: viewptr->ShrinkSelection(true); break; case ID_RANDOM: viewptr->RandomFill(); break; case ID_FLIPTB: viewptr->FlipSelection(true); break; case ID_FLIPLR: viewptr->FlipSelection(false); break; case ID_ROTATEC: viewptr->RotateSelection(true); break; case ID_ROTATEA: viewptr->RotateSelection(false); break; case ID_DRAW: viewptr->SetCursorMode(curs_pencil); break; case ID_PICK: viewptr->SetCursorMode(curs_pick); break; case ID_SELECT: viewptr->SetCursorMode(curs_cross); break; case ID_MOVE: viewptr->SetCursorMode(curs_hand); break; case ID_ZOOMIN: viewptr->SetCursorMode(curs_zoomin); break; case ID_ZOOMOUT: viewptr->SetCursorMode(curs_zoomout); break; // Control menu case ID_START: if (inscript || generating) { Stop(); } else if (TimelineExists()) { PlayTimeline(1); } else { GeneratePattern(); } break; case ID_NEXT: NextGeneration(false); break; case ID_STEP: NextGeneration(true); break; case ID_RESET: ResetPattern(); break; case ID_SETGEN: SetGeneration(); break; case ID_FASTER: GoFaster(); break; case ID_SLOWER: GoSlower(); break; case ID_SETBASE: SetBaseStep(); break; case ID_AUTO: ToggleAutoFit(); break; case ID_HYPER: ToggleHyperspeed(); break; case ID_HINFO: ToggleHashInfo(); break; case ID_RECORD: StartStopRecording(); break; case ID_DELTIME: DeleteTimeline(); break; case ID_CONVERT: ConvertOldRules(); break; case ID_SETRULE: ShowRuleDialog(); break; // View menu case ID_FULL: ToggleFullScreen(); break; case ID_FIT: viewptr->FitPattern(); break; case ID_FIT_SEL: viewptr->FitSelection(); break; case ID_MIDDLE: viewptr->ViewOrigin(); break; case ID_RESTORE00: viewptr->RestoreOrigin(); break; case wxID_ZOOM_IN: viewptr->ZoomIn(); break; case wxID_ZOOM_OUT: viewptr->ZoomOut(); break; case ID_SCALE_1: viewptr->SetPixelsPerCell(1); break; case ID_SCALE_2: viewptr->SetPixelsPerCell(2); break; case ID_SCALE_4: viewptr->SetPixelsPerCell(4); break; case ID_SCALE_8: viewptr->SetPixelsPerCell(8); break; case ID_SCALE_16: viewptr->SetPixelsPerCell(16); break; case ID_SCALE_32: viewptr->SetPixelsPerCell(32); break; case ID_TOOL_BAR: ToggleToolBar(); break; case ID_LAYER_BAR: ToggleLayerBar(); break; case ID_EDIT_BAR: ToggleEditBar(); break; case ID_ALL_STATES: ToggleAllStates(); break; case ID_STATUS_BAR: ToggleStatusBar(); break; case ID_EXACT: ToggleExactNumbers(); break; case ID_GRID: viewptr->ToggleGridLines(); break; case ID_ICONS: viewptr->ToggleCellIcons(); break; case ID_INVERT: viewptr->ToggleCellColors(); break; case ID_BUFF: viewptr->ToggleBuffering(); break; case ID_TIMELINE: ToggleTimelineBar(); break; case ID_INFO: ShowPatternInfo(); break; // Layer menu case ID_ADD_LAYER: AddLayer(); break; case ID_CLONE: CloneLayer(); break; case ID_DUPLICATE: DuplicateLayer(); break; case ID_DEL_LAYER: DeleteLayer(); break; case ID_DEL_OTHERS: DeleteOtherLayers(); break; case ID_MOVE_LAYER: MoveLayerDialog(); break; case ID_NAME_LAYER: NameLayerDialog(); break; case ID_SET_COLORS: SetLayerColors(); break; case ID_SYNC_VIEW: ToggleSyncViews(); break; case ID_SYNC_CURS: ToggleSyncCursors(); break; case ID_STACK: ToggleStackLayers(); break; case ID_TILE: ToggleTileLayers(); break; // Help menu case ID_HELP_INDEX: ShowHelp(_("Help/index.html")); break; case ID_HELP_INTRO: ShowHelp(_("Help/intro.html")); break; case ID_HELP_TIPS: ShowHelp(_("Help/tips.html")); break; case ID_HELP_ALGOS: ShowHelp(_("Help/algos.html")); break; case ID_HELP_LEXICON: ShowHelp(_("Help/Lexicon/lex.htm")); break; case ID_HELP_ARCHIVES: ShowHelp(_("Help/archives.html")); break; case ID_HELP_PERL: ShowHelp(_("Help/perl.html")); break; case ID_HELP_PYTHON: ShowHelp(_("Help/python.html")); break; case ID_HELP_KEYBOARD: ShowHelp(SHOW_KEYBOARD_SHORTCUTS); break; case ID_HELP_MOUSE: ShowHelp(_("Help/mouse.html")); break; case ID_HELP_FILE: ShowHelp(_("Help/file.html")); break; case ID_HELP_EDIT: ShowHelp(_("Help/edit.html")); break; case ID_HELP_CONTROL: ShowHelp(_("Help/control.html")); break; case ID_HELP_VIEW: ShowHelp(_("Help/view.html")); break; case ID_HELP_LAYER: ShowHelp(_("Help/layer.html")); break; case ID_HELP_HELP: ShowHelp(_("Help/help.html")); break; case ID_HELP_REFS: ShowHelp(_("Help/refs.html")); break; case ID_HELP_FORMATS: ShowHelp(_("Help/formats.html")); break; case ID_HELP_BOUNDED: ShowHelp(_("Help/bounded.html")); break; case ID_HELP_PROBLEMS: ShowHelp(_("Help/problems.html")); break; case ID_HELP_CHANGES: ShowHelp(_("Help/changes.html")); break; case ID_HELP_CREDITS: ShowHelp(_("Help/credits.html")); break; case ID_HELP_BUTT: ShowHelp(wxEmptyString); break; case wxID_ABOUT: ShowAboutBox(); break; // Open/Run Recent submenus case ID_CLEAR_MISSING_PATTERNS: ClearMissingPatterns(); break; case ID_CLEAR_ALL_PATTERNS: ClearAllPatterns(); break; case ID_CLEAR_MISSING_SCRIPTS: ClearMissingScripts(); break; case ID_CLEAR_ALL_SCRIPTS: ClearAllScripts(); break; default: if ( id > ID_OPEN_RECENT && id <= ID_OPEN_RECENT + numpatterns ) { OpenRecentPattern(id); } else if ( id > ID_RUN_RECENT && id <= ID_RUN_RECENT + numscripts ) { OpenRecentScript(id); } else if ( id >= ID_ALGO0 && id <= ID_ALGOMAX ) { int newtype = id - ID_ALGO0; ChangeAlgorithm(newtype); } else if ( id >= ID_LAYER0 && id <= ID_LAYERMAX ) { SetLayer(id - ID_LAYER0); } else { // wxOSX app needs this to handle app menu items like "Hide Golly" event.Skip(); } } UpdateUserInterface(); if (inscript) { // update viewport, status bar, scroll bars, window title inscript = false; UpdatePatternAndStatus(); bigview->UpdateScrollBars(); SetWindowTitle(wxEmptyString); inscript = true; } } // ----------------------------------------------------------------------------- void MainFrame::OnSetFocus(wxFocusEvent& WXUNUSED(event)) { // this is never called in Mac app, presumably because it doesn't // make any sense for a wxFrame to get the keyboard focus #ifdef __WXMSW__ // fix wxMSW problem: don't let main window get focus after being minimized if (viewptr) viewptr->SetFocus(); #endif } // ----------------------------------------------------------------------------- void MainFrame::OnActivate(wxActivateEvent& event) { // IsActive() is not always reliable so we set infront flag infront = event.GetActive(); if (viewptr->waitingforclick && !infront) { // cancel paste if main window is no longer in front viewptr->AbortPaste(); } if (infront) { // we must only call UpdateMenuItems when main window is being activated // (otherwise menu problems will occur on Ubuntu when using Unity) UpdateUserInterface(); viewptr->SetFocus(); // play safe } else { #ifdef __WXMAC__ // avoid problems with incorrect cursor in help window wxSetCursor(*wxSTANDARD_CURSOR); #endif } #if defined(__WXGTK__) && !wxCHECK_VERSION(2,9,0) /* wxGTK 2.8 requires this hack to re-enable menu items after a modal dialog closes. With wxGTK 2.9 it causes deadlocks due to concurrent calls to UpdateMenuItems() (which calls ClipboardHasText() which is non-reentrant). Maybe caused by timer events not being dispatched from the GUI thread? */ if (infront) onetimer->Start(20, wxTIMER_ONE_SHOT); // OnOneTimer will be called after delay of 0.02 secs #endif event.Skip(); } // ----------------------------------------------------------------------------- void MainFrame::OnSize(wxSizeEvent& event) { #ifdef __WXMSW__ // save current location and size for use in SavePrefs if app // is closed when window is minimized wxRect r = GetRect(); mainx = r.x; mainy = r.y; mainwd = r.width; mainht = r.height; #endif int wd, ht; GetClientSize(&wd, &ht); if (wd > 0 && ht > 0) { // toolbarptr/statusptr/viewptr might be NULL if OnSize is called from MainFrame ctor if (toolbarptr && showtool) { // adjust size of tool bar toolbarptr->SetSize(0, 0, toolbarwd, ht); } if (statusptr && showstatus) { // adjust size of status bar ResizeStatusBar(wd, ht); } if (viewptr && statusptr && ht > statusptr->statusht) { // adjust size of viewport (and pattern/script directory if visible) ResizeSplitWindow(wd, ht); } } #ifdef __WXGTK__ // need to do default processing for menu bar and tool bar event.Skip(); #else wxUnusedVar(event); #endif } // ----------------------------------------------------------------------------- // avoid recursive call of OpenFile in OnIdle; // this can happen if user clicks a script which then opens some sort of dialog // (idle events are sent to the main window while the dialog is open) static bool inidle = false; void MainFrame::OnIdle(wxIdleEvent& event) { if (inidle) return; #ifdef __WXMSW__ if (set_focus) { set_focus = false; // calling SetFocus once doesn't stuff up layer bar buttons if (infront && viewptr) viewptr->SetFocus(); } if (!editpath.IsEmpty()) { EditFile(editpath); editpath.Clear(); } #else // ensure viewport window has keyboard focus if main window is active; // note that we can't do this on Windows because it stuffs up clicks // in layer bar buttons if (infront && viewptr) viewptr->SetFocus(); #endif // process any pending script/pattern files if ( pendingfiles.GetCount() > 0 ) { inidle = true; for ( size_t n = 0; n < pendingfiles.GetCount(); n++ ) { OpenFile(pendingfiles[n]); } inidle = false; pendingfiles.Clear(); } if (call_close) { call_close = false; Close(false); // false allows OnClose handler to veto close } if (TimelineExists() && AutoPlay()) { // in autoplay mode so we need another idle event // (this works much better than calling wxWakeUpIdle) event.RequestMore(); } event.Skip(); } // ----------------------------------------------------------------------------- void MainFrame::EditFile(const wxString& filepath) { // prompt user if text editor hasn't been set yet if (texteditor.IsEmpty()) { ChooseTextEditor(this, texteditor); if (texteditor.IsEmpty()) return; } // execute a command to open given file in user's preferred text editor wxString cmd = wxString::Format(wxT("\"%s\" \"%s\""), texteditor.c_str(), filepath.c_str()); long result = wxExecute(cmd, wxEXEC_ASYNC); #if defined(__WXMSW__) // on Windows, wxExecute returns 0 if cmd fails if (result == 0) #elif defined(__WXMAC__) // on Mac, wxExecute returns -1 if cmd succeeds (bug, or wx docs are wrong) if (result != -1) #elif defined(__WXGTK__) // on Linux, wxExecute always returns a +ve number (pid?) if cmd fails OR succeeds (sheesh!) // but if it fails an error message appears in shell window if (result <= 0) #endif { wxString msg = _("Failed to open file in your preferred text editor.\n"); msg += _("Try choosing a different editor in Preferences > File."); Warning(msg); } } // ----------------------------------------------------------------------------- #if defined(__WXMAC__) && wxCHECK_VERSION(2,9,0) // wxMOD_CONTROL has been changed to mean Command key down (sheesh!) #define wxMOD_CONTROL wxMOD_RAW_CONTROL #define ControlDown RawControlDown #endif void MainFrame::OnTreeClick(wxMouseEvent& event) { // set global flag for testing in OnDirTreeSelection edit_file = event.ControlDown() || event.RightDown(); wxGenericDirCtrl* dirctrl = NULL; // we need to use mainptr to access next 2 members (it's something to do with Connect) if (showpatterns) dirctrl = mainptr->patternctrl; if (showscripts) dirctrl = mainptr->scriptctrl; if (dirctrl) { wxTreeCtrl* treectrl = dirctrl->GetTreeCtrl(); if (treectrl) { // determine if an item was clicked wxPoint pt = event.GetPosition(); int flags; wxTreeItemId id = treectrl->HitTest(pt, flags); if (!id.IsOk()) { // click wasn't in any item event.Skip(); return; } if (treectrl->ItemHasChildren(id)) { // click was in a folder item event.Skip(); return; } // check for click in an already selected item if (id == treectrl->GetSelection()) { // force a selection change so OnDirTreeSelection gets called treectrl->Unselect(); } treectrl->SelectItem(id); // OnDirTreeSelection will be called -- don't call event.Skip() } } } // ----------------------------------------------------------------------------- void MainFrame::OnDirTreeSelection(wxTreeEvent& event) { if (viewptr == NULL) return; // ignore 1st call from MainFrame::MainFrame wxTreeItemId id = event.GetItem(); if ( !id.IsOk() ) return; wxGenericDirCtrl* dirctrl = NULL; if (showpatterns) dirctrl = patternctrl; if (showscripts) dirctrl = scriptctrl; if (dirctrl == NULL) return; wxString filepath = dirctrl->GetFilePath(); if ( filepath.IsEmpty() ) { // user clicked on a folder name } else if (edit_file) { // open file in text editor #ifdef __WXMSW__ // call EditFile in later OnIdle to avoid right-click problem editpath = filepath; #else EditFile(filepath); #endif } else { // user clicked on a file name if ( inscript ) { // use Warning because statusptr->ErrorMessage does nothing if inscript if ( IsScriptFile(filepath) ) Warning(_("Cannot run script while another script is running.")); else Warning(_("Cannot open file while a script is running.")); } else { #ifdef __WXMAC__ if ( !wxFileName::FileExists(filepath) ) { // avoid wxMac bug in wxGenericDirCtrl::GetFilePath; ie. file name // can contain "/" rather than ":" (but directory path is okay) wxFileName fullpath(filepath); wxString dir = fullpath.GetPath(); wxString name = fullpath.GetFullName(); wxString newpath = dir + wxT(":") + name; if ( wxFileName::FileExists(newpath) ) filepath = newpath; } #endif if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; if ( IsScriptFile(filepath) ) { AddRecentScript(filepath); cmdevent.SetId(ID_RUN_RECENT + 1); } else { AddRecentPattern(filepath); cmdevent.SetId(ID_OPEN_RECENT + 1); } } else { // load pattern or run script // OpenFile(filepath); // call OpenFile in later OnIdle -- this prevents the main window // moving in front of the help window if a script calls help(...) pendingfiles.Add(filepath); } } } #ifdef __WXMSW__ // call SetFocus in next OnIdle set_focus = true; #else viewptr->SetFocus(); #endif } // ----------------------------------------------------------------------------- void MainFrame::OnSashDblClick(wxSplitterEvent& WXUNUSED(event)) { // splitwin's sash was double-clicked if (showpatterns) ToggleShowPatterns(); if (showscripts) ToggleShowScripts(); UpdateMenuItems(); UpdateToolBar(); } // ----------------------------------------------------------------------------- void MainFrame::OnOneTimer(wxTimerEvent& WXUNUSED(event)) { // fix drag and drop problem on Mac -- see DnDFile::OnDropFiles #ifdef __WXMAC__ // remove colored frame if (bigview) bigview->Refresh(false); #endif // fix menu item problem on Linux after modal dialog has closed #ifdef __WXGTK__ UpdateMenuItems(); #endif } // ----------------------------------------------------------------------------- bool MainFrame::SaveCurrentLayer() { if (currlayer->algo->isEmpty()) return true; // no need to save empty universe wxString query; if (numlayers > 1) { // make it clear which layer we're asking about query.Printf(_("Save the changes to layer %d: \"%s\"?"), currindex, currlayer->currname.c_str()); } else { query.Printf(_("Save the changes to \"%s\"?"), currlayer->currname.c_str()); } int answer = SaveChanges(query, _("If you don't save, your changes will be lost.")); switch (answer) { case 2: { bool result = SavePattern(); // true only if pattern was saved if (inscript && !result) { PassKeyToScript(WXK_ESCAPE); // abort script } return result; } case 1: { // don't save changes (but continue) return true; } default: { // answer == 0 (ie. user selected Cancel) if (inscript) { PassKeyToScript(WXK_ESCAPE); // abort script } return false; } } } // ----------------------------------------------------------------------------- void MainFrame::OnClose(wxCloseEvent& event) { if (event.CanVeto()) { // we can cancel the close event if necessary if (viewptr->waitingforclick) { event.Veto(); return; } if (inscript || generating) { Stop(); /* using wxPostEvent doesn't work if we've been called from Yield: wxCommandEvent quitevt(wxEVT_COMMAND_MENU_SELECTED, wxID_EXIT); wxPostEvent(this->GetEventHandler(), quitevt); */ // set flag so OnClose gets called again in next OnIdle call_close = true; event.Veto(); return; } if (askonquit) { // keep track of which unique clones have been seen; // we add 1 below to allow for cloneseen[0] (always false) const int maxseen = MAX_LAYERS/2 + 1; bool cloneseen[maxseen]; for (int i = 0; i < maxseen; i++) cloneseen[i] = false; // for each dirty layer, ask user if they want to save changes int oldindex = currindex; for (int i = 0; i < numlayers; i++) { // only ask once for each unique clone (cloneid == 0 for non-clone) int cid = GetLayer(i)->cloneid; if (!cloneseen[cid]) { if (cid > 0) cloneseen[cid] = true; if (GetLayer(i)->dirty) { if (i != currindex) SetLayer(i); if (!SaveCurrentLayer()) { // user cancelled "save changes" dialog so restore layer SetLayer(oldindex); UpdateUserInterface(); event.Veto(); return; } } } } } } if (GetHelpFrame()) GetHelpFrame()->Close(true); if (GetInfoFrame()) GetInfoFrame()->Close(true); if (splitwin->IsSplit()) dirwinwd = splitwin->GetSashPosition(); // if script is running or pattern is generating then CanVeto was false // (probably due to user logging out or shutting down system) // and we need to call exit below bool callexit = inscript || generating; // abort any running script and tidy up; also restores current directory // to location of Golly app so prefs file will be saved in correct place FinishScripting(); // save main window location and other user preferences SavePrefs(); // delete any temporary files if (wxFileExists(perlfile)) wxRemoveFile(perlfile); if (wxFileExists(pythonfile)) wxRemoveFile(pythonfile); for (int i = 0; i < numlayers; i++) { Layer* layer = GetLayer(i); if (wxFileExists(layer->tempstart)) wxRemoveFile(layer->tempstart); // clear all undo/redo history for this layer layer->undoredo->ClearUndoRedo(); } if (wxFileName::DirExists(tempdir)) { // delete all files in tempdir (we assume it has no subdirs) wxDir* dir = new wxDir(tempdir); wxArrayString files; wxString filename; bool more = dir->GetFirst(&filename); while (more) { files.Add(tempdir + filename); more = dir->GetNext(&filename); } // delete wxDir object now otherwise Rmdir below will fail on Windows delete dir; for (size_t n = 0; n < files.GetCount(); n++) { wxRemoveFile(files[n]); } // delete the (hopefully) empty tempdir if (!wxFileName::Rmdir(tempdir)) { Warning(_("Could not delete temporary directory:\n") + tempdir); } } // allow clipboard data to persist after app exits // (needed on Windows, not needed on Mac, doesn't work on Linux -- sheesh!) if (wxTheClipboard->Open()) { wxTheClipboard->Flush(); wxTheClipboard->Close(); } // avoid possible error message or seg fault if (callexit) exit(0); Destroy(); #ifdef __WXGTK__ // avoid seg fault on Linux (only happens if ctrl-Q is used to quit) exit(0); #endif // deallocate things (usually no need) to help find any real memory leaks if (debuglevel == 666) { wxGetApp().Yield(); // (because Destroy() doesn't act immediately) if (numlayers > 1) DeleteOtherLayers(); delete currlayer; delete stopwatch; DeleteAlgorithms(); FreeCursors(); FreeDefaultColors(); } } // ----------------------------------------------------------------------------- void MainFrame::QuitApp() { Close(false); // false allows OnClose handler to veto close } // ----------------------------------------------------------------------------- #if wxUSE_DRAG_AND_DROP // derive a simple class for handling dropped files class DnDFile : public wxFileDropTarget { public: DnDFile() {} virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames); }; bool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames) { // bring app to front #ifdef __WXMAC__ ProcessSerialNumber process; if ( GetCurrentProcess(&process) == noErr ) SetFrontProcess(&process); #endif #ifdef __WXMSW__ SetForegroundWindow( (HWND)mainptr->GetHandle() ); #endif mainptr->Raise(); size_t numfiles = filenames.GetCount(); for ( size_t n = 0; n < numfiles; n++ ) { mainptr->OpenFile(filenames[n]); } #ifdef __WXMAC__ // need to call Refresh a bit later to remove colored frame on Mac onetimer->Start(10, wxTIMER_ONE_SHOT); // OnOneTimer will be called once after a delay of 0.01 secs #endif return true; } wxDropTarget* MainFrame::NewDropTarget() { return new DnDFile(); } #endif // wxUSE_DRAG_AND_DROP // ----------------------------------------------------------------------------- void MainFrame::SetRandomFillPercentage() { // update Random Fill menu item to show randomfill value wxMenuBar* mbar = GetMenuBar(); if (mbar) { wxString randlabel; randlabel.Printf(_("Random Fill (%d%c)"), randomfill, '%'); randlabel += GetAccelerator(DO_RANDFILL); mbar->SetLabel(ID_RANDOM, randlabel); } } // ----------------------------------------------------------------------------- void MainFrame::UpdateLayerItem(int index) { // update name in given layer's menu item Layer* layer = GetLayer(index); wxMenuBar* mbar = GetMenuBar(); if (mbar) { wxString label = wxEmptyString; // we no longer show index in front of name // label.Printf(_("%d: "), index); // display asterisk if pattern has been modified if (layer->dirty) label += wxT("*"); int cid = layer->cloneid; while (cid > 0) { // display one or more "=" chars to indicate this is a cloned layer label += wxT("="); cid--; } label += layer->currname; // duplicate any ampersands so they appear label.Replace(wxT("&"), wxT("&&")); mbar->SetLabel(ID_LAYER0 + index, label); // also update name in corresponding layer button UpdateLayerButton(index, label); } } // ----------------------------------------------------------------------------- void MainFrame::AppendLayerItem() { wxMenuBar* mbar = GetMenuBar(); if (mbar) { wxMenu* layermenu = mbar->GetMenu( mbar->FindMenu(_("Layer")) ); if (layermenu) { // no point setting the item name here because UpdateLayerItem // will be called very soon layermenu->AppendCheckItem(ID_LAYER0 + numlayers - 1, _("foo")); } else { Warning(_("Could not find Layer menu!")); } } } // ----------------------------------------------------------------------------- void MainFrame::RemoveLayerItem() { wxMenuBar* mbar = GetMenuBar(); if (mbar) { wxMenu* layermenu = mbar->GetMenu( mbar->FindMenu(_("Layer")) ); if (layermenu) { layermenu->Delete(ID_LAYER0 + numlayers); } else { Warning(_("Could not find Layer menu!")); } } } // ----------------------------------------------------------------------------- void MainFrame::CreateMenus() { wxMenu* fileMenu = new wxMenu(); wxMenu* editMenu = new wxMenu(); wxMenu* controlMenu = new wxMenu(); wxMenu* viewMenu = new wxMenu(); wxMenu* layerMenu = new wxMenu(); wxMenu* helpMenu = new wxMenu(); // create submenus wxMenu* plocSubMenu = new wxMenu(); wxMenu* pmodeSubMenu = new wxMenu(); wxMenu* cmodeSubMenu = new wxMenu(); wxMenu* scaleSubMenu = new wxMenu(); plocSubMenu->AppendCheckItem(ID_PL_TL, _("Top Left")); plocSubMenu->AppendCheckItem(ID_PL_TR, _("Top Right")); plocSubMenu->AppendCheckItem(ID_PL_BR, _("Bottom Right")); plocSubMenu->AppendCheckItem(ID_PL_BL, _("Bottom Left")); plocSubMenu->AppendCheckItem(ID_PL_MID, _("Middle")); pmodeSubMenu->AppendCheckItem(ID_PM_AND, _("And")); pmodeSubMenu->AppendCheckItem(ID_PM_COPY, _("Copy")); pmodeSubMenu->AppendCheckItem(ID_PM_OR, _("Or")); pmodeSubMenu->AppendCheckItem(ID_PM_XOR, _("Xor")); cmodeSubMenu->AppendCheckItem(ID_DRAW, _("Draw") + GetAccelerator(DO_CURSDRAW)); cmodeSubMenu->AppendCheckItem(ID_PICK, _("Pick") + GetAccelerator(DO_CURSPICK)); cmodeSubMenu->AppendCheckItem(ID_SELECT, _("Select") + GetAccelerator(DO_CURSSEL)); cmodeSubMenu->AppendCheckItem(ID_MOVE, _("Move") + GetAccelerator(DO_CURSMOVE)); cmodeSubMenu->AppendCheckItem(ID_ZOOMIN, _("Zoom In") + GetAccelerator(DO_CURSIN)); cmodeSubMenu->AppendCheckItem(ID_ZOOMOUT, _("Zoom Out") + GetAccelerator(DO_CURSOUT)); scaleSubMenu->AppendCheckItem(ID_SCALE_1, _("1:1") + GetAccelerator(DO_SCALE1)); scaleSubMenu->AppendCheckItem(ID_SCALE_2, _("1:2") + GetAccelerator(DO_SCALE2)); scaleSubMenu->AppendCheckItem(ID_SCALE_4, _("1:4") + GetAccelerator(DO_SCALE4)); scaleSubMenu->AppendCheckItem(ID_SCALE_8, _("1:8") + GetAccelerator(DO_SCALE8)); scaleSubMenu->AppendCheckItem(ID_SCALE_16, _("1:16") + GetAccelerator(DO_SCALE16)); scaleSubMenu->AppendCheckItem(ID_SCALE_32, _("1:32") + GetAccelerator(DO_SCALE32)); fileMenu->Append(wxID_NEW, _("New Pattern") + GetAccelerator(DO_NEWPATT)); fileMenu->AppendSeparator(); fileMenu->Append(wxID_OPEN, _("Open Pattern...") + GetAccelerator(DO_OPENPATT)); fileMenu->Append(ID_OPEN_CLIP, _("Open Clipboard") + GetAccelerator(DO_OPENCLIP)); fileMenu->Append(ID_OPEN_RECENT, _("Open Recent"), patternSubMenu); fileMenu->AppendSeparator(); fileMenu->AppendCheckItem(ID_SHOW_PATTERNS, _("Show Patterns") + GetAccelerator(DO_PATTERNS)); fileMenu->Append(ID_PATTERN_DIR, _("Set Pattern Folder...") + GetAccelerator(DO_PATTDIR)); fileMenu->AppendSeparator(); fileMenu->Append(wxID_SAVE, _("Save Pattern...") + GetAccelerator(DO_SAVE)); fileMenu->AppendCheckItem(ID_SAVE_XRLE, _("Save Extended RLE") + GetAccelerator(DO_SAVEXRLE)); fileMenu->AppendSeparator(); fileMenu->Append(ID_RUN_SCRIPT, _("Run Script...") + GetAccelerator(DO_RUNSCRIPT)); fileMenu->Append(ID_RUN_CLIP, _("Run Clipboard") + GetAccelerator(DO_RUNCLIP)); fileMenu->Append(ID_RUN_RECENT, _("Run Recent"), scriptSubMenu); fileMenu->AppendSeparator(); fileMenu->AppendCheckItem(ID_SHOW_SCRIPTS, _("Show Scripts") + GetAccelerator(DO_SCRIPTS)); fileMenu->Append(ID_SCRIPT_DIR, _("Set Script Folder...") + GetAccelerator(DO_SCRIPTDIR)); #if !defined(__WXOSX_COCOA__) fileMenu->AppendSeparator(); #endif // on the Mac the wxID_PREFERENCES item is moved to the app menu fileMenu->Append(wxID_PREFERENCES, _("Preferences...") + GetAccelerator(DO_PREFS)); #if !defined(__WXOSX_COCOA__) fileMenu->AppendSeparator(); #endif // on the Mac the wxID_EXIT item is moved to the app menu and the app name is appended to "Quit " fileMenu->Append(wxID_EXIT, _("Quit") + GetAccelerator(DO_QUIT)); editMenu->Append(ID_UNDO, _("Undo") + GetAccelerator(DO_UNDO)); editMenu->Append(ID_REDO, _("Redo") + GetAccelerator(DO_REDO)); editMenu->AppendCheckItem(ID_NO_UNDO, _("Disable Undo/Redo") + GetAccelerator(DO_DISABLE)); editMenu->AppendSeparator(); editMenu->Append(ID_CUT, _("Cut") + GetAccelerator(DO_CUT)); editMenu->Append(ID_COPY, _("Copy") + GetAccelerator(DO_COPY)); editMenu->Append(ID_CLEAR, _("Clear") + GetAccelerator(DO_CLEAR)); editMenu->Append(ID_OUTSIDE, _("Clear Outside") + GetAccelerator(DO_CLEAROUT)); editMenu->AppendSeparator(); editMenu->Append(ID_PASTE, _("Paste") + GetAccelerator(DO_PASTE)); editMenu->Append(ID_PMODE, _("Paste Mode"), pmodeSubMenu); editMenu->Append(ID_PLOCATION, _("Paste Location"), plocSubMenu); editMenu->Append(ID_PASTE_SEL, _("Paste to Selection") + GetAccelerator(DO_PASTESEL)); editMenu->AppendSeparator(); editMenu->Append(ID_SELECTALL, _("Select All") + GetAccelerator(DO_SELALL)); editMenu->Append(ID_REMOVE, _("Remove Selection") + GetAccelerator(DO_REMOVESEL)); editMenu->Append(ID_SHRINK, _("Shrink Selection") + GetAccelerator(DO_SHRINK)); // full label will be set later by SetRandomFillPercentage editMenu->Append(ID_RANDOM, _("Random Fill") + GetAccelerator(DO_RANDFILL)); editMenu->Append(ID_FLIPTB, _("Flip Top-Bottom") + GetAccelerator(DO_FLIPTB)); editMenu->Append(ID_FLIPLR, _("Flip Left-Right") + GetAccelerator(DO_FLIPLR)); editMenu->Append(ID_ROTATEC, _("Rotate Clockwise") + GetAccelerator(DO_ROTATECW)); editMenu->Append(ID_ROTATEA, _("Rotate Anticlockwise") + GetAccelerator(DO_ROTATEACW)); editMenu->AppendSeparator(); editMenu->Append(ID_CMODE, _("Cursor Mode"), cmodeSubMenu); controlMenu->Append(ID_START, _("Start Generating") + GetAccelerator(DO_STARTSTOP)); controlMenu->Append(ID_NEXT, _("Next Generation") + GetAccelerator(DO_NEXTGEN)); controlMenu->Append(ID_STEP, _("Next Step") + GetAccelerator(DO_NEXTSTEP)); controlMenu->AppendSeparator(); controlMenu->Append(ID_RESET, _("Reset") + GetAccelerator(DO_RESET)); controlMenu->Append(ID_SETGEN, _("Set Generation...") + GetAccelerator(DO_SETGEN)); controlMenu->AppendSeparator(); controlMenu->Append(ID_FASTER, _("Faster") + GetAccelerator(DO_FASTER)); controlMenu->Append(ID_SLOWER, _("Slower") + GetAccelerator(DO_SLOWER)); controlMenu->Append(ID_SETBASE, _("Set Base Step...") + GetAccelerator(DO_SETBASE)); controlMenu->AppendSeparator(); controlMenu->AppendCheckItem(ID_AUTO, _("Auto Fit") + GetAccelerator(DO_AUTOFIT)); controlMenu->AppendCheckItem(ID_HYPER, _("Hyperspeed") + GetAccelerator(DO_HYPER)); controlMenu->AppendCheckItem(ID_HINFO, _("Show Hash Info") + GetAccelerator(DO_HASHINFO)); controlMenu->AppendSeparator(); controlMenu->Append(ID_RECORD, _("Start Recording") + GetAccelerator(DO_RECORD)); controlMenu->Append(ID_DELTIME, _("Delete Timeline") + GetAccelerator(DO_DELTIME)); controlMenu->AppendSeparator(); controlMenu->Append(ID_CONVERT, _("Convert Old Rules")); // rarely used, so no accelerator controlMenu->AppendSeparator(); controlMenu->Append(ID_SETALGO, _("Set Algorithm"), algomenu); controlMenu->Append(ID_SETRULE, _("Set Rule...") + GetAccelerator(DO_SETRULE)); viewMenu->Append(ID_FULL, _("Full Screen") + GetAccelerator(DO_FULLSCREEN)); viewMenu->AppendSeparator(); viewMenu->Append(ID_FIT, _("Fit Pattern") + GetAccelerator(DO_FIT)); viewMenu->Append(ID_FIT_SEL, _("Fit Selection") + GetAccelerator(DO_FITSEL)); viewMenu->Append(ID_MIDDLE, _("Middle") + GetAccelerator(DO_MIDDLE)); viewMenu->Append(ID_RESTORE00, _("Restore Origin") + GetAccelerator(DO_RESTORE00)); viewMenu->AppendSeparator(); viewMenu->Append(wxID_ZOOM_IN, _("Zoom In") + GetAccelerator(DO_ZOOMIN)); viewMenu->Append(wxID_ZOOM_OUT, _("Zoom Out") + GetAccelerator(DO_ZOOMOUT)); viewMenu->Append(ID_SET_SCALE, _("Set Scale"), scaleSubMenu); viewMenu->AppendSeparator(); viewMenu->AppendCheckItem(ID_TOOL_BAR, _("Show Tool Bar") + GetAccelerator(DO_SHOWTOOL)); viewMenu->AppendCheckItem(ID_LAYER_BAR, _("Show Layer Bar") + GetAccelerator(DO_SHOWLAYER)); viewMenu->AppendCheckItem(ID_EDIT_BAR, _("Show Edit Bar") + GetAccelerator(DO_SHOWEDIT)); viewMenu->AppendCheckItem(ID_ALL_STATES, _("Show All States") + GetAccelerator(DO_SHOWSTATES)); viewMenu->AppendCheckItem(ID_STATUS_BAR, _("Show Status Bar") + GetAccelerator(DO_SHOWSTATUS)); viewMenu->AppendCheckItem(ID_EXACT, _("Show Exact Numbers") + GetAccelerator(DO_SHOWEXACT)); viewMenu->AppendCheckItem(ID_GRID, _("Show Grid Lines") + GetAccelerator(DO_SHOWGRID)); viewMenu->AppendCheckItem(ID_ICONS, _("Show Cell Icons") + GetAccelerator(DO_SHOWICONS)); viewMenu->AppendCheckItem(ID_INVERT, _("Invert Colors") + GetAccelerator(DO_INVERT)); viewMenu->AppendCheckItem(ID_BUFF, _("Buffered") + GetAccelerator(DO_BUFFERED)); viewMenu->AppendCheckItem(ID_TIMELINE, _("Show Timeline") + GetAccelerator(DO_SHOWTIME)); viewMenu->AppendSeparator(); viewMenu->Append(ID_INFO, _("Pattern Info") + GetAccelerator(DO_INFO)); layerMenu->Append(ID_ADD_LAYER, _("Add Layer") + GetAccelerator(DO_ADD)); layerMenu->Append(ID_CLONE, _("Clone Layer") + GetAccelerator(DO_CLONE)); layerMenu->Append(ID_DUPLICATE, _("Duplicate Layer") + GetAccelerator(DO_DUPLICATE)); layerMenu->AppendSeparator(); layerMenu->Append(ID_DEL_LAYER, _("Delete Layer") + GetAccelerator(DO_DELETE)); layerMenu->Append(ID_DEL_OTHERS, _("Delete Other Layers") + GetAccelerator(DO_DELOTHERS)); layerMenu->AppendSeparator(); layerMenu->Append(ID_MOVE_LAYER, _("Move Layer...") + GetAccelerator(DO_MOVELAYER)); layerMenu->Append(ID_NAME_LAYER, _("Name Layer...") + GetAccelerator(DO_NAMELAYER)); layerMenu->Append(ID_SET_COLORS, _("Set Layer Colors...") + GetAccelerator(DO_SETCOLORS)); layerMenu->AppendSeparator(); layerMenu->AppendCheckItem(ID_SYNC_VIEW, _("Synchronize Views") + GetAccelerator(DO_SYNCVIEWS)); layerMenu->AppendCheckItem(ID_SYNC_CURS, _("Synchronize Cursors") + GetAccelerator(DO_SYNCCURS)); layerMenu->AppendSeparator(); layerMenu->AppendCheckItem(ID_STACK, _("Stack Layers") + GetAccelerator(DO_STACK)); layerMenu->AppendCheckItem(ID_TILE, _("Tile Layers") + GetAccelerator(DO_TILE)); layerMenu->AppendSeparator(); layerMenu->AppendCheckItem(ID_LAYER0, _("0")); // UpdateLayerItem will soon change the above item name helpMenu->Append(ID_HELP_INDEX, _("Contents")); helpMenu->Append(ID_HELP_INTRO, _("Introduction")); helpMenu->Append(ID_HELP_TIPS, _("Hints and Tips")); helpMenu->Append(ID_HELP_ALGOS, _("Algorithms")); helpMenu->Append(ID_HELP_LEXICON, _("Life Lexicon")); helpMenu->Append(ID_HELP_ARCHIVES, _("Online Archives")); helpMenu->AppendSeparator(); helpMenu->Append(ID_HELP_PERL, _("Perl Scripting")); helpMenu->Append(ID_HELP_PYTHON, _("Python Scripting")); helpMenu->AppendSeparator(); helpMenu->Append(ID_HELP_KEYBOARD, _("Keyboard Shortcuts")); helpMenu->Append(ID_HELP_MOUSE, _("Mouse Shortcuts")); helpMenu->AppendSeparator(); helpMenu->Append(ID_HELP_FILE, _("File Menu")); helpMenu->Append(ID_HELP_EDIT, _("Edit Menu")); helpMenu->Append(ID_HELP_CONTROL, _("Control Menu")); helpMenu->Append(ID_HELP_VIEW, _("View Menu")); helpMenu->Append(ID_HELP_LAYER, _("Layer Menu")); helpMenu->Append(ID_HELP_HELP, _("Help Menu")); helpMenu->AppendSeparator(); helpMenu->Append(ID_HELP_REFS, _("References")); helpMenu->Append(ID_HELP_FORMATS, _("File Formats")); helpMenu->Append(ID_HELP_BOUNDED, _("Bounded Grids")); helpMenu->Append(ID_HELP_PROBLEMS, _("Known Problems")); helpMenu->Append(ID_HELP_CHANGES, _("Changes")); helpMenu->Append(ID_HELP_CREDITS, _("Credits")); #ifndef __WXMAC__ helpMenu->AppendSeparator(); #endif // on the Mac the wxID_ABOUT item gets moved to the app menu helpMenu->Append(wxID_ABOUT, _("About Golly") + GetAccelerator(DO_ABOUT)); // create the menu bar and append menus; // avoid using "&" in menu names because it prevents using keyboard shortcuts // like Alt+L on Linux wxMenuBar* menuBar = new wxMenuBar(); if (menuBar == NULL) Fatal(_("Failed to create menu bar!")); menuBar->Append(fileMenu, _("File")); menuBar->Append(editMenu, _("Edit")); menuBar->Append(controlMenu, _("Control")); menuBar->Append(viewMenu, _("View")); menuBar->Append(layerMenu, _("Layer")); #ifdef __WXMAC__ // wxMac bug: need the "&" otherwise we get an extra Help menu menuBar->Append(helpMenu, _("&Help")); #else menuBar->Append(helpMenu, _("Help")); #endif #ifdef __WXMAC__ // prevent Window menu being added automatically by wxMac 2.6.1+ menuBar->SetAutoWindowMenu(false); #endif // attach menu bar to the frame SetMenuBar(menuBar); } // ----------------------------------------------------------------------------- void MainFrame::UpdateMenuAccelerators() { // keyboard shortcuts have changed, so update all menu item accelerators wxMenuBar* mbar = GetMenuBar(); if (mbar) { // wxMac bug: these app menu items aren't updated (but user isn't likely // to change them so don't bother trying to fix the bug) SetAccelerator(mbar, wxID_ABOUT, DO_ABOUT); SetAccelerator(mbar, wxID_PREFERENCES, DO_PREFS); SetAccelerator(mbar, wxID_EXIT, DO_QUIT); SetAccelerator(mbar, ID_DRAW, DO_CURSDRAW); SetAccelerator(mbar, ID_PICK, DO_CURSPICK); SetAccelerator(mbar, ID_SELECT, DO_CURSSEL); SetAccelerator(mbar, ID_MOVE, DO_CURSMOVE); SetAccelerator(mbar, ID_ZOOMIN, DO_CURSIN); SetAccelerator(mbar, ID_ZOOMOUT, DO_CURSOUT); SetAccelerator(mbar, ID_SCALE_1, DO_SCALE1); SetAccelerator(mbar, ID_SCALE_2, DO_SCALE2); SetAccelerator(mbar, ID_SCALE_4, DO_SCALE4); SetAccelerator(mbar, ID_SCALE_8, DO_SCALE8); SetAccelerator(mbar, ID_SCALE_16, DO_SCALE16); SetAccelerator(mbar, ID_SCALE_32, DO_SCALE32); SetAccelerator(mbar, wxID_NEW, DO_NEWPATT); SetAccelerator(mbar, wxID_OPEN, DO_OPENPATT); SetAccelerator(mbar, ID_OPEN_CLIP, DO_OPENCLIP); SetAccelerator(mbar, ID_SHOW_PATTERNS, DO_PATTERNS); SetAccelerator(mbar, ID_PATTERN_DIR, DO_PATTDIR); SetAccelerator(mbar, wxID_SAVE, DO_SAVE); SetAccelerator(mbar, ID_SAVE_XRLE, DO_SAVEXRLE); SetAccelerator(mbar, ID_RUN_SCRIPT, DO_RUNSCRIPT); SetAccelerator(mbar, ID_RUN_CLIP, DO_RUNCLIP); SetAccelerator(mbar, ID_SHOW_SCRIPTS, DO_SCRIPTS); SetAccelerator(mbar, ID_SCRIPT_DIR, DO_SCRIPTDIR); SetAccelerator(mbar, ID_UNDO, DO_UNDO); SetAccelerator(mbar, ID_REDO, DO_REDO); SetAccelerator(mbar, ID_NO_UNDO, DO_DISABLE); SetAccelerator(mbar, ID_CUT, DO_CUT); SetAccelerator(mbar, ID_COPY, DO_COPY); SetAccelerator(mbar, ID_CLEAR, DO_CLEAR); SetAccelerator(mbar, ID_OUTSIDE, DO_CLEAROUT); SetAccelerator(mbar, ID_PASTE, DO_PASTE); SetAccelerator(mbar, ID_PASTE_SEL, DO_PASTESEL); SetAccelerator(mbar, ID_SELECTALL, DO_SELALL); SetAccelerator(mbar, ID_REMOVE, DO_REMOVESEL); SetAccelerator(mbar, ID_SHRINK, DO_SHRINK); SetAccelerator(mbar, ID_RANDOM, DO_RANDFILL); SetAccelerator(mbar, ID_FLIPTB, DO_FLIPTB); SetAccelerator(mbar, ID_FLIPLR, DO_FLIPLR); SetAccelerator(mbar, ID_ROTATEC, DO_ROTATECW); SetAccelerator(mbar, ID_ROTATEA, DO_ROTATEACW); SetAccelerator(mbar, ID_START, DO_STARTSTOP); SetAccelerator(mbar, ID_NEXT, DO_NEXTGEN); SetAccelerator(mbar, ID_STEP, DO_NEXTSTEP); SetAccelerator(mbar, ID_RESET, DO_RESET); SetAccelerator(mbar, ID_SETGEN, DO_SETGEN); SetAccelerator(mbar, ID_FASTER, DO_FASTER); SetAccelerator(mbar, ID_SLOWER, DO_SLOWER); SetAccelerator(mbar, ID_SETBASE, DO_SETBASE); SetAccelerator(mbar, ID_AUTO, DO_AUTOFIT); SetAccelerator(mbar, ID_HYPER, DO_HYPER); SetAccelerator(mbar, ID_HINFO, DO_HASHINFO); SetAccelerator(mbar, ID_RECORD, DO_RECORD); SetAccelerator(mbar, ID_DELTIME, DO_DELTIME); SetAccelerator(mbar, ID_SETRULE, DO_SETRULE); SetAccelerator(mbar, ID_FULL, DO_FULLSCREEN); SetAccelerator(mbar, ID_FIT, DO_FIT); SetAccelerator(mbar, ID_FIT_SEL, DO_FITSEL); SetAccelerator(mbar, ID_MIDDLE, DO_MIDDLE); SetAccelerator(mbar, ID_RESTORE00, DO_RESTORE00); SetAccelerator(mbar, wxID_ZOOM_IN, DO_ZOOMIN); SetAccelerator(mbar, wxID_ZOOM_OUT, DO_ZOOMOUT); SetAccelerator(mbar, ID_TOOL_BAR, DO_SHOWTOOL); SetAccelerator(mbar, ID_LAYER_BAR, DO_SHOWLAYER); SetAccelerator(mbar, ID_EDIT_BAR, DO_SHOWEDIT); SetAccelerator(mbar, ID_ALL_STATES, DO_SHOWSTATES); SetAccelerator(mbar, ID_STATUS_BAR, DO_SHOWSTATUS); SetAccelerator(mbar, ID_EXACT, DO_SHOWEXACT); SetAccelerator(mbar, ID_GRID, DO_SHOWGRID); SetAccelerator(mbar, ID_ICONS, DO_SHOWICONS); SetAccelerator(mbar, ID_INVERT, DO_INVERT); SetAccelerator(mbar, ID_BUFF, DO_BUFFERED); SetAccelerator(mbar, ID_TIMELINE, DO_SHOWTIME); SetAccelerator(mbar, ID_INFO, DO_INFO); SetAccelerator(mbar, ID_ADD_LAYER, DO_ADD); SetAccelerator(mbar, ID_CLONE, DO_CLONE); SetAccelerator(mbar, ID_DUPLICATE, DO_DUPLICATE); SetAccelerator(mbar, ID_DEL_LAYER, DO_DELETE); SetAccelerator(mbar, ID_DEL_OTHERS, DO_DELOTHERS); SetAccelerator(mbar, ID_MOVE_LAYER, DO_MOVELAYER); SetAccelerator(mbar, ID_NAME_LAYER, DO_NAMELAYER); SetAccelerator(mbar, ID_SET_COLORS, DO_SETCOLORS); SetAccelerator(mbar, ID_SYNC_VIEW, DO_SYNCVIEWS); SetAccelerator(mbar, ID_SYNC_CURS, DO_SYNCCURS); SetAccelerator(mbar, ID_STACK, DO_STACK); SetAccelerator(mbar, ID_TILE, DO_TILE); } } // ----------------------------------------------------------------------------- void MainFrame::CreateDirControls() { patternctrl = new wxGenericDirCtrl(splitwin, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, #ifdef __WXMSW__ // speed up a bit wxDIRCTRL_DIR_ONLY | wxNO_BORDER, #else wxNO_BORDER, #endif wxEmptyString // see all file types ); if (patternctrl == NULL) Fatal(_("Failed to create pattern directory control!")); scriptctrl = new wxGenericDirCtrl(splitwin, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, #ifdef __WXMSW__ // speed up a bit wxDIRCTRL_DIR_ONLY | wxNO_BORDER, #else wxNO_BORDER, #endif #if wxCHECK_VERSION(2,9,0) // avoid seeing the wxChoice control (ugly and buggy) wxEmptyString #else _T("Perl/Python scripts|*.pl;*.py") #endif ); if (scriptctrl == NULL) Fatal(_("Failed to create script directory control!")); #ifdef __WXMSW__ // now remove wxDIRCTRL_DIR_ONLY so we see files patternctrl->SetWindowStyle(wxNO_BORDER); scriptctrl->SetWindowStyle(wxNO_BORDER); #endif #if defined(__WXGTK__) // make sure background is white when using KDE's GTK theme #if wxCHECK_VERSION(2,9,0) patternctrl->GetTreeCtrl()->SetBackgroundStyle(wxBG_STYLE_ERASE); scriptctrl->GetTreeCtrl()->SetBackgroundStyle(wxBG_STYLE_ERASE); #else patternctrl->GetTreeCtrl()->SetBackgroundStyle(wxBG_STYLE_COLOUR); scriptctrl->GetTreeCtrl()->SetBackgroundStyle(wxBG_STYLE_COLOUR); #endif patternctrl->GetTreeCtrl()->SetBackgroundColour(*wxWHITE); scriptctrl->GetTreeCtrl()->SetBackgroundColour(*wxWHITE); // reduce indent a bit patternctrl->GetTreeCtrl()->SetIndent(8); scriptctrl->GetTreeCtrl()->SetIndent(8); #elif defined(__WXMAC__) // reduce indent a bit more patternctrl->GetTreeCtrl()->SetIndent(6); scriptctrl->GetTreeCtrl()->SetIndent(6); #else // reduce indent a lot on Windows patternctrl->GetTreeCtrl()->SetIndent(4); scriptctrl->GetTreeCtrl()->SetIndent(4); #endif #ifdef __WXMAC__ // reduce font size (to get this to reduce line height we had to // make a few changes to wxMac/src/generic/treectlg.cpp) wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); font.SetPointSize(12); patternctrl->GetTreeCtrl()->SetFont(font); scriptctrl->GetTreeCtrl()->SetFont(font); #endif if ( wxFileName::DirExists(patterndir) ) { // only show patterndir and its contents SimplifyTree(patterndir, patternctrl->GetTreeCtrl(), patternctrl->GetRootId()); } if ( wxFileName::DirExists(scriptdir) ) { // only show scriptdir and its contents SimplifyTree(scriptdir, scriptctrl->GetTreeCtrl(), scriptctrl->GetRootId()); } // install event handler to detect clicking on a file patternctrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(MainFrame::OnTreeClick)); patternctrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainFrame::OnTreeClick)); patternctrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_LEFT_DCLICK, wxMouseEventHandler(MainFrame::OnTreeClick)); scriptctrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(MainFrame::OnTreeClick)); scriptctrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainFrame::OnTreeClick)); scriptctrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_LEFT_DCLICK, wxMouseEventHandler(MainFrame::OnTreeClick)); } // ----------------------------------------------------------------------------- // create the main window MainFrame::MainFrame() : wxFrame(NULL, wxID_ANY, wxEmptyString, wxPoint(mainx,mainy), wxSize(mainwd,mainht)) { wxGetApp().SetFrameIcon(this); // initialize paths to some temporary files (in datadir so no need to be hidden); // they must be absolute paths in case they are used from a script command when the // current directory has been changed to the location of the script file clipfile = datadir + wxT("golly_clipboard"); perlfile = datadir + wxT("golly_clip.pl"); pythonfile = datadir + wxT("golly_clip.py"); // create one-shot timer (see OnOneTimer) onetimer = new wxTimer(this, wxID_ANY); CreateMenus(); CreateToolbar(); // if tool bar is visible then adjust position of other child windows int toolwd = showtool ? toolbarwd : 0; int wd, ht; GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; // wxStatusBar can only appear at bottom of frame so we use our own // status bar class which creates a child window at top of frame // but to the right of the tool bar int statht = showexact ? STATUS_EXHT : STATUS_HT; if (!showstatus) statht = 0; statusptr = new StatusBar(this, toolwd, 0, wd - toolwd, statht); if (statusptr == NULL) Fatal(_("Failed to create status bar!")); // create a split window with pattern/script directory in left pane // and layer/edit/timeline bars and pattern viewport in right pane splitwin = new wxSplitterWindow(this, wxID_ANY, wxPoint(toolwd, statht), wxSize(wd - toolwd, ht - statht), #ifdef __WXMSW__ wxSP_BORDER | #endif wxSP_3DSASH | wxSP_NO_XP_THEME | wxSP_LIVE_UPDATE); if (splitwin == NULL) Fatal(_("Failed to create split window!")); // create patternctrl and scriptctrl in left pane CreateDirControls(); // create a window for right pane which contains layer/edit/timeline bars // and pattern viewport rightpane = new RightWindow(splitwin); if (rightpane == NULL) Fatal(_("Failed to create right pane!")); // create layer bar and initial layer CreateLayerBar(rightpane); AddLayer(); // create edit bar CreateEditBar(rightpane); // create timeline bar CreateTimelineBar(rightpane); // enable/disable tool tips after creating bars with buttons #if wxUSE_TOOLTIPS wxToolTip::Enable(showtips); wxToolTip::SetDelay(1500); // 1.5 secs #endif CreateTranslucentControls(); // must be done BEFORE creating viewport // create viewport at minimum size to avoid scroll bars being clipped on Mac int y = 0; if (showlayer) y += LayerBarHeight(); if (showedit) y += EditBarHeight(); viewptr = new PatternView(rightpane, 0, y, 40, 40, wxNO_BORDER | wxWANTS_CHARS | // receive all keyboard events wxFULL_REPAINT_ON_RESIZE | wxVSCROLL | wxHSCROLL); if (viewptr == NULL) Fatal(_("Failed to create viewport window!")); // this is the main viewport window (tile windows have a tileindex >= 0) viewptr->tileindex = -1; bigview = viewptr; #if wxUSE_DRAG_AND_DROP // let users drop files onto viewport viewptr->SetDropTarget(new DnDFile()); #endif // these seemingly redundant steps are needed to avoid problems on Windows splitwin->SplitVertically(patternctrl, rightpane, dirwinwd); splitwin->SetSashPosition(dirwinwd); splitwin->SetMinimumPaneSize(MIN_DIRWD); splitwin->Unsplit(patternctrl); splitwin->UpdateSize(); splitwin->SplitVertically(scriptctrl, rightpane, dirwinwd); splitwin->SetSashPosition(dirwinwd); splitwin->SetMinimumPaneSize(MIN_DIRWD); splitwin->Unsplit(scriptctrl); splitwin->UpdateSize(); if (showpatterns) splitwin->SplitVertically(patternctrl, rightpane, dirwinwd); if (showscripts) splitwin->SplitVertically(scriptctrl, rightpane, dirwinwd); InitDrawingData(); // do this after viewptr has been set pendingfiles.Clear(); // no pending script/pattern files command_pending = false; // no pending command draw_pending = false; // no pending draw keepmessage = false; // clear status message generating = false; // not generating pattern fullscreen = false; // not in full screen mode showbanner = true; // avoid first file clearing banner message } // ----------------------------------------------------------------------------- MainFrame::~MainFrame() { delete onetimer; DestroyDrawingData(); } golly-2.7-src/gui-wx/wxutils.h0000644000175000017500000001001512536111364013325 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXUTILS_H_ #define _WXUTILS_H_ // Various utility routines: void Note(const wxString& msg); // Display given message in a modal dialog. void Warning(const wxString& msg); // Beep and display message in a modal dialog. void Fatal(const wxString& msg); // Beep, display message in a modal dialog, then exit app. void Beep(); // Play beep sound, depending on preference setting. bool GetString(const wxString& title, const wxString& prompt, const wxString& instring, wxString& outstring); // Display a dialog box to get a string from the user. // Returns false if user hits Cancel button. bool GetInteger(const wxString& title, const wxString& prompt, int inval, int minval, int maxval, int* outval); // Display a dialog box to get an integer value from the user. // Returns false if user hits Cancel button. int SaveChanges(const wxString& query, const wxString& msg); // Ask user if changes should be saved and return following result: // 2 if user selects Yes/Save button, // 1 if user selects No/Don't Save button, // 0 if user selects Cancel button. void BeginProgress(const wxString& dlgtitle); // Call at the start of a lengthy task. The cursor changes to indicate // the app is busy but the progress dialog won't appear immediately. bool AbortProgress(double fraction_done, const wxString& newmsg); // Call frequently while the task is being carried out. The progress // dialog only appears if the task is likely to take more than a few secs. // Pass in a fraction from 0.0 to 1.0 indicating how much has been done, // or any negative value to show an indeterminate progress gauge. // The given string can be used to display extra information. // The call returns true if the user cancels the progress dialog. void EndProgress(); // Call when the task has finished (even if it was aborted). void FillRect(wxDC& dc, wxRect& rect, wxBrush& brush); // Fill given rectangle using given brush. void CreatePaleBitmap(const wxBitmap& inmap, wxBitmap& outmap); // Create a pale gray version of given bitmap. bool IsScriptFile(const wxString& filename); // Return true if the given file is a Perl or Python script. // It simply checks if the file's extension is .pl or .py // (ignoring case). bool IsHTMLFile(const wxString& filename); // Return true if the given file's extension is .htm or .html // (ignoring case). bool IsTextFile(const wxString& filename); // Return true if the given file's extension is .txt or .doc, // or if it's not a HTML file and its name contains "readme" // (ignoring case). bool IsZipFile(const wxString& filename); // Return true if the given file's extension is .zip or .gar // (ignoring case). bool IsRuleFile(const wxString& filename); // Return true if the given file is a rule-related file with // an extension of .rule or .table or .tree or .colors or .icons // (ignoring case). // Following macro is used to create a wxBitmap from included XPM data: #if defined(__WXGTK__) || defined(__WXMAC__) #define XPM_BITMAP(name) wxBitmap(name##_xpm) #else // other platforms (eg. wxMSW) #define XPM_BITMAP(name) wxBitmap(name##_xpm, wxBITMAP_TYPE_XPM) #endif #endif // _WXUTILS_H_ golly-2.7-src/gui-wx/wxselect.cpp0000644000175000017500000022313312536111364014006 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "bigint.h" #include "lifealgo.h" #include "viewport.h" #include "wxgolly.h" // for wxGetApp, mainptr, viewptr, statusptr, insideYield #include "wxutils.h" // for Warning #include "wxprefs.h" // for randomfill, etc #include "wxmain.h" // for mainptr->... #include "wxstatus.h" // for statusptr->... #include "wxscript.h" // for inscript #include "wxview.h" // for viewptr->... #include "wxundo.h" // for currlayer->undoredo->... #include "wxalgos.h" // for *_ALGO, CreateNewUniverse #include "wxlayer.h" // for currlayer, MarkLayerDirty, etc #include "wxselect.h" // This module implements operations on selections. // ----------------------------------------------------------------------------- Selection::Selection() { exists = false; } // ----------------------------------------------------------------------------- Selection::Selection(int t, int l, int b, int r) { // create rectangular selection if given edges are valid exists = (t <= b && l <= r); if (exists) { seltop = t; selleft = l; selbottom = b; selright = r; } } // ----------------------------------------------------------------------------- Selection::~Selection() { // no need to do anything at the moment } // ----------------------------------------------------------------------------- bool Selection::operator==(const Selection& s) const { if (!exists && !s.exists) { // neither selection exists return true; } else if (exists && s.exists) { // check if edges match return (seltop == s.seltop && selleft == s.selleft && selbottom == s.selbottom && selright == s.selright); } else { // one selection exists but not the other return false; } } // ----------------------------------------------------------------------------- bool Selection::operator!=(const Selection& s) const { return !(*this == s); } // ----------------------------------------------------------------------------- bool Selection::Exists() { return exists; } // ----------------------------------------------------------------------------- void Selection::Deselect() { exists = false; } // ----------------------------------------------------------------------------- bool Selection::TooBig() { return viewptr->OutsideLimits(seltop, selleft, selbottom, selright); } // ----------------------------------------------------------------------------- void Selection::DisplaySize() { bigint wd = selright; wd -= selleft; wd += bigint::one; bigint ht = selbottom; ht -= seltop; ht += bigint::one; wxString msg = _("Selection wd x ht = "); msg += statusptr->Stringify(wd); msg += _(" x "); msg += statusptr->Stringify(ht); statusptr->SetMessage(msg); } // ----------------------------------------------------------------------------- void Selection::SetRect(int x, int y, int wd, int ht) { exists = (wd > 0 && ht > 0); if (exists) { seltop = y; selleft = x; // avoid int overflow ht--; wd--; selbottom = y; selbottom += ht; selright = x; selright += wd; } } // ----------------------------------------------------------------------------- void Selection::GetRect(int* x, int* y, int* wd, int* ht) { *x = selleft.toint(); *y = seltop.toint(); *wd = selright.toint() - *x + 1; *ht = selbottom.toint() - *y + 1; } // ----------------------------------------------------------------------------- void Selection::SetEdges(bigint& t, bigint& l, bigint& b, bigint& r) { exists = true; seltop = t; selleft = l; selbottom = b; selright = r; CheckGridEdges(); } // ----------------------------------------------------------------------------- void Selection::CheckGridEdges() { if (exists) { // change selection edges if necessary to ensure they are inside a bounded grid if (currlayer->algo->gridwd > 0) { if (selleft > currlayer->algo->gridright || selright < currlayer->algo->gridleft) { exists = false; // selection is outside grid return; } if (selleft < currlayer->algo->gridleft) selleft = currlayer->algo->gridleft; if (selright > currlayer->algo->gridright) selright = currlayer->algo->gridright; } if (currlayer->algo->gridht > 0) { if (seltop > currlayer->algo->gridbottom || selbottom < currlayer->algo->gridtop) { exists = false; // selection is outside grid return; } if (seltop < currlayer->algo->gridtop) seltop = currlayer->algo->gridtop; if (selbottom > currlayer->algo->gridbottom) selbottom = currlayer->algo->gridbottom; } } } // ----------------------------------------------------------------------------- bool Selection::Contains(bigint& t, bigint& l, bigint& b, bigint& r) { return ( seltop <= t && selleft <= l && selbottom >= b && selright >= r ); } // ----------------------------------------------------------------------------- bool Selection::Outside(bigint& t, bigint& l, bigint& b, bigint& r) { return ( seltop > b || selleft > r || selbottom < t || selright < l ); } // ----------------------------------------------------------------------------- bool Selection::ContainsCell(int x, int y) { return ( x >= selleft.toint() && x <= selright.toint() && y >= seltop.toint() && y <= selbottom.toint() ); } // ----------------------------------------------------------------------------- bool Selection::SaveDifferences(lifealgo* oldalgo, lifealgo* newalgo, int itop, int ileft, int ibottom, int iright) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; // compare patterns in given algos and call SaveCellChange for each different cell BeginProgress(_("Saving cell changes")); for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int oldstate = oldalgo->getcell(cx, cy); int newstate = newalgo->getcell(cx, cy); if ( oldstate != newstate ) { // assume this is only called if allowundo && !currlayer->stayclean currlayer->undoredo->SaveCellChange(cx, cy, oldstate, newstate); } cntr++; if ((cntr % 4096) == 0) { abort = AbortProgress((double)cntr / maxcount, wxEmptyString); if (abort) break; } } if (abort) break; } EndProgress(); return !abort; } // ----------------------------------------------------------------------------- void Selection::Advance() { if (mainptr->generating || viewptr->drawingcells || viewptr->waitingforclick) return; if (!exists) { statusptr->ErrorMessage(no_selection); return; } if (currlayer->algo->isEmpty()) { statusptr->ErrorMessage(empty_selection); return; } bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); // check if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { statusptr->ErrorMessage(empty_selection); return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; if (savecells && inscript) SavePendingChanges(); bool boundedgrid = (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0); // check if selection encloses entire pattern; // can't do this if qlife because it uses gen parity to decide which bits to draw; // also avoid this if undo/redo is enabled (too messy to remember cell changes) if ( currlayer->algtype != QLIFE_ALGO && !savecells && Contains(top, left, bottom, right) ) { mainptr->generating = true; wxGetApp().PollerReset(); // step by one gen without changing gen count bigint savegen = currlayer->algo->getGeneration(); bigint saveinc = currlayer->algo->getIncrement(); currlayer->algo->setIncrement(1); if (boundedgrid) mainptr->CreateBorderCells(currlayer->algo); currlayer->algo->step(); if (boundedgrid) mainptr->DeleteBorderCells(currlayer->algo); currlayer->algo->setIncrement(saveinc); currlayer->algo->setGeneration(savegen); mainptr->generating = false; // clear 1-cell thick strips just outside selection ClearOutside(); MarkLayerDirty(); mainptr->UpdateEverything(); return; } // find intersection of selection and pattern to minimize work if (seltop > top) top = seltop; if (selleft > left) left = selleft; if (selbottom < bottom) bottom = selbottom; if (selright < right) right = selright; // check that intersection is within setcell/getcell limits if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(selection_too_big); return; } // create a temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype); if (tempalgo->setrule(currlayer->algo->getrule())) tempalgo->setrule(tempalgo->DefaultRule()); // copy live cells in selection to temporary universe if ( !viewptr->CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, tempalgo, false, _("Saving selection")) ) { delete tempalgo; return; } if ( tempalgo->isEmpty() ) { statusptr->ErrorMessage(empty_selection); delete tempalgo; return; } // advance temporary universe by one gen mainptr->generating = true; wxGetApp().PollerReset(); tempalgo->setIncrement(1); if (boundedgrid) mainptr->CreateBorderCells(tempalgo); tempalgo->step(); if (boundedgrid) mainptr->DeleteBorderCells(tempalgo); mainptr->generating = false; if ( !tempalgo->isEmpty() ) { // temporary pattern might have expanded bigint temptop, templeft, tempbottom, tempright; tempalgo->findedges(&temptop, &templeft, &tempbottom, &tempright); if (temptop < top) top = temptop; if (templeft < left) left = templeft; if (tempbottom > bottom) bottom = tempbottom; if (tempright > right) right = tempright; // but ignore live cells created outside selection edges if (top < seltop) top = seltop; if (left < selleft) left = selleft; if (bottom > selbottom) bottom = selbottom; if (right > selright) right = selright; } if (savecells) { // compare selection rect in currlayer->algo and tempalgo and call SaveCellChange // for each cell that has a different state if ( SaveDifferences(currlayer->algo, tempalgo, top.toint(), left.toint(), bottom.toint(), right.toint()) ) { if ( !currlayer->undoredo->RememberCellChanges(_("Advance Selection"), currlayer->dirty) ) { // pattern inside selection didn't change delete tempalgo; return; } } else { currlayer->undoredo->ForgetCellChanges(); delete tempalgo; return; } } // copy all cells in new selection from tempalgo to currlayer->algo viewptr->CopyAllRect(top.toint(), left.toint(), bottom.toint(), right.toint(), tempalgo, currlayer->algo, _("Copying advanced selection")); delete tempalgo; MarkLayerDirty(); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void Selection::AdvanceOutside() { if (mainptr->generating || viewptr->drawingcells || viewptr->waitingforclick) return; if (!exists) { statusptr->ErrorMessage(no_selection); return; } if (currlayer->algo->isEmpty()) { statusptr->ErrorMessage(empty_outside); return; } bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); // check if selection encloses entire pattern if (Contains(top, left, bottom, right)) { statusptr->ErrorMessage(empty_outside); return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; if (savecells && inscript) SavePendingChanges(); bool boundedgrid = (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0); // check if selection is completely outside pattern edges; // can't do this if qlife because it uses gen parity to decide which bits to draw; // also avoid this if undo/redo is enabled (too messy to remember cell changes) if ( currlayer->algtype != QLIFE_ALGO && !savecells && Outside(top, left, bottom, right) ) { mainptr->generating = true; wxGetApp().PollerReset(); // step by one gen without changing gen count bigint savegen = currlayer->algo->getGeneration(); bigint saveinc = currlayer->algo->getIncrement(); currlayer->algo->setIncrement(1); if (boundedgrid) mainptr->CreateBorderCells(currlayer->algo); currlayer->algo->step(); if (boundedgrid) mainptr->DeleteBorderCells(currlayer->algo); currlayer->algo->setIncrement(saveinc); currlayer->algo->setGeneration(savegen); mainptr->generating = false; // clear selection in case pattern expanded into it Clear(); MarkLayerDirty(); mainptr->UpdateEverything(); return; } // check that pattern is within setcell/getcell limits if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Pattern is outside +/- 10^9 boundary.")); return; } lifealgo* oldalgo = NULL; if (savecells) { // copy current pattern to oldalgo, using same type and gen count // so we can switch to oldalgo if user decides to abort below oldalgo = CreateNewUniverse(currlayer->algtype); if (oldalgo->setrule(currlayer->algo->getrule())) oldalgo->setrule(oldalgo->DefaultRule()); oldalgo->setGeneration( currlayer->algo->getGeneration() ); if ( !viewptr->CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, oldalgo, false, _("Saving pattern")) ) { delete oldalgo; return; } } // create a new universe of same type lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); if (newalgo->setrule(currlayer->algo->getrule())) newalgo->setrule(newalgo->DefaultRule()); newalgo->setGeneration( currlayer->algo->getGeneration() ); // copy (and kill) live cells in selection to new universe int iseltop = seltop.toint(); int iselleft = selleft.toint(); int iselbottom = selbottom.toint(); int iselright = selright.toint(); if ( !viewptr->CopyRect(iseltop, iselleft, iselbottom, iselright, currlayer->algo, newalgo, true, _("Saving and erasing selection")) ) { // aborted, so best to restore selection if ( !newalgo->isEmpty() ) { newalgo->findedges(&top, &left, &bottom, &right); viewptr->CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), newalgo, currlayer->algo, false, _("Restoring selection")); } delete newalgo; if (savecells) delete oldalgo; mainptr->UpdateEverything(); return; } // advance current universe by 1 generation mainptr->generating = true; wxGetApp().PollerReset(); currlayer->algo->setIncrement(1); if (boundedgrid) mainptr->CreateBorderCells(currlayer->algo); currlayer->algo->step(); if (boundedgrid) mainptr->DeleteBorderCells(currlayer->algo); mainptr->generating = false; if ( !currlayer->algo->isEmpty() ) { // find new edges and copy current pattern to new universe, // except for any cells that were created in selection // (newalgo contains the original selection) bigint t, l, b, r; currlayer->algo->findedges(&t, &l, &b, &r); int itop = t.toint(); int ileft = l.toint(); int ibottom = b.toint(); int iright = r.toint(); int ht = ibottom - itop + 1; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = currlayer->algo->getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; int v = 0; bool abort = false; BeginProgress(_("Copying advanced pattern")); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { currcount++; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; // only copy cell if outside selection if ( cx < iselleft || cx > iselright || cy < iseltop || cy > iselbottom ) { newalgo->setcell(cx, cy, v); } currcount++; } else { cx = iright; // done this row } if (currcount > 1024) { accumcount += currcount; currcount = 0; abort = AbortProgress(accumcount / maxcount, wxEmptyString); if (abort) break; } } if (abort) break; } newalgo->endofpattern(); EndProgress(); if (abort && savecells) { // revert back to pattern saved in oldalgo delete newalgo; delete currlayer->algo; currlayer->algo = oldalgo; mainptr->SetGenIncrement(); mainptr->UpdateEverything(); return; } } // switch to new universe (best to do this even if aborted) delete currlayer->algo; currlayer->algo = newalgo; mainptr->SetGenIncrement(); if (savecells) { // compare patterns in oldalgo and currlayer->algo and call SaveCellChange // for each cell that has a different state; note that we need to compare // the union of the original pattern's rect and the new pattern's rect int otop = top.toint(); int oleft = left.toint(); int obottom = bottom.toint(); int oright = right.toint(); if (!currlayer->algo->isEmpty()) { currlayer->algo->findedges(&top, &left, &bottom, &right); int ntop = top.toint(); int nleft = left.toint(); int nbottom = bottom.toint(); int nright = right.toint(); if (ntop < otop) otop = ntop; if (nleft < oleft) oleft = nleft; if (nbottom > obottom) obottom = nbottom; if (nright > oright) oright = nright; } if ( SaveDifferences(oldalgo, currlayer->algo, otop, oleft, obottom, oright) ) { delete oldalgo; if ( !currlayer->undoredo->RememberCellChanges(_("Advance Outside"), currlayer->dirty) ) { // pattern outside selection didn't change mainptr->UpdateEverything(); return; } } else { // revert back to pattern saved in oldalgo currlayer->undoredo->ForgetCellChanges(); delete currlayer->algo; currlayer->algo = oldalgo; mainptr->SetGenIncrement(); mainptr->UpdateEverything(); return; } } MarkLayerDirty(); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void Selection::Modify(const bigint& xclick, const bigint& yclick, bigint& anchorx, bigint& anchory, bool* forceh, bool* forcev) { // note that we include "=" in following tests to get sensible // results when modifying small selections (ht or wd <= 3) if ( yclick <= seltop && xclick <= selleft ) { // click is in or outside top left corner seltop = yclick; selleft = xclick; anchory = selbottom; anchorx = selright; } else if ( yclick <= seltop && xclick >= selright ) { // click is in or outside top right corner seltop = yclick; selright = xclick; anchory = selbottom; anchorx = selleft; } else if ( yclick >= selbottom && xclick >= selright ) { // click is in or outside bottom right corner selbottom = yclick; selright = xclick; anchory = seltop; anchorx = selleft; } else if ( yclick >= selbottom && xclick <= selleft ) { // click is in or outside bottom left corner selbottom = yclick; selleft = xclick; anchory = seltop; anchorx = selright; } else if (yclick <= seltop) { // click is in or above top edge *forcev = true; seltop = yclick; anchory = selbottom; } else if (yclick >= selbottom) { // click is in or below bottom edge *forcev = true; selbottom = yclick; anchory = seltop; } else if (xclick <= selleft) { // click is in or left of left edge *forceh = true; selleft = xclick; anchorx = selright; } else if (xclick >= selright) { // click is in or right of right edge *forceh = true; selright = xclick; anchorx = selleft; } else { // click is somewhere inside selection double wd = selright.todouble() - selleft.todouble() + 1.0; double ht = selbottom.todouble() - seltop.todouble() + 1.0; double onethirdx = selleft.todouble() + wd / 3.0; double twothirdx = selleft.todouble() + wd * 2.0 / 3.0; double onethirdy = seltop.todouble() + ht / 3.0; double twothirdy = seltop.todouble() + ht * 2.0 / 3.0; double midy = seltop.todouble() + ht / 2.0; double x = xclick.todouble(); double y = yclick.todouble(); if ( y < onethirdy && x < onethirdx ) { // click is near top left corner seltop = yclick; selleft = xclick; anchory = selbottom; anchorx = selright; } else if ( y < onethirdy && x > twothirdx ) { // click is near top right corner seltop = yclick; selright = xclick; anchory = selbottom; anchorx = selleft; } else if ( y > twothirdy && x > twothirdx ) { // click is near bottom right corner selbottom = yclick; selright = xclick; anchory = seltop; anchorx = selleft; } else if ( y > twothirdy && x < onethirdx ) { // click is near bottom left corner selbottom = yclick; selleft = xclick; anchory = seltop; anchorx = selright; } else if ( x < onethirdx ) { // click is near middle of left edge *forceh = true; selleft = xclick; anchorx = selright; } else if ( x > twothirdx ) { // click is near middle of right edge *forceh = true; selright = xclick; anchorx = selleft; } else if ( y < midy ) { // click is below middle section of top edge *forcev = true; seltop = yclick; anchory = selbottom; } else { // click is above middle section of bottom edge *forcev = true; selbottom = yclick; anchory = seltop; } } } // ----------------------------------------------------------------------------- void Selection::SetLeftRight(const bigint& x, const bigint& anchorx) { if (x <= anchorx) { selleft = x; selright = anchorx; } else { selleft = anchorx; selright = x; } exists = true; } // ----------------------------------------------------------------------------- void Selection::SetTopBottom(const bigint& y, const bigint& anchory) { if (y <= anchory) { seltop = y; selbottom = anchory; } else { seltop = anchory; selbottom = y; } exists = true; } // ----------------------------------------------------------------------------- void Selection::Fit() { bigint newx = selright; newx -= selleft; newx += bigint::one; newx.div2(); newx += selleft; bigint newy = selbottom; newy -= seltop; newy += bigint::one; newy.div2(); newy += seltop; int mag = MAX_MAG; while (true) { currlayer->view->setpositionmag(newx, newy, mag); if ( currlayer->view->contains(selleft, seltop) && currlayer->view->contains(selright, selbottom) ) break; mag--; } } // ----------------------------------------------------------------------------- void Selection::Shrink(bool fit) { if (!exists) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(fit ? ID_SHRINKFIT : ID_SHRINK); return; } // check if there is no pattern if (currlayer->algo->isEmpty()) { statusptr->ErrorMessage(empty_selection); if (fit) viewptr->FitSelection(); return; } // check if selection encloses entire pattern bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if (Contains(top, left, bottom, right)) { // shrink edges viewptr->SaveCurrentSelection(); seltop = top; selleft = left; selbottom = bottom; selright = right; viewptr->RememberNewSelection(_("Shrink Selection")); viewptr->DisplaySelectionSize(); if (fit) viewptr->FitSelection(); // calls UpdateEverything else mainptr->UpdatePatternAndStatus(); return; } // check if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { statusptr->ErrorMessage(empty_selection); if (fit) viewptr->FitSelection(); return; } // find intersection of selection and pattern to minimize work if (seltop > top) top = seltop; if (selleft > left) left = selleft; if (selbottom < bottom) bottom = selbottom; if (selright < right) right = selright; // check that selection is small enough to save if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(selection_too_big); if (fit) viewptr->FitSelection(); return; } if ( insideYield ) { // we've been called from checkevents() so we don't attempt to shrink a very // large selection because the progress dialog can't be cancelled, presumably // because normal event handling isn't available inside Yield() double wd = right.todouble() - left.todouble() + 1.0; double ht = bottom.todouble() - top.todouble() + 1.0; if ( wd * ht > 1.0e12 ) { statusptr->ErrorMessage(_("Selection is too big to shrink.")); if (fit) viewptr->FitSelection(); return; } } // the easy way to shrink selection is to create a new temporary universe, // copy selection into new universe and then call findedges; // if only 2 cell states then use qlife because its findedges call is faster lifealgo* tempalgo = CreateNewUniverse(currlayer->algo->NumCellStates() > 2 ? currlayer->algtype : QLIFE_ALGO); // make sure temporary universe has same # of cell states if (currlayer->algo->NumCellStates() > 2) if (tempalgo->setrule(currlayer->algo->getrule())) tempalgo->setrule(tempalgo->DefaultRule()); // copy live cells in selection to temporary universe if ( viewptr->CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, tempalgo, false, _("Copying selection")) ) { if ( tempalgo->isEmpty() ) { statusptr->ErrorMessage(empty_selection); } else { viewptr->SaveCurrentSelection(); tempalgo->findedges(&seltop, &selleft, &selbottom, &selright); viewptr->RememberNewSelection(_("Shrink Selection")); viewptr->DisplaySelectionSize(); if (!fit) mainptr->UpdatePatternAndStatus(); } } delete tempalgo; if (fit) viewptr->FitSelection(); } // ----------------------------------------------------------------------------- bool Selection::Visible(wxRect* visrect) { if (!exists) return false; pair lt = currlayer->view->screenPosOf(selleft, seltop, currlayer->algo); pair rb = currlayer->view->screenPosOf(selright, selbottom, currlayer->algo); if (lt.first > currlayer->view->getxmax() || rb.first < 0 || lt.second > currlayer->view->getymax() || rb.second < 0) { // no part of selection is visible return false; } // all or some of selection is visible in viewport; // only set visible rectangle if requested if (visrect) { // first we must clip coords to viewport if (lt.first < 0) lt.first = 0; if (lt.second < 0) lt.second = 0; if (rb.first > currlayer->view->getxmax()) rb.first = currlayer->view->getxmax(); if (rb.second > currlayer->view->getymax()) rb.second = currlayer->view->getymax(); if (currlayer->view->getmag() > 0) { // move rb to pixel at bottom right corner of cell rb.first += (1 << currlayer->view->getmag()) - 1; rb.second += (1 << currlayer->view->getmag()) - 1; if (currlayer->view->getmag() > 1) { // avoid covering gaps at scale 1:4 and above rb.first--; rb.second--; } // clip to viewport again if (rb.first > currlayer->view->getxmax()) rb.first = currlayer->view->getxmax(); if (rb.second > currlayer->view->getymax()) rb.second = currlayer->view->getymax(); } visrect->SetX(lt.first); visrect->SetY(lt.second); visrect->SetWidth(rb.first - lt.first + 1); visrect->SetHeight(rb.second - lt.second + 1); } return true; } // ----------------------------------------------------------------------------- void Selection::EmptyUniverse() { // save current step, scale, position and gen count int savebase = currlayer->currbase; int saveexpo = currlayer->currexpo; int savemag = currlayer->view->getmag(); bigint savex = currlayer->view->x; bigint savey = currlayer->view->y; bigint savegen = currlayer->algo->getGeneration(); // kill all live cells by replacing the current universe with a // new, empty universe which also uses the same rule mainptr->CreateUniverse(); // restore step, scale, position and gen count currlayer->currbase = savebase; mainptr->SetStepExponent(saveexpo); // SetStepExponent calls SetGenIncrement currlayer->view->setpositionmag(savex, savey, savemag); currlayer->algo->setGeneration(savegen); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void Selection::Clear() { if (!exists) return; // no need to do anything if there is no pattern if (currlayer->algo->isEmpty()) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_CLEAR); return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; if (savecells && inscript) SavePendingChanges(); bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( !savecells && Contains(top, left, bottom, right) ) { // selection encloses entire pattern so just create empty universe EmptyUniverse(); MarkLayerDirty(); return; } // no need to do anything if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { return; } // find intersection of selection and pattern to minimize work if (seltop > top) top = seltop; if (selleft > left) left = selleft; if (selbottom < bottom) bottom = selbottom; if (selright < right) right = selright; // can only use setcell in limited domain if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(selection_too_big); return; } // clear all live cells in selection int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; double maxcount = (double)wd * (double)ht; int cntr = 0; int v = 0; bool abort = false; bool selchanged = false; BeginProgress(_("Clearing selection")); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; curralgo->setcell(cx, cy, 0); selchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, v, 0); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, wxEmptyString); if (abort) break; } } if (abort) break; } if (selchanged) curralgo->endofpattern(); EndProgress(); if (selchanged) { if (savecells) currlayer->undoredo->RememberCellChanges(_("Clear"), currlayer->dirty); MarkLayerDirty(); mainptr->UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- bool Selection::SaveOutside(bigint& t, bigint& l, bigint& b, bigint& r) { if ( viewptr->OutsideLimits(t, l, b, r) ) { statusptr->ErrorMessage(pattern_too_big); return false; } int itop = t.toint(); int ileft = l.toint(); int ibottom = b.toint(); int iright = r.toint(); // save ALL cells if selection is completely outside pattern edges bool saveall = Outside(t, l, b, r); // integer selection edges must not be outside pattern edges int stop = itop; int sleft = ileft; int sbottom = ibottom; int sright = iright; if (!saveall) { if (seltop > t) stop = seltop.toint(); if (selleft > l) sleft = selleft.toint(); if (selbottom < b) sbottom = selbottom.toint(); if (selright < r) sright = selright.toint(); } int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; int v = 0; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; BeginProgress(_("Saving outside selection")); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; if (saveall || cx < sleft || cx > sright || cy < stop || cy > sbottom) { // cell is outside selection edges currlayer->undoredo->SaveCellChange(cx, cy, v, 0); } } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, wxEmptyString); if (abort) break; } } if (abort) break; } EndProgress(); if (abort) currlayer->undoredo->ForgetCellChanges(); return !abort; } // ----------------------------------------------------------------------------- void Selection::ClearOutside() { if (!exists) return; // no need to do anything if there is no pattern if (currlayer->algo->isEmpty()) return; // no need to do anything if selection encloses entire pattern bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if (Contains(top, left, bottom, right)) { return; } if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_OUTSIDE); return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; if (savecells && inscript) SavePendingChanges(); if (savecells) { // save live cells outside selection if ( !SaveOutside(top, left, bottom, right) ) { return; } } else { // create empty universe if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { EmptyUniverse(); MarkLayerDirty(); return; } } // find intersection of selection and pattern to minimize work if (seltop > top) top = seltop; if (selleft > left) left = selleft; if (selbottom < bottom) bottom = selbottom; if (selright < right) right = selright; // check that selection is small enough to save if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(selection_too_big); return; } // create a new universe of same type lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); if (newalgo->setrule(currlayer->algo->getrule())) newalgo->setrule(newalgo->DefaultRule()); // set same gen count newalgo->setGeneration( currlayer->algo->getGeneration() ); // copy live cells in selection to new universe if ( viewptr->CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, newalgo, false, _("Saving selection")) ) { // delete old universe and point currlayer->algo at new universe delete currlayer->algo; currlayer->algo = newalgo; mainptr->SetGenIncrement(); if (savecells) currlayer->undoredo->RememberCellChanges(_("Clear Outside"), currlayer->dirty); MarkLayerDirty(); mainptr->UpdatePatternAndStatus(); } else { // CopyRect was aborted, so don't change current universe delete newalgo; if (savecells) currlayer->undoredo->ForgetCellChanges(); } } // ----------------------------------------------------------------------------- void Selection::AddEOL(char* &chptr) { #ifdef __WXMSW__ // use DOS line ending (CR+LF) on Windows *chptr = '\r'; chptr += 1; *chptr = '\n'; chptr += 1; #else // use LF on Linux or Mac *chptr = '\n'; chptr += 1; #endif } // ----------------------------------------------------------------------------- const int WRLE_NONE = -3; const int WRLE_EOP = -2; const int WRLE_NEWLINE = -1; void Selection::AddRun(int state, // in: state of cell to write int multistate, // true if #cell states > 2 unsigned int &run, // in and out unsigned int &linelen, // ditto char* &chptr) // ditto { // output of RLE pattern data is channelled thru here to make it easier to // ensure all lines have <= maxrleline characters const unsigned int maxrleline = 70; unsigned int i, numlen; char numstr[32]; if ( run > 1 ) { sprintf(numstr, "%u", run); numlen = (unsigned int)strlen(numstr); } else { numlen = 0; // no run count shown if 1 } // keep linelen <= maxrleline if ( linelen + numlen + 1 + multistate > maxrleline ) { AddEOL(chptr); linelen = 0; } i = 0; while (i < numlen) { *chptr = numstr[i]; chptr += 1; i++; } if (multistate) { if (state <= 0) *chptr = ".$!"[-state]; else { if (state > 24) { int hi = (state - 25) / 24; *chptr = hi + 'p'; chptr += 1; linelen += 1; state -= (hi + 1) * 24; } *chptr = 'A' + state - 1; } } else *chptr = "!$bo"[state+2]; chptr += 1; linelen += numlen + 1; run = 0; // reset run count } // ----------------------------------------------------------------------------- void Selection::CopyToClipboard(bool cut) { // can only use getcell/setcell in limited domain if (TooBig()) { statusptr->ErrorMessage(selection_too_big); return; } int itop = seltop.toint(); int ileft = selleft.toint(); int ibottom = selbottom.toint(); int iright = selright.toint(); unsigned int wd = iright - ileft + 1; unsigned int ht = ibottom - itop + 1; // convert cells in selection to RLE data in textptr char* textptr; char* etextptr; int cursize = 4096; textptr = (char*)malloc(cursize); if (textptr == NULL) { statusptr->ErrorMessage(_("Not enough memory for clipboard data!")); return; } etextptr = textptr + cursize; // add RLE header line sprintf(textptr, "x = %u, y = %u, rule = %s", wd, ht, currlayer->algo->getrule()); char* chptr = textptr; chptr += strlen(textptr); AddEOL(chptr); // save start of data in case livecount is zero int datastart = chptr - textptr; // add RLE pattern data unsigned int livecount = 0; unsigned int linelen = 0; unsigned int brun = 0; unsigned int orun = 0; unsigned int dollrun = 0; int laststate; int cx, cy; int v = 0; // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; if (savecells && inscript) SavePendingChanges(); double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; if (cut) BeginProgress(_("Cutting selection")); else BeginProgress(_("Copying selection")); lifealgo* curralgo = currlayer->algo; int multistate = curralgo->NumCellStates() > 2; for ( cy=itop; cy<=ibottom; cy++ ) { laststate = WRLE_NONE; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip > 0) { // have exactly "skip" empty cells here if (laststate == 0) { brun += skip; } else { if (orun > 0) { // output current run of live cells AddRun(laststate, multistate, orun, linelen, chptr); } laststate = 0; brun = skip; } } if (skip >= 0) { // found next live cell cx += skip; livecount++; if (cut) { curralgo->setcell(cx, cy, 0); if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, v, 0); } if (laststate == v) { orun++; } else { if (dollrun > 0) // output current run of $ chars AddRun(WRLE_NEWLINE, multistate, dollrun, linelen, chptr); if (brun > 0) // output current run of dead cells AddRun(0, multistate, brun, linelen, chptr); if (orun > 0) // output current run of other live cells AddRun(laststate, multistate, orun, linelen, chptr); laststate = v; orun = 1; } } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, wxEmptyString); if (abort) break; } if (chptr + 60 >= etextptr) { // nearly out of space; try to increase allocation char* ntxtptr = (char*) realloc(textptr, 2*cursize); if (ntxtptr == 0) { statusptr->ErrorMessage(_("No more memory for clipboard data!")); // don't return here -- best to set abort flag and break so that // partially cut/copied portion gets saved to clipboard abort = true; break; } chptr = ntxtptr + (chptr - textptr); cursize *= 2; etextptr = ntxtptr + cursize; textptr = ntxtptr; } } if (abort) break; // end of current row if (laststate == 0) // forget dead cells at end of row brun = 0; else if (laststate >= 0) // output current run of live cells AddRun(laststate, multistate, orun, linelen, chptr); dollrun++; } if (livecount == 0) { // no live cells in selection so simplify RLE data to "!" chptr = textptr + datastart; *chptr = '!'; chptr++; } else { // terminate RLE data dollrun = 1; AddRun(WRLE_EOP, multistate, dollrun, linelen, chptr); if (cut) currlayer->algo->endofpattern(); } AddEOL(chptr); *chptr = 0; EndProgress(); if (cut && livecount > 0) { if (savecells) currlayer->undoredo->RememberCellChanges(_("Cut"), currlayer->dirty); // update currlayer->dirty AFTER RememberCellChanges MarkLayerDirty(); mainptr->UpdatePatternAndStatus(); } wxString text = wxString(textptr,wxConvLocal); mainptr->CopyTextToClipboard(text); free(textptr); } // ----------------------------------------------------------------------------- bool Selection::CanPaste(const bigint& wd, const bigint& ht, bigint& top, bigint& left) { bigint selht = selbottom; selht -= seltop; selht += 1; bigint selwd = selright; selwd -= selleft; selwd += 1; if ( ht > selht || wd > selwd ) return false; // set paste rectangle's top left cell coord top = seltop; left = selleft; return true; } // ----------------------------------------------------------------------------- void Selection::RandomFill() { if (!exists) return; // can only use getcell/setcell in limited domain if (TooBig()) { statusptr->ErrorMessage(selection_too_big); return; } if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_RANDOM); return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; if (savecells && inscript) SavePendingChanges(); // no need to kill cells if selection is empty bool killcells = !currlayer->algo->isEmpty(); if ( killcells ) { // find pattern edges and compare with selection edges bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if (Contains(top, left, bottom, right)) { // selection encloses entire pattern so create empty universe if (savecells) { // don't kill pattern otherwise we can't use SaveCellChange below } else { EmptyUniverse(); killcells = false; } } else if (Outside(top, left, bottom, right)) { // selection is completely outside pattern edges killcells = false; } } int itop = seltop.toint(); int ileft = selleft.toint(); int ibottom = selbottom.toint(); int iright = selright.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; BeginProgress(_("Randomly filling selection")); int cx, cy; lifealgo* curralgo = currlayer->algo; int livestates = curralgo->NumCellStates() - 1; // don't count dead state for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { // randomfill is from 1..100 if (savecells) { // remember cell change only if state changes int oldstate = curralgo->getcell(cx, cy); if ((rand() % 100) < randomfill) { int newstate = livestates < 2 ? 1 : 1 + (rand() % livestates); if (oldstate != newstate) { curralgo->setcell(cx, cy, newstate); currlayer->undoredo->SaveCellChange(cx, cy, oldstate, newstate); } } else if (killcells && oldstate > 0) { curralgo->setcell(cx, cy, 0); currlayer->undoredo->SaveCellChange(cx, cy, oldstate, 0); } } else { if ((rand() % 100) < randomfill) { if (livestates < 2) { curralgo->setcell(cx, cy, 1); } else { curralgo->setcell(cx, cy, 1 + (rand() % livestates)); } } else if (killcells) { curralgo->setcell(cx, cy, 0); } } cntr++; if ((cntr % 4096) == 0) { abort = AbortProgress((double)cntr / maxcount, wxEmptyString); if (abort) break; } } if (abort) break; } currlayer->algo->endofpattern(); EndProgress(); if (savecells) currlayer->undoredo->RememberCellChanges(_("Random Fill"), currlayer->dirty); // update currlayer->dirty AFTER RememberCellChanges MarkLayerDirty(); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- bool Selection::FlipRect(bool topbottom, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, int itop, int ileft, int ibottom, int iright) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; int v = 0; int cx, cy, newx, newy, newxinc, newyinc; if (topbottom) { BeginProgress(_("Flipping top-bottom")); newy = ibottom; newyinc = -1; newxinc = 1; } else { BeginProgress(_("Flipping left-right")); newy = itop; newyinc = 1; newxinc = -1; } for ( cy=itop; cy<=ibottom; cy++ ) { newx = topbottom ? ileft : iright; for ( cx=ileft; cx<=iright; cx++ ) { int skip = srcalgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; if (erasesrc) srcalgo->setcell(cx, cy, 0); newx += newxinc * skip; destalgo->setcell(newx, newy, v); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, wxEmptyString); if (abort) break; } newx += newxinc; } if (abort) break; newy += newyinc; } if (erasesrc) srcalgo->endofpattern(); destalgo->endofpattern(); EndProgress(); return !abort; } // ----------------------------------------------------------------------------- bool Selection::Flip(bool topbottom, bool inundoredo) { if (!exists) return false; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(topbottom ? ID_FLIPTB : ID_FLIPLR); return true; } if (topbottom) { if (seltop == selbottom) return true; } else { if (selleft == selright) return true; } if (currlayer->algo->isEmpty()) return true; bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); bigint stop = seltop; bigint sleft = selleft; bigint sbottom = selbottom; bigint sright = selright; bool simpleflip; if (Contains(top, left, bottom, right)) { // selection encloses entire pattern so we may only need to flip a smaller rectangle if (topbottom) { bigint tdiff = top; tdiff -= stop; bigint bdiff = sbottom; bdiff -= bottom; bigint mindiff = tdiff; if (bdiff < mindiff) mindiff = bdiff; stop += mindiff; sbottom -= mindiff; sleft = left; sright = right; } else { bigint ldiff = left; ldiff -= sleft; bigint rdiff = sright; rdiff -= right; bigint mindiff = ldiff; if (rdiff < mindiff) mindiff = rdiff; sleft += mindiff; sright -= mindiff; stop = top; sbottom = bottom; } simpleflip = true; } else { // selection encloses part of pattern so we can clip some selection edges // if they are outside the pattern edges if (topbottom) { if (sleft < left) sleft = left; if (sright > right) sright = right; } else { if (stop < top) stop = top; if (sbottom > bottom) sbottom = bottom; } simpleflip = false; } // can only use getcell/setcell in limited domain if ( viewptr->OutsideLimits(stop, sbottom, sleft, sright) ) { statusptr->ErrorMessage(selection_too_big); return false; } int itop = stop.toint(); int ileft = sleft.toint(); int ibottom = sbottom.toint(); int iright = sright.toint(); if (simpleflip) { // selection encloses all of pattern so we can flip into new universe // (must be same type) without killing live cells in selection lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); if (newalgo->setrule(currlayer->algo->getrule())) newalgo->setrule(newalgo->DefaultRule()); newalgo->setGeneration( currlayer->algo->getGeneration() ); if ( FlipRect(topbottom, currlayer->algo, newalgo, false, itop, ileft, ibottom, iright) ) { // switch to newalgo delete currlayer->algo; currlayer->algo = newalgo; mainptr->SetGenIncrement(); } else { // user aborted flip delete newalgo; return false; } } else { // flip into temporary universe and kill all live cells in selection; // if only 2 cell states then use qlife because its setcell/getcell calls are faster lifealgo* tempalgo = CreateNewUniverse(currlayer->algo->NumCellStates() > 2 ? currlayer->algtype : QLIFE_ALGO); // make sure temporary universe has same # of cell states if (currlayer->algo->NumCellStates() > 2) if (tempalgo->setrule(currlayer->algo->getrule())) tempalgo->setrule(tempalgo->DefaultRule()); if ( FlipRect(topbottom, currlayer->algo, tempalgo, true, itop, ileft, ibottom, iright) ) { // find pattern edges in temporary universe (could be much smaller) // and copy temporary pattern into current universe tempalgo->findedges(&top, &left, &bottom, &right); viewptr->CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), tempalgo, currlayer->algo, false, _("Adding flipped selection")); delete tempalgo; } else { // user aborted flip so flip tempalgo pattern back into current universe FlipRect(topbottom, tempalgo, currlayer->algo, false, itop, ileft, ibottom, iright); delete tempalgo; return false; } } // flips are always reversible so no need to use SaveCellChange and RememberCellChanges if (allowundo && !currlayer->stayclean && !inundoredo) { if (inscript) SavePendingChanges(); currlayer->undoredo->RememberFlip(topbottom, currlayer->dirty); } // update currlayer->dirty AFTER RememberFlip if (!inundoredo) MarkLayerDirty(); mainptr->UpdatePatternAndStatus(); return true; } // ----------------------------------------------------------------------------- const wxString rotate_clockwise = _("Rotating selection +90 degrees"); const wxString rotate_anticlockwise = _("Rotating selection -90 degrees"); bool Selection::RotateRect(bool clockwise, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, int itop, int ileft, int ibottom, int iright, int ntop, int nleft, int nbottom, int nright) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; int cx, cy, newx, newy, newxinc, newyinc, v=0; if (clockwise) { BeginProgress(rotate_clockwise); newx = nright; newyinc = 1; newxinc = -1; } else { BeginProgress(rotate_anticlockwise); newx = nleft; newyinc = -1; newxinc = 1; } for ( cy=itop; cy<=ibottom; cy++ ) { newy = clockwise ? ntop : nbottom; for ( cx=ileft; cx<=iright; cx++ ) { int skip = srcalgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; if (erasesrc) srcalgo->setcell(cx, cy, 0); newy += newyinc * skip; destalgo->setcell(newx, newy, v); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, wxEmptyString); if (abort) break; } newy += newyinc; } if (abort) break; newx += newxinc; } if (erasesrc) srcalgo->endofpattern(); destalgo->endofpattern(); EndProgress(); return !abort; } // ----------------------------------------------------------------------------- bool Selection::RotatePattern(bool clockwise, bigint& newtop, bigint& newbottom, bigint& newleft, bigint& newright, bool inundoredo) { // create new universe of same type as current universe lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); if (newalgo->setrule(currlayer->algo->getrule())) newalgo->setrule(newalgo->DefaultRule()); // set same gen count newalgo->setGeneration( currlayer->algo->getGeneration() ); // copy all live cells to new universe, rotating the coords by +/- 90 degrees int itop = seltop.toint(); int ileft = selleft.toint(); int ibottom = selbottom.toint(); int iright = selright.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; int cx, cy, newx, newy, newxinc, newyinc, firstnewy, v=0; if (clockwise) { BeginProgress(rotate_clockwise); firstnewy = newtop.toint(); newx = newright.toint(); newyinc = 1; newxinc = -1; } else { BeginProgress(rotate_anticlockwise); firstnewy = newbottom.toint(); newx = newleft.toint(); newyinc = -1; newxinc = 1; } lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { newy = firstnewy; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; newy += newyinc * skip; newalgo->setcell(newx, newy, v); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, wxEmptyString); if (abort) break; } newy += newyinc; } if (abort) break; newx += newxinc; } newalgo->endofpattern(); EndProgress(); if (abort) { delete newalgo; } else { // rotate the selection edges seltop = newtop; selbottom = newbottom; selleft = newleft; selright = newright; // switch to new universe and display results delete currlayer->algo; currlayer->algo = newalgo; mainptr->SetGenIncrement(); viewptr->DisplaySelectionSize(); // rotating entire pattern is easily reversible so no need to use // SaveCellChange and RememberCellChanges in this case if (allowundo && !currlayer->stayclean && !inundoredo) { if (inscript) SavePendingChanges(); currlayer->undoredo->RememberRotation(clockwise, currlayer->dirty); } // update currlayer->dirty AFTER RememberRotation if (!inundoredo) MarkLayerDirty(); mainptr->UpdatePatternAndStatus(); } return !abort; } // ----------------------------------------------------------------------------- bool Selection::Rotate(bool clockwise, bool inundoredo) { if (!exists) return false; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(clockwise ? ID_ROTATEC : ID_ROTATEA); return true; } // determine rotated selection edges bigint halfht = selbottom; halfht -= seltop; halfht.div2(); bigint halfwd = selright; halfwd -= selleft; halfwd.div2(); bigint midy = seltop; midy += halfht; bigint midx = selleft; midx += halfwd; bigint newtop = midy; newtop += selleft; newtop -= midx; bigint newbottom = midy; newbottom += selright; newbottom -= midx; bigint newleft = midx; newleft += seltop; newleft -= midy; bigint newright = midx; newright += selbottom; newright -= midy; if (!inundoredo) { // check if rotated selection edges are outside bounded grid if ( (currlayer->algo->gridwd > 0 && (newleft < currlayer->algo->gridleft || newright > currlayer->algo->gridright)) || (currlayer->algo->gridht > 0 && (newtop < currlayer->algo->gridtop || newbottom > currlayer->algo->gridbottom)) ) { statusptr->ErrorMessage(_("New selection would be outside grid boundary.")); return false; } } // if there is no pattern then just rotate the selection edges if (currlayer->algo->isEmpty()) { viewptr->SaveCurrentSelection(); seltop = newtop; selbottom = newbottom; selleft = newleft; selright = newright; viewptr->RememberNewSelection(_("Rotation")); viewptr->DisplaySelectionSize(); mainptr->UpdatePatternAndStatus(); return true; } // if the current selection and the rotated selection are both outside the // pattern edges (ie. both are empty) then just rotate the selection edges bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( (seltop > bottom || selbottom < top || selleft > right || selright < left) && (newtop > bottom || newbottom < top || newleft > right || newright < left) ) { viewptr->SaveCurrentSelection(); seltop = newtop; selbottom = newbottom; selleft = newleft; selright = newright; viewptr->RememberNewSelection(_("Rotation")); viewptr->DisplaySelectionSize(); mainptr->UpdatePatternAndStatus(); return true; } // can only use nextcell/getcell/setcell in limited domain if (TooBig()) { statusptr->ErrorMessage(selection_too_big); return false; } // make sure rotated selection edges are also within limits if ( viewptr->OutsideLimits(newtop, newbottom, newleft, newright) ) { statusptr->ErrorMessage(_("New selection would be outside +/- 10^9 boundary.")); return false; } // use faster method if selection encloses entire pattern if (Contains(top, left, bottom, right)) { return RotatePattern(clockwise, newtop, newbottom, newleft, newright, inundoredo); } int itop = seltop.toint(); int ileft = selleft.toint(); int ibottom = selbottom.toint(); int iright = selright.toint(); int ntop = newtop.toint(); int nleft = newleft.toint(); int nbottom = newbottom.toint(); int nright = newright.toint(); // save cell changes if undo/redo is enabled and script isn't constructing a pattern // and we're not undoing/redoing an earlier rotation bool savecells = allowundo && !currlayer->stayclean && !inundoredo; if (savecells && inscript) SavePendingChanges(); lifealgo* oldalgo = NULL; int otop = itop; int oleft = ileft; int obottom = ibottom; int oright = iright; if (savecells) { // copy current pattern to oldalgo using union of old and new selection rects if (otop > ntop) otop = ntop; if (oleft > nleft) oleft = nleft; if (obottom < nbottom) obottom = nbottom; if (oright < nright) oright = nright; oldalgo = CreateNewUniverse(currlayer->algo->NumCellStates() > 2 ? currlayer->algtype : QLIFE_ALGO); // make sure universe has same # of cell states if (currlayer->algo->NumCellStates() > 2) if (oldalgo->setrule(currlayer->algo->getrule())) oldalgo->setrule(oldalgo->DefaultRule()); if ( !viewptr->CopyRect(otop, oleft, obottom, oright, currlayer->algo, oldalgo, false, _("Saving part of pattern")) ) { delete oldalgo; return false; } } // create temporary universe; doesn't need to match current universe so // if only 2 cell states then use qlife because its setcell/getcell calls are faster lifealgo* tempalgo = CreateNewUniverse(currlayer->algo->NumCellStates() > 2 ? currlayer->algtype : QLIFE_ALGO); // make sure temporary universe has same # of cell states if (currlayer->algo->NumCellStates() > 2) if (tempalgo->setrule(currlayer->algo->getrule())) tempalgo->setrule(tempalgo->DefaultRule()); // copy (and kill) live cells in selection to temporary universe, // rotating the new coords by +/- 90 degrees if ( !RotateRect(clockwise, currlayer->algo, tempalgo, true, itop, ileft, ibottom, iright, ntop, nleft, nbottom, nright) ) { // user aborted rotation if (savecells) { // use oldalgo to restore erased selection viewptr->CopyRect(itop, ileft, ibottom, iright, oldalgo, currlayer->algo, false, _("Restoring selection")); delete oldalgo; } else { // restore erased selection by rotating tempalgo in opposite direction // back into the current universe RotateRect(!clockwise, tempalgo, currlayer->algo, false, ntop, nleft, nbottom, nright, itop, ileft, ibottom, iright); } delete tempalgo; mainptr->UpdatePatternAndStatus(); return false; } // copy rotated selection from temporary universe to current universe; // check if new selection rect is outside modified pattern edges currlayer->algo->findedges(&top, &left, &bottom, &right); if ( newtop > bottom || newbottom < top || newleft > right || newright < left ) { // safe to use fast nextcell calls viewptr->CopyRect(ntop, nleft, nbottom, nright, tempalgo, currlayer->algo, false, _("Adding rotated selection")); } else { // have to use slow getcell calls viewptr->CopyAllRect(ntop, nleft, nbottom, nright, tempalgo, currlayer->algo, _("Pasting rotated selection")); } // don't need temporary universe any more delete tempalgo; // rotate the selection edges seltop = newtop; selbottom = newbottom; selleft = newleft; selright = newright; if (savecells) { // compare patterns in oldalgo and currlayer->algo and call SaveCellChange // for each cell that has a different state if ( SaveDifferences(oldalgo, currlayer->algo, otop, oleft, obottom, oright) ) { Selection oldsel(itop, ileft, ibottom, iright); Selection newsel(ntop, nleft, nbottom, nright); currlayer->undoredo->RememberRotation(clockwise, oldsel, newsel, currlayer->dirty); } else { currlayer->undoredo->ForgetCellChanges(); Warning(_("You can't undo this change!")); } delete oldalgo; } // display results viewptr->DisplaySelectionSize(); if (!inundoredo) MarkLayerDirty(); mainptr->UpdatePatternAndStatus(); return true; } golly-2.7-src/gui-wx/wxmain.h0000755000175000017500000002656112536111364013131 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXMAIN_H_ #define _WXMAIN_H_ #include "wx/splitter.h" // for wxSplitterWindow, wxSplitterEvent #include "wx/dirctrl.h" // for wxGenericDirCtrl #include "wx/treectrl.h" // for wxTreeCtrl, wxTreeEvent #include "wx/dataobj.h" // for wxTextDataObject #include "bigint.h" // for bigint #include "lifealgo.h" // for lifealgo #include "writepattern.h" // for pattern_format #include "wxprefs.h" // for MAX_RECENT #include "wxalgos.h" // for MAX_ALGOS, algo_type #include "wxlayer.h" // for MAX_LAYERS // Golly's main window: class MainFrame : public wxFrame { public: MainFrame(); ~MainFrame(); // update functions void UpdateEverything(); void UpdateUserInterface(); void UpdateToolBar(); void EnableAllMenus(bool enable); void UpdateMenuItems(); void UpdatePatternAndStatus(); void UpdateStatus(); void UpdateMenuAccelerators(); // clipboard functions bool ClipboardHasText(); bool CopyTextToClipboard(const wxString& text); bool GetTextFromClipboard(wxTextDataObject* data); bool ClipboardContainsRule(); void OpenClipboard(); void RunClipboard(); // file functions void OpenFile(const wxString& path, bool remember = true); void LoadPattern(const wxString& path, const wxString& newtitle, bool updatestatus = true, bool updateall = true); void NewPattern(const wxString& title = _("untitled")); void CreateUniverse(); void SetWindowTitle(const wxString& filename); void OpenPattern(); void OpenScript(); void ToggleShowPatterns(); void ToggleShowScripts(); void ChangePatternDir(); void ChangeScriptDir(); void SetPatternDir(const wxString& newdir); void SetScriptDir(const wxString& newdir); bool SavePattern(); bool SaveCurrentLayer(); const char* SaveFile(const wxString& path, const wxString& format, bool remember); const char* WritePattern(const wxString& path, pattern_format format, output_compression compression, int top, int left, int bottom, int right); void CheckBeforeRunning(const wxString& scriptpath, bool remember, const wxString& zippath); bool ExtractZipEntry(const wxString& zippath, const wxString& entryname, const wxString& outfile); #if wxUSE_DRAG_AND_DROP wxDropTarget* NewDropTarget(); #endif // edit functions void ToggleAllowUndo(); void RestorePattern(bigint& gen, const wxString& filename, bigint& x, bigint& y, int mag, int base, int expo); // prefs functions void SetRandomFillPercentage(); void SetMinimumStepExponent(); void UpdateStepExponent(); void ShowPrefsDialog(const wxString& page = wxEmptyString); // control functions void GeneratePattern(); void GoFaster(); void GoSlower(); void Stop(); void DisplayTimingInfo(); void NextGeneration(bool useinc); void ToggleAutoFit(); void ToggleHyperspeed(); void ToggleHashInfo(); void SetStepExponent(int newexpo); void SetGenIncrement(); bool SaveStartingPattern(); void ResetPattern(bool resetundo = true); void SetGeneration(); const char* ChangeGenCount(const char* genstring, bool inundoredo = false); void SetBaseStep(); void ClearOutsideGrid(); void ReduceCellStates(int newmaxstate); void ShowRuleDialog(); void ConvertOldRules(); wxString CreateRuleFiles(const wxSortedArrayString& deprecated, const wxSortedArrayString& ziprules); void ChangeAlgorithm(algo_type newalgotype, const wxString& newrule = wxEmptyString, bool inundoredo = false); bool CreateBorderCells(lifealgo* curralgo); bool DeleteBorderCells(lifealgo* curralgo); void ClearRect(lifealgo* curralgo, int top, int left, int bottom, int right); // view functions void ToggleStatusBar(); void ToggleExactNumbers(); void ToggleToolBar(); void ToggleFullScreen(); void ShowPatternInfo(); void ResizeSplitWindow(int wd, int ht); void ResizeStatusBar(int wd, int ht); wxWindow* RightPane(); // layer functions void UpdateLayerItem(int index); void AppendLayerItem(); void RemoveLayerItem(); // miscellaneous functions void OnTreeClick(wxMouseEvent& event); void EditFile(const wxString& filepath); void QuitApp(); bool generating; // currently generating pattern? bool fullscreen; // in full screen mode? bool showbanner; // showing banner message? bool keepmessage; // don't clear message created by script? bool command_pending; // user selected a command while generating? bool draw_pending; // user wants to draw while generating? wxCommandEvent cmdevent; // the pending command wxMouseEvent mouseevent; // the pending draw // temporary files wxString clipfile; // name of temporary file for storing clipboard data wxString perlfile; // name of temporary Perl script wxString pythonfile; // name of temporary Python script // store files passed via command line (processed in first OnIdle) wxArrayString pendingfiles; bool infront; // main window is active? private: // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() // event handlers void OnMenu(wxCommandEvent& event); void OnSetFocus(wxFocusEvent& event); void OnActivate(wxActivateEvent& event); void OnSize(wxSizeEvent& event); void OnIdle(wxIdleEvent& event); void OnDirTreeSelection(wxTreeEvent& event); void OnSashDblClick(wxSplitterEvent& event); void OnOneTimer(wxTimerEvent& event); void OnClose(wxCloseEvent& event); // file functions bool LoadImage(const wxString& path); void MySetTitle(const wxString& title); wxString GetBaseName(const wxString& path); void SaveSucceeded(const wxString& path); void AddRecentPattern(const wxString& path); void OpenRecentPattern(int id); void ClearMissingPatterns(); void ClearAllPatterns(); void AddRecentScript(const wxString& path); void OpenRecentScript(int id); void ClearMissingScripts(); void ClearAllScripts(); wxString GetScriptFileName(const wxString& text); void OpenZipFile(const wxString& path); // control functions void DisplayPattern(); bool StepPattern(); // miscellaneous functions void CreateMenus(); void CreateToolbar(); void CreateDirControls(); void SimplifyTree(wxString& dir, wxTreeCtrl* treectrl, wxTreeItemId root); void DoPendingAction(bool restart); // splittable window contains pattern/script directory in left pane // and layer bar plus viewport window in right pane wxSplitterWindow* splitwin; wxGenericDirCtrl* patternctrl; wxGenericDirCtrl* scriptctrl; int minexpo; // currexpo at maximum delay (must be <= 0) long whentosee; // when to do next gen (if currexpo < 0) long begintime, endtime; // for timing info double begingen, endgen; // ditto }; // ids for menu commands enum { // File menu // wxID_NEW, // wxID_OPEN, ID_OPEN_CLIP = wxID_HIGHEST + 1, ID_OPEN_RECENT, // last 2 items in Open Recent submenu ID_CLEAR_MISSING_PATTERNS = ID_OPEN_RECENT + MAX_RECENT + 1, ID_CLEAR_ALL_PATTERNS, ID_SHOW_PATTERNS, ID_PATTERN_DIR, // wxID_SAVE, ID_SAVE_XRLE, ID_RUN_SCRIPT, ID_RUN_CLIP, ID_RUN_RECENT, // last 2 items in Run Recent submenu ID_CLEAR_MISSING_SCRIPTS = ID_RUN_RECENT + MAX_RECENT + 1, ID_CLEAR_ALL_SCRIPTS, ID_SHOW_SCRIPTS, ID_SCRIPT_DIR, // wxID_PREFERENCES, // wxID_EXIT, // Edit menu // due to wxMac bugs we don't use wxID_UNDO/REDO/CUT/COPY/CLEAR/PASTE/SELECTALL // (problems occur when info window or a modal dialog is active, and we can't // change the Undo/Redo menu labels) ID_UNDO, ID_REDO, ID_CUT, ID_COPY, ID_NO_UNDO, ID_CLEAR, ID_OUTSIDE, ID_PASTE, ID_PMODE, ID_PLOCATION, ID_PASTE_SEL, ID_SELECTALL, ID_REMOVE, ID_SHRINK, ID_SHRINKFIT, // there's currently no menu item for "Shrink and Fit" ID_RANDOM, ID_FLIPTB, ID_FLIPLR, ID_ROTATEC, ID_ROTATEA, ID_CMODE, // Paste Location submenu ID_PL_TL, ID_PL_TR, ID_PL_BR, ID_PL_BL, ID_PL_MID, // Paste Mode submenu ID_PM_AND, ID_PM_COPY, ID_PM_OR, ID_PM_XOR, // Cursor Mode submenu ID_DRAW, ID_PICK, ID_SELECT, ID_MOVE, ID_ZOOMIN, ID_ZOOMOUT, // Control menu ID_START, ID_NEXT, ID_STEP, ID_RESET, ID_SETGEN, ID_FASTER, ID_SLOWER, ID_SETBASE, ID_AUTO, ID_HYPER, ID_HINFO, ID_RECORD, ID_DELTIME, ID_SETALGO, ID_SETRULE, ID_CONVERT, // Set Algorithm submenu ID_ALGO0, ID_ALGOMAX = ID_ALGO0 + MAX_ALGOS - 1, // View menu ID_FULL, ID_FIT, ID_FIT_SEL, ID_MIDDLE, ID_RESTORE00, // wxID_ZOOM_IN, // wxID_ZOOM_OUT, ID_SET_SCALE, ID_TOOL_BAR, ID_LAYER_BAR, ID_EDIT_BAR, ID_ALL_STATES, ID_STATUS_BAR, ID_EXACT, ID_GRID, ID_ICONS, ID_INVERT, ID_BUFF, ID_TIMELINE, ID_INFO, // Set Scale submenu ID_SCALE_1, ID_SCALE_2, ID_SCALE_4, ID_SCALE_8, ID_SCALE_16, ID_SCALE_32, // Layer menu ID_ADD_LAYER, ID_CLONE, ID_DUPLICATE, ID_DEL_LAYER, ID_DEL_OTHERS, ID_MOVE_LAYER, ID_NAME_LAYER, ID_SET_COLORS, ID_SYNC_VIEW, ID_SYNC_CURS, ID_STACK, ID_TILE, ID_LAYER0, ID_LAYERMAX = ID_LAYER0 + MAX_LAYERS - 1, // Help menu ID_HELP_INDEX, ID_HELP_INTRO, ID_HELP_TIPS, ID_HELP_ALGOS, ID_HELP_KEYBOARD, ID_HELP_MOUSE, ID_HELP_PERL, ID_HELP_PYTHON, ID_HELP_LEXICON, ID_HELP_ARCHIVES, ID_HELP_FILE, ID_HELP_EDIT, ID_HELP_CONTROL, ID_HELP_VIEW, ID_HELP_LAYER, ID_HELP_HELP, ID_HELP_REFS, ID_HELP_FORMATS, ID_HELP_BOUNDED, ID_HELP_PROBLEMS, ID_HELP_CHANGES, ID_HELP_CREDITS, // these ids aren't associated with any menu item ID_LOAD_LEXICON, // load lexicon pattern ID_HELP_BUTT // help button in tool bar }; #endif golly-2.7-src/gui-wx/wxfile.cpp0000644000175000017500000021337612536111364013456 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/file.h" // for wxFile #include "wx/filename.h" // for wxFileName #include "wx/menuitem.h" // for SetText #include "wx/clipbrd.h" // for wxTheClipboard #include "wx/dataobj.h" // for wxTextDataObject #include "wx/zipstrm.h" // for wxZipEntry, wxZipInputStream #include "wx/wfstream.h" // for wxFFileInputStream #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "readpattern.h" // for readpattern #include "writepattern.h" // for writepattern, pattern_format #include "wxgolly.h" // for wxGetApp, statusptr, viewptr, bigview #include "wxutils.h" // for Warning #include "wxprefs.h" // for SavePrefs, allowundo, userrules, etc #include "wxrule.h" // for GetRuleName #include "wxinfo.h" // for GetInfoFrame #include "wxstatus.h" // for statusptr->... #include "wxview.h" // for viewptr->... #include "wxrender.h" // for SetSelectionColor #include "wxscript.h" // for RunScript, inscript #include "wxmain.h" // for MainFrame, etc #include "wxundo.h" // for currlayer->undoredo->... #include "wxalgos.h" // for CreateNewUniverse, algo_type, algoinfo, etc #include "wxlayer.h" // for currlayer, etc #include "wxhelp.h" // for ShowHelp, LoadRule #include "wxtimeline.h" // for InitTimelineFrame, ToggleTimelineBar, etc #if defined(__WXMAC__) && !defined(__WXOSX_COCOA__) #include // for OpaqueWindowPtr, etc #include "wx/mac/corefoundation/cfstring.h" // for wxMacCFStringHolder #endif #ifdef __WXMAC__ // convert path to decomposed UTF8 so fopen will work #define FILEPATH path.fn_str() #else #define FILEPATH path.mb_str(wxConvLocal) #endif #if wxCHECK_VERSION(2,9,0) // some wxMenuItem method names have changed in wx 2.9 #define GetText GetItemLabel #define SetText SetItemLabel #endif // File menu functions: // ----------------------------------------------------------------------------- wxString MainFrame::GetBaseName(const wxString& path) { // extract basename from given path return path.AfterLast(wxFILE_SEP_PATH); } // ----------------------------------------------------------------------------- void MainFrame::MySetTitle(const wxString& title) { // fix if SetTitle still causes window refresh in Cocoa version!!! #if defined(__WXMAC__) && !defined(__WXOSX_COCOA__) // avoid wxMac's SetTitle call -- it causes an undesirable window refresh SetWindowTitleWithCFString((OpaqueWindowPtr*)this->MacGetWindowRef(), wxMacCFStringHolder(title, wxFONTENCODING_DEFAULT)); #else SetTitle(title); #endif } // ----------------------------------------------------------------------------- void MainFrame::SetWindowTitle(const wxString& filename) { if ( !filename.IsEmpty() ) { // remember current file name currlayer->currname = filename; // show currname in current layer's menu item UpdateLayerItem(currindex); } if (inscript) { // avoid window title flashing; eg. script might be switching layers ShowTitleLater(); return; } wxString prefix = wxEmptyString; // display asterisk if pattern has been modified if (currlayer->dirty) prefix += wxT("*"); int cid = currlayer->cloneid; while (cid > 0) { // display one or more "=" chars to indicate this is a cloned layer prefix += wxT("="); cid--; } wxString rule = GetRuleName( wxString(currlayer->algo->getrule(),wxConvLocal) ); wxString wtitle; #ifdef __WXMAC__ wtitle.Printf(_("%s%s [%s]"), prefix.c_str(), currlayer->currname.c_str(), rule.c_str()); #else wtitle.Printf(_("%s%s [%s] - Golly"), prefix.c_str(), currlayer->currname.c_str(), rule.c_str()); #endif // nicer to truncate a really long title??? MySetTitle(wtitle); } // ----------------------------------------------------------------------------- void MainFrame::SetGenIncrement() { if (currlayer->currexpo > 0) { bigint inc = 1; // set increment to currbase^currexpo int i = currlayer->currexpo; while (i > 0) { inc.mul_smallint(currlayer->currbase); i--; } currlayer->algo->setIncrement(inc); } else { currlayer->algo->setIncrement(1); } } // ----------------------------------------------------------------------------- void MainFrame::CreateUniverse() { // save current rule wxString oldrule = wxString(currlayer->algo->getrule(), wxConvLocal); // delete old universe and create new one of same type delete currlayer->algo; currlayer->algo = CreateNewUniverse(currlayer->algtype); // ensure new universe uses same rule (and thus same # of cell states) RestoreRule(oldrule); // increment has been reset to 1 but that's probably not always desirable // so set increment using current step size SetGenIncrement(); } // ----------------------------------------------------------------------------- void MainFrame::NewPattern(const wxString& title) { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(wxID_NEW); return; } if (askonnew && currlayer->dirty && !SaveCurrentLayer()) return; if (inscript) stop_after_script = true; currlayer->savestart = false; currlayer->currfile.Clear(); currlayer->startgen = 0; // reset step size before CreateUniverse calls SetGenIncrement currlayer->currbase = algoinfo[currlayer->algtype]->defbase; currlayer->currexpo = 0; // create new, empty universe of same type and using same rule CreateUniverse(); // reset timing info used in DisplayTimingInfo endtime = begintime = 0; // clear all undo/redo history currlayer->undoredo->ClearUndoRedo(); if (newremovesel) currlayer->currsel.Deselect(); if (newcurs) currlayer->curs = newcurs; viewptr->SetPosMag(bigint::zero, bigint::zero, newmag); // best to restore true origin if (currlayer->originx != bigint::zero || currlayer->originy != bigint::zero) { currlayer->originx = 0; currlayer->originy = 0; statusptr->SetMessage(origin_restored); } // restore default colors for current algo/rule UpdateLayerColors(); MarkLayerClean(title); // calls SetWindowTitle UpdateEverything(); } // ----------------------------------------------------------------------------- static bool IsImageFile(const wxString& path) { wxString ext = path.AfterLast('.'); // if path has no extension then ext == path if (ext == path) return false; // supported extensions match image handlers added in GollyApp::OnInit() return ext.IsSameAs(wxT("bmp"),false) || ext.IsSameAs(wxT("gif"),false) || ext.IsSameAs(wxT("png"),false) || ext.IsSameAs(wxT("tif"),false) || ext.IsSameAs(wxT("tiff"),false) || ext.IsSameAs(wxT("icons"),false) || // we don't actually support JPEG files but let LoadImage handle them ext.IsSameAs(wxT("jpg"),false) || ext.IsSameAs(wxT("jpeg"),false); } // ----------------------------------------------------------------------------- bool MainFrame::LoadImage(const wxString& path) { // don't try to load JPEG file wxString ext = path.AfterLast('.'); if ( ext.IsSameAs(wxT("jpg"),false) || ext.IsSameAs(wxT("jpeg"),false) ) { Warning(_("Golly cannot import JPEG data, only BMP/GIF/PNG/TIFF.")); // pattern will be empty return true; } wxImage image; if ( image.LoadFile(path) ) { // don't change the current rule here -- that way the image can // be loaded into any algo unsigned char maskr, maskg, maskb; bool hasmask = image.GetOrFindMaskColour(&maskr, &maskg, &maskb); int wd = image.GetWidth(); int ht = image.GetHeight(); unsigned char* idata = image.GetData(); int x, y; lifealgo* curralgo = currlayer->algo; for (y = 0; y < ht; y++) { for (x = 0; x < wd; x++) { long pos = (y * wd + x) * 3; unsigned char r = idata[pos]; unsigned char g = idata[pos+1]; unsigned char b = idata[pos+2]; if ( hasmask && r == maskr && g == maskg && b == maskb ) { // treat transparent pixel as a dead cell } else if ( r < 255 || g < 255 || b < 255 ) { // treat non-white pixel as a live cell curralgo->setcell(x, y, 1); } } } curralgo->endofpattern(); } else { Warning(_("Could not load image from file!")); } return true; } // ----------------------------------------------------------------------------- void MainFrame::LoadPattern(const wxString& path, const wxString& newtitle, bool updatestatus, bool updateall) { if ( !wxFileName::FileExists(path) ) { Warning(_("The file does not exist:\n") + path); return; } // newtitle is only empty if called from ResetPattern/RestorePattern if (!newtitle.IsEmpty()) { if (askonload && currlayer->dirty && !SaveCurrentLayer()) return; if (inscript) stop_after_script = true; currlayer->savestart = false; currlayer->currfile = path; // reset step size now in case UpdateStatus is called below currlayer->currbase = algoinfo[currlayer->algtype]->defbase; currlayer->currexpo = 0; if (GetInfoFrame()) { // comments will no longer be relevant so close info window GetInfoFrame()->Close(true); } // reset timing info used in DisplayTimingInfo endtime = begintime = 0; // clear all undo/redo history currlayer->undoredo->ClearUndoRedo(); } if (!showbanner) statusptr->ClearMessage(); // set nopattupdate BEFORE UpdateStatus() call so we see gen=0 and pop=0; // in particular, it avoids getPopulation being called which would // slow down hlife pattern loading viewptr->nopattupdate = true; if (updatestatus) { // update all of status bar so we don't see different colored lines; // on Mac, DrawView also gets called if there are pending updates UpdateStatus(); } // save current algo and rule algo_type oldalgo = currlayer->algtype; wxString oldrule = wxString(currlayer->algo->getrule(), wxConvLocal); // delete old universe and create new one of same type delete currlayer->algo; currlayer->algo = CreateNewUniverse(currlayer->algtype); if (!newtitle.IsEmpty()) { // show new file name in window title but no rule (which readpattern can change); // nicer if user can see file name while loading a very large pattern MySetTitle(_("Loading ") + newtitle); } if (IsImageFile(path)) { // ensure new universe uses same rule RestoreRule(oldrule); LoadImage(path); viewptr->nopattupdate = false; } else { const char* err = readpattern(FILEPATH, *currlayer->algo); if (err) { wxString bigerr = _("File could not be loaded by any algorithm."); wxString algoname = wxString(GetAlgoName(currlayer->algtype), wxConvLocal); bigerr += wxString::Format(_("\n\nError from %s:\n"), algoname.c_str()); bigerr += wxString(err, wxConvLocal); // cycle thru all other algos until readpattern succeeds for (int i = 0; i < NumAlgos(); i++) { if (i != oldalgo) { currlayer->algtype = i; delete currlayer->algo; currlayer->algo = CreateNewUniverse(currlayer->algtype); // readpattern will call setrule err = readpattern(FILEPATH, *currlayer->algo); if (err) { algoname = wxString(GetAlgoName(currlayer->algtype), wxConvLocal); bigerr += wxString::Format(_("\n\nError from %s:\n"), algoname.c_str()); bigerr += wxString(err, wxConvLocal); } else { break; } } } viewptr->nopattupdate = false; if (err) { // no algo could read pattern so restore original algo and rule currlayer->algtype = oldalgo; delete currlayer->algo; currlayer->algo = CreateNewUniverse(currlayer->algtype); RestoreRule(oldrule); // also show full path to file (useful when debugging!) bigerr += wxString::Format(_("\n\nFile path:\n%s"), wxString(FILEPATH,wxConvLocal).c_str()); Warning(bigerr); } } viewptr->nopattupdate = false; } if (!newtitle.IsEmpty()) { MarkLayerClean(newtitle); // calls SetWindowTitle if (TimelineExists()) { // we've loaded a .mc file with a timeline so go to 1st frame InitTimelineFrame(); if (!showtimeline) ToggleTimelineBar(); // switch to the base step and exponent used to record the timeline pair be = currlayer->algo->getbaseexpo(); currlayer->currbase = be.first; currlayer->currexpo = be.second; } else { // restore default base step for current algo // (currlayer->currexpo was set to 0 above) currlayer->currbase = algoinfo[currlayer->algtype]->defbase; } SetGenIncrement(); // restore default colors for current algo/rule UpdateLayerColors(); if (openremovesel) currlayer->currsel.Deselect(); if (opencurs) currlayer->curs = opencurs; viewptr->FitInView(1); currlayer->startgen = currlayer->algo->getGeneration(); // might be > 0 if (updateall) UpdateEverything(); showbanner = false; } else { // ResetPattern/RestorePattern does the update } } // ----------------------------------------------------------------------------- void MainFrame::CheckBeforeRunning(const wxString& scriptpath, bool remember, const wxString& zippath) { bool ask; if (zippath.IsEmpty()) { // script was downloaded via "get:" link (script is in downloaddir -- // see GetURL in wxhelp.cpp) so always ask user if it's okay to run ask = true; } else { // script is included in zip file (scriptpath starts with tempdir) so only // ask user if zip file was downloaded via "get:" link ask = zippath.StartsWith(downloaddir); } if (ask) { UpdateEverything(); // in case OpenZipFile called LoadPattern #ifdef __WXMAC__ wxSetCursor(*wxSTANDARD_CURSOR); #endif // create our own dialog with a View button??? probably no need now that // user can ctrl/right-click on link to open script in their text editor wxString msg = scriptpath + _("\n\nClick \"No\" if the script is from an untrusted source."); int answer = wxMessageBox(msg, _("Do you want to run this script?"), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT, wxGetActiveWindow()); switch (answer) { case wxYES: break; case wxNO: return; default: return; // No } } // also do this??? // save script info (download path or zip path + script entry) in list of safe scripts // (stored in prefs file) so we can search for this script and not ask again Raise(); if (remember) AddRecentScript(scriptpath); RunScript(scriptpath); } // ----------------------------------------------------------------------------- bool MainFrame::ExtractZipEntry(const wxString& zippath, const wxString& entryname, const wxString& outfile) { wxFFileInputStream instream(zippath); if (!instream.Ok()) { Warning(_("Could not create input stream for zip file:\n") + zippath); return false; } wxZipInputStream zip(instream); wxZipEntry* entry; while ((entry = zip.GetNextEntry()) != NULL) { wxString thisname = entry->GetName(); if (thisname == entryname) { // we've found the desired entry so copy entry data to given output file wxFileOutputStream outstream(outfile); if (outstream.Ok()) { // read and write in chunks so we can show a progress dialog const int BUFFER_SIZE = 4000; char buf[BUFFER_SIZE]; size_t incount = 0; size_t outcount = 0; size_t lastread, lastwrite; double filesize = (double) entry->GetSize(); if (filesize <= 0.0) filesize = -1.0; // show indeterminate progress BeginProgress(_("Extracting file")); while (true) { zip.Read(buf, BUFFER_SIZE); lastread = zip.LastRead(); if (lastread == 0) break; outstream.Write(buf, lastread); lastwrite = outstream.LastWrite(); incount += lastread; outcount += lastwrite; if (incount != outcount) { Warning(_("Error occurred while writing file:\n") + outfile); break; } char msg[128]; sprintf(msg, "File size: %.2f MB", double(incount) / 1048576.0); if (AbortProgress((double)incount / filesize, wxString(msg,wxConvLocal))) { outcount = 0; break; } } EndProgress(); if (incount == outcount) { // successfully copied entry data to outfile delete entry; return true; } else { // delete incomplete outfile if (wxFileExists(outfile)) wxRemoveFile(outfile); } } else { Warning(_("Could not open output stream for file:\n") + outfile); } delete entry; return false; } delete entry; } // should not get here Warning(_("Could not find zip file entry:\n") + entryname); return false; } // ----------------------------------------------------------------------------- static bool RuleInstalled(wxZipInputStream& zip, const wxString& rulepath) { wxFileOutputStream outstream(rulepath); bool ok = outstream.Ok(); if (ok) { zip.Read(outstream); ok = (outstream.GetLastError() == wxSTREAM_NO_ERROR); } return ok; } // ----------------------------------------------------------------------------- void MainFrame::OpenZipFile(const wxString& zippath) { // Process given zip file in the following manner: // - If it contains any .rule files then extract and install those // files into userrules (the user's rules directory). // - If the zip file is "complex" (contains any folders, rule files, text files, // or more than one pattern, or more than one script), build a temporary html // file with clickable links to each file entry and show it in the help window. // - If the zip file contains at most one pattern and at most one script (both // at the root level) then load the pattern (if present) and then run the script // (if present and if allowed). const wxString indent = wxT("    "); bool dirseen = false; bool diffdirs = (userrules != rulesdir); wxString firstdir = wxEmptyString; wxString lastpattern = wxEmptyString; wxString lastscript = wxEmptyString; int patternseps = 0; // # of separators in lastpattern int scriptseps = 0; // # of separators in lastscript int patternfiles = 0; int scriptfiles = 0; int textfiles = 0; // includes html files int rulefiles = 0; int deprecated = 0; // # of .table/tree/colors/icons files wxSortedArrayString deplist; // list of installed deprecated files wxSortedArrayString rulelist; // list of installed .rule files wxString contents = wxT("") + GetBaseName(zippath); contents += wxT("\n"); contents += wxT("\n"); contents += wxT("

\n"); contents += wxT("Zip file: "); contents += zippath; contents += wxT("

\n"); contents += wxT("Contents:
\n"); wxFFileInputStream instream(zippath); if (!instream.Ok()) { Warning(_("Could not create input stream for zip file:\n") + zippath); return; } wxZipInputStream zip(instream); // examine each entry in zip file and build contents string; // also install any .rule files wxZipEntry* entry; while ((entry = zip.GetNextEntry()) != NULL) { wxString name = entry->GetName(); if (name.StartsWith(wxT("__MACOSX")) || name.EndsWith(wxT(".DS_Store"))) { // ignore meta-data stuff in zip file created on Mac } else { // indent depending on # of separators in name unsigned int sepcount = 0; unsigned int i = 0; unsigned int len = (unsigned int)name.length(); while (i < len) { if (name[i] == wxFILE_SEP_PATH) sepcount++; i++; } // check if 1st directory has multiple separators (eg. in jslife.zip) if (entry->IsDir() && !dirseen && sepcount > 1) { firstdir = name.BeforeFirst(wxFILE_SEP_PATH); contents += firstdir; contents += wxT("
\n"); } for (i = 1; i < sepcount; i++) contents += indent; if (entry->IsDir()) { // remove terminating separator from directory name name = name.BeforeLast(wxFILE_SEP_PATH); name = name.AfterLast(wxFILE_SEP_PATH); if (dirseen && name == firstdir) { // ignore dir already output earlier (eg. in jslife.zip) } else { contents += name; contents += wxT("
\n"); } dirseen = true; } else { // entry is for some sort of file wxString filename = name.AfterLast(wxFILE_SEP_PATH); if (dirseen) contents += indent; if ( IsRuleFile(filename) && !filename.EndsWith(wxT(".rule")) ) { // this is a deprecated .table/tree/colors/icons file contents += filename; contents += indent; contents += wxT("[deprecated]"); deprecated++; // install it into userrules so it can be used below to create a .rule file wxString outfile = userrules + filename; if (RuleInstalled(zip, outfile)) { deplist.Add(filename); } else { contents += indent; contents += wxT("INSTALL FAILED!"); } } else { // user can extract file via special "unzip:" link contents += wxT(""); contents += filename; contents += wxT(""); if ( IsRuleFile(filename) ) { // extract and install .rule file into userrules wxString outfile = userrules + filename; if (RuleInstalled(zip, outfile)) { // file successfully installed rulelist.Add(filename); contents += indent; contents += wxT("[installed]"); if (diffdirs) { // check if this file overrides similarly named file in rulesdir wxString clashfile = rulesdir + filename; if (wxFileExists(clashfile)) { contents += indent; contents += wxT("(overrides file in Rules folder)"); } } } else { // file could not be installed contents += indent; contents += wxT("[NOT installed]"); // file is probably incomplete so best to delete it if (wxFileExists(outfile)) wxRemoveFile(outfile); } rulefiles++; } else if ( IsHTMLFile(filename) || IsTextFile(filename) ) { textfiles++; } else if ( IsScriptFile(filename) ) { scriptfiles++; lastscript = name; scriptseps = sepcount; } else { patternfiles++; lastpattern = name; patternseps = sepcount; } } contents += wxT("
\n"); } } delete entry; } // end while if (rulefiles > 0) { contents += wxT("

Files marked as \"[installed]\" have been stored in your rules folder:
\n"); contents += userrules; contents += wxT("\n"); } if (deprecated > 0) { wxString newrules = CreateRuleFiles(deplist, rulelist); if (newrules.length() > 0) { contents += wxT("

Files marked as \"[deprecated]\" have been used to create new .rule files:
\n"); contents += newrules; } } contents += wxT("\n"); if (dirseen || rulefiles > 0 || deprecated > 0 || textfiles > 0 || patternfiles > 1 || scriptfiles > 1) { // complex zip, so write contents to a temporary html file and display it in help window; // use a unique file name so user can go back/forwards wxString htmlfile = wxFileName::CreateTempFileName(tempdir + wxT("zip_contents_")); wxRemoveFile(htmlfile); htmlfile += wxT(".html"); wxFile outfile(htmlfile, wxFile::write); if (outfile.IsOpened()) { outfile.Write(contents); outfile.Close(); ShowHelp(htmlfile); } else { Warning(_("Could not create html file:\n") + htmlfile); } } if (patternfiles <= 1 && scriptfiles <= 1 && patternseps == 0 && scriptseps == 0) { // load lastpattern (if present), then run lastscript (if present); // the script might be a long-running one that allows user interaction, // so it's best to run it AFTER calling ShowHelp above if (patternfiles == 1) { wxString tempfile = tempdir + lastpattern.AfterLast(wxFILE_SEP_PATH); if (ExtractZipEntry(zippath, lastpattern, tempfile)) { Raise(); // don't call AddRecentPattern(tempfile) here; OpenFile has added // zippath to recent patterns LoadPattern(tempfile, GetBaseName(tempfile), true, scriptfiles == 0); } } if (scriptfiles == 1) { wxString tempfile = tempdir + lastscript.AfterLast(wxFILE_SEP_PATH); if (ExtractZipEntry(zippath, lastscript, tempfile)) { // run script depending on safety check CheckBeforeRunning(tempfile, false, zippath); } else { // should never happen but play safe UpdateEverything(); } } } } // ----------------------------------------------------------------------------- static bool RuleCanBeFound(const wxString& path) { // ensure given path to .rule file is a full path wxString fullpath = path; wxFileName fname(fullpath); if (!fname.IsAbsolute()) fullpath = gollydir + path; // check that .rule file is in userrules or rulesdir wxString dir = fullpath.BeforeLast(wxFILE_SEP_PATH); dir += wxFILE_SEP_PATH; if (dir == userrules || dir == rulesdir) { return true; } else { wxString msg = _("You need to move "); msg += fullpath.AfterLast(wxFILE_SEP_PATH); msg += _(" into your rules folder ("); msg += userrules; msg += _(") so the RuleLoader algorithm can find it."); Warning(msg); return false; } } // ----------------------------------------------------------------------------- void MainFrame::OpenFile(const wxString& path, bool remember) { if (IsHTMLFile(path)) { // show HTML file in help window ShowHelp(path); return; } if (IsTextFile(path)) { // open text file in user's preferred text editor EditFile(path); return; } if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; // assume remember is true (should only be false if called from a script) if ( IsScriptFile(path) ) { AddRecentScript(path); cmdevent.SetId(ID_RUN_RECENT + 1); } else { AddRecentPattern(path); cmdevent.SetId(ID_OPEN_RECENT + 1); } return; } if (IsScriptFile(path)) { // execute script if (remember) AddRecentScript(path); RunScript(path); } else if (IsZipFile(path)) { // process zip file if (remember) AddRecentPattern(path); // treat it like a pattern OpenZipFile(path); } else if (IsRuleFile(path)) { // switch to rule, but only if it's in rulesdir or userrules if (RuleCanBeFound(path)) LoadRule(path.AfterLast(wxFILE_SEP_PATH).BeforeLast('.')); } else { // load pattern if (remember) AddRecentPattern(path); // ensure path is a full path because a script might want to reset() to it // (in which case the cwd is the script's directory, not gollydir) wxString newpath = path; wxFileName fname(newpath); if (!fname.IsAbsolute()) newpath = gollydir + path; LoadPattern(newpath, GetBaseName(path)); } } // ----------------------------------------------------------------------------- void MainFrame::AddRecentPattern(const wxString& inpath) { if (inpath.IsEmpty()) return; wxString path = inpath; if (path.StartsWith(gollydir)) { // remove gollydir from start of path path.erase(0, gollydir.length()); } // duplicate any ampersands so they appear in menu path.Replace(wxT("&"), wxT("&&")); // put given path at start of patternSubMenu #ifdef __WXGTK__ // avoid wxGTK bug in FindItem if path contains underscores int id = wxNOT_FOUND; for (int i = 0; i < numpatterns; i++) { wxMenuItem* item = patternSubMenu->FindItemByPosition(i); wxString temp = item->GetText(); temp.Replace(wxT("__"), wxT("_")); temp.Replace(wxT("&"), wxT("&&")); if (temp == path) { id = ID_OPEN_RECENT + 1 + i; break; } } #else int id = patternSubMenu->FindItem(path); #endif if ( id == wxNOT_FOUND ) { if ( numpatterns < maxpatterns ) { // add new path numpatterns++; id = ID_OPEN_RECENT + numpatterns; patternSubMenu->Insert(numpatterns - 1, id, path); } else { // replace last item with new path wxMenuItem* item = patternSubMenu->FindItemByPosition(maxpatterns - 1); item->SetText(path); id = ID_OPEN_RECENT + maxpatterns; } } // path exists in patternSubMenu if ( id > ID_OPEN_RECENT + 1 ) { // move path to start of menu wxMenuItem* item; while ( id > ID_OPEN_RECENT + 1 ) { wxMenuItem* previtem = patternSubMenu->FindItem(id - 1); wxString prevpath = previtem->GetText(); #ifdef __WXGTK__ // remove duplicate underscores prevpath.Replace(wxT("__"), wxT("_")); prevpath.Replace(wxT("&"), wxT("&&")); #endif item = patternSubMenu->FindItem(id); item->SetText(prevpath); id--; } item = patternSubMenu->FindItem(id); item->SetText(path); } } // ----------------------------------------------------------------------------- void MainFrame::AddRecentScript(const wxString& inpath) { if (inpath.IsEmpty()) return; wxString path = inpath; if (path.StartsWith(gollydir)) { // remove gollydir from start of path path.erase(0, gollydir.length()); } // duplicate ampersands so they appear in menu path.Replace(wxT("&"), wxT("&&")); // put given path at start of scriptSubMenu #ifdef __WXGTK__ // avoid wxGTK bug in FindItem if path contains underscores int id = wxNOT_FOUND; for (int i = 0; i < numscripts; i++) { wxMenuItem* item = scriptSubMenu->FindItemByPosition(i); wxString temp = item->GetText(); temp.Replace(wxT("__"), wxT("_")); temp.Replace(wxT("&"), wxT("&&")); if (temp == path) { id = ID_RUN_RECENT + 1 + i; break; } } #else int id = scriptSubMenu->FindItem(path); #endif if ( id == wxNOT_FOUND ) { if ( numscripts < maxscripts ) { // add new path numscripts++; id = ID_RUN_RECENT + numscripts; scriptSubMenu->Insert(numscripts - 1, id, path); } else { // replace last item with new path wxMenuItem* item = scriptSubMenu->FindItemByPosition(maxscripts - 1); item->SetText(path); id = ID_RUN_RECENT + maxscripts; } } // path exists in scriptSubMenu if ( id > ID_RUN_RECENT + 1 ) { // move path to start of menu wxMenuItem* item; while ( id > ID_RUN_RECENT + 1 ) { wxMenuItem* previtem = scriptSubMenu->FindItem(id - 1); wxString prevpath = previtem->GetText(); #ifdef __WXGTK__ // remove duplicate underscores prevpath.Replace(wxT("__"), wxT("_")); prevpath.Replace(wxT("&"), wxT("&&")); #endif item = scriptSubMenu->FindItem(id); item->SetText(prevpath); id--; } item = scriptSubMenu->FindItem(id); item->SetText(path); } } // ----------------------------------------------------------------------------- void MainFrame::OpenPattern() { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(wxID_OPEN); return; } wxString filetypes = _("All files (*)|*"); filetypes += _("|RLE (*.rle)|*.rle"); filetypes += _("|Macrocell (*.mc)|*.mc"); filetypes += _("|Gzip (*.gz)|*.gz"); filetypes += _("|Life 1.05/1.06 (*.lif)|*.lif"); filetypes += _("|dblife (*.l)|*.l"); filetypes += _("|MCell (*.mcl)|*.mcl"); filetypes += _("|Zip (*.zip;*.gar)|*.zip;*.gar"); filetypes += _("|BMP (*.bmp)|*.bmp"); filetypes += _("|GIF (*.gif)|*.gif"); filetypes += _("|PNG (*.png)|*.png"); filetypes += _("|TIFF (*.tiff;*.tif)|*.tiff;*.tif"); wxFileDialog opendlg(this, _("Choose a pattern"), opensavedir, wxEmptyString, filetypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST); #ifdef __WXGTK__ // opensavedir is ignored above (bug in wxGTK 2.8.0???) opendlg.SetDirectory(opensavedir); #endif if ( opendlg.ShowModal() == wxID_OK ) { wxFileName fullpath( opendlg.GetPath() ); opensavedir = fullpath.GetPath(); OpenFile( opendlg.GetPath() ); } } // ----------------------------------------------------------------------------- void MainFrame::OpenScript() { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_RUN_SCRIPT); return; } wxString filetypes = _("Perl or Python (*.pl;*.py)|*.pl;*.py"); filetypes += _("|Perl (*.pl)|*.pl"); filetypes += _("|Python (*.py)|*.py"); wxFileDialog opendlg(this, _("Choose a script"), rundir, wxEmptyString, filetypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST); #ifdef __WXGTK__ // rundir is ignored above (bug in wxGTK 2.8.0???) opendlg.SetDirectory(rundir); #endif if ( opendlg.ShowModal() == wxID_OK ) { wxFileName fullpath( opendlg.GetPath() ); rundir = fullpath.GetPath(); AddRecentScript( opendlg.GetPath() ); RunScript( opendlg.GetPath() ); } } // ----------------------------------------------------------------------------- bool MainFrame::CopyTextToClipboard(const wxString& text) { bool result = true; if (wxTheClipboard->Open()) { if ( !wxTheClipboard->SetData(new wxTextDataObject(text)) ) { Warning(_("Could not copy text to clipboard!")); result = false; } wxTheClipboard->Close(); } else { Warning(_("Could not open clipboard!")); result = false; } return result; } // ----------------------------------------------------------------------------- #if wxCHECK_VERSION(2,9,0) // wxTextDataObject also has GetText and SetText methods so don't change them #undef GetText #undef SetText #endif bool MainFrame::GetTextFromClipboard(wxTextDataObject* textdata) { bool gotdata = false; if ( wxTheClipboard->Open() ) { if ( wxTheClipboard->IsSupported( wxDF_TEXT ) ) { gotdata = wxTheClipboard->GetData( *textdata ); if (!gotdata) { statusptr->ErrorMessage(_("Could not get clipboard text!")); } } else if ( wxTheClipboard->IsSupported( wxDF_BITMAP ) ) { wxBitmapDataObject bmapdata; gotdata = wxTheClipboard->GetData( bmapdata ); if (gotdata) { // convert bitmap data to text data wxString str; wxBitmap bmap = bmapdata.GetBitmap(); wxImage image = bmap.ConvertToImage(); if (image.Ok()) { /* there doesn't seem to be any mask or alpha info, at least on Mac if (bmap.GetMask() != NULL) Warning(_("Bitmap has mask!")); if (image.HasMask()) Warning(_("Image has mask!")); if (image.HasAlpha()) Warning(_("Image has alpha!")); */ int wd = image.GetWidth(); int ht = image.GetHeight(); unsigned char* idata = image.GetData(); int x, y; for (y = 0; y < ht; y++) { for (x = 0; x < wd; x++) { long pos = (y * wd + x) * 3; if ( idata[pos] < 255 || idata[pos+1] < 255 || idata[pos+2] < 255 ) { // non-white pixel is a live cell str += 'o'; } else { // white pixel is a dead cell str += '.'; } } str += '\n'; } textdata->SetText(str); } else { statusptr->ErrorMessage(_("Could not convert clipboard bitmap!")); gotdata = false; } } else { statusptr->ErrorMessage(_("Could not get clipboard bitmap!")); } } else { statusptr->ErrorMessage(_("No data in clipboard.")); } wxTheClipboard->Close(); } else { statusptr->ErrorMessage(_("Could not open clipboard!")); } return gotdata; } // ----------------------------------------------------------------------------- bool MainFrame::ClipboardContainsRule() { wxTextDataObject data; if (!GetTextFromClipboard(&data)) return false; wxString cliptext = data.GetText(); if (!cliptext.StartsWith(wxT("@RULE "))) return false; // extract rule name wxString rulename; int i = 6; while (cliptext[i] > ' ') { rulename += cliptext[i]; i++; } // check if rulename.rule already exists wxString rulepath = userrules + rulename; rulepath += wxT(".rule"); if (wxFileExists(rulepath)) { wxString question = _("Do you want to replace the existing ") + rulename; question += _(".rule with the version in the clipboard?"); int answer = wxMessageBox(question, _("Replace existing .rule file?"), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT, wxGetActiveWindow()); if (answer == wxNO) { // don't overwrite existing .rule file return true; } } // create rulename.rule in user-specific rules folder wxFile rulefile(rulepath, wxFile::write); if (!rulefile.IsOpened()) { Warning(_("Could not open .rule file for writing:\n") + rulepath); return true; } if (!rulefile.Write(data.GetText())) { Warning(_("Could not write clipboard data to .rule file!")); rulefile.Close(); return true; } rulefile.Close(); statusptr->DisplayMessage(_("Created ") + rulepath); // now switch to the newly created rule LoadRule(rulename); return true; } // ----------------------------------------------------------------------------- void MainFrame::OpenClipboard() { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_OPEN_CLIP); return; } // if clipboard text starts with "@RULE rulename" then install rulename.rule // and switch to that rule if (ClipboardContainsRule()) return; // load and view pattern data stored in clipboard wxTextDataObject data; if (GetTextFromClipboard(&data)) { // copy clipboard data to tempstart so we can handle all formats // supported by readpattern wxFile outfile(currlayer->tempstart, wxFile::write); if ( outfile.IsOpened() ) { outfile.Write( data.GetText() ); outfile.Close(); LoadPattern(currlayer->tempstart, _("clipboard")); // do NOT delete tempstart -- it can be reloaded by ResetPattern // or used by ShowPatternInfo } else { statusptr->ErrorMessage(_("Could not create tempstart file!")); } } } // ----------------------------------------------------------------------------- wxString MainFrame::GetScriptFileName(const wxString& text) { // examine given text to see if it contains Perl or Python code; // if "use" or "my" occurs at start of line then we assume Perl, // if "import" or "from" occurs at start of line then we assume Python, // otherwise we compare counts for dollars + semicolons vs colons int dollars = 0; int semicolons = 0; int colons = 0; int linelen = 0; // need to be careful converting Unicode wxString to char* wxCharBuffer buff = text.mb_str(wxConvLocal); const char* p = (const char*) buff; while (*p) { switch (*p) { case '#': // probably a comment, so ignore rest of line while (*p && *p != 13 && *p != 10) p++; linelen = 0; if (*p) p++; break; case 34: // double quote -- ignore until quote closes, even multiple lines p++; while (*p && *p != 34) p++; linelen = 0; if (*p) p++; break; case 39: // single quote -- ignore until quote closes p++; while (*p && *p != 39 && *p != 13 && *p != 10) p++; linelen = 0; if (*p) p++; break; case '$': dollars++; linelen++; p++; break; case ':': colons++; linelen++; p++; break; case ';': semicolons++; linelen++; p++; break; case 13: case 10: // if colon/semicolon is at eol then count it twice if (linelen > 0 && p[-1] == ':') colons++; if (linelen > 0 && p[-1] == ';') semicolons++; linelen = 0; p++; break; case ' ': // look for language-specific keyword at start of line if (linelen == 2 && strncmp(p-2,"my",2) == 0) return perlfile; if (linelen == 3 && strncmp(p-3,"use",3) == 0) return perlfile; if (linelen == 4 && strncmp(p-4,"from",4) == 0) return pythonfile; if (linelen == 6 && strncmp(p-6,"import",6) == 0) return pythonfile; // don't break default: if (linelen == 0 && (*p == ' ' || *p == 9)) { // ignore spaces/tabs at start of line } else { linelen++; } p++; } } /* check totals: char msg[128]; sprintf(msg, "dollars=%d semicolons=%d colons=%d", dollars, semicolons, colons); Note(wxString(msg,wxConvLocal)); */ if (dollars + semicolons > colons) return perlfile; else return pythonfile; } // ----------------------------------------------------------------------------- void MainFrame::RunClipboard() { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_RUN_CLIP); return; } // run script stored in clipboard wxTextDataObject data; if (GetTextFromClipboard(&data)) { // scriptfile extension depends on whether the clipboard data // contains Perl or Python code wxString scriptfile = GetScriptFileName( data.GetText() ); // copy clipboard data to scriptfile wxFile outfile(scriptfile, wxFile::write); if (outfile.IsOpened()) { #ifdef __WXMAC__ if (scriptfile == perlfile) { // Perl script, so replace CRs with LFs wxString str = data.GetText(); str.Replace(wxT("\015"), wxT("\012")); outfile.Write( str ); } else { outfile.Write( data.GetText() ); } #else outfile.Write( data.GetText() ); #endif outfile.Close(); RunScript(scriptfile); } else { statusptr->ErrorMessage(_("Could not create script file!")); } } } #if wxCHECK_VERSION(2,9,0) // restore new wxMenuItem method names in wx 2.9 #define GetText GetItemLabel #define SetText SetItemLabel #endif // ----------------------------------------------------------------------------- void MainFrame::OpenRecentPattern(int id) { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(id); return; } wxMenuItem* item = patternSubMenu->FindItem(id); if (item) { wxString path = item->GetText(); #ifdef __WXGTK__ // remove duplicate underscores path.Replace(wxT("__"), wxT("_")); #endif // remove duplicate ampersands path.Replace(wxT("&&"), wxT("&")); // if path isn't absolute then prepend Golly directory wxFileName fname(path); if (!fname.IsAbsolute()) path = gollydir + path; // path might be a zip file so call OpenFile rather than LoadPattern OpenFile(path); } } // ----------------------------------------------------------------------------- void MainFrame::OpenRecentScript(int id) { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(id); return; } wxMenuItem* item = scriptSubMenu->FindItem(id); if (item) { wxString path = item->GetText(); #ifdef __WXGTK__ // remove duplicate underscores path.Replace(wxT("__"), wxT("_")); #endif // remove duplicate ampersands path.Replace(wxT("&&"), wxT("&")); // if path isn't absolute then prepend Golly directory wxFileName fname(path); if (!fname.IsAbsolute()) path = gollydir + path; AddRecentScript(path); RunScript(path); } } // ----------------------------------------------------------------------------- void MainFrame::ClearMissingPatterns() { int pos = 0; while (pos < numpatterns) { wxMenuItem* item = patternSubMenu->FindItemByPosition(pos); wxString path = item->GetText(); #ifdef __WXGTK__ // remove duplicate underscores path.Replace(wxT("__"), wxT("_")); #endif // remove duplicate ampersands path.Replace(wxT("&&"), wxT("&")); // if path isn't absolute then prepend Golly directory wxFileName fname(path); if (!fname.IsAbsolute()) path = gollydir + path; if (wxFileExists(path)) { // keep this item pos++; } else { // remove this item by shifting up later items int nextpos = pos + 1; while (nextpos < numpatterns) { wxMenuItem* nextitem = patternSubMenu->FindItemByPosition(nextpos); #ifdef __WXGTK__ // avoid wxGTK bug if item contains underscore wxString temp = nextitem->GetText(); temp.Replace(wxT("__"), wxT("_")); temp.Replace(wxT("&"), wxT("&&")); item->SetText( temp ); #else item->SetText( nextitem->GetText() ); #endif item = nextitem; nextpos++; } // delete last item patternSubMenu->Delete(item); numpatterns--; } } wxMenuBar* mbar = GetMenuBar(); if (mbar) mbar->Enable(ID_OPEN_RECENT, numpatterns > 0); } // ----------------------------------------------------------------------------- void MainFrame::ClearMissingScripts() { int pos = 0; while (pos < numscripts) { wxMenuItem* item = scriptSubMenu->FindItemByPosition(pos); wxString path = item->GetText(); #ifdef __WXGTK__ // remove duplicate underscores path.Replace(wxT("__"), wxT("_")); #endif // remove duplicate ampersands path.Replace(wxT("&&"), wxT("&")); // if path isn't absolute then prepend Golly directory wxFileName fname(path); if (!fname.IsAbsolute()) path = gollydir + path; if (wxFileExists(path)) { // keep this item pos++; } else { // remove this item by shifting up later items int nextpos = pos + 1; while (nextpos < numscripts) { wxMenuItem* nextitem = scriptSubMenu->FindItemByPosition(nextpos); #ifdef __WXGTK__ // avoid wxGTK bug if item contains underscore wxString temp = nextitem->GetText(); temp.Replace(wxT("__"), wxT("_")); temp.Replace(wxT("&"), wxT("&&")); item->SetText( temp ); #else item->SetText( nextitem->GetText() ); #endif item = nextitem; nextpos++; } // delete last item scriptSubMenu->Delete(item); numscripts--; } } wxMenuBar* mbar = GetMenuBar(); if (mbar) mbar->Enable(ID_RUN_RECENT, numscripts > 0); } // ----------------------------------------------------------------------------- void MainFrame::ClearAllPatterns() { while (numpatterns > 0) { patternSubMenu->Delete( patternSubMenu->FindItemByPosition(0) ); numpatterns--; } wxMenuBar* mbar = GetMenuBar(); if (mbar) mbar->Enable(ID_OPEN_RECENT, false); } // ----------------------------------------------------------------------------- void MainFrame::ClearAllScripts() { while (numscripts > 0) { scriptSubMenu->Delete( scriptSubMenu->FindItemByPosition(0) ); numscripts--; } wxMenuBar* mbar = GetMenuBar(); if (mbar) mbar->Enable(ID_RUN_RECENT, false); } // ----------------------------------------------------------------------------- const char* MainFrame::WritePattern(const wxString& path, pattern_format format, output_compression compression, int top, int left, int bottom, int right) { // if the format is RLE_format and the grid is bounded then force XRLE_format so that // position info is recorded (this position will be used when the file is read) if (format == RLE_format && (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0)) format = XRLE_format; const char* err = writepattern(FILEPATH, *currlayer->algo, format, compression, top, left, bottom, right); #ifdef __WXMAC__ if (!err) { // set the file's creator and type wxFileName filename(path); wxUint32 creator = 'GoLy'; wxUint32 type = 'GoLR'; // RLE or XRLE if (format == MC_format) { type = 'GoLM'; } #if defined(__WXOSX_COCOA__) // there is no Cocoa call to set file type and creator creator = 'GoLy'; // avoid compiler warning #else filename.MacSetTypeAndCreator(type, creator); #endif } #endif return err; } // ----------------------------------------------------------------------------- bool MainFrame::SavePattern() { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(wxID_SAVE); return false; } if (warn_on_save && currlayer->dirty && currlayer->algo->getGeneration() > currlayer->startgen) { wxString msg = _("Saving this generation will not save the changes you made earlier, "); msg += _("so you might want to select Reset or Undo and save those changes."); msg += _("\n\n(This warning can be disabled in Preferences > Layer.)"); Warning(msg); } wxString filetypes; int MCindex, RLEindex; // initially all formats are not allowed (use any -ve number) MCindex = RLEindex = -1; // adding "*.gz" to the file types avoids a duplication bug in the wxOSX app wxString MCfiles, RLEfiles; MCfiles = _("Macrocell (*.mc)|*.mc"); MCfiles += _("|Compressed Macrocell (*.mc.gz)|*.mc.gz;*.gz"); if (savexrle) { RLEfiles = _("Extended RLE (*.rle)|*.rle"); RLEfiles += _("|Compressed Extended RLE (*.rle.gz)|*.rle.gz;*.gz"); } else { RLEfiles = _("RLE (*.rle)|*.rle"); RLEfiles += _("|Compressed RLE (*.rle.gz)|*.rle.gz;*.gz"); } bigint top, left, bottom, right; int itop, ileft, ibottom, iright; currlayer->algo->findedges(&top, &left, &bottom, &right); if (currlayer->algo->hyperCapable()) { // algorithm uses hashlife if ( viewptr->OutsideLimits(top, left, bottom, right) ) { // too big so only allow saving as MC file itop = ileft = ibottom = iright = 0; filetypes = MCfiles; MCindex = 0; } else { // allow saving as MC or RLE file itop = top.toint(); ileft = left.toint(); ibottom = bottom.toint(); iright = right.toint(); filetypes = MCfiles; filetypes += _("|"); filetypes += RLEfiles; MCindex = 0; RLEindex = 1; } } else { // allow saving file only if pattern is small enough if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Pattern is outside +/- 10^9 boundary.")); return false; } itop = top.toint(); ileft = left.toint(); ibottom = bottom.toint(); iright = right.toint(); filetypes = RLEfiles; RLEindex = 0; } wxFileDialog savedlg( this, _("Save pattern"), opensavedir, currlayer->currname, filetypes, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); #ifdef __WXGTK__ // opensavedir is ignored above (bug in wxGTK 2.8.0???) savedlg.SetDirectory(opensavedir); #endif if ( savedlg.ShowModal() == wxID_OK ) { wxFileName fullpath( savedlg.GetPath() ); opensavedir = fullpath.GetPath(); wxString ext = fullpath.GetExt(); pattern_format format; output_compression compression = no_compression; // detect if user supplied a compression suffix (.gz) if ( ext.IsSameAs(wxT("gz"),false) ) { compression = gzip_compression; ext = wxFileName(fullpath.GetName()).GetExt(); } // if user supplied a known extension then use that format if it is // allowed, otherwise use current format specified in filter menu if ( ext.IsSameAs(wxT("rle"),false) && RLEindex >= 0 ) { format = savexrle ? XRLE_format : RLE_format; } else if ( ext.IsSameAs(wxT("mc"),false) && MCindex >= 0 ) { format = MC_format; } else if ( savedlg.GetFilterIndex()/2 == MCindex ) { format = MC_format; if (savedlg.GetFilterIndex()%2) compression = gzip_compression; } else if ( savedlg.GetFilterIndex()/2 == RLEindex ) { format = savexrle ? XRLE_format : RLE_format; if (savedlg.GetFilterIndex()%2) compression = gzip_compression; } else { statusptr->ErrorMessage(_("Bug in SavePattern!")); return false; } const char* err = WritePattern(savedlg.GetPath(), format, compression, itop, ileft, ibottom, iright); if (err) { statusptr->ErrorMessage(wxString(err,wxConvLocal)); } else { statusptr->DisplayMessage(_("Pattern saved in file: ") + savedlg.GetPath()); AddRecentPattern(savedlg.GetPath()); SaveSucceeded(savedlg.GetPath()); return true; } } return false; } // ----------------------------------------------------------------------------- // called by script command to save current pattern to given file const char* MainFrame::SaveFile(const wxString& path, const wxString& fileformat, bool remember) { bigint top, left, bottom, right; int itop, ileft, ibottom, iright; currlayer->algo->findedges(&top, &left, &bottom, &right); wxString format = fileformat.Lower(); output_compression compression = no_compression; if (format.EndsWith(wxT(".gz"))) { compression = gzip_compression; } // check that given file format is valid pattern_format pattfmt; if (format.StartsWith(wxT("rle"))) { if ( viewptr->OutsideLimits(top, left, bottom, right) ) { return "Pattern is too big to save as RLE."; } pattfmt = savexrle ? XRLE_format : RLE_format; itop = top.toint(); ileft = left.toint(); ibottom = bottom.toint(); iright = right.toint(); } else if (format.StartsWith(wxT("mc"))) { if (!currlayer->algo->hyperCapable()) { return "Macrocell format is not supported by the current algorithm."; } pattfmt = MC_format; // writepattern will ignore itop, ileft, ibottom, iright itop = ileft = ibottom = iright = 0; } else { return "Unknown pattern format."; } const char* err = WritePattern(path, pattfmt, compression, itop, ileft, ibottom, iright); if (!err) { if (remember) AddRecentPattern(path); SaveSucceeded(path); } return err; } // ----------------------------------------------------------------------------- void MainFrame::SaveSucceeded(const wxString& path) { // save old info for RememberNameChange wxString oldname = currlayer->currname; wxString oldfile = currlayer->currfile; bool oldsave = currlayer->savestart; bool olddirty = currlayer->dirty; if (allowundo && !currlayer->stayclean && inscript) { SavePendingChanges(); } if ( currlayer->algo->getGeneration() == currlayer->startgen ) { // no need to save starting pattern (ResetPattern can load currfile) currlayer->currfile = path; currlayer->savestart = false; } // set dirty flag false and update currlayer->currname MarkLayerClean(GetBaseName(path)); if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberNameChange(oldname, oldfile, oldsave, olddirty); } } // ----------------------------------------------------------------------------- void MainFrame::ToggleShowPatterns() { if (splitwin->IsSplit()) dirwinwd = splitwin->GetSashPosition(); #ifndef __WXMAC__ // hide scroll bars bigview->SetScrollbar(wxHORIZONTAL, 0, 0, 0, true); bigview->SetScrollbar(wxVERTICAL, 0, 0, 0, true); #endif showpatterns = !showpatterns; if (showpatterns && showscripts) { showscripts = false; splitwin->Unsplit(scriptctrl); splitwin->SplitVertically(patternctrl, RightPane(), dirwinwd); } else { if (splitwin->IsSplit()) { // hide left pane splitwin->Unsplit(patternctrl); } else { splitwin->SplitVertically(patternctrl, RightPane(), dirwinwd); } viewptr->SetFocus(); } #ifndef __WXMAC__ // restore scroll bars bigview->UpdateScrollBars(); #endif } // ----------------------------------------------------------------------------- void MainFrame::ToggleShowScripts() { if (splitwin->IsSplit()) dirwinwd = splitwin->GetSashPosition(); #ifndef __WXMAC__ // hide scroll bars bigview->SetScrollbar(wxHORIZONTAL, 0, 0, 0, true); bigview->SetScrollbar(wxVERTICAL, 0, 0, 0, true); #endif showscripts = !showscripts; if (showscripts && showpatterns) { showpatterns = false; splitwin->Unsplit(patternctrl); splitwin->SplitVertically(scriptctrl, RightPane(), dirwinwd); } else { if (splitwin->IsSplit()) { // hide left pane splitwin->Unsplit(scriptctrl); } else { splitwin->SplitVertically(scriptctrl, RightPane(), dirwinwd); } viewptr->SetFocus(); } #ifndef __WXMAC__ // restore scroll bars bigview->UpdateScrollBars(); #endif } // ----------------------------------------------------------------------------- void MainFrame::ChangePatternDir() { wxDirDialog dirdlg(this, _("Choose a new pattern folder"), patterndir, wxDD_NEW_DIR_BUTTON); if (dirdlg.ShowModal() == wxID_OK) SetPatternDir(dirdlg.GetPath()); } // ----------------------------------------------------------------------------- void MainFrame::ChangeScriptDir() { wxDirDialog dirdlg(this, _("Choose a new script folder"), scriptdir, wxDD_NEW_DIR_BUTTON); if (dirdlg.ShowModal() == wxID_OK) SetScriptDir(dirdlg.GetPath()); } // ----------------------------------------------------------------------------- void MainFrame::SetPatternDir(const wxString& newdir) { if (patterndir != newdir) { patterndir = newdir; if (showpatterns) { // show new pattern directory SimplifyTree(patterndir, patternctrl->GetTreeCtrl(), patternctrl->GetRootId()); } } } // ----------------------------------------------------------------------------- void MainFrame::SetScriptDir(const wxString& newdir) { if (scriptdir != newdir) { scriptdir = newdir; if (showscripts) { // show new script directory SimplifyTree(scriptdir, scriptctrl->GetTreeCtrl(), scriptctrl->GetRootId()); } } } // ----------------------------------------------------------------------------- void MainFrame::SetStepExponent(int newexpo) { currlayer->currexpo = newexpo; if (currlayer->currexpo < minexpo) currlayer->currexpo = minexpo; SetGenIncrement(); } // ----------------------------------------------------------------------------- void MainFrame::SetMinimumStepExponent() { // set minexpo depending on mindelay and maxdelay minexpo = 0; if (mindelay > 0) { int d = mindelay; minexpo--; while (d < maxdelay) { d *= 2; minexpo--; } } } // ----------------------------------------------------------------------------- void MainFrame::UpdateStepExponent() { SetMinimumStepExponent(); if (currlayer->currexpo < minexpo) currlayer->currexpo = minexpo; SetGenIncrement(); } // ----------------------------------------------------------------------------- void MainFrame::ShowPrefsDialog(const wxString& page) { if (viewptr->waitingforclick) return; if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(wxID_PREFERENCES); return; } if (inscript) { // safe to allow prefs dialog while script is running??? // if so, maybe we need some sort of warning like this: // Warning(_("The currently running script might clobber any changes you make.")); } int oldtileborder = tileborder; int oldcontrolspos = controlspos; if (ChangePrefs(page)) { // user hit OK button // selection color may have changed SetSelectionColor(); // if maxpatterns was reduced then we may need to remove some paths while (numpatterns > maxpatterns) { numpatterns--; patternSubMenu->Delete( patternSubMenu->FindItemByPosition(numpatterns) ); } // if maxscripts was reduced then we may need to remove some paths while (numscripts > maxscripts) { numscripts--; scriptSubMenu->Delete( scriptSubMenu->FindItemByPosition(numscripts) ); } // randomfill might have changed SetRandomFillPercentage(); // if mindelay/maxdelay changed then may need to change minexpo and currexpo UpdateStepExponent(); // maximum memory might have changed for (int i = 0; i < numlayers; i++) { Layer* layer = GetLayer(i); AlgoData* ad = algoinfo[layer->algtype]; if (ad->algomem >= 0) layer->algo->setMaxMemory(ad->algomem); } // tileborder might have changed if (tilelayers && numlayers > 1 && tileborder != oldtileborder) { int wd, ht; bigview->GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; ResizeLayers(wd, ht); } // position of translucent controls might have changed if (controlspos != oldcontrolspos) { int wd, ht; if (tilelayers && numlayers > 1) { for (int i = 0; i < numlayers; i++) { Layer* layer = GetLayer(i); layer->tilewin->GetClientSize(&wd, &ht); layer->tilewin->SetViewSize(wd, ht); } } bigview->GetClientSize(&wd, &ht); bigview->SetViewSize(wd, ht); } SavePrefs(); } // safer to update everything even if user hit Cancel UpdateEverything(); } golly-2.7-src/gui-wx/wxtimeline.cpp0000644000175000017500000010456112536111364014340 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #if wxUSE_TOOLTIPS #include "wx/tooltip.h" // for wxToolTip #endif #include "wx/dcbuffer.h" // for wxBufferedPaintDC #include "bigint.h" #include "lifealgo.h" #include "wxgolly.h" // for viewptr, statusptr, mainptr #include "wxmain.h" // for mainptr->... #include "wxutils.h" // for Warning, etc #include "wxprefs.h" // for showtimeline, etc #include "wxstatus.h" // for statusptr->... #include "wxscript.h" // for inscript #include "wxview.h" // for viewptr->... #include "wxlayer.h" // for currlayer #include "wxtimeline.h" // bitmaps for timeline bar buttons #include "bitmaps/record.xpm" #include "bitmaps/stop.xpm" #include "bitmaps/backwards.xpm" #include "bitmaps/forwards.xpm" #include "bitmaps/stopplay.xpm" #include "bitmaps/deltime.xpm" // ----------------------------------------------------------------------------- // Define timeline bar window: enum { // ids for bitmap buttons in timeline bar RECORD_BUTT = 0, STOPREC_BUTT, BACKWARDS_BUTT, FORWARDS_BUTT, STOPPLAY_BUTT, DELETE_BUTT, NUM_BUTTONS, // must be after all buttons ID_SLIDER, // for slider ID_SCROLL // for scroll bar }; // derive from wxPanel so we get current theme's background color on Windows class TimelineBar : public wxPanel { public: TimelineBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht); ~TimelineBar(); void AddButton(int id, const wxString& tip); void AddSeparator(); void EnableButton(int id, bool enable); void UpdateButtons(); void UpdateSlider(); void UpdateScrollBar(); void DisplayCurrentFrame(); // detect press and release of a bitmap button void OnButtonDown(wxMouseEvent& event); void OnButtonUp(wxMouseEvent& event); void OnKillFocus(wxFocusEvent& event); wxSlider* slider; // slider for controlling autoplay speed wxScrollBar* framebar; // scroll bar for displaying timeline frames // positioning data used by AddButton and AddSeparator int ypos, xpos, smallgap, biggap; private: // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() // event handlers void OnPaint(wxPaintEvent& event); void OnMouseDown(wxMouseEvent& event); void OnButton(wxCommandEvent& event); void OnSlider(wxScrollEvent& event); void OnScroll(wxScrollEvent& event); void SetTimelineFont(wxDC& dc); void DisplayText(wxDC& dc, const wxString& s, wxCoord x, wxCoord y); void DrawTimelineBar(wxDC& dc, int wd, int ht); // bitmaps for normal buttons wxBitmap normbutt[NUM_BUTTONS]; #ifdef __WXMSW__ // on Windows we need bitmaps for disabled buttons wxBitmap disnormbutt[NUM_BUTTONS]; #endif // remember state of buttons to avoid unnecessary updates int buttstate[NUM_BUTTONS]; wxBitmap* timelinebitmap; // timeline bar bitmap int timelinebitmapwd; // width of timeline bar bitmap int timelinebitmapht; // height of timeline bar bitmap int digitwd; // width of digit in timeline bar font int digitht; // height of digit in timeline bar font int textascent; // vertical adjustment used in DrawText calls wxFont* timelinefont; // timeline bar font }; BEGIN_EVENT_TABLE(TimelineBar, wxPanel) EVT_PAINT ( TimelineBar::OnPaint) EVT_LEFT_DOWN ( TimelineBar::OnMouseDown) EVT_BUTTON (wxID_ANY, TimelineBar::OnButton) EVT_COMMAND_SCROLL (ID_SLIDER, TimelineBar::OnSlider) EVT_COMMAND_SCROLL (ID_SCROLL, TimelineBar::OnScroll) END_EVENT_TABLE() // ----------------------------------------------------------------------------- static TimelineBar* tbarptr = NULL; // global pointer to timeline bar static int mindelpos; // minimum x position of DELETE_BUTT const int TBARHT = 32; // height of timeline bar const int SCROLLHT = 17; // height of scroll bar const int PAGESIZE = 10; // scroll amount when paging const int MINSPEED = -10; // minimum autoplay speed const int MAXSPEED = 10; // maximum autoplay speed // width and height of bitmap buttons #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) const int BUTTON_WD = 24; const int BUTTON_HT = 24; #elif defined(__WXOSX_COCOA__) || defined(__WXGTK__) const int BUTTON_WD = 28; const int BUTTON_HT = 28; #else const int BUTTON_WD = 24; const int BUTTON_HT = 24; #endif // timeline bar buttons (must be global to use Connect/Disconnect on Windows) static wxBitmapButton* tlbutt[NUM_BUTTONS]; // ----------------------------------------------------------------------------- TimelineBar::TimelineBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht) : wxPanel(parent, wxID_ANY, wxPoint(xorg,yorg), wxSize(wd,ht), wxNO_FULL_REPAINT_ON_RESIZE) { #ifdef __WXGTK__ // avoid erasing background on GTK+ SetBackgroundStyle(wxBG_STYLE_CUSTOM); #endif // init bitmaps for normal state normbutt[RECORD_BUTT] = XPM_BITMAP(record); normbutt[STOPREC_BUTT] = XPM_BITMAP(stop); normbutt[BACKWARDS_BUTT] = XPM_BITMAP(backwards); normbutt[FORWARDS_BUTT] = XPM_BITMAP(forwards); normbutt[STOPPLAY_BUTT] = XPM_BITMAP(stopplay); normbutt[DELETE_BUTT] = XPM_BITMAP(deltime); #ifdef __WXMSW__ for (int i = 0; i < NUM_BUTTONS; i++) { CreatePaleBitmap(normbutt[i], disnormbutt[i]); } #endif for (int i = 0; i < NUM_BUTTONS; i++) { buttstate[i] = 0; } // init position variables used by AddButton and AddSeparator #ifdef __WXGTK__ // buttons are a different size in wxGTK xpos = 2; ypos = 2; smallgap = 6; #else xpos = 4; ypos = (32 - BUTTON_HT) / 2; smallgap = 4; #endif biggap = 16; // add buttons AddButton(RECORD_BUTT, _("Start recording")); AddSeparator(); AddButton(BACKWARDS_BUTT, _("Play backwards")); AddButton(FORWARDS_BUTT, _("Play forwards")); // create font for text in timeline bar and set textascent for use in DisplayText #ifdef __WXMSW__ // use smaller, narrower font on Windows timelinefont = wxFont::New(8, wxDEFAULT, wxNORMAL, wxNORMAL); int major, minor; wxGetOsVersion(&major, &minor); if ( major > 5 || (major == 5 && minor >= 1) ) { // 5.1+ means XP or later (Vista if major >= 6) textascent = 11; } else { textascent = 10; } #elif defined(__WXGTK__) // use smaller font on GTK timelinefont = wxFont::New(8, wxMODERN, wxNORMAL, wxNORMAL); textascent = 11; #elif defined(__WXOSX_COCOA__) // we need to specify facename to get Monaco instead of Courier timelinefont = wxFont::New(10, wxMODERN, wxNORMAL, wxNORMAL, false, wxT("Monaco")); textascent = 10; #elif defined(__WXMAC__) timelinefont = wxFont::New(10, wxMODERN, wxNORMAL, wxNORMAL); textascent = 10; #else timelinefont = wxFont::New(10, wxMODERN, wxNORMAL, wxNORMAL); textascent = 10; #endif if (timelinefont == NULL) Fatal(_("Failed to create timeline bar font!")); wxClientDC dc(this); SetTimelineFont(dc); dc.GetTextExtent(_("9"), &digitwd, &digitht); digitht -= 4; timelinebitmap = NULL; timelinebitmapwd = -1; timelinebitmapht = -1; // add slider int x, y; int sliderwd = 80; #ifdef __WXMAC__ int sliderht = 15; #else int sliderht = 24; // for Windows and wxGTK #endif x = xpos + 20 - smallgap; y = (TBARHT - (sliderht + 1)) / 2; slider = new wxSlider(this, ID_SLIDER, 0, MINSPEED, MAXSPEED, wxPoint(x, y), wxSize(sliderwd, sliderht), wxSL_HORIZONTAL); if (slider == NULL) Fatal(_("Failed to create timeline slider!")); #ifdef __WXMAC__ slider->SetWindowVariant(wxWINDOW_VARIANT_SMALL); slider->Move(x, y+1); #endif xpos = x + sliderwd; // add scroll bar int scrollbarwd = 60; // minimum width (ResizeTimelineBar will alter it) #ifdef __WXMAC__ int scrollbarht = 15; // must be this height on Mac #else int scrollbarht = SCROLLHT; #endif x = xpos + 20; y = (TBARHT - (scrollbarht + 1)) / 2; framebar = new wxScrollBar(this, ID_SCROLL, wxPoint(x, y), wxSize(scrollbarwd, scrollbarht), wxSB_HORIZONTAL); if (framebar == NULL) Fatal(_("Failed to create timeline scroll bar!")); xpos = x + scrollbarwd + 4; mindelpos = xpos; AddButton(DELETE_BUTT, _("Delete timeline")); // ResizeTimelineBar will move this button to right end of scroll bar } // ----------------------------------------------------------------------------- TimelineBar::~TimelineBar() { delete timelinefont; delete timelinebitmap; delete slider; delete framebar; } // ----------------------------------------------------------------------------- void TimelineBar::SetTimelineFont(wxDC& dc) { dc.SetFont(*timelinefont); dc.SetTextForeground(*wxBLACK); dc.SetBrush(*wxBLACK_BRUSH); dc.SetBackgroundMode(wxTRANSPARENT); } // ----------------------------------------------------------------------------- void TimelineBar::DisplayText(wxDC& dc, const wxString& s, wxCoord x, wxCoord y) { // DrawText's y parameter is top of text box but we pass in baseline // so adjust by textascent which depends on platform and OS version -- yuk! dc.DrawText(s, x, y - textascent); } // ----------------------------------------------------------------------------- void TimelineBar::DrawTimelineBar(wxDC& dc, int wd, int ht) { wxRect r = wxRect(0, 0, wd, ht); #ifdef __WXMAC__ wxBrush brush(wxColor(202,202,202)); FillRect(dc, r, brush); #endif #ifdef __WXMSW__ // use theme background color on Windows wxBrush brush(GetBackgroundColour()); FillRect(dc, r, brush); #endif // draw gray border line at top edge #if defined(__WXMSW__) dc.SetPen(*wxGREY_PEN); #elif defined(__WXMAC__) wxPen linepen(wxColor(140,140,140)); dc.SetPen(linepen); #else dc.SetPen(*wxLIGHT_GREY_PEN); #endif dc.DrawLine(0, 0, r.width, 0); dc.SetPen(wxNullPen); if (currlayer->algo->hyperCapable()) { bool canplay = TimelineExists() && !currlayer->algo->isrecording(); tlbutt[RECORD_BUTT]->Show(true); tlbutt[BACKWARDS_BUTT]->Show(canplay); tlbutt[FORWARDS_BUTT]->Show(canplay); tlbutt[DELETE_BUTT]->Show(canplay); slider->Show(canplay); framebar->Show(canplay); if (currlayer->algo->isrecording()) { // show number of frames recorded so far SetTimelineFont(dc); dc.SetPen(*wxBLACK_PEN); int x = smallgap + BUTTON_WD + 10; int y = TBARHT - 8; wxString str; str.Printf(_("Frames recorded: %d"), currlayer->algo->getframecount()); DisplayText(dc, str, x, y - (SCROLLHT - digitht)/2); dc.SetPen(wxNullPen); } } else { tlbutt[RECORD_BUTT]->Show(false); tlbutt[BACKWARDS_BUTT]->Show(false); tlbutt[FORWARDS_BUTT]->Show(false); tlbutt[DELETE_BUTT]->Show(false); slider->Show(false); framebar->Show(false); SetTimelineFont(dc); dc.SetPen(*wxBLACK_PEN); int x = 6; int y = TBARHT - 8; DisplayText(dc, _("The current algorithm does not support timelines."), x, y - (SCROLLHT - digitht)/2); dc.SetPen(wxNullPen); } } // ----------------------------------------------------------------------------- void TimelineBar::OnPaint(wxPaintEvent& WXUNUSED(event)) { int wd, ht; GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; #if defined(__WXMAC__) || defined(__WXGTK__) // windows on Mac OS X and GTK+ 2.0 are automatically buffered wxPaintDC dc(this); #else // use wxWidgets buffering to avoid flicker if (wd != timelinebitmapwd || ht != timelinebitmapht) { // need to create a new bitmap for timeline bar delete timelinebitmap; timelinebitmap = new wxBitmap(wd, ht); timelinebitmapwd = wd; timelinebitmapht = ht; } if (timelinebitmap == NULL) Fatal(_("Not enough memory to render timeline bar!")); wxBufferedPaintDC dc(this, *timelinebitmap); #endif if (showtimeline) DrawTimelineBar(dc, wd, ht); } // ----------------------------------------------------------------------------- void TimelineBar::OnMouseDown(wxMouseEvent& WXUNUSED(event)) { // on Win/Linux we need to reset keyboard focus to viewport window viewptr->SetFocus(); mainptr->showbanner = false; statusptr->ClearMessage(); } // ----------------------------------------------------------------------------- void TimelineBar::OnButton(wxCommandEvent& event) { #ifdef __WXMAC__ // close any open tool tip window (fixes wxMac bug?) wxToolTip::RemoveToolTips(); #endif mainptr->showbanner = false; statusptr->ClearMessage(); int id = event.GetId(); int cmdid; switch (id) { case RECORD_BUTT: cmdid = ID_RECORD; break; case BACKWARDS_BUTT: PlayTimeline(-1); return; case FORWARDS_BUTT: PlayTimeline(1); return; case DELETE_BUTT: cmdid = ID_DELTIME; break; default: Warning(_("Unexpected button id!")); return; } // call MainFrame::OnMenu after OnButton finishes wxCommandEvent cmdevt(wxEVT_COMMAND_MENU_SELECTED, cmdid); wxPostEvent(mainptr->GetEventHandler(), cmdevt); // avoid possible problems viewptr->SetFocus(); } // ----------------------------------------------------------------------------- void TimelineBar::OnSlider(wxScrollEvent& event) { WXTYPE type = event.GetEventType(); if (type == wxEVT_SCROLL_LINEUP) { currlayer->tlspeed--; if (currlayer->tlspeed < MINSPEED) currlayer->tlspeed = MINSPEED; } else if (type == wxEVT_SCROLL_LINEDOWN) { currlayer->tlspeed++; if (currlayer->tlspeed > MAXSPEED) currlayer->tlspeed = MAXSPEED; } else if (type == wxEVT_SCROLL_PAGEUP) { currlayer->tlspeed -= PAGESIZE; if (currlayer->tlspeed < MINSPEED) currlayer->tlspeed = MINSPEED; } else if (type == wxEVT_SCROLL_PAGEDOWN) { currlayer->tlspeed += PAGESIZE; if (currlayer->tlspeed > MAXSPEED) currlayer->tlspeed = MAXSPEED; } else if (type == wxEVT_SCROLL_THUMBTRACK) { currlayer->tlspeed = event.GetPosition(); if (currlayer->tlspeed < MINSPEED) currlayer->tlspeed = MINSPEED; if (currlayer->tlspeed > MAXSPEED) currlayer->tlspeed = MAXSPEED; } else if (type == wxEVT_SCROLL_THUMBRELEASE) { UpdateSlider(); } #ifndef __WXMAC__ viewptr->SetFocus(); // need on Win/Linux #endif } // ----------------------------------------------------------------------------- void TimelineBar::DisplayCurrentFrame() { currlayer->algo->gotoframe(currlayer->currframe); // FitInView(0) would be less jerky but has the disadvantage that // scale won't change if a pattern shrinks when going backwards if (currlayer->autofit) viewptr->FitInView(1); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void TimelineBar::OnScroll(wxScrollEvent& event) { WXTYPE type = event.GetEventType(); // best to stop autoplay if scroll bar is used if (currlayer->autoplay != 0) { currlayer->autoplay = 0; mainptr->UpdateUserInterface(); } if (type == wxEVT_SCROLL_LINEUP) { currlayer->currframe--; if (currlayer->currframe < 0) currlayer->currframe = 0; DisplayCurrentFrame(); } else if (type == wxEVT_SCROLL_LINEDOWN) { currlayer->currframe++; if (currlayer->currframe >= currlayer->algo->getframecount()) currlayer->currframe = currlayer->algo->getframecount() - 1; DisplayCurrentFrame(); } else if (type == wxEVT_SCROLL_PAGEUP) { currlayer->currframe -= PAGESIZE; if (currlayer->currframe < 0) currlayer->currframe = 0; DisplayCurrentFrame(); } else if (type == wxEVT_SCROLL_PAGEDOWN) { currlayer->currframe += PAGESIZE; if (currlayer->currframe >= currlayer->algo->getframecount()) currlayer->currframe = currlayer->algo->getframecount() - 1; DisplayCurrentFrame(); } else if (type == wxEVT_SCROLL_THUMBTRACK) { currlayer->currframe = event.GetPosition(); if (currlayer->currframe < 0) currlayer->currframe = 0; if (currlayer->currframe >= currlayer->algo->getframecount()) currlayer->currframe = currlayer->algo->getframecount() - 1; DisplayCurrentFrame(); } else if (type == wxEVT_SCROLL_THUMBRELEASE) { UpdateScrollBar(); } #ifndef __WXMAC__ viewptr->SetFocus(); // need on Win/Linux #endif } // ----------------------------------------------------------------------------- void TimelineBar::OnKillFocus(wxFocusEvent& event) { int id = event.GetId(); tlbutt[id]->SetFocus(); // don't let button lose focus } // ----------------------------------------------------------------------------- void TimelineBar::OnButtonDown(wxMouseEvent& event) { // timeline bar button has been pressed int id = event.GetId(); // connect a handler that keeps focus with the pressed button tlbutt[id]->Connect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(TimelineBar::OnKillFocus)); event.Skip(); } // ----------------------------------------------------------------------------- void TimelineBar::OnButtonUp(wxMouseEvent& event) { // timeline bar button has been released int id = event.GetId(); wxPoint pt = tlbutt[id]->ScreenToClient( wxGetMousePosition() ); int wd, ht; tlbutt[id]->GetClientSize(&wd, &ht); wxRect r(0, 0, wd, ht); // diconnect kill-focus handler tlbutt[id]->Disconnect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(TimelineBar::OnKillFocus)); viewptr->SetFocus(); if (r.Contains(pt)) { // call OnButton wxCommandEvent buttevt(wxEVT_COMMAND_BUTTON_CLICKED, id); buttevt.SetEventObject(tlbutt[id]); tlbutt[id]->GetEventHandler()->ProcessEvent(buttevt); } } // ----------------------------------------------------------------------------- void TimelineBar::AddButton(int id, const wxString& tip) { tlbutt[id] = new wxBitmapButton(this, id, normbutt[id], wxPoint(xpos,ypos), #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) wxSize(BUTTON_WD, BUTTON_HT), wxBORDER_SIMPLE #else wxSize(BUTTON_WD, BUTTON_HT) #endif ); if (tlbutt[id] == NULL) { Fatal(_("Failed to create timeline bar button!")); } else { xpos += BUTTON_WD + smallgap; tlbutt[id]->SetToolTip(tip); #ifdef __WXMSW__ // fix problem with timeline bar buttons when generating/inscript // due to focus being changed to viewptr tlbutt[id]->Connect(id, wxEVT_LEFT_DOWN, wxMouseEventHandler(TimelineBar::OnButtonDown)); tlbutt[id]->Connect(id, wxEVT_LEFT_UP, wxMouseEventHandler(TimelineBar::OnButtonUp)); #endif } } // ----------------------------------------------------------------------------- void TimelineBar::AddSeparator() { xpos += biggap - smallgap; } // ----------------------------------------------------------------------------- void TimelineBar::EnableButton(int id, bool enable) { if (enable == tlbutt[id]->IsEnabled()) return; #ifdef __WXMSW__ tlbutt[id]->SetBitmapDisabled(disnormbutt[id]); #endif tlbutt[id]->Enable(enable); } // ----------------------------------------------------------------------------- void TimelineBar::UpdateButtons() { if (currlayer->algo->isrecording()) { if (buttstate[RECORD_BUTT] != -1) { buttstate[RECORD_BUTT] = -1; tlbutt[RECORD_BUTT]->SetBitmapLabel(normbutt[STOPREC_BUTT]); tlbutt[RECORD_BUTT]->SetToolTip(_("Stop recording")); if (showtimeline) tlbutt[RECORD_BUTT]->Refresh(false); } } else { if (buttstate[RECORD_BUTT] != 1) { buttstate[RECORD_BUTT] = 1; tlbutt[RECORD_BUTT]->SetBitmapLabel(normbutt[RECORD_BUTT]); tlbutt[RECORD_BUTT]->SetToolTip(_("Start recording")); if (showtimeline) tlbutt[RECORD_BUTT]->Refresh(false); } } // these buttons are only shown if there is a timeline and we're not recording // (see DrawTimelineBar) if (TimelineExists() && !currlayer->algo->isrecording()) { if (currlayer->autoplay == 0) { if (buttstate[BACKWARDS_BUTT] != 1) { buttstate[BACKWARDS_BUTT] = 1; tlbutt[BACKWARDS_BUTT]->SetBitmapLabel(normbutt[BACKWARDS_BUTT]); tlbutt[BACKWARDS_BUTT]->SetToolTip(_("Play backwards")); if (showtimeline) tlbutt[BACKWARDS_BUTT]->Refresh(false); } if (buttstate[FORWARDS_BUTT] != 1) { buttstate[FORWARDS_BUTT] = 1; tlbutt[FORWARDS_BUTT]->SetBitmapLabel(normbutt[FORWARDS_BUTT]); tlbutt[FORWARDS_BUTT]->SetToolTip(_("Play forwards")); if (showtimeline) tlbutt[FORWARDS_BUTT]->Refresh(false); } } else if (currlayer->autoplay > 0) { if (buttstate[BACKWARDS_BUTT] != 1) { buttstate[BACKWARDS_BUTT] = 1; tlbutt[BACKWARDS_BUTT]->SetBitmapLabel(normbutt[BACKWARDS_BUTT]); tlbutt[BACKWARDS_BUTT]->SetToolTip(_("Play backwards")); if (showtimeline) tlbutt[BACKWARDS_BUTT]->Refresh(false); } if (buttstate[FORWARDS_BUTT] != -1) { buttstate[FORWARDS_BUTT] = -1; tlbutt[FORWARDS_BUTT]->SetBitmapLabel(normbutt[STOPPLAY_BUTT]); tlbutt[FORWARDS_BUTT]->SetToolTip(_("Stop playing")); if (showtimeline) tlbutt[FORWARDS_BUTT]->Refresh(false); } } else { // currlayer->autoplay < 0 if (buttstate[BACKWARDS_BUTT] != -1) { buttstate[BACKWARDS_BUTT] = -1; tlbutt[BACKWARDS_BUTT]->SetBitmapLabel(normbutt[STOPPLAY_BUTT]); tlbutt[BACKWARDS_BUTT]->SetToolTip(_("Stop playing")); if (showtimeline) tlbutt[BACKWARDS_BUTT]->Refresh(false); } if (buttstate[FORWARDS_BUTT] != 1) { buttstate[FORWARDS_BUTT] = 1; tlbutt[FORWARDS_BUTT]->SetBitmapLabel(normbutt[FORWARDS_BUTT]); tlbutt[FORWARDS_BUTT]->SetToolTip(_("Play forwards")); if (showtimeline) tlbutt[FORWARDS_BUTT]->Refresh(false); } } } } // ----------------------------------------------------------------------------- void TimelineBar::UpdateSlider() { slider->SetValue(currlayer->tlspeed); } // ----------------------------------------------------------------------------- void TimelineBar::UpdateScrollBar() { framebar->SetScrollbar(currlayer->currframe, 1, currlayer->algo->getframecount(), PAGESIZE, true); } // ----------------------------------------------------------------------------- void CreateTimelineBar(wxWindow* parent) { // create timeline bar underneath given window int wd, ht; parent->GetClientSize(&wd, &ht); tbarptr = new TimelineBar(parent, 0, ht - TBARHT, wd, TBARHT); if (tbarptr == NULL) Fatal(_("Failed to create timeline bar!")); tbarptr->Show(showtimeline); } // ----------------------------------------------------------------------------- int TimelineBarHeight() { return (showtimeline ? TBARHT : 0); } // ----------------------------------------------------------------------------- void UpdateTimelineBar() { if (tbarptr && showtimeline && !mainptr->IsIconized()) { bool active = !inscript; // may need to change bitmaps in some buttons tbarptr->UpdateButtons(); tbarptr->EnableButton(RECORD_BUTT, active && currlayer->algo->hyperCapable()); // note that slider, scroll bar and some buttons are only shown if there is // a timeline and we're not recording (see DrawTimelineBar) if (TimelineExists() && !currlayer->algo->isrecording()) { tbarptr->EnableButton(BACKWARDS_BUTT, active); tbarptr->EnableButton(FORWARDS_BUTT, active); tbarptr->EnableButton(DELETE_BUTT, active); tbarptr->UpdateSlider(); tbarptr->UpdateScrollBar(); } if (currlayer->algo->isrecording()) { // don't refresh RECORD_BUTT (otherwise button flickers on Windows) int wd, ht; tbarptr->GetClientSize(&wd, &ht); wxRect r(BUTTON_WD + tbarptr->smallgap * 2, 0, wd, ht); tbarptr->RefreshRect(r, false); } else { tbarptr->Refresh(false); } } } // ----------------------------------------------------------------------------- void ResizeTimelineBar(int y, int wd) { if (tbarptr) { tbarptr->SetSize(0, y, wd, TBARHT); // change width of scroll bar to nearly fill timeline bar wxRect r = tbarptr->framebar->GetRect(); r.width = wd - r.x - 20 - BUTTON_WD - 20; tbarptr->framebar->SetSize(r); // move DELETE_BUTT to right edge of timeline bar r = tlbutt[DELETE_BUTT]->GetRect(); r.x = wd - 20 - BUTTON_WD; if (r.x < mindelpos && TimelineExists()) r.x = mindelpos; tlbutt[DELETE_BUTT]->SetSize(r); } } // ----------------------------------------------------------------------------- void ToggleTimelineBar() { showtimeline = !showtimeline; wxRect r = bigview->GetRect(); if (showtimeline) { // show timeline bar underneath viewport window r.height -= TBARHT; ResizeTimelineBar(r.y + r.height, r.width); } else { // hide timeline bar r.height += TBARHT; } bigview->SetSize(r); tbarptr->Show(showtimeline); // needed on Windows mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void StartStopRecording() { if (!inscript && currlayer->algo->hyperCapable()) { if (currlayer->algo->isrecording()) { // terminate GeneratePattern mainptr->Stop(); } else { if (currlayer->algo->isEmpty()) { statusptr->ErrorMessage(_("There is no pattern to record.")); return; } if (!showtimeline) ToggleTimelineBar(); if (currlayer->algo->getframecount() == MAX_FRAME_COUNT) { wxString msg; msg.Printf(_("The timeline can't be extended any further (max frames = %d)."), MAX_FRAME_COUNT); statusptr->ErrorMessage(msg); return; } // record a new timeline, or extend the existing one if (currlayer->algo->startrecording(currlayer->currbase, currlayer->currexpo) > 0) { if (currlayer->algo->getGeneration() == currlayer->startgen) { // ensure the SaveStartingPattern call in DeleteTimeline will // create a new temporary .mc file (with only one frame) currlayer->savestart = true; } // temporarily disable allowundo so that GeneratePattern won't // try to save any temporary files bool saveundo = allowundo; allowundo = false; mainptr->GeneratePattern(); allowundo = saveundo; // GeneratePattern has called currlayer->algo->stoprecording() } else { // can this ever happen???!!! Warning(_("Could not start recording!")); } } } } // ----------------------------------------------------------------------------- void DeleteTimeline() { if (!inscript && TimelineExists() && !currlayer->algo->isrecording()) { if (currlayer->currframe > 0) { // tell writeNativeFormat to only save the current frame // so that the temporary .mc files created by SaveStartingPattern and // RememberGenStart/Finish won't store the entire timeline currlayer->algo->savetimelinewithframe(0); // do stuff so user can select Reset/Undo to go back to 1st frame currlayer->algo->gotoframe(0); if (currlayer->autofit) viewptr->FitInView(1); if (currlayer->algo->getGeneration() == currlayer->startgen) { mainptr->SaveStartingPattern(); } if (allowundo) currlayer->undoredo->RememberGenStart(); // return to the current frame currlayer->algo->gotoframe(currlayer->currframe); if (currlayer->autofit) viewptr->FitInView(1); if (allowundo) currlayer->undoredo->RememberGenFinish(); // restore flag that tells writeNativeFormat to save entire timeline currlayer->algo->savetimelinewithframe(1); } currlayer->algo->destroytimeline(); mainptr->UpdateUserInterface(); } } // ----------------------------------------------------------------------------- void InitTimelineFrame() { // the user has just loaded a .mc file with a timeline, // so prepare to display the first frame currlayer->algo->gotoframe(0); currlayer->currframe = 0; currlayer->autoplay = 0; currlayer->tlspeed = 0; // first frame is starting gen (needed for DeleteTimeline) currlayer->startgen = currlayer->algo->getGeneration(); // ensure SaveStartingPattern call in DeleteTimeline will create // a new temporary .mc file with one frame currlayer->savestart = true; } // ----------------------------------------------------------------------------- bool TimelineExists() { // on Linux MainFrame::OnIdle is called before currlayer is set return currlayer && currlayer->algo->getframecount() > 0; } // ----------------------------------------------------------------------------- bool AutoPlay() { // assume currlayer->algo->getframecount() > 0 if (currlayer->autoplay == 0) return false; if (currlayer->algo->isrecording()) return false; int frameinc = 1; long delay = 0; if (currlayer->tlspeed > 0) { // skip 2^tlspeed frames frameinc = 1 << currlayer->tlspeed; } if (currlayer->tlspeed < 0) { // set delay between each frame delay = 100 * (-currlayer->tlspeed); if (stopwatch->Time() - currlayer->lastframe < delay) { return true; // request another idle event } } #ifdef __WXMSW__ // need to slow things down on Windows! wxMilliSleep(20); #endif if (currlayer->autoplay > 0) { // play timeline forwards currlayer->currframe += frameinc; if (currlayer->currframe >= currlayer->algo->getframecount() - 1) { currlayer->currframe = currlayer->algo->getframecount() - 1; currlayer->autoplay = -1; // reverse direction when we hit last frame tbarptr->UpdateButtons(); } } else { // currlayer->autoplay < 0 so play timeline backwards currlayer->currframe -= frameinc; if (currlayer->currframe <= 0) { currlayer->currframe = 0; currlayer->autoplay = 1; // reverse direction when we hit first frame tbarptr->UpdateButtons(); } } tbarptr->DisplayCurrentFrame(); tbarptr->UpdateScrollBar(); currlayer->lastframe = stopwatch->Time(); return true; // request another idle event } // ----------------------------------------------------------------------------- void PlayTimeline(int direction) { if (currlayer->algo->isrecording()) return; if (direction > 0 && currlayer->autoplay > 0) { currlayer->autoplay = 0; } else if (direction < 0 && currlayer->autoplay < 0) { currlayer->autoplay = 0; } else { currlayer->autoplay = direction; } mainptr->UpdateUserInterface(); } // ----------------------------------------------------------------------------- void PlayTimelineFaster() { if (currlayer->algo->isrecording()) return; if (currlayer->tlspeed < MAXSPEED) { currlayer->tlspeed++; if (showtimeline) tbarptr->UpdateSlider(); } } // ----------------------------------------------------------------------------- void PlayTimelineSlower() { if (currlayer->algo->isrecording()) return; if (currlayer->tlspeed > MINSPEED) { currlayer->tlspeed--; if (showtimeline) tbarptr->UpdateSlider(); } } // ----------------------------------------------------------------------------- void ResetTimelineSpeed() { if (currlayer->algo->isrecording()) return; currlayer->tlspeed = 0; if (showtimeline) tbarptr->UpdateSlider(); } // ----------------------------------------------------------------------------- bool TimelineIsPlaying() { return currlayer->autoplay != 0; } golly-2.7-src/gui-wx/wxedit.cpp0000644000175000017500000010210012536111364013442 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/dcbuffer.h" // for wxBufferedPaintDC #if wxUSE_TOOLTIPS #include "wx/tooltip.h" // for wxToolTip #endif #include "bigint.h" #include "lifealgo.h" #include "wxgolly.h" // for viewptr, statusptr, mainptr #include "wxmain.h" // for mainptr->... #include "wxutils.h" // for Fatal #include "wxprefs.h" // for showedit, showallstates, etc #include "wxstatus.h" // for statusptr->... #include "wxscript.h" // for inscript #include "wxview.h" // for viewptr->... #include "wxrender.h" // for DrawOneIcon #include "wxlayer.h" // for currlayer, LayerBarHeight, SetLayerColors #include "wxundo.h" // for currlayer->undoredo->... #include "wxtimeline.h" // for TimelineExists #include "wxedit.h" // ----------------------------------------------------------------------------- enum { // ids for bitmap buttons in edit bar UNDO_BUTT = 0, REDO_BUTT, DRAW_BUTT, PICK_BUTT, SELECT_BUTT, MOVE_BUTT, ZOOMIN_BUTT, ZOOMOUT_BUTT, ALLSTATES_BUTT, NUM_BUTTONS, // must be after all buttons STATE_BAR }; // bitmaps for edit bar buttons #include "bitmaps/undo.xpm" #include "bitmaps/redo.xpm" #include "bitmaps/draw.xpm" #include "bitmaps/pick.xpm" #include "bitmaps/select.xpm" #include "bitmaps/move.xpm" #include "bitmaps/zoomin.xpm" #include "bitmaps/zoomout.xpm" #include "bitmaps/allstates.xpm" // bitmaps for down state of toggle buttons #include "bitmaps/draw_down.xpm" #include "bitmaps/pick_down.xpm" #include "bitmaps/select_down.xpm" #include "bitmaps/move_down.xpm" #include "bitmaps/zoomin_down.xpm" #include "bitmaps/zoomout_down.xpm" #include "bitmaps/allstates_down.xpm" // width and height of bitmap buttons #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) const int BUTTON_WD = 24; const int BUTTON_HT = 24; #elif defined(__WXOSX_COCOA__) || defined(__WXGTK__) const int BUTTON_WD = 28; const int BUTTON_HT = 28; #else const int BUTTON_WD = 24; const int BUTTON_HT = 24; #endif // ----------------------------------------------------------------------------- // Define edit bar window: // derive from wxPanel so we get current theme's background color on Windows class EditBar : public wxPanel { public: EditBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht); ~EditBar(); // add a bitmap button to edit bar void AddButton(int id, const wxString& tip); // add gap between buttons void AddSeparator(); // enable/disable button void EnableButton(int id, bool enable); // set state of a toggle button void SelectButton(int id, bool select); // update scroll bar void UpdateScrollBar(); // detect press and release of a bitmap button void OnButtonDown(wxMouseEvent& event); void OnButtonUp(wxMouseEvent& event); void OnKillFocus(wxFocusEvent& event); private: // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() // event handlers void OnPaint(wxPaintEvent& event); void OnMouseDown(wxMouseEvent& event); void OnButton(wxCommandEvent& event); void OnScroll(wxScrollEvent& event); void SetEditFont(wxDC& dc); void DisplayText(wxDC& dc, const wxString& s, wxCoord x, wxCoord y); void DrawAllStates(wxDC& dc, int wd); void DrawEditBar(wxDC& dc, int wd, int ht); // bitmaps for normal or down state wxBitmap normbutt[NUM_BUTTONS]; wxBitmap downbutt[NUM_BUTTONS]; #ifdef __WXMSW__ // on Windows we need bitmaps for disabled buttons wxBitmap disnormbutt[NUM_BUTTONS]; wxBitmap disdownbutt[NUM_BUTTONS]; #endif // remember state of toggle buttons to avoid unnecessary drawing; // 0 = not yet initialized, 1 = selected, -1 = not selected int buttstate[NUM_BUTTONS]; // positioning data used by AddButton and AddSeparator int ypos, xpos, smallgap, biggap; wxBitmap* editbitmap; // edit bar bitmap int editbitmapwd; // width of edit bar bitmap int editbitmapht; // height of edit bar bitmap wxRect colorbox; // box showing current color wxRect iconbox; // box showing current icon wxScrollBar* drawbar; // scroll bar for changing drawing state int firststate; // first visible state (if showing all states) int h_col1; // horizontal position of labels int h_col2; // horizontal position of info for state 0 int digitwd; // width of digit in edit bar font int digitht; // height of digit in edit bar font int textascent; // vertical adjustment used in DrawText calls wxFont* editfont; // edit bar font }; BEGIN_EVENT_TABLE(EditBar, wxPanel) EVT_PAINT ( EditBar::OnPaint) EVT_LEFT_DOWN ( EditBar::OnMouseDown) EVT_LEFT_DCLICK ( EditBar::OnMouseDown) EVT_BUTTON (wxID_ANY, EditBar::OnButton) EVT_COMMAND_SCROLL (STATE_BAR, EditBar::OnScroll) END_EVENT_TABLE() // ----------------------------------------------------------------------------- EditBar* editbarptr = NULL; // global pointer to edit bar const int BIGHT = 80; // height of edit bar if showallstates const int SMALLHT = 32; // height of edit bar if not showallstates static int editbarht; // current height (BIGHT or SMALLHT) const int LINEHT = 14; // distance between each baseline const int BASELINE1 = SMALLHT+LINEHT-1; // baseline of 1st line const int BASELINE2 = BASELINE1+LINEHT; // baseline of 2nd line const int BASELINE3 = BASELINE2+LINEHT; // baseline of 3rd line const int COLWD = 22; // column width of state/color/icon info const int BOXWD = 9; // width (and height) of small color/icon boxes const int BOXSIZE = 17; // width and height of colorbox and iconbox const int BOXGAP = 8; // gap between colorbox and iconbox const int PAGESIZE = 10; // scroll amount when paging // edit bar buttons (must be global to use Connect/Disconnect on Windows) wxBitmapButton* ebbutt[NUM_BUTTONS]; // ----------------------------------------------------------------------------- EditBar::EditBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht) : wxPanel(parent, wxID_ANY, wxPoint(xorg,yorg), wxSize(wd,ht), wxNO_FULL_REPAINT_ON_RESIZE) { #ifdef __WXGTK__ // avoid erasing background on GTK+ SetBackgroundStyle(wxBG_STYLE_CUSTOM); #endif // init bitmaps for normal state normbutt[UNDO_BUTT] = XPM_BITMAP(undo); normbutt[REDO_BUTT] = XPM_BITMAP(redo); normbutt[DRAW_BUTT] = XPM_BITMAP(draw); normbutt[PICK_BUTT] = XPM_BITMAP(pick); normbutt[SELECT_BUTT] = XPM_BITMAP(select); normbutt[MOVE_BUTT] = XPM_BITMAP(move); normbutt[ZOOMIN_BUTT] = XPM_BITMAP(zoomin); normbutt[ZOOMOUT_BUTT] = XPM_BITMAP(zoomout); normbutt[ALLSTATES_BUTT] = XPM_BITMAP(allstates); // toggle buttons also have a down state downbutt[DRAW_BUTT] = XPM_BITMAP(draw_down); downbutt[PICK_BUTT] = XPM_BITMAP(pick_down); downbutt[SELECT_BUTT] = XPM_BITMAP(select_down); downbutt[MOVE_BUTT] = XPM_BITMAP(move_down); downbutt[ZOOMIN_BUTT] = XPM_BITMAP(zoomin_down); downbutt[ZOOMOUT_BUTT] = XPM_BITMAP(zoomout_down); downbutt[ALLSTATES_BUTT] = XPM_BITMAP(allstates_down); #ifdef __WXMSW__ for (int i = 0; i < NUM_BUTTONS; i++) { CreatePaleBitmap(normbutt[i], disnormbutt[i]); } CreatePaleBitmap(downbutt[DRAW_BUTT], disdownbutt[DRAW_BUTT]); CreatePaleBitmap(downbutt[PICK_BUTT], disdownbutt[PICK_BUTT]); CreatePaleBitmap(downbutt[SELECT_BUTT], disdownbutt[SELECT_BUTT]); CreatePaleBitmap(downbutt[MOVE_BUTT], disdownbutt[MOVE_BUTT]); CreatePaleBitmap(downbutt[ZOOMIN_BUTT], disdownbutt[ZOOMIN_BUTT]); CreatePaleBitmap(downbutt[ZOOMOUT_BUTT], disdownbutt[ZOOMOUT_BUTT]); CreatePaleBitmap(downbutt[ALLSTATES_BUTT], disdownbutt[ALLSTATES_BUTT]); #endif for (int i = 0; i < NUM_BUTTONS; i++) { buttstate[i] = 0; } // init position variables used by AddButton and AddSeparator #ifdef __WXGTK__ // buttons are a different size in wxGTK xpos = 2; ypos = 2; smallgap = 6; #else xpos = 4; ypos = (32 - BUTTON_HT) / 2; smallgap = 4; #endif biggap = 16; // add buttons AddButton(UNDO_BUTT, _("Undo")); AddButton(REDO_BUTT, _("Redo")); AddSeparator(); AddButton(DRAW_BUTT, _("Draw")); AddButton(PICK_BUTT, _("Pick")); AddButton(SELECT_BUTT, _("Select")); AddButton(MOVE_BUTT, _("Move")); AddButton(ZOOMIN_BUTT, _("Zoom in")); AddButton(ZOOMOUT_BUTT, _("Zoom out")); AddSeparator(); AddButton(ALLSTATES_BUTT, _("Show/hide all states")); // create font for text in edit bar and set textascent for use in DisplayText #ifdef __WXMSW__ // use smaller, narrower font on Windows editfont = wxFont::New(8, wxDEFAULT, wxNORMAL, wxNORMAL); int major, minor; wxGetOsVersion(&major, &minor); if ( major > 5 || (major == 5 && minor >= 1) ) { // 5.1+ means XP or later (Vista if major >= 6) textascent = 11; } else { textascent = 10; } #elif defined(__WXGTK__) // use smaller font on GTK editfont = wxFont::New(8, wxMODERN, wxNORMAL, wxNORMAL); textascent = 11; #elif defined(__WXOSX_COCOA__) // we need to specify facename to get Monaco instead of Courier editfont = wxFont::New(10, wxMODERN, wxNORMAL, wxNORMAL, false, wxT("Monaco")); textascent = 10; #elif defined(__WXMAC__) editfont = wxFont::New(10, wxMODERN, wxNORMAL, wxNORMAL); textascent = 10; #else editfont = wxFont::New(10, wxMODERN, wxNORMAL, wxNORMAL); textascent = 10; #endif if (editfont == NULL) Fatal(_("Failed to create edit bar font!")); // determine horizontal offsets for info in edit bar wxClientDC dc(this); int textwd, textht; SetEditFont(dc); h_col1 = 4; dc.GetTextExtent(_("State:"), &textwd, &textht); h_col2 = h_col1 + textwd + 4; dc.GetTextExtent(_("9"), &digitwd, &digitht); digitht -= 4; editbitmap = NULL; editbitmapwd = -1; editbitmapht = -1; // add scroll bar int scrollbarwd = 100; #ifdef __WXMAC__ int scrollbarht = 15; // must be this height on Mac #else int scrollbarht = BOXSIZE; #endif int x = xpos + 3*digitwd + BOXGAP + 2*(BOXSIZE + BOXGAP); int y = (SMALLHT - (scrollbarht + 1)) / 2; drawbar = new wxScrollBar(this, STATE_BAR, wxPoint(x, y), wxSize(scrollbarwd, scrollbarht), wxSB_HORIZONTAL); if (drawbar == NULL) Fatal(_("Failed to create scroll bar!")); firststate = 0; } // ----------------------------------------------------------------------------- EditBar::~EditBar() { delete editfont; delete editbitmap; delete drawbar; } // ----------------------------------------------------------------------------- void EditBar::SetEditFont(wxDC& dc) { dc.SetFont(*editfont); dc.SetTextForeground(*wxBLACK); dc.SetBrush(*wxBLACK_BRUSH); dc.SetBackgroundMode(wxTRANSPARENT); } // ----------------------------------------------------------------------------- void EditBar::DisplayText(wxDC& dc, const wxString& s, wxCoord x, wxCoord y) { // DrawText's y parameter is top of text box but we pass in baseline // so adjust by textascent which depends on platform and OS version -- yuk! dc.DrawText(s, x, y - textascent); } // ----------------------------------------------------------------------------- void EditBar::DrawAllStates(wxDC& dc, int wd) { DisplayText(dc, _("State:"), h_col1, BASELINE1); DisplayText(dc, _("Color:"), h_col1, BASELINE2); DisplayText(dc, _("Icon:"), h_col1, BASELINE3); wxBitmap** iconmaps = currlayer->icons7x7; dc.SetPen(*wxBLACK_PEN); // calculate number of (completely) visible states int visstates = (wd - h_col2) / COLWD; if (visstates >= currlayer->algo->NumCellStates()) { // all states are visible firststate = 0; visstates = currlayer->algo->NumCellStates(); } else { // change firststate if necessary so that drawing state is visible if (currlayer->drawingstate < firststate) { firststate = currlayer->drawingstate; } else if (currlayer->drawingstate >= firststate + visstates) { firststate = currlayer->drawingstate - visstates + 1; } // may need to reduce firststate if window width has increased if (firststate + visstates >= currlayer->algo->NumCellStates()) { firststate = currlayer->algo->NumCellStates() - visstates; } } // add 1 to visstates so we see partial box at right edge for (int i = firststate; i < firststate + visstates + 1; i++) { // this test is needed because we added 1 to visstates if (i >= currlayer->algo->NumCellStates()) break; wxString strbuf; wxRect r; int x; // draw state value strbuf.Printf(_("%d"), i); x = (int)(h_col2 + (i - firststate) * COLWD + (COLWD - strbuf.length() * digitwd) / 2); DisplayText(dc, strbuf, x, BASELINE1); // draw color box x = 1 + h_col2 + (i - firststate) * COLWD + (COLWD - BOXWD) / 2; wxColor color(currlayer->cellr[i], currlayer->cellg[i], currlayer->cellb[i]); r = wxRect(x, BASELINE2 - BOXWD, BOXWD, BOXWD); dc.SetBrush(wxBrush(color)); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); // draw icon box r = wxRect(x, BASELINE3 - BOXWD, BOXWD, BOXWD); if (iconmaps && iconmaps[i]) { dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); DrawOneIcon(dc, x + 1, BASELINE3 - BOXWD + 1, iconmaps[i], currlayer->cellr[0], currlayer->cellg[0], currlayer->cellb[0], currlayer->cellr[i], currlayer->cellg[i], currlayer->cellb[i], currlayer->multicoloricons); } else { dc.SetBrush(wxBrush(color)); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } } // draw rect around current drawing state if (currlayer->drawingstate >= firststate && currlayer->drawingstate <= firststate + visstates) { int x = 1 + h_col2 + (currlayer->drawingstate - firststate) * COLWD; #ifdef __WXGTK__ wxRect r(x, SMALLHT + 1, COLWD - 1, BIGHT - SMALLHT - 5); #else wxRect r(x, SMALLHT + 2, COLWD - 1, BIGHT - SMALLHT - 5); #endif dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } dc.SetPen(wxNullPen); } // ----------------------------------------------------------------------------- void EditBar::DrawEditBar(wxDC& dc, int wd, int ht) { wxRect r = wxRect(0, 0, wd, ht); #ifdef __WXMAC__ wxBrush brush(wxColor(202,202,202)); FillRect(dc, r, brush); #endif #ifdef __WXMSW__ // use theme background color on Windows wxBrush brush(GetBackgroundColour()); FillRect(dc, r, brush); #endif // draw gray border line at bottom edge #if defined(__WXMSW__) dc.SetPen(*wxGREY_PEN); #elif defined(__WXMAC__) wxPen linepen(wxColor(140,140,140)); dc.SetPen(linepen); #else dc.SetPen(*wxLIGHT_GREY_PEN); #endif dc.DrawLine(0, r.GetBottom(), r.width, r.GetBottom()); dc.SetPen(wxNullPen); // reset drawing state in case it's no longer valid (due to algo/rule change) if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) { currlayer->drawingstate = 1; } SetEditFont(dc); // for DisplayText calls if (showallstates) DrawAllStates(dc, wd); dc.SetPen(*wxBLACK_PEN); // draw current drawing state int state = currlayer->drawingstate; int x = xpos; int y = SMALLHT - 8; wxString strbuf; if (state < 10) x += digitwd; if (state < 100) x += digitwd; strbuf.Printf(_("%d"), state); DisplayText(dc, strbuf, x, y - (BOXSIZE - digitht)/2); wxColor cellcolor(currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state]); // draw color box x = xpos + 3*digitwd + BOXGAP; colorbox = wxRect(x, y - BOXSIZE, BOXSIZE, BOXSIZE); dc.SetBrush(wxBrush(cellcolor)); dc.DrawRectangle(colorbox); dc.SetBrush(wxNullBrush); // draw icon box wxBitmap** iconmaps = currlayer->icons15x15; x += BOXSIZE + BOXGAP; iconbox = wxRect(x, y - BOXSIZE, BOXSIZE, BOXSIZE); if (iconmaps && iconmaps[state]) { dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRectangle(iconbox); dc.SetBrush(wxNullBrush); DrawOneIcon(dc, x + 1, y - BOXSIZE + 1, iconmaps[state], currlayer->cellr[0], currlayer->cellg[0], currlayer->cellb[0], currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state], currlayer->multicoloricons); } else { dc.SetBrush(wxBrush(cellcolor)); dc.DrawRectangle(iconbox); dc.SetBrush(wxNullBrush); } // show whether color or icon mode is selected dc.SetBrush(*wxTRANSPARENT_BRUSH); if (showicons) { iconbox.Inflate(2,2); dc.DrawRectangle(iconbox); iconbox.Inflate(-2,-2); } else { colorbox.Inflate(2,2); dc.DrawRectangle(colorbox); colorbox.Inflate(-2,-2); } dc.SetBrush(wxNullBrush); dc.SetPen(wxNullPen); } // ----------------------------------------------------------------------------- void EditBar::OnPaint(wxPaintEvent& WXUNUSED(event)) { int wd, ht; GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; #if defined(__WXMAC__) || defined(__WXGTK__) // windows on Mac OS X and GTK+ 2.0 are automatically buffered wxPaintDC dc(this); #else // use wxWidgets buffering to avoid flicker if (wd != editbitmapwd || ht != editbitmapht) { // need to create a new bitmap for edit bar delete editbitmap; editbitmap = new wxBitmap(wd, ht); editbitmapwd = wd; editbitmapht = ht; } if (editbitmap == NULL) Fatal(_("Not enough memory to render edit bar!")); wxBufferedPaintDC dc(this, *editbitmap); #endif if (showedit) DrawEditBar(dc, wd, ht); } // ----------------------------------------------------------------------------- void EditBar::OnMouseDown(wxMouseEvent& event) { // on Win/Linux we need to reset keyboard focus to viewport window viewptr->SetFocus(); mainptr->showbanner = false; statusptr->ClearMessage(); if (inscript) return; // let script control drawing state int x = event.GetX(); int y = event.GetY(); if (showallstates) { // user can change drawing state by clicking in appropriate box int right = h_col2 + COLWD * currlayer->algo->NumCellStates(); int box = -1; if (x > h_col2 && x < right && y > SMALLHT) { box = (x - h_col2) / COLWD + firststate; } if (box >= 0 && box < currlayer->algo->NumCellStates() && currlayer->drawingstate != box) { currlayer->drawingstate = box; Refresh(false); UpdateScrollBar(); return; } } if (event.LeftDClick()) { // open Set Layer Colors dialog if user double-clicks in color/icon box if (colorbox.Contains(x,y) || iconbox.Contains(x,y)) { SetLayerColors(); } } else { // user can change color/icon mode by clicking in color/icon box if (colorbox.Contains(x,y) && showicons) { viewptr->ToggleCellIcons(); } else if (iconbox.Contains(x,y) && !showicons) { viewptr->ToggleCellIcons(); } } } // ----------------------------------------------------------------------------- void EditBar::OnButton(wxCommandEvent& event) { #ifdef __WXMAC__ // close any open tool tip window (fixes wxMac bug?) wxToolTip::RemoveToolTips(); #endif mainptr->showbanner = false; statusptr->ClearMessage(); int id = event.GetId(); int cmdid; switch (id) { case UNDO_BUTT: cmdid = ID_UNDO; break; case REDO_BUTT: cmdid = ID_REDO; break; case DRAW_BUTT: cmdid = ID_DRAW; break; case PICK_BUTT: cmdid = ID_PICK; break; case SELECT_BUTT: cmdid = ID_SELECT; break; case MOVE_BUTT: cmdid = ID_MOVE; break; case ZOOMIN_BUTT: cmdid = ID_ZOOMIN; break; case ZOOMOUT_BUTT: cmdid = ID_ZOOMOUT; break; case ALLSTATES_BUTT: cmdid = ID_ALL_STATES; break; default: Warning(_("Unexpected button id!")); return; } // call MainFrame::OnMenu after OnButton finishes wxCommandEvent cmdevt(wxEVT_COMMAND_MENU_SELECTED, cmdid); wxPostEvent(mainptr->GetEventHandler(), cmdevt); // avoid possible problems viewptr->SetFocus(); } // ----------------------------------------------------------------------------- void EditBar::OnScroll(wxScrollEvent& event) { WXTYPE type = event.GetEventType(); if (type == wxEVT_SCROLL_LINEUP) { currlayer->drawingstate--; if (currlayer->drawingstate < 0) currlayer->drawingstate = 0; Refresh(false); } else if (type == wxEVT_SCROLL_LINEDOWN) { currlayer->drawingstate++; if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) currlayer->drawingstate = currlayer->algo->NumCellStates() - 1; Refresh(false); } else if (type == wxEVT_SCROLL_PAGEUP) { currlayer->drawingstate -= PAGESIZE; if (currlayer->drawingstate < 0) currlayer->drawingstate = 0; Refresh(false); } else if (type == wxEVT_SCROLL_PAGEDOWN) { currlayer->drawingstate += PAGESIZE; if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) currlayer->drawingstate = currlayer->algo->NumCellStates() - 1; Refresh(false); } else if (type == wxEVT_SCROLL_THUMBTRACK) { currlayer->drawingstate = event.GetPosition(); if (currlayer->drawingstate < 0) currlayer->drawingstate = 0; if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) currlayer->drawingstate = currlayer->algo->NumCellStates() - 1; Refresh(false); } else if (type == wxEVT_SCROLL_THUMBRELEASE) { UpdateScrollBar(); } #ifndef __WXMAC__ viewptr->SetFocus(); // need on Win/Linux #endif } // ----------------------------------------------------------------------------- void EditBar::OnKillFocus(wxFocusEvent& event) { int id = event.GetId(); ebbutt[id]->SetFocus(); // don't let button lose focus } // ----------------------------------------------------------------------------- void EditBar::OnButtonDown(wxMouseEvent& event) { // edit bar button has been pressed int id = event.GetId(); // connect a handler that keeps focus with the pressed button ebbutt[id]->Connect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(EditBar::OnKillFocus)); event.Skip(); } // ----------------------------------------------------------------------------- void EditBar::OnButtonUp(wxMouseEvent& event) { // edit bar button has been released int id = event.GetId(); wxPoint pt = ebbutt[id]->ScreenToClient( wxGetMousePosition() ); int wd, ht; ebbutt[id]->GetClientSize(&wd, &ht); wxRect r(0, 0, wd, ht); // diconnect kill-focus handler ebbutt[id]->Disconnect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(EditBar::OnKillFocus)); viewptr->SetFocus(); if (r.Contains(pt)) { // call OnButton wxCommandEvent buttevt(wxEVT_COMMAND_BUTTON_CLICKED, id); buttevt.SetEventObject(ebbutt[id]); ebbutt[id]->GetEventHandler()->ProcessEvent(buttevt); } } // ----------------------------------------------------------------------------- void EditBar::AddButton(int id, const wxString& tip) { ebbutt[id] = new wxBitmapButton(this, id, normbutt[id], wxPoint(xpos,ypos), #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) wxSize(BUTTON_WD, BUTTON_HT), wxBORDER_SIMPLE #else wxSize(BUTTON_WD, BUTTON_HT) #endif ); if (ebbutt[id] == NULL) { Fatal(_("Failed to create edit bar button!")); } else { xpos += BUTTON_WD + smallgap; ebbutt[id]->SetToolTip(tip); #ifdef __WXMSW__ // fix problem with edit bar buttons when generating/inscript // due to focus being changed to viewptr ebbutt[id]->Connect(id, wxEVT_LEFT_DOWN, wxMouseEventHandler(EditBar::OnButtonDown)); ebbutt[id]->Connect(id, wxEVT_LEFT_UP, wxMouseEventHandler(EditBar::OnButtonUp)); #endif } } // ----------------------------------------------------------------------------- void EditBar::AddSeparator() { xpos += biggap - smallgap; } // ----------------------------------------------------------------------------- void EditBar::EnableButton(int id, bool enable) { if (enable == ebbutt[id]->IsEnabled()) return; #ifdef __WXMSW__ if (id == DRAW_BUTT && currlayer->curs == curs_pencil) { ebbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else if (id == PICK_BUTT && currlayer->curs == curs_pick) { ebbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else if (id == SELECT_BUTT && currlayer->curs == curs_cross) { ebbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else if (id == MOVE_BUTT && currlayer->curs == curs_hand) { ebbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else if (id == ZOOMIN_BUTT && currlayer->curs == curs_zoomin) { ebbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else if (id == ZOOMOUT_BUTT && currlayer->curs == curs_zoomout) { ebbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else if (id == ALLSTATES_BUTT && showallstates) { ebbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else { ebbutt[id]->SetBitmapDisabled(disnormbutt[id]); } #endif ebbutt[id]->Enable(enable); } // ----------------------------------------------------------------------------- void EditBar::SelectButton(int id, bool select) { if (select) { if (buttstate[id] == 1) return; buttstate[id] = 1; ebbutt[id]->SetBitmapLabel(downbutt[id]); } else { if (buttstate[id] == -1) return; buttstate[id] = -1; ebbutt[id]->SetBitmapLabel(normbutt[id]); } ebbutt[id]->Refresh(false); } // ----------------------------------------------------------------------------- void EditBar::UpdateScrollBar() { drawbar->SetScrollbar(currlayer->drawingstate, 1, currlayer->algo->NumCellStates(), PAGESIZE, true); } // ----------------------------------------------------------------------------- void CreateEditBar(wxWindow* parent) { // create edit bar underneath layer bar int wd, ht; parent->GetClientSize(&wd, &ht); editbarht = showallstates ? BIGHT : SMALLHT; editbarptr = new EditBar(parent, 0, LayerBarHeight(), wd, editbarht); if (editbarptr == NULL) Fatal(_("Failed to create edit bar!")); editbarptr->Show(showedit); } // ----------------------------------------------------------------------------- int EditBarHeight() { return (showedit ? editbarht : 0); } // ----------------------------------------------------------------------------- void ResizeEditBar(int wd) { if (editbarptr) { editbarptr->SetSize(wd, editbarht); } } // ----------------------------------------------------------------------------- void UpdateEditBar() { if (editbarptr && showedit) { bool active = !viewptr->waitingforclick; bool timeline = TimelineExists(); // set state of toggle buttons editbarptr->SelectButton(DRAW_BUTT, currlayer->curs == curs_pencil); editbarptr->SelectButton(PICK_BUTT, currlayer->curs == curs_pick); editbarptr->SelectButton(SELECT_BUTT, currlayer->curs == curs_cross); editbarptr->SelectButton(MOVE_BUTT, currlayer->curs == curs_hand); editbarptr->SelectButton(ZOOMIN_BUTT, currlayer->curs == curs_zoomin); editbarptr->SelectButton(ZOOMOUT_BUTT, currlayer->curs == curs_zoomout); editbarptr->SelectButton(ALLSTATES_BUTT, showallstates); // CanUndo() returns false if drawing/selecting cells so the user can't undo // while in those modes (by pressing a key), but we want the Undo button to // appear to be active bool canundo = (allowundo && (viewptr->drawingcells || viewptr->selectingcells)) || currlayer->undoredo->CanUndo(); editbarptr->EnableButton(UNDO_BUTT, active && !timeline && canundo); editbarptr->EnableButton(REDO_BUTT, active && !timeline && currlayer->undoredo->CanRedo()); editbarptr->EnableButton(DRAW_BUTT, active); editbarptr->EnableButton(PICK_BUTT, active); editbarptr->EnableButton(SELECT_BUTT, active); editbarptr->EnableButton(MOVE_BUTT, active); editbarptr->EnableButton(ZOOMIN_BUTT, active); editbarptr->EnableButton(ZOOMOUT_BUTT, active); editbarptr->EnableButton(ALLSTATES_BUTT, active); editbarptr->Refresh(false); // drawing state might have changed editbarptr->UpdateScrollBar(); } } // ----------------------------------------------------------------------------- void ToggleEditBar() { showedit = !showedit; wxRect r = bigview->GetRect(); if (showedit) { // show edit bar at top of viewport window or underneath layer bar r.y += editbarht; r.height -= editbarht; ResizeEditBar(r.width); } else { // hide edit bar r.y -= editbarht; r.height += editbarht; } bigview->SetSize(r); editbarptr->Show(showedit); // needed on Windows if (showlayer) { // line at bottom of layer bar may need to be added/removed RedrawLayerBar(); } mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void ToggleAllStates() { showallstates = !showallstates; editbarht = showallstates ? BIGHT : SMALLHT; if (showedit) { int diff = BIGHT - SMALLHT; if (!showallstates) diff *= -1; wxRect r = bigview->GetRect(); ResizeEditBar(r.width); r.y += diff; r.height -= diff; bigview->SetSize(r); mainptr->UpdateEverything(); } else if (showallstates) { // show the edit bar using new height ToggleEditBar(); } else { mainptr->UpdateMenuItems(); } } // ----------------------------------------------------------------------------- void ShiftEditBar(int yamount) { int x, y; editbarptr->GetPosition(&x, &y); editbarptr->Move(x, y + yamount); } // ----------------------------------------------------------------------------- void CycleDrawingState(bool higher) { if (viewptr->drawingcells) return; int maxstate = currlayer->algo->NumCellStates() - 1; if (higher) { if (currlayer->drawingstate == maxstate) currlayer->drawingstate = 0; else currlayer->drawingstate++; } else { if (currlayer->drawingstate == 0) currlayer->drawingstate = maxstate; else currlayer->drawingstate--; } if (showedit) { editbarptr->Refresh(false); editbarptr->UpdateScrollBar(); } } golly-2.7-src/gui-wx/wxlayer.cpp0000644000175000017500000035162512536111364013653 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #if wxUSE_TOOLTIPS #include "wx/tooltip.h" // for wxToolTip #endif #include "wx/rawbmp.h" // for wxAlphaPixelData #include "wx/filename.h" // for wxFileName #include "wx/colordlg.h" // for wxColourDialog #include "wx/tglbtn.h" // for wxToggleButton #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "viewport.h" #include "util.h" // for linereader #include "wxgolly.h" // for wxGetApp, mainptr, viewptr, bigview, statusptr #include "wxmain.h" // for mainptr->... #include "wxedit.h" // for ShiftEditBar #include "wxselect.h" // for Selection #include "wxview.h" // for viewptr->... #include "wxstatus.h" // for statusptr->... #include "wxutils.h" // for Warning, FillRect, CreatePaleBitmap, etc #include "wxrender.h" // for DrawOneIcon #include "wxprefs.h" // for initrule, swapcolors, userrules, rulesdir, etc #include "wxscript.h" // for inscript #include "wxundo.h" // for UndoRedo, etc #include "wxalgos.h" // for algo_type, initalgo, algoinfo, CreateNewUniverse, etc #include "wxlayer.h" #ifdef _MSC_VER #pragma warning(disable:4702) // disable "unreachable code" warnings from MSVC #endif #include // for std::map #ifdef _MSC_VER #pragma warning(default:4702) // enable "unreachable code" warnings #endif #ifdef __WXMAC__ // we need to convert filepath to decomposed UTF8 so fopen will work #define OPENFILE(filepath) fopen(filepath.fn_str(),"r") #else #define OPENFILE(filepath) fopen(filepath.mb_str(wxConvLocal),"r") #endif // ----------------------------------------------------------------------------- const int layerbarht = 32; // height of layer bar int numlayers = 0; // number of existing layers int numclones = 0; // number of cloned layers int currindex = -1; // index of current layer Layer* currlayer = NULL; // pointer to current layer Layer* layer[MAX_LAYERS]; // array of layers bool cloneavail[MAX_LAYERS]; // for setting unique cloneid bool cloning = false; // adding a cloned layer? bool duplicating = false; // adding a duplicated layer? algo_type oldalgo; // algorithm in old layer wxString oldrule; // rule in old layer int oldmag; // scale in old layer bigint oldx; // X position in old layer bigint oldy; // Y position in old layer wxCursor* oldcurs; // cursor mode in old layer // ids for bitmap buttons in layer bar enum { LAYER_0 = 0, // LAYER_0 must be first id LAYER_LAST = LAYER_0 + MAX_LAYERS - 1, ADD_LAYER, CLONE_LAYER, DUPLICATE_LAYER, DELETE_LAYER, STACK_LAYERS, TILE_LAYERS, NUM_BUTTONS // must be last }; // bitmaps for layer bar buttons #include "bitmaps/add.xpm" #include "bitmaps/clone.xpm" #include "bitmaps/duplicate.xpm" #include "bitmaps/delete.xpm" #include "bitmaps/stack.xpm" #include "bitmaps/stack_down.xpm" #include "bitmaps/tile.xpm" #include "bitmaps/tile_down.xpm" // ----------------------------------------------------------------------------- // Define layer bar window: // derive from wxPanel so we get current theme's background color on Windows class LayerBar : public wxPanel { public: LayerBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht); ~LayerBar() {} // add a button to layer bar void AddButton(int id, const wxString& tip); // add a horizontal gap between buttons void AddSeparator(); // enable/disable button void EnableButton(int id, bool enable); // set state of a toggle button void SelectButton(int id, bool select); // might need to expand/shrink width of layer buttons void ResizeLayerButtons(); // detect press and release of button void OnButtonDown(wxMouseEvent& event); void OnButtonUp(wxMouseEvent& event); void OnMouseMotion(wxMouseEvent& event); void OnKillFocus(wxFocusEvent& event); private: // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() // event handlers void OnPaint(wxPaintEvent& event); void OnSize(wxSizeEvent& event); void OnMouseDown(wxMouseEvent& event); void OnButton(wxCommandEvent& event); // bitmaps for normal or down state wxBitmap normbutt[NUM_BUTTONS]; wxBitmap downbutt[NUM_BUTTONS]; #ifdef __WXMSW__ // on Windows we need bitmaps for disabled buttons wxBitmap disnormbutt[NUM_BUTTONS]; wxBitmap disdownbutt[NUM_BUTTONS]; #endif // positioning data used by AddButton and AddSeparator int ypos, xpos, smallgap, biggap; int downid; // id of currently pressed layer button int currbuttwd; // current width of each layer button }; BEGIN_EVENT_TABLE(LayerBar, wxPanel) EVT_PAINT ( LayerBar::OnPaint) EVT_SIZE ( LayerBar::OnSize) EVT_LEFT_DOWN ( LayerBar::OnMouseDown) EVT_BUTTON (wxID_ANY, LayerBar::OnButton) EVT_TOGGLEBUTTON (wxID_ANY, LayerBar::OnButton) END_EVENT_TABLE() static LayerBar* layerbarptr = NULL; // global pointer to layer bar // layer bar buttons must be global to use Connect/Disconnect on Windows; // note that bitmapbutt[0..MAX_LAYERS-1] are not used, but it simplifies // our logic to have those dummy indices static wxBitmapButton* bitmapbutt[NUM_BUTTONS] = {NULL}; static wxToggleButton* togglebutt[MAX_LAYERS] = {NULL}; // width and height of toggle buttons const int MAX_TOGGLE_WD = 128; const int MIN_TOGGLE_WD = 48; #if defined(__WXMSW__) const int TOGGLE_HT = 22; #elif defined(__WXGTK__) const int TOGGLE_HT = 24; #elif defined(__WXOSX_COCOA__) && !wxCHECK_VERSION(3,0,0) const int TOGGLE_HT = 24; #else const int TOGGLE_HT = 20; #endif // width and height of bitmap buttons #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) const int BUTTON_WD = 24; const int BUTTON_HT = 24; #elif defined(__WXOSX_COCOA__) || defined(__WXGTK__) const int BUTTON_WD = 28; const int BUTTON_HT = 28; #else const int BUTTON_WD = 24; const int BUTTON_HT = 24; #endif const wxString SWITCH_LAYER = _("Switch to this layer"); // ----------------------------------------------------------------------------- LayerBar::LayerBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht) : wxPanel(parent, wxID_ANY, wxPoint(xorg,yorg), wxSize(wd,ht), wxNO_FULL_REPAINT_ON_RESIZE) { #ifdef __WXGTK__ // avoid erasing background on GTK+ SetBackgroundStyle(wxBG_STYLE_CUSTOM); #endif // init bitmaps for normal state normbutt[ADD_LAYER] = XPM_BITMAP(add); normbutt[ADD_LAYER] = XPM_BITMAP(add); normbutt[CLONE_LAYER] = XPM_BITMAP(clone); normbutt[DUPLICATE_LAYER] = XPM_BITMAP(duplicate); normbutt[DELETE_LAYER] = XPM_BITMAP(delete); normbutt[STACK_LAYERS] = XPM_BITMAP(stack); normbutt[TILE_LAYERS] = XPM_BITMAP(tile); // some bitmap buttons also have a down state downbutt[STACK_LAYERS] = XPM_BITMAP(stack_down); downbutt[TILE_LAYERS] = XPM_BITMAP(tile_down); #ifdef __WXMSW__ // create bitmaps for disabled buttons CreatePaleBitmap(normbutt[ADD_LAYER], disnormbutt[ADD_LAYER]); CreatePaleBitmap(normbutt[CLONE_LAYER], disnormbutt[CLONE_LAYER]); CreatePaleBitmap(normbutt[DUPLICATE_LAYER], disnormbutt[DUPLICATE_LAYER]); CreatePaleBitmap(normbutt[DELETE_LAYER], disnormbutt[DELETE_LAYER]); CreatePaleBitmap(normbutt[STACK_LAYERS], disnormbutt[STACK_LAYERS]); CreatePaleBitmap(normbutt[TILE_LAYERS], disnormbutt[TILE_LAYERS]); // create bitmaps for disabled buttons in down state CreatePaleBitmap(downbutt[STACK_LAYERS], disdownbutt[STACK_LAYERS]); CreatePaleBitmap(downbutt[TILE_LAYERS], disdownbutt[TILE_LAYERS]); #endif // init position variables used by AddButton and AddSeparator biggap = 16; #ifdef __WXGTK__ // buttons are a different size in wxGTK xpos = 2; ypos = 2; smallgap = 6; #else xpos = 4; ypos = (32 - BUTTON_HT) / 2; smallgap = 4; #endif downid = -1; // no layer button down as yet currbuttwd = MAX_TOGGLE_WD; } // ----------------------------------------------------------------------------- void LayerBar::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); int wd, ht; GetClientSize(&wd, &ht); if (wd < 1 || ht < 1 || !showlayer) return; #ifdef __WXMSW__ // needed on Windows dc.Clear(); #endif wxRect r = wxRect(0, 0, wd, ht); #ifdef __WXMAC__ wxBrush brush(wxColor(202,202,202)); FillRect(dc, r, brush); #endif if (!showedit) { // draw gray border line at bottom edge #if defined(__WXMSW__) dc.SetPen(*wxGREY_PEN); #elif defined(__WXMAC__) wxPen linepen(wxColor(140,140,140)); dc.SetPen(linepen); #else dc.SetPen(*wxLIGHT_GREY_PEN); #endif dc.DrawLine(0, r.GetBottom(), r.width, r.GetBottom()); dc.SetPen(wxNullPen); } } // ----------------------------------------------------------------------------- void LayerBar::OnSize(wxSizeEvent& event) { ResizeLayerButtons(); event.Skip(); } // ----------------------------------------------------------------------------- void LayerBar::ResizeLayerButtons() { // might need to expand/shrink width of layer button(s) if (layerbarptr) { int wd, ht; GetClientSize(&wd, &ht); wxRect r1 = togglebutt[0]->GetRect(); int x = r1.GetLeft(); int y = r1.GetTop(); const int rgap = 4; int viswidth = wd - x - rgap; int oldbuttwd = currbuttwd; if (numlayers*currbuttwd <= viswidth) { // all layer buttons are visible so try to expand widths while (currbuttwd < MAX_TOGGLE_WD && numlayers*(currbuttwd+1) <= viswidth) { currbuttwd++; } } else { // try to reduce widths until all layer buttons are visible while (currbuttwd > MIN_TOGGLE_WD && numlayers*currbuttwd > viswidth) { currbuttwd--; } } if (currbuttwd != oldbuttwd) { for (int i = 0; i < MAX_LAYERS; i++) { togglebutt[i]->SetSize(x, y, currbuttwd, TOGGLE_HT); #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) // ensure there is a gap between buttons togglebutt[i]->SetSize(x, y, currbuttwd-4, TOGGLE_HT); #else togglebutt[i]->SetSize(x, y, currbuttwd, TOGGLE_HT); #endif x += currbuttwd; } } } } // ----------------------------------------------------------------------------- void LayerBar::OnMouseDown(wxMouseEvent& WXUNUSED(event)) { // this is NOT called if user clicks a layer bar button; // on Windows we need to reset keyboard focus to viewport window viewptr->SetFocus(); mainptr->showbanner = false; statusptr->ClearMessage(); } // ----------------------------------------------------------------------------- void LayerBar::OnButton(wxCommandEvent& event) { #ifdef __WXMAC__ // close any open tool tip window (fixes wxMac bug?) wxToolTip::RemoveToolTips(); #endif mainptr->showbanner = false; statusptr->ClearMessage(); int id = event.GetId(); #ifdef __WXMSW__ // disconnect focus handler and reset focus to viewptr; // we must do latter before button becomes disabled if (id < MAX_LAYERS) { togglebutt[id]->Disconnect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(LayerBar::OnKillFocus)); } else { bitmapbutt[id]->Disconnect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(LayerBar::OnKillFocus)); } viewptr->SetFocus(); #endif switch (id) { case ADD_LAYER: AddLayer(); break; case CLONE_LAYER: CloneLayer(); break; case DUPLICATE_LAYER: DuplicateLayer(); break; case DELETE_LAYER: DeleteLayer(); break; case STACK_LAYERS: ToggleStackLayers(); break; case TILE_LAYERS: ToggleTileLayers(); break; default: // id < MAX_LAYERS if (id == currindex) { // make sure toggle button stays in selected state togglebutt[id]->SetValue(true); } else { SetLayer(id); if (inscript) { // update window title, viewport and status bar inscript = false; mainptr->SetWindowTitle(wxEmptyString); mainptr->UpdatePatternAndStatus(); inscript = true; } } } // avoid weird bug on Mac where viewport can lose keyboard focus after // the user hits DELETE_LAYER button *and* the "All controls" option // is ticked in System Prefs > Keyboard & Mouse > Keyboard Shortcuts viewptr->SetFocus(); } // ----------------------------------------------------------------------------- void LayerBar::OnKillFocus(wxFocusEvent& event) { int id = event.GetId(); if (id < MAX_LAYERS) { togglebutt[id]->SetFocus(); // don't let button lose focus } else { bitmapbutt[id]->SetFocus(); // don't let button lose focus } } // ----------------------------------------------------------------------------- // global flag is not used at the moment (probably need later for dragging button) static bool buttdown = false; void LayerBar::OnButtonDown(wxMouseEvent& event) { // a layer bar button has been pressed buttdown = true; int id = event.GetId(); // connect a handler that keeps focus with the pressed button if (id < MAX_LAYERS) { togglebutt[id]->Connect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(LayerBar::OnKillFocus)); } else { bitmapbutt[id]->Connect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(LayerBar::OnKillFocus)); } event.Skip(); } // ----------------------------------------------------------------------------- void LayerBar::OnButtonUp(wxMouseEvent& event) { // a layer bar button has been released buttdown = false; wxPoint pt; int wd, ht; int id = event.GetId(); if (id < MAX_LAYERS) { pt = togglebutt[id]->ScreenToClient( wxGetMousePosition() ); togglebutt[id]->GetClientSize(&wd, &ht); // disconnect kill-focus handler togglebutt[id]->Disconnect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(LayerBar::OnKillFocus)); } else { pt = bitmapbutt[id]->ScreenToClient( wxGetMousePosition() ); bitmapbutt[id]->GetClientSize(&wd, &ht); // disconnect kill-focus handler bitmapbutt[id]->Disconnect(id, wxEVT_KILL_FOCUS, wxFocusEventHandler(LayerBar::OnKillFocus)); } viewptr->SetFocus(); wxRect r(0, 0, wd, ht); if ( r.Contains(pt) ) { // call OnButton wxCommandEvent buttevt(wxEVT_COMMAND_BUTTON_CLICKED, id); if (id < MAX_LAYERS) { buttevt.SetEventObject(togglebutt[id]); togglebutt[id]->GetEventHandler()->ProcessEvent(buttevt); } else { buttevt.SetEventObject(bitmapbutt[id]); bitmapbutt[id]->GetEventHandler()->ProcessEvent(buttevt); } } } // ----------------------------------------------------------------------------- // not used at the moment (probably need later for button dragging) void LayerBar::OnMouseMotion(wxMouseEvent& event) { if (buttdown) { //??? } event.Skip(); } // ----------------------------------------------------------------------------- void LayerBar::AddButton(int id, const wxString& tip) { if (id < MAX_LAYERS) { // create toggle button int y = (layerbarht - TOGGLE_HT) / 2; togglebutt[id] = new wxToggleButton(this, id, wxT("?"), wxPoint(xpos, y), #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) wxSize(MIN_TOGGLE_WD, TOGGLE_HT), wxBORDER_SIMPLE #else wxSize(MIN_TOGGLE_WD, TOGGLE_HT) #endif ); if (togglebutt[id] == NULL) { Fatal(_("Failed to create layer bar bitmap button!")); } else { #if defined(__WXGTK__) || defined(__WXOSX_COCOA__) // use smaller font on Linux and OS X Cocoa togglebutt[id]->SetWindowVariant(wxWINDOW_VARIANT_SMALL); #endif // we need to create size using MIN_TOGGLE_WD above and resize now // using MAX_TOGGLE_WD, otherwise we can't shrink size later // (possibly only needed by wxMac) #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) // ensure there is a gap between buttons togglebutt[id]->SetSize(xpos, y, MAX_TOGGLE_WD-4, TOGGLE_HT); #else togglebutt[id]->SetSize(xpos, y, MAX_TOGGLE_WD, TOGGLE_HT); #endif xpos += MAX_TOGGLE_WD; togglebutt[id]->SetToolTip(SWITCH_LAYER); #ifdef __WXMSW__ // fix problem with layer bar buttons when generating/inscript // due to focus being changed to viewptr togglebutt[id]->Connect(id, wxEVT_LEFT_DOWN, wxMouseEventHandler(LayerBar::OnButtonDown)); togglebutt[id]->Connect(id, wxEVT_LEFT_UP, wxMouseEventHandler(LayerBar::OnButtonUp)); /* don't need this handler at the moment togglebutt[id]->Connect(id, wxEVT_MOTION, wxMouseEventHandler(LayerBar::OnMouseMotion)); */ #endif } } else { // create bitmap button bitmapbutt[id] = new wxBitmapButton(this, id, normbutt[id], wxPoint(xpos,ypos), #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) wxSize(BUTTON_WD, BUTTON_HT), wxBORDER_SIMPLE #else wxSize(BUTTON_WD, BUTTON_HT) #endif ); if (bitmapbutt[id] == NULL) { Fatal(_("Failed to create layer bar bitmap button!")); } else { xpos += BUTTON_WD + smallgap; bitmapbutt[id]->SetToolTip(tip); #ifdef __WXMSW__ // fix problem with layer bar buttons when generating/inscript // due to focus being changed to viewptr bitmapbutt[id]->Connect(id, wxEVT_LEFT_DOWN, wxMouseEventHandler(LayerBar::OnButtonDown)); bitmapbutt[id]->Connect(id, wxEVT_LEFT_UP, wxMouseEventHandler(LayerBar::OnButtonUp)); /* don't need this handler at the moment bitmapbutt[id]->Connect(id, wxEVT_MOTION, wxMouseEventHandler(LayerBar::OnMouseMotion)); */ #endif } } } // ----------------------------------------------------------------------------- void LayerBar::AddSeparator() { xpos += biggap - smallgap; } // ----------------------------------------------------------------------------- void LayerBar::EnableButton(int id, bool enable) { if (id < MAX_LAYERS) { // toggle button if (enable == togglebutt[id]->IsEnabled()) return; togglebutt[id]->Enable(enable); } else { // bitmap button if (enable == bitmapbutt[id]->IsEnabled()) return; #ifdef __WXMSW__ if (id == STACK_LAYERS && stacklayers) { bitmapbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else if (id == TILE_LAYERS && tilelayers) { bitmapbutt[id]->SetBitmapDisabled(disdownbutt[id]); } else { bitmapbutt[id]->SetBitmapDisabled(disnormbutt[id]); } #endif bitmapbutt[id]->Enable(enable); } } // ----------------------------------------------------------------------------- void LayerBar::SelectButton(int id, bool select) { if (id < MAX_LAYERS) { // toggle button if (select) { if (downid >= LAYER_0) { // deselect old layer button togglebutt[downid]->SetValue(false); togglebutt[downid]->SetToolTip(SWITCH_LAYER); } downid = id; togglebutt[id]->SetToolTip(_("Current layer")); } togglebutt[id]->SetValue(select); } else { // bitmap button if (select) { bitmapbutt[id]->SetBitmapLabel(downbutt[id]); } else { bitmapbutt[id]->SetBitmapLabel(normbutt[id]); } if (showlayer) bitmapbutt[id]->Refresh(false); } } // ----------------------------------------------------------------------------- void CreateLayerBar(wxWindow* parent) { int wd, ht; parent->GetClientSize(&wd, &ht); layerbarptr = new LayerBar(parent, 0, 0, wd, layerbarht); if (layerbarptr == NULL) Fatal(_("Failed to create layer bar!")); // create bitmap buttons layerbarptr->AddButton(ADD_LAYER, _("Add new layer")); layerbarptr->AddButton(CLONE_LAYER, _("Clone current layer")); layerbarptr->AddButton(DUPLICATE_LAYER, _("Duplicate current layer")); layerbarptr->AddButton(DELETE_LAYER, _("Delete current layer")); layerbarptr->AddSeparator(); layerbarptr->AddButton(STACK_LAYERS, _("Stack layers")); layerbarptr->AddButton(TILE_LAYERS, _("Tile layers")); layerbarptr->AddSeparator(); // create a toggle button for each layer for (int i = 0; i < MAX_LAYERS; i++) { layerbarptr->AddButton(i, wxEmptyString); } // hide all toggle buttons except for layer 0 for (int i = 1; i < MAX_LAYERS; i++) togglebutt[i]->Show(false); // select STACK_LAYERS or TILE_LAYERS if necessary if (stacklayers) layerbarptr->SelectButton(STACK_LAYERS, true); if (tilelayers) layerbarptr->SelectButton(TILE_LAYERS, true); // select LAYER_0 button layerbarptr->SelectButton(LAYER_0, true); layerbarptr->Show(showlayer); } // ----------------------------------------------------------------------------- int LayerBarHeight() { return (showlayer ? layerbarht : 0); } // ----------------------------------------------------------------------------- void ResizeLayerBar(int wd) { if (layerbarptr) { layerbarptr->SetSize(wd, layerbarht); } } // ----------------------------------------------------------------------------- void UpdateLayerBar() { if (layerbarptr && showlayer) { bool active = !viewptr->waitingforclick; layerbarptr->EnableButton(ADD_LAYER, active && !inscript && numlayers < MAX_LAYERS); layerbarptr->EnableButton(CLONE_LAYER, active && !inscript && numlayers < MAX_LAYERS); layerbarptr->EnableButton(DUPLICATE_LAYER, active && !inscript && numlayers < MAX_LAYERS); layerbarptr->EnableButton(DELETE_LAYER, active && !inscript && numlayers > 1); layerbarptr->EnableButton(STACK_LAYERS, active); layerbarptr->EnableButton(TILE_LAYERS, active); for (int i = 0; i < numlayers; i++) layerbarptr->EnableButton(i, active && CanSwitchLayer(i)); // no need to redraw entire bar here if it only contains buttons // layerbarptr->Refresh(false); } } // ----------------------------------------------------------------------------- void UpdateLayerButton(int index, const wxString& name) { // assume caller has replaced any "&" with "&&" togglebutt[index]->SetLabel(name); } // ----------------------------------------------------------------------------- void RedrawLayerBar() { layerbarptr->Refresh(false); } // ----------------------------------------------------------------------------- void ToggleLayerBar() { showlayer = !showlayer; wxRect r = bigview->GetRect(); if (showlayer) { // show layer bar at top of viewport window r.y += layerbarht; r.height -= layerbarht; ShiftEditBar(layerbarht); // move edit bar down } else { // hide layer bar r.y -= layerbarht; r.height += layerbarht; ShiftEditBar(-layerbarht); // move edit bar up } bigview->SetSize(r); layerbarptr->Show(showlayer); // needed on Windows mainptr->UpdateMenuItems(); } // ----------------------------------------------------------------------------- void CalculateTileRects(int bigwd, int bight) { // set tilerect in each layer wxRect r; bool portrait = (bigwd <= bight); int rows, cols; // try to avoid the aspect ratio of each tile becoming too large switch (numlayers) { case 4: rows = 2; cols = 2; break; case 9: rows = 3; cols = 3; break; case 3: case 5: case 7: rows = portrait ? numlayers / 2 + 1 : 2; cols = portrait ? 2 : numlayers / 2 + 1; break; case 6: case 8: case 10: rows = portrait ? numlayers / 2 : 2; cols = portrait ? 2 : numlayers / 2; break; default: // numlayers == 2 or > 10 rows = portrait ? numlayers : 1; cols = portrait ? 1 : numlayers; } int tilewd = bigwd / cols; int tileht = bight / rows; if ( float(tilewd) > float(tileht) * 2.5 ) { rows = 1; cols = numlayers; tileht = bight; tilewd = bigwd / numlayers; } else if ( float(tileht) > float(tilewd) * 2.5 ) { cols = 1; rows = numlayers; tilewd = bigwd; tileht = bight / numlayers; } for ( int i = 0; i < rows; i++ ) { for ( int j = 0; j < cols; j++ ) { r.x = j * tilewd; r.y = i * tileht; r.width = tilewd; r.height = tileht; if (i == rows - 1) { // may need to increase height of bottom-edge tile r.height += bight - (rows * tileht); } if (j == cols - 1) { // may need to increase width of right-edge tile r.width += bigwd - (cols * tilewd); } int index = i * cols + j; if (index == numlayers) { // numlayers == 3,5,7 layer[index - 1]->tilerect.width += r.width; } else { layer[index]->tilerect = r; } } } if (tileborder > 0) { // make tilerects smaller to allow for equal-width tile borders for ( int i = 0; i < rows; i++ ) { for ( int j = 0; j < cols; j++ ) { int index = i * cols + j; if (index == numlayers) { // numlayers == 3,5,7 layer[index - 1]->tilerect.width -= tileborder; } else { layer[index]->tilerect.x += tileborder; layer[index]->tilerect.y += tileborder; layer[index]->tilerect.width -= tileborder; layer[index]->tilerect.height -= tileborder; if (j == cols - 1) layer[index]->tilerect.width -= tileborder; if (i == rows - 1) layer[index]->tilerect.height -= tileborder; } } } } } // ----------------------------------------------------------------------------- void ResizeTiles(int bigwd, int bight) { // set tilerect for each layer so they tile bigview's client area CalculateTileRects(bigwd, bight); // set size of each tile window for ( int i = 0; i < numlayers; i++ ) layer[i]->tilewin->SetSize( layer[i]->tilerect ); // set viewport size for each tile; this is currently the same as the // tilerect size because tile windows are created with wxNO_BORDER for ( int i = 0; i < numlayers; i++ ) { int wd, ht; layer[i]->tilewin->GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; layer[i]->view->resize(wd, ht); } } // ----------------------------------------------------------------------------- void ResizeLayers(int wd, int ht) { // this is called whenever the size of the bigview window changes; // wd and ht are the dimensions of bigview's client area if (tilelayers && numlayers > 1) { ResizeTiles(wd, ht); } else { // resize viewport in each layer to bigview's client area for (int i = 0; i < numlayers; i++) layer[i]->view->resize(wd, ht); } } // ----------------------------------------------------------------------------- void CreateTiles() { // create tile windows for ( int i = 0; i < numlayers; i++ ) { layer[i]->tilewin = new PatternView(bigview, // correct size will be set below by ResizeTiles 0, 0, 0, 0, // we draw our own tile borders wxNO_BORDER | // needed for wxGTK wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS); if (layer[i]->tilewin == NULL) Fatal(_("Failed to create tile window!")); // set tileindex >= 0; this must always match the layer index, so we'll need to // destroy and recreate all tiles whenever a tile is added, deleted or moved layer[i]->tilewin->tileindex = i; #if wxUSE_DRAG_AND_DROP // let user drop file onto any tile (but file will be loaded into current tile) layer[i]->tilewin->SetDropTarget(mainptr->NewDropTarget()); #endif } // init tilerects, tile window sizes and their viewport sizes int wd, ht; bigview->GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; ResizeTiles(wd, ht); // change viewptr to tile window for current layer viewptr = currlayer->tilewin; if (mainptr->infront) viewptr->SetFocus(); } // ----------------------------------------------------------------------------- void DestroyTiles() { // reset viewptr to main viewport window viewptr = bigview; if (mainptr->infront) viewptr->SetFocus(); // destroy all tile windows for ( int i = 0; i < numlayers; i++ ) delete layer[i]->tilewin; // resize viewport in each layer to bigview's client area int wd, ht; bigview->GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; for ( int i = 0; i < numlayers; i++ ) layer[i]->view->resize(wd, ht); } // ----------------------------------------------------------------------------- void SyncClones() { if (numclones == 0) return; if (currlayer->cloneid > 0) { // make sure clone algo and most other settings are synchronized for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = layer[i]; if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { // universe might have been re-created, or algorithm changed cloneptr->algo = currlayer->algo; cloneptr->algtype = currlayer->algtype; cloneptr->rule = currlayer->rule; // no need to sync undo/redo history // cloneptr->undoredo = currlayer->undoredo; // along with view, don't sync these settings // cloneptr->autofit = currlayer->autofit; // cloneptr->hyperspeed = currlayer->hyperspeed; // cloneptr->showhashinfo = currlayer->showhashinfo; // cloneptr->drawingstate = currlayer->drawingstate; // cloneptr->curs = currlayer->curs; // cloneptr->originx = currlayer->originx; // cloneptr->originy = currlayer->originy; // cloneptr->currname = currlayer->currname; // sync various flags cloneptr->dirty = currlayer->dirty; cloneptr->savedirty = currlayer->savedirty; cloneptr->stayclean = currlayer->stayclean; // sync step size cloneptr->currbase = currlayer->currbase; cloneptr->currexpo = currlayer->currexpo; // sync selection info cloneptr->currsel = currlayer->currsel; cloneptr->savesel = currlayer->savesel; // sync the stuff needed to reset pattern cloneptr->startalgo = currlayer->startalgo; cloneptr->savestart = currlayer->savestart; cloneptr->startdirty = currlayer->startdirty; cloneptr->startrule = currlayer->startrule; cloneptr->startfile = currlayer->startfile; cloneptr->startgen = currlayer->startgen; cloneptr->currfile = currlayer->currfile; cloneptr->startsel = currlayer->startsel; // clone can have different starting name, pos, scale, step // cloneptr->startname = currlayer->startname; // cloneptr->startx = currlayer->startx; // cloneptr->starty = currlayer->starty; // cloneptr->startmag = currlayer->startmag; // cloneptr->startbase = currlayer->startbase; // cloneptr->startexpo = currlayer->startexpo; // sync timeline settings cloneptr->currframe = currlayer->currframe; cloneptr->autoplay = currlayer->autoplay; cloneptr->tlspeed = currlayer->tlspeed; cloneptr->lastframe = currlayer->lastframe; } } } } // ----------------------------------------------------------------------------- void SaveLayerSettings() { // set oldalgo and oldrule for use in CurrentLayerChanged oldalgo = currlayer->algtype; oldrule = wxString(currlayer->algo->getrule(), wxConvLocal); // we're about to change layer so remember current rule // in case we switch back to this layer currlayer->rule = oldrule; // synchronize clone info (do AFTER setting currlayer->rule) SyncClones(); if (syncviews) { // save scale and location for use in CurrentLayerChanged oldmag = currlayer->view->getmag(); oldx = currlayer->view->x; oldy = currlayer->view->y; } if (synccursors) { // save cursor mode for use in CurrentLayerChanged oldcurs = currlayer->curs; } } // ----------------------------------------------------------------------------- bool RestoreRule(const wxString& rule) { const char* err = currlayer->algo->setrule( rule.mb_str(wxConvLocal) ); if (err) { // this can happen if the given rule's table/tree file was deleted // or it was edited and some sort of error introduced, so best to // use algo's default rule (which should never fail) currlayer->algo->setrule( currlayer->algo->DefaultRule() ); wxString msg = _("The rule \"") + rule; msg += _("\" is no longer valid!\nUsing the default rule instead."); Warning(msg); return false; } return true; } // ----------------------------------------------------------------------------- void CurrentLayerChanged() { // currlayer has changed since SaveLayerSettings was called; // update rule if the new currlayer uses a different algorithm or rule if ( currlayer->algtype != oldalgo || !currlayer->rule.IsSameAs(oldrule,false) ) { RestoreRule(currlayer->rule); } if (syncviews) currlayer->view->setpositionmag(oldx, oldy, oldmag); if (synccursors) currlayer->curs = oldcurs; // select current layer button (also deselects old button) layerbarptr->SelectButton(currindex, true); if (tilelayers && numlayers > 1) { // switch to new tile viewptr = currlayer->tilewin; if (mainptr->infront) viewptr->SetFocus(); } if (allowundo) { // update Undo/Redo items so they show the correct action currlayer->undoredo->UpdateUndoRedoItems(); } else { // undo/redo is disabled so clear history; // this also removes action from Undo/Redo items currlayer->undoredo->ClearUndoRedo(); } mainptr->SetStepExponent(currlayer->currexpo); // SetStepExponent calls SetGenIncrement mainptr->SetWindowTitle(currlayer->currname); mainptr->UpdateUserInterface(); mainptr->UpdatePatternAndStatus(); bigview->UpdateScrollBars(); } // ----------------------------------------------------------------------------- void UpdateLayerNames() { // update names in all layer items at end of Layer menu for (int i = 0; i < numlayers; i++) mainptr->UpdateLayerItem(i); } // ----------------------------------------------------------------------------- static wxBitmap** CopyIcons(wxBitmap** srcicons, int maxstate) { wxBitmap** iconptr = (wxBitmap**) malloc(256 * sizeof(wxBitmap*)); if (iconptr) { for (int i = 0; i < 256; i++) iconptr[i] = NULL; for (int i = 0; i <= maxstate; i++) { if (srcicons && srcicons[i]) { wxRect rect(0, 0, srcicons[i]->GetWidth(), srcicons[i]->GetHeight()); iconptr[i] = new wxBitmap(srcicons[i]->GetSubBitmap(rect)); } } } return iconptr; } // ----------------------------------------------------------------------------- static void CopyBuiltinIcons(wxBitmap** i7x7, wxBitmap** i15x15, wxBitmap** i31x31) { int maxstate = currlayer->algo->NumCellStates() - 1; if (currlayer->icons7x7) FreeIconBitmaps(currlayer->icons7x7); if (currlayer->icons15x15) FreeIconBitmaps(currlayer->icons15x15); if (currlayer->icons31x31) FreeIconBitmaps(currlayer->icons31x31); currlayer->icons7x7 = CopyIcons(i7x7, maxstate); currlayer->icons15x15 = CopyIcons(i15x15, maxstate); currlayer->icons31x31 = CopyIcons(i31x31, maxstate); } // ----------------------------------------------------------------------------- void AddLayer() { if (numlayers >= MAX_LAYERS) return; // we need to test mainptr here because AddLayer is called from main window's ctor if (mainptr && mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_ADD_LAYER); return; } if (numlayers == 0) { // creating the very first layer currindex = 0; } else { if (tilelayers && numlayers > 1) DestroyTiles(); SaveLayerSettings(); // insert new layer after currindex currindex++; if (currindex < numlayers) { // shift right one or more layers for (int i = numlayers; i > currindex; i--) layer[i] = layer[i-1]; } } Layer* oldlayer = NULL; if (cloning || duplicating) oldlayer = currlayer; currlayer = new Layer(); if (currlayer == NULL) Fatal(_("Failed to create new layer!")); layer[currindex] = currlayer; if (cloning || duplicating) { // copy old layer's colors to new layer currlayer->fromrgb = oldlayer->fromrgb; currlayer->torgb = oldlayer->torgb; for (int n = 0; n < currlayer->algo->NumCellStates(); n++) { currlayer->cellr[n] = oldlayer->cellr[n]; currlayer->cellg[n] = oldlayer->cellg[n]; currlayer->cellb[n] = oldlayer->cellb[n]; } currlayer->deadbrush->SetColour( oldlayer->deadbrush->GetColour() ); currlayer->gridpen->SetColour( oldlayer->gridpen->GetColour() ); currlayer->boldpen->SetColour( oldlayer->boldpen->GetColour() ); if (cloning) { // use same icon pointers currlayer->icons7x7 = oldlayer->icons7x7; currlayer->icons15x15 = oldlayer->icons15x15; currlayer->icons31x31 = oldlayer->icons31x31; } else { // duplicate icons from old layer int maxstate = currlayer->algo->NumCellStates() - 1; currlayer->icons7x7 = CopyIcons(oldlayer->icons7x7, maxstate); currlayer->icons15x15 = CopyIcons(oldlayer->icons15x15, maxstate); currlayer->icons31x31 = CopyIcons(oldlayer->icons31x31, maxstate); } } else { // set new layer's colors+icons to default colors+icons for current algo+rule UpdateLayerColors(); } numlayers++; if (numlayers > 1) { // add toggle button at end of layer bar layerbarptr->ResizeLayerButtons(); togglebutt[numlayers-1]->Show(true); // add another item at end of Layer menu mainptr->AppendLayerItem(); UpdateLayerNames(); if (tilelayers && numlayers > 1) CreateTiles(); CurrentLayerChanged(); } } // ----------------------------------------------------------------------------- void CloneLayer() { if (numlayers >= MAX_LAYERS) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_CLONE); return; } cloning = true; AddLayer(); cloning = false; } // ----------------------------------------------------------------------------- void DuplicateLayer() { if (numlayers >= MAX_LAYERS) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_DUPLICATE); return; } duplicating = true; AddLayer(); duplicating = false; } // ----------------------------------------------------------------------------- void DeleteLayer() { if (numlayers <= 1) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_DEL_LAYER); return; } // note that we don't need to ask to delete a clone if (askondelete && currlayer->dirty && currlayer->cloneid == 0 && !mainptr->SaveCurrentLayer()) return; // numlayers > 1 if (tilelayers) DestroyTiles(); SaveLayerSettings(); delete currlayer; numlayers--; if (currindex < numlayers) { // shift left one or more layers for (int i = currindex; i < numlayers; i++) layer[i] = layer[i+1]; } if (currindex > 0) currindex--; currlayer = layer[currindex]; // remove toggle button at end of layer bar togglebutt[numlayers]->Show(false); layerbarptr->ResizeLayerButtons(); // remove item from end of Layer menu mainptr->RemoveLayerItem(); UpdateLayerNames(); if (tilelayers && numlayers > 1) CreateTiles(); CurrentLayerChanged(); } // ----------------------------------------------------------------------------- void DeleteOtherLayers() { if (inscript || numlayers <= 1) return; if (askondelete) { // keep track of which unique clones have been seen; // we add 1 below to allow for cloneseen[0] (always false) const int maxseen = MAX_LAYERS/2 + 1; bool cloneseen[maxseen]; for (int i = 0; i < maxseen; i++) cloneseen[i] = false; // for each dirty layer, except current layer and all of its clones, // ask user if they want to save changes int cid = layer[currindex]->cloneid; if (cid > 0) cloneseen[cid] = true; int oldindex = currindex; for (int i = 0; i < numlayers; i++) { // only ask once for each unique clone (cloneid == 0 for non-clone) cid = layer[i]->cloneid; if (i != oldindex && !cloneseen[cid]) { if (cid > 0) cloneseen[cid] = true; if (layer[i]->dirty) { // temporarily turn off generating flag for SetLayer bool oldgen = mainptr->generating; mainptr->generating = false; SetLayer(i); if (!mainptr->SaveCurrentLayer()) { // user hit Cancel so restore current layer and generating flag SetLayer(oldindex); mainptr->generating = oldgen; mainptr->UpdateUserInterface(); return; } SetLayer(oldindex); mainptr->generating = oldgen; } } } } // numlayers > 1 if (tilelayers) DestroyTiles(); SyncClones(); // delete all layers except current layer; // we need to do this carefully because ~Layer() requires numlayers // and the layer array to be correct when deleting a cloned layer int i = numlayers; while (numlayers > 1) { i--; if (i != currindex) { delete layer[i]; // ~Layer() is called numlayers--; // may need to shift the current layer left one place if (i < numlayers) layer[i] = layer[i+1]; // remove toggle button at end of layer bar togglebutt[numlayers]->Show(false); // remove item from end of Layer menu mainptr->RemoveLayerItem(); } } layerbarptr->ResizeLayerButtons(); currindex = 0; // currlayer doesn't change // update the only layer item mainptr->UpdateLayerItem(0); // update window title (may need to remove "=" prefix) mainptr->SetWindowTitle(wxEmptyString); // select LAYER_0 button (also deselects old button) layerbarptr->SelectButton(LAYER_0, true); mainptr->UpdateMenuItems(); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void SetLayer(int index) { if (currindex == index) return; if (index < 0 || index >= numlayers) return; if (inscript) { // always allow a script to switch layers } else if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_LAYER0 + index); return; } SaveLayerSettings(); currindex = index; currlayer = layer[currindex]; CurrentLayerChanged(); } // ----------------------------------------------------------------------------- bool CanSwitchLayer(int WXUNUSED(index)) { if (inscript) { // user can only switch layers if script has set the appropriate option return canswitch; } else { // user can switch to any layer return true; } } // ----------------------------------------------------------------------------- void SwitchToClickedTile(int index) { if (inscript && !CanSwitchLayer(index)) { // statusptr->ErrorMessage does nothing if inscript is true Warning(_("You cannot switch to another layer while this script is running.")); return; } // switch current layer to clicked tile SetLayer(index); if (inscript) { // update window title, viewport and status bar inscript = false; mainptr->SetWindowTitle(wxEmptyString); mainptr->UpdatePatternAndStatus(); inscript = true; } } // ----------------------------------------------------------------------------- void MoveLayer(int fromindex, int toindex) { if (fromindex == toindex) return; if (fromindex < 0 || fromindex >= numlayers) return; if (toindex < 0 || toindex >= numlayers) return; SaveLayerSettings(); if (fromindex > toindex) { Layer* savelayer = layer[fromindex]; for (int i = fromindex; i > toindex; i--) layer[i] = layer[i - 1]; layer[toindex] = savelayer; } else { // fromindex < toindex Layer* savelayer = layer[fromindex]; for (int i = fromindex; i < toindex; i++) layer[i] = layer[i + 1]; layer[toindex] = savelayer; } currindex = toindex; currlayer = layer[currindex]; UpdateLayerNames(); if (tilelayers && numlayers > 1) { DestroyTiles(); CreateTiles(); } CurrentLayerChanged(); } // ----------------------------------------------------------------------------- // remove this eventually if user can drag layer buttons??? void MoveLayerDialog() { if (inscript || numlayers <= 1) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_MOVE_LAYER); return; } wxString msg = _("Move the current layer to a new position:"); if (currindex > 0) { msg += _("\n(enter 0 to make it the first layer)"); } int newindex; if ( GetInteger(_("Move Layer"), msg, currindex, 0, numlayers - 1, &newindex) ) { MoveLayer(currindex, newindex); } } // ----------------------------------------------------------------------------- void NameLayerDialog() { if (inscript) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_NAME_LAYER); return; } wxString oldname = currlayer->currname; wxString newname; if ( GetString(_("Name Layer"), _("Enter a new name for the current layer:"), oldname, newname) && !newname.IsEmpty() && oldname != newname ) { // inscript is false so no need to call SavePendingChanges // if (allowundo) SavePendingChanges(); // show new name in main window's title bar; // also sets currlayer->currname and updates menu item mainptr->SetWindowTitle(newname); if (allowundo) { // note that currfile and savestart/dirty flags don't change here currlayer->undoredo->RememberNameChange(oldname, currlayer->currfile, currlayer->savestart, currlayer->dirty); } } } // ----------------------------------------------------------------------------- void MarkLayerDirty() { // need to save starting pattern currlayer->savestart = true; // if script has reset dirty flag then don't change it; this makes sense // for scripts that call new() and then construct a pattern if (currlayer->stayclean) return; if (!currlayer->dirty) { currlayer->dirty = true; // pass in currname so UpdateLayerItem(currindex) gets called mainptr->SetWindowTitle(currlayer->currname); if (currlayer->cloneid > 0) { // synchronize other clones for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = layer[i]; if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { // set dirty flag and display asterisk in layer item cloneptr->dirty = true; mainptr->UpdateLayerItem(i); } } } } } // ----------------------------------------------------------------------------- void MarkLayerClean(const wxString& title) { currlayer->dirty = false; // if script is resetting dirty flag -- eg. via new() -- then don't allow // dirty flag to be set true for the remainder of the script; this is // nicer for scripts that construct a pattern (ie. running such a script // is equivalent to loading a pattern file) if (inscript) currlayer->stayclean = true; if (title.IsEmpty()) { // pass in currname so UpdateLayerItem(currindex) gets called mainptr->SetWindowTitle(currlayer->currname); } else { // set currlayer->currname to title and call UpdateLayerItem(currindex) mainptr->SetWindowTitle(title); } if (currlayer->cloneid > 0) { // synchronize other clones for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = layer[i]; if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { // reset dirty flag cloneptr->dirty = false; if (inscript) cloneptr->stayclean = true; // always allow clones to have different names // cloneptr->currname = currlayer->currname; // remove asterisk from layer item mainptr->UpdateLayerItem(i); } } } } // ----------------------------------------------------------------------------- void ToggleSyncViews() { syncviews = !syncviews; mainptr->UpdateUserInterface(); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void ToggleSyncCursors() { synccursors = !synccursors; mainptr->UpdateUserInterface(); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void ToggleStackLayers() { stacklayers = !stacklayers; if (stacklayers && tilelayers) { tilelayers = false; layerbarptr->SelectButton(TILE_LAYERS, false); if (numlayers > 1) DestroyTiles(); } layerbarptr->SelectButton(STACK_LAYERS, stacklayers); mainptr->UpdateUserInterface(); if (inscript) { // always update viewport and status bar inscript = false; mainptr->UpdatePatternAndStatus(); inscript = true; } else { mainptr->UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- void ToggleTileLayers() { tilelayers = !tilelayers; if (tilelayers && stacklayers) { stacklayers = false; layerbarptr->SelectButton(STACK_LAYERS, false); } layerbarptr->SelectButton(TILE_LAYERS, tilelayers); if (tilelayers) { if (numlayers > 1) CreateTiles(); } else { if (numlayers > 1) DestroyTiles(); } mainptr->UpdateUserInterface(); if (inscript) { // always update viewport and status bar inscript = false; mainptr->UpdatePatternAndStatus(); inscript = true; } else { mainptr->UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- void CreateColorGradient() { int maxstate = currlayer->algo->NumCellStates() - 1; unsigned char r1 = currlayer->fromrgb.Red(); unsigned char g1 = currlayer->fromrgb.Green(); unsigned char b1 = currlayer->fromrgb.Blue(); unsigned char r2 = currlayer->torgb.Red(); unsigned char g2 = currlayer->torgb.Green(); unsigned char b2 = currlayer->torgb.Blue(); // set cell colors for states 1..maxstate using a color gradient // starting with r1,g1,b1 and ending with r2,g2,b2 currlayer->cellr[1] = r1; currlayer->cellg[1] = g1; currlayer->cellb[1] = b1; if (maxstate > 2) { int N = maxstate - 1; double rfrac = (double)(r2 - r1) / (double)N; double gfrac = (double)(g2 - g1) / (double)N; double bfrac = (double)(b2 - b1) / (double)N; for (int n = 1; n < N; n++) { currlayer->cellr[n+1] = (int)(r1 + n * rfrac + 0.5); currlayer->cellg[n+1] = (int)(g1 + n * gfrac + 0.5); currlayer->cellb[n+1] = (int)(b1 + n * bfrac + 0.5); } } if (maxstate > 1) { currlayer->cellr[maxstate] = r2; currlayer->cellg[maxstate] = g2; currlayer->cellb[maxstate] = b2; } } // ----------------------------------------------------------------------------- void UpdateBrushAndPens(Layer* layerptr) { // update deadbrush, gridpen, boldpen in given layer int r = layerptr->cellr[0]; int g = layerptr->cellg[0]; int b = layerptr->cellb[0]; layerptr->deadbrush->SetColour(r, g, b); // no need to use this standard grayscale conversion??? // gray = (int) (0.299*r + 0.587*g + 0.114*b); int gray = (int) ((r + g + b) / 3.0); if (gray > 127) { // use darker grid layerptr->gridpen->SetColour(r > 32 ? r - 32 : 0, g > 32 ? g - 32 : 0, b > 32 ? b - 32 : 0); layerptr->boldpen->SetColour(r > 64 ? r - 64 : 0, g > 64 ? g - 64 : 0, b > 64 ? b - 64 : 0); } else { // use lighter grid layerptr->gridpen->SetColour(r + 32 < 256 ? r + 32 : 255, g + 32 < 256 ? g + 32 : 255, b + 32 < 256 ? b + 32 : 255); layerptr->boldpen->SetColour(r + 64 < 256 ? r + 64 : 255, g + 64 < 256 ? g + 64 : 255, b + 64 < 256 ? b + 64 : 255); } } // ----------------------------------------------------------------------------- void UpdateCloneColors() { // first update deadbrush, gridpen, boldpen UpdateBrushAndPens(currlayer); if (currlayer->cloneid > 0) { int maxstate = currlayer->algo->NumCellStates() - 1; for (int i = 0; i < numlayers; i++) { Layer* cloneptr = layer[i]; if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->fromrgb = currlayer->fromrgb; cloneptr->torgb = currlayer->torgb; for (int n = 0; n <= maxstate; n++) { cloneptr->cellr[n] = currlayer->cellr[n]; cloneptr->cellg[n] = currlayer->cellg[n]; cloneptr->cellb[n] = currlayer->cellb[n]; } // use same icon pointers cloneptr->icons7x7 = currlayer->icons7x7; cloneptr->icons15x15 = currlayer->icons15x15; cloneptr->icons31x31 = currlayer->icons31x31; // use same colors in deadbrush, gridpen and boldpen cloneptr->deadbrush->SetColour( currlayer->deadbrush->GetColour() ); cloneptr->gridpen->SetColour( currlayer->gridpen->GetColour() ); cloneptr->boldpen->SetColour( currlayer->boldpen->GetColour() ); } } } } // ----------------------------------------------------------------------------- static FILE* FindRuleFile(const wxString& rulename) { const wxString extn = wxT(".rule"); wxString path; // first look for rulename.rule in userrules path = userrules + rulename; path += extn; FILE* f = OPENFILE(path); if (f) return f; // now look for rulename.rule in rulesdir path = rulesdir + rulename; path += extn; return OPENFILE(path); } // ----------------------------------------------------------------------------- static void CheckRuleHeader(char* linebuf, const wxString& rulename) { // check that 1st line of rulename.rule file contains "@RULE rulename" // where rulename must match the file name exactly (to avoid problems on // case-sensitive file systems) if (strncmp(linebuf, "@RULE ", 6) != 0) { wxString msg = _("The first line in "); msg += rulename; msg += _(".rule does not start with @RULE."); Warning(msg); } else if (strcmp(linebuf+6, (const char*)rulename.mb_str(wxConvLocal)) != 0) { wxString ruleinfile = wxString(linebuf+6, wxConvLocal); wxString msg = _("The specified rule ("); msg += rulename; msg += _(") does not match the rule name in the .rule file ("); msg += ruleinfile; msg += _(").\n\nThis will cause problems if you save or copy patterns"); msg += _(" and try to use them on a case-sensitive file system."); Warning(msg); } } // ----------------------------------------------------------------------------- static void ParseColors(linereader& reader, char* linebuf, int MAXLINELEN, int* linenum, bool* eof) { // parse @COLORS section in currently open .rule file int state, r, g, b, r1, g1, b1, r2, g2, b2; int maxstate = currlayer->algo->NumCellStates() - 1; while (reader.fgets(linebuf, MAXLINELEN) != 0) { *linenum = *linenum + 1; if (linebuf[0] == '#' || linebuf[0] == 0) { // skip comment or empty line } else if (sscanf(linebuf, "%d%d%d%d%d%d", &r1, &g1, &b1, &r2, &g2, &b2) == 6) { // assume line is like this: // 255 0 0 0 0 255 use a gradient from red to blue currlayer->fromrgb.Set(r1, g1, b1); currlayer->torgb.Set(r2, g2, b2); CreateColorGradient(); } else if (sscanf(linebuf, "%d%d%d%d", &state, &r, &g, &b) == 4) { // assume line is like this: // 1 0 128 255 state 1 is light blue if (state >= 0 && state <= maxstate) { currlayer->cellr[state] = r; currlayer->cellg[state] = g; currlayer->cellb[state] = b; } } else if (linebuf[0] == '@') { // found next section, so stop parsing *eof = false; return; } // ignore unexpected syntax (better for upward compatibility) } *eof = true; } // ----------------------------------------------------------------------------- static void DeleteXPMData(char** xpmdata, int numstrings) { if (xpmdata) { for (int i = 0; i < numstrings; i++) if (xpmdata[i]) free(xpmdata[i]); free(xpmdata); } } // ----------------------------------------------------------------------------- static void CreateIcons(const char** xpmdata, int size) { int maxstates = currlayer->algo->NumCellStates(); // we only need to call FreeIconBitmaps if .rule file has duplicate XPM data // (unlikely but best to play it safe) if (size == 7) { if (currlayer->icons7x7) FreeIconBitmaps(currlayer->icons7x7); currlayer->icons7x7 = CreateIconBitmaps(xpmdata, maxstates); } else if (size == 15) { if (currlayer->icons15x15) FreeIconBitmaps(currlayer->icons15x15); currlayer->icons15x15 = CreateIconBitmaps(xpmdata, maxstates); } else if (size == 31) { if (currlayer->icons31x31) FreeIconBitmaps(currlayer->icons31x31); currlayer->icons31x31 = CreateIconBitmaps(xpmdata, maxstates); } } // ----------------------------------------------------------------------------- static void ParseIcons(const wxString& rulename, linereader& reader, char* linebuf, int MAXLINELEN, int* linenum, bool* eof) { // parse @ICONS section in currently open .rule file char** xpmdata = NULL; int xpmstarted = 0, xpmstrings = 0, maxstrings = 0; int wd = 0, ht = 0, numcolors = 0, chars_per_pixel = 0; std::map colormap; while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) { *eof = true; break; } *linenum = *linenum + 1; if (linebuf[0] == '#' || linebuf[0] == '/' || linebuf[0] == 0) { // skip comment or empty line } else if (linebuf[0] == '"') { if (xpmstarted) { // we have a "..." string containing XPM data if (xpmstrings == 0) { if (sscanf(linebuf, "\"%d%d%d%d\"", &wd, &ht, &numcolors, &chars_per_pixel) == 4 && wd > 0 && ht > 0 && numcolors > 0 && chars_per_pixel > 0 && ht % wd == 0) { if (wd != 7 && wd != 15 && wd != 31) { // this version of Golly doesn't support the supplied icon size // so silently ignore the rest of this XPM data xpmstarted = 0; continue; } maxstrings = 1 + numcolors + ht; // create and initialize xpmdata xpmdata = (char**) malloc(maxstrings * sizeof(char*)); if (xpmdata) { for (int i = 0; i < maxstrings; i++) xpmdata[i] = NULL; } else { Warning(_("Failed to allocate memory for XPM icon data!")); *eof = true; return; } } else { wxString msg; msg.Printf(_("The XPM header string on line %d in "), *linenum); msg += rulename; msg += _(".rule is incorrect"); if (wd > 0 && ht > 0 && ht % wd != 0) msg += _(" (height must be a multiple of width)."); else if (chars_per_pixel < 1 || chars_per_pixel > 2) msg += _(" (chars_per_pixel must be 1 or 2)."); else msg += _(" (4 positive integers are required)."); Warning(msg); *eof = true; return; } } // copy data inside "..." to next string in xpmdata int len = strlen(linebuf); while (linebuf[len] != '"') len--; len--; if (xpmstrings > 0 && xpmstrings <= numcolors) { // build colormap so we can validate chars in pixel data std::string pixel; char ch1, ch2; if (chars_per_pixel == 1) { sscanf(linebuf+1, "%c ", &ch1); pixel += ch1; } else { sscanf(linebuf+1, "%c%c ", &ch1, &ch2); pixel += ch1; pixel += ch2; } colormap[pixel] = xpmstrings; } else if (xpmstrings > numcolors) { // check length of string containing pixel data if (len != wd * chars_per_pixel) { DeleteXPMData(xpmdata, maxstrings); wxString msg; msg.Printf(_("The XPM data string on line %d in "), *linenum); msg += rulename; msg += _(".rule has the wrong length."); Warning(msg); *eof = true; return; } // now check that chars in pixel data are valid (ie. in colormap) for (int i = 1; i <= len; i += chars_per_pixel) { std::string pixel; pixel += linebuf[i]; if (chars_per_pixel > 1) pixel += linebuf[i+1]; if (colormap.find(pixel) == colormap.end()) { DeleteXPMData(xpmdata, maxstrings); wxString msg; msg.Printf(_("The XPM data string on line %d in "), *linenum); msg += rulename; msg += _(".rule has an unknown pixel: "); msg += wxString(pixel.c_str(), wxConvLocal); Warning(msg); *eof = true; return; } } } char* str = (char*) malloc(len+1); if (str) { strncpy(str, linebuf+1, len); str[len] = 0; xpmdata[xpmstrings] = str; } else { DeleteXPMData(xpmdata, maxstrings); Warning(_("Failed to allocate memory for XPM string!")); *eof = true; return; } xpmstrings++; if (xpmstrings == maxstrings) { // we've got all the data for this icon size CreateIcons((const char**)xpmdata, wd); DeleteXPMData(xpmdata, maxstrings); xpmdata = NULL; xpmstarted = 0; colormap.clear(); } } } else if (strcmp(linebuf, "XPM") == 0) { // start parsing XPM data on following lines if (xpmstarted) break; // handle error below xpmstarted = *linenum; xpmstrings = 0; } else if (strcmp(linebuf, "circles") == 0) { // use circular icons CopyBuiltinIcons(circles7x7, circles15x15, circles31x31); } else if (strcmp(linebuf, "diamonds") == 0) { // use diamond-shaped icons CopyBuiltinIcons(diamonds7x7, diamonds15x15, diamonds31x31); } else if (strcmp(linebuf, "hexagons") == 0) { // use hexagonal icons CopyBuiltinIcons(hexagons7x7, hexagons15x15, hexagons31x31); } else if (strcmp(linebuf, "triangles") == 0) { // use triangular icons if (currlayer->algo->NumCellStates() != 4) { wxString msg; msg.Printf(_("The triangular icons specified on line %d in "), *linenum); msg += rulename; msg += _(".rule can only be used with a 4-state rule."); Warning(msg); // don't return } else { CopyBuiltinIcons(triangles7x7, triangles15x15, triangles31x31); } } else if (linebuf[0] == '@') { // found next section, so stop parsing *eof = false; break; } // ignore unexpected syntax (better for upward compatibility) } if (xpmstarted) { // XPM data was incomplete DeleteXPMData(xpmdata, maxstrings); wxString msg; msg.Printf(_("The XPM icon data starting on line %d in "), xpmstarted); msg += rulename; msg += _(".rule does not have enough strings."); Warning(msg); *eof = true; return; } // create scaled bitmaps if size(s) not supplied if (!currlayer->icons7x7) { if (currlayer->icons15x15) { // scale down 15x15 bitmaps currlayer->icons7x7 = ScaleIconBitmaps(currlayer->icons15x15, 7); } else if (currlayer->icons31x31) { // scale down 31x31 bitmaps currlayer->icons7x7 = ScaleIconBitmaps(currlayer->icons31x31, 7); } } if (!currlayer->icons15x15) { if (currlayer->icons31x31) { // scale down 31x31 bitmaps currlayer->icons15x15 = ScaleIconBitmaps(currlayer->icons31x31, 15); } else if (currlayer->icons7x7) { // scale up 7x7 bitmaps currlayer->icons15x15 = ScaleIconBitmaps(currlayer->icons7x7, 15); } } if (!currlayer->icons31x31) { if (currlayer->icons15x15) { // scale up 15x15 bitmaps currlayer->icons31x31 = ScaleIconBitmaps(currlayer->icons15x15, 31); } else if (currlayer->icons7x7) { // scale up 7x7 bitmaps currlayer->icons31x31 = ScaleIconBitmaps(currlayer->icons7x7, 31); } } } // ----------------------------------------------------------------------------- static void LoadRuleInfo(FILE* rulefile, const wxString& rulename, bool* loadedcolors, bool* loadedicons) { // load any color and/or icon info from the currently open .rule file const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; int linenum = 0; bool eof = false; bool skipget = false; // the linereader class handles all line endings (CR, CR+LF, LF) linereader reader(rulefile); while (true) { if (skipget) { // ParseColors/ParseIcons has stopped at next section // (ie. linebuf contains @...) so skip fgets call skipget = false; } else { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; linenum++; if (linenum == 1) CheckRuleHeader(linebuf, rulename); } // look for @COLORS or @ICONS section if (strcmp(linebuf, "@COLORS") == 0 && !*loadedcolors) { *loadedcolors = true; ParseColors(reader, linebuf, MAXLINELEN, &linenum, &eof); if (eof) break; // otherwise linebuf contains @... so skip next fgets call skipget = true; } else if (strcmp(linebuf, "@ICONS") == 0 && !*loadedicons) { *loadedicons = true; ParseIcons(rulename, reader, linebuf, MAXLINELEN, &linenum, &eof); if (eof) break; // otherwise linebuf contains @... so skip next fgets call skipget = true; } } reader.close(); // closes rulefile } // ----------------------------------------------------------------------------- static FILE* FindColorFile(const wxString& rule, const wxString& dir) { const wxString extn = wxT(".colors"); wxString path; // first look for rule.colors in given directory path = dir + rule; path += extn; FILE* f = OPENFILE(path); if (f) return f; // if rule has the form foo-* then look for foo.colors in dir; // this allows related rules to share a single .colors file wxString prefix = rule.BeforeLast('-'); if (!prefix.IsEmpty()) { path = dir + prefix; path += extn; f = OPENFILE(path); if (f) return f; } return NULL; } // ----------------------------------------------------------------------------- static bool LoadRuleColors(const wxString& rule, int maxstate) { // if rule.colors file exists in userrules or rulesdir then // change colors according to info in file FILE* f = FindColorFile(rule, userrules); if (!f) f = FindColorFile(rule, rulesdir); if (f) { // the linereader class handles all line endings (CR, CR+LF, LF) linereader reader(f); // not needed here, but useful if we ever return early due to error // reader.setcloseonfree(); const int MAXLINELEN = 512; char buf[MAXLINELEN + 1]; while (reader.fgets(buf, MAXLINELEN) != 0) { if (buf[0] == '#' || buf[0] == 0) { // skip comment or empty line } else { // look for "color" or "gradient" keyword at start of line char* keyword = buf; char* value; while (*keyword == ' ') keyword++; value = keyword; while (*value >= 'a' && *value <= 'z') value++; while (*value == ' ' || *value == '=') value++; if (strncmp(keyword, "color", 5) == 0) { int state, r, g, b; if (sscanf(value, "%d%d%d%d", &state, &r, &g, &b) == 4) { if (state >= 0 && state <= maxstate) { currlayer->cellr[state] = r; currlayer->cellg[state] = g; currlayer->cellb[state] = b; } }; } else if (strncmp(keyword, "gradient", 8) == 0) { int r1, g1, b1, r2, g2, b2; if (sscanf(value, "%d%d%d%d%d%d", &r1, &g1, &b1, &r2, &g2, &b2) == 6) { currlayer->fromrgb.Set(r1, g1, b1); currlayer->torgb.Set(r2, g2, b2); CreateColorGradient(); }; } } } reader.close(); return true; } return false; } // ----------------------------------------------------------------------------- static void DeleteIcons(Layer* layer) { // delete given layer's existing icons if (layer->icons7x7) { for (int i = 0; i < 256; i++) delete layer->icons7x7[i]; free(layer->icons7x7); layer->icons7x7 = NULL; } if (layer->icons15x15) { for (int i = 0; i < 256; i++) delete layer->icons15x15[i]; free(layer->icons15x15); layer->icons15x15 = NULL; } if (layer->icons31x31) { for (int i = 0; i < 256; i++) delete layer->icons31x31[i]; free(layer->icons31x31); layer->icons31x31 = NULL; } } // ----------------------------------------------------------------------------- static bool FindIconFile(const wxString& rule, const wxString& dir, wxString& path) { const wxString extn = wxT(".icons"); // first look for rule.icons in given directory path = dir + rule; path += extn; if (wxFileName::FileExists(path)) return true; // if rule has the form foo-* then look for foo.icons in dir; // this allows related rules to share a single .icons file wxString prefix = rule.BeforeLast('-'); if (!prefix.IsEmpty()) { path = dir + prefix; path += extn; if (wxFileName::FileExists(path)) return true; } return false; } // ----------------------------------------------------------------------------- static bool LoadRuleIcons(const wxString& rule, int maxstate) { // if rule.icons file exists in userrules or rulesdir then // load icons for current layer wxString path; return (FindIconFile(rule, userrules, path) || FindIconFile(rule, rulesdir, path)) && LoadIconFile(path, maxstate, &currlayer->icons7x7, &currlayer->icons15x15, &currlayer->icons31x31); } // ----------------------------------------------------------------------------- static void UseDefaultIcons(int maxstate) { // icons weren't specified so use default icons if (currlayer->algo->getgridtype() == lifealgo::HEX_GRID) { // use hexagonal icons currlayer->icons7x7 = CopyIcons(hexagons7x7, maxstate); currlayer->icons15x15 = CopyIcons(hexagons15x15, maxstate); currlayer->icons31x31 = CopyIcons(hexagons31x31, maxstate); } else if (currlayer->algo->getgridtype() == lifealgo::VN_GRID) { // use diamond-shaped icons for 4-neighbor von Neumann neighborhood currlayer->icons7x7 = CopyIcons(diamonds7x7, maxstate); currlayer->icons15x15 = CopyIcons(diamonds15x15, maxstate); currlayer->icons31x31 = CopyIcons(diamonds31x31, maxstate); } else { // otherwise use default icons from current algo AlgoData* ad = algoinfo[currlayer->algtype]; currlayer->icons7x7 = CopyIcons(ad->icons7x7, maxstate); currlayer->icons15x15 = CopyIcons(ad->icons15x15, maxstate); currlayer->icons31x31 = CopyIcons(ad->icons31x31, maxstate); } } // ----------------------------------------------------------------------------- static bool MultiColorBitmaps(wxBitmap** iconmaps, int maxstate) { // return true if any icon contains at least one color that isn't a shade of gray for (int n = 1; n <= maxstate; n++) { wxBitmap* icon = iconmaps[n]; if (icon) { int wd = icon->GetWidth(); int ht = icon->GetHeight(); wxAlphaPixelData icondata(*icon); if (icondata) { wxAlphaPixelData::Iterator iconpxl(icondata); for (int i = 0; i < ht; i++) { wxAlphaPixelData::Iterator iconrow = iconpxl; for (int j = 0; j < wd; j++) { unsigned char r = iconpxl.Red(); unsigned char g = iconpxl.Green(); unsigned char b = iconpxl.Blue(); if (r != g || g != b) return true; iconpxl++; } // move to next row iconpxl = iconrow; iconpxl.OffsetY(icondata, 1); } } } } return false; // all icons are grayscale } // ----------------------------------------------------------------------------- static void SetAverageColor(int state, wxBitmap* icon) { // set non-icon color to average color of non-black pixels in given icon if (icon) { int wd = icon->GetWidth(); int ht = icon->GetHeight(); wxAlphaPixelData icondata(*icon); if (icondata) { wxAlphaPixelData::Iterator iconpxl(icondata); int nbcount = 0; // # of non-black pixels int totalr = 0; int totalg = 0; int totalb = 0; for (int i = 0; i < ht; i++) { wxAlphaPixelData::Iterator iconrow = iconpxl; for (int j = 0; j < wd; j++) { if (iconpxl.Red() || iconpxl.Green() || iconpxl.Blue()) { // non-black pixel totalr += iconpxl.Red(); totalg += iconpxl.Green(); totalb += iconpxl.Blue(); nbcount++; } iconpxl++; } // move to next row of icon bitmap iconpxl = iconrow; iconpxl.OffsetY(icondata, 1); } if (nbcount>0) { currlayer->cellr[state] = int(totalr / nbcount); currlayer->cellg[state] = int(totalg / nbcount); currlayer->cellb[state] = int(totalb / nbcount); } else { // avoid div0 currlayer->cellr[state] = 0; currlayer->cellg[state] = 0; currlayer->cellb[state] = 0; } } } } // ----------------------------------------------------------------------------- void UpdateCurrentColors() { // set current layer's colors and icons according to current algo and rule AlgoData* ad = algoinfo[currlayer->algtype]; int maxstate = currlayer->algo->NumCellStates() - 1; // copy default colors from current algo currlayer->fromrgb = ad->fromrgb; currlayer->torgb = ad->torgb; if (ad->gradient) { CreateColorGradient(); // state 0 is not part of the gradient currlayer->cellr[0] = ad->algor[0]; currlayer->cellg[0] = ad->algog[0]; currlayer->cellb[0] = ad->algob[0]; } else { for (int n = 0; n <= maxstate; n++) { currlayer->cellr[n] = ad->algor[n]; currlayer->cellg[n] = ad->algog[n]; currlayer->cellb[n] = ad->algob[n]; } } wxString rulename = wxString(currlayer->algo->getrule(), wxConvLocal); // replace any '\' and '/' chars with underscores; // ie. given 12/34/6 we look for 12_34_6.rule rulename.Replace(wxT("\\"), wxT("_")); rulename.Replace(wxT("/"), wxT("_")); // strip off any suffix like ":T100,200" used to specify a bounded grid if (rulename.Find(':') >= 0) rulename = rulename.BeforeFirst(':'); // deallocate current layer's old icons DeleteIcons(currlayer); // this flag will change if any icon uses a non-grayscale color currlayer->multicoloricons = false; bool loadedcolors = false; bool loadedicons = false; // look for rulename.rule first FILE* rulefile = FindRuleFile(rulename); if (rulefile) { LoadRuleInfo(rulefile, rulename, &loadedcolors, &loadedicons); if (!loadedcolors || !loadedicons) { // if rulename has the form foo-* then look for foo-shared.rule // and load its colors and/or icons wxString prefix = rulename.BeforeLast('-'); if (!prefix.IsEmpty() && !rulename.EndsWith(wxT("-shared"))) { rulename = prefix + wxT("-shared"); rulefile = FindRuleFile(rulename); if (rulefile) LoadRuleInfo(rulefile, rulename, &loadedcolors, &loadedicons); } } if (!loadedicons) UseDefaultIcons(maxstate); // use the smallest icons to check if they are multi-color if (currlayer->icons7x7 && MultiColorBitmaps(currlayer->icons7x7, maxstate)) currlayer->multicoloricons = true; // if the icons are multi-color then we don't call SetAverageColor as we do below // (better if the .rule file sets the appropriate non-icon colors) } else { // no rulename.rule so look for deprecated rulename.colors and/or rulename.icons loadedcolors = LoadRuleColors(rulename, maxstate); loadedicons = LoadRuleIcons(rulename, maxstate); if (!loadedicons) UseDefaultIcons(maxstate); // if rulename.colors wasn't supplied and icons are multi-color then we set // non-icon colors to the average of the non-black pixels in each icon // (note that we use the 7x7 icons because they are faster to scan) wxBitmap** iconmaps = currlayer->icons7x7; if (!loadedcolors && iconmaps && currlayer->multicoloricons) { for (int n = 1; n <= maxstate; n++) { SetAverageColor(n, iconmaps[n]); } // if extra 15x15 icon was supplied then use it to set state 0 color iconmaps = currlayer->icons15x15; if (iconmaps && iconmaps[0]) { wxAlphaPixelData icondata(*iconmaps[0]); if (icondata) { wxAlphaPixelData::Iterator iconpxl(icondata); // iconpxl is the top left pixel currlayer->cellr[0] = iconpxl.Red(); currlayer->cellg[0] = iconpxl.Green(); currlayer->cellb[0] = iconpxl.Blue(); } } } } if (swapcolors) { // invert cell colors in current layer for (int n = 0; n <= maxstate; n++) { currlayer->cellr[n] = 255 - currlayer->cellr[n]; currlayer->cellg[n] = 255 - currlayer->cellg[n]; currlayer->cellb[n] = 255 - currlayer->cellb[n]; } } } // ----------------------------------------------------------------------------- void UpdateLayerColors() { UpdateCurrentColors(); // if current layer has clones then update their colors UpdateCloneColors(); } // ----------------------------------------------------------------------------- void InvertCellColors() { // invert cell colors in all layers for (int i = 0; i < numlayers; i++) { Layer* layerptr = layer[i]; // do NOT use layerptr->algo->... here -- it might not be correct // for a non-current layer (but we can use layerptr->algtype) for (int n = 0; n < algoinfo[layerptr->algtype]->maxstates; n++) { layerptr->cellr[n] = 255 - layerptr->cellr[n]; layerptr->cellg[n] = 255 - layerptr->cellg[n]; layerptr->cellb[n] = 255 - layerptr->cellb[n]; } UpdateBrushAndPens(layerptr); } } // ----------------------------------------------------------------------------- Layer* GetLayer(int index) { if (index < 0 || index >= numlayers) { Warning(_("Bad index in GetLayer!")); return NULL; } else { return layer[index]; } } // ----------------------------------------------------------------------------- int GetUniqueCloneID() { // find first available index (> 0) to use as cloneid for (int i = 1; i < MAX_LAYERS; i++) { if (cloneavail[i]) { cloneavail[i] = false; return i; } } // bug if we get here Warning(_("Bug in GetUniqueCloneID!")); return 1; } // ----------------------------------------------------------------------------- Layer::Layer() { if (!cloning) { // use a unique temporary file for saving starting patterns tempstart = wxFileName::CreateTempFileName(tempdir + wxT("golly_start_")); } dirty = false; // user has not modified pattern savedirty = false; // in case script created layer stayclean = inscript; // if true then keep the dirty flag false // for the duration of the script savestart = false; // no need to save starting pattern startfile.Clear(); // no starting pattern startgen = 0; // initial starting generation currname = _("untitled"); // initial window title currfile.Clear(); // no pattern file has been loaded originx = 0; // no X origin offset originy = 0; // no Y origin offset icons7x7 = NULL; // no 7x7 icons icons15x15 = NULL; // no 15x15 icons icons31x31 = NULL; // no 31x31 icons currframe = 0; // first frame in timeline autoplay = 0; // not playing tlspeed = 0; // default speed for autoplay lastframe = 0; // no frame displayed deadbrush = new wxBrush(*wxBLACK); gridpen = new wxPen(*wxBLACK); boldpen = new wxPen(*wxBLACK); if (deadbrush == NULL) Fatal(_("Failed to create deadbrush!")); if (gridpen == NULL) Fatal(_("Failed to create gridpen!")); if (boldpen == NULL) Fatal(_("Failed to create boldpen!")); // create viewport; the initial size is not important because it will soon change view = new viewport(100,100); if (view == NULL) Fatal(_("Failed to create viewport!")); if (numlayers == 0) { // creating very first layer (can't be a clone) cloneid = 0; // initialize cloneavail array (cloneavail[0] is never used) cloneavail[0] = false; for (int i = 1; i < MAX_LAYERS; i++) cloneavail[i] = true; // set some options using initial values stored in prefs file algtype = initalgo; hyperspeed = inithyperspeed; showhashinfo = initshowhashinfo; autofit = initautofit; // initial base step and exponent currbase = algoinfo[algtype]->defbase; currexpo = 0; // create empty universe algo = CreateNewUniverse(algtype); // set rule using initrule stored in prefs file const char* err = algo->setrule(initrule); if (err) { // user might have edited rule in prefs file, or deleted table/tree file algo->setrule( algo->DefaultRule() ); } // don't need to remember rule here (SaveLayerSettings will do it) rule = wxEmptyString; // initialize undo/redo history undoredo = new UndoRedo(); if (undoredo == NULL) Fatal(_("Failed to create new undo/redo object!")); // set cursor in case newcurs/opencurs are set to "No Change" curs = curs_pencil; drawingstate = 1; } else { // adding a new layer after currlayer (see AddLayer) // inherit current universe type and other settings algtype = currlayer->algtype; hyperspeed = currlayer->hyperspeed; showhashinfo = currlayer->showhashinfo; autofit = currlayer->autofit; // initial base step and exponent currbase = algoinfo[algtype]->defbase; currexpo = 0; if (cloning) { if (currlayer->cloneid == 0) { // first time this universe is being cloned so need a unique cloneid cloneid = GetUniqueCloneID(); currlayer->cloneid = cloneid; // current layer also becomes a clone numclones += 2; } else { // we're cloning an existing clone cloneid = currlayer->cloneid; numclones++; } // clones share the same universe and undo/redo history algo = currlayer->algo; undoredo = currlayer->undoredo; // clones also share the same timeline currframe = currlayer->currframe; autoplay = currlayer->autoplay; tlspeed = currlayer->tlspeed; lastframe = currlayer->lastframe; // clones use same name for starting file tempstart = currlayer->tempstart; } else { // this layer isn't a clone cloneid = 0; // create empty universe algo = CreateNewUniverse(algtype); // use current rule const char* err = algo->setrule(currlayer->algo->getrule()); if (err) { // table/tree file might have been deleted algo->setrule( algo->DefaultRule() ); } // initialize undo/redo history undoredo = new UndoRedo(); if (undoredo == NULL) Fatal(_("Failed to create new undo/redo object!")); } // inherit current rule rule = wxString(currlayer->algo->getrule(), wxConvLocal); // inherit current viewport's size, scale and location view->resize( currlayer->view->getwidth(), currlayer->view->getheight() ); view->setpositionmag( currlayer->view->x, currlayer->view->y, currlayer->view->getmag() ); // inherit current cursor and drawing state curs = currlayer->curs; drawingstate = currlayer->drawingstate; if (cloning || duplicating) { // duplicate all the other current settings currname = currlayer->currname; dirty = currlayer->dirty; savedirty = currlayer->savedirty; stayclean = currlayer->stayclean; currbase = currlayer->currbase; currexpo = currlayer->currexpo; autofit = currlayer->autofit; hyperspeed = currlayer->hyperspeed; showhashinfo = currlayer->showhashinfo; originx = currlayer->originx; originy = currlayer->originy; // duplicate selection info currsel = currlayer->currsel; savesel = currlayer->savesel; // duplicate the stuff needed to reset pattern savestart = currlayer->savestart; startalgo = currlayer->startalgo; startdirty = currlayer->startdirty; startname = currlayer->startname; startrule = currlayer->startrule; startx = currlayer->startx; starty = currlayer->starty; startbase = currlayer->startbase; startexpo = currlayer->startexpo; startmag = currlayer->startmag; startfile = currlayer->startfile; startgen = currlayer->startgen; currfile = currlayer->currfile; startsel = currlayer->startsel; } if (duplicating) { // first set same gen count algo->setGeneration( currlayer->algo->getGeneration() ); // duplicate pattern if ( !currlayer->algo->isEmpty() ) { bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { Warning(_("Pattern is too big to duplicate.")); } else { viewptr->CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, algo, false, _("Duplicating layer")); } } // tempstart file must remain unique in duplicate layer if ( wxFileExists(currlayer->tempstart) ) { if ( !wxCopyFile(currlayer->tempstart, tempstart, true) ) { Warning(_("Could not copy tempstart file!")); } } if (currlayer->startfile == currlayer->tempstart) { startfile = tempstart; } if (currlayer->currfile == currlayer->tempstart) { // starting pattern came from clipboard or lexicon pattern currfile = tempstart; } if (allowundo) { // duplicate current undo/redo history in new layer undoredo->DuplicateHistory(currlayer, this); } } } } // ----------------------------------------------------------------------------- Layer::~Layer() { // delete stuff allocated in ctor delete view; delete deadbrush; delete gridpen; delete boldpen; if (cloneid > 0) { // this layer is a clone, so count how many layers have the same cloneid int clonecount = 0; for (int i = 0; i < numlayers; i++) { if (layer[i]->cloneid == cloneid) clonecount++; // tell undo/redo which clone is being deleted if (this == layer[i]) undoredo->DeletingClone(i); } if (clonecount > 2) { // only delete this clone numclones--; } else { // first make this cloneid available for the next clone cloneavail[cloneid] = true; // reset the other cloneid to 0 (should only be one such clone) for (int i = 0; i < numlayers; i++) { // careful -- layer[i] might be this layer if (this != layer[i] && layer[i]->cloneid == cloneid) layer[i]->cloneid = 0; } numclones -= 2; } } else { // this layer is not a clone, so delete universe and undo/redo history delete algo; delete undoredo; // delete tempstart file if it exists if (wxFileExists(tempstart)) wxRemoveFile(tempstart); // deallocate any icons DeleteIcons(this); } } // ----------------------------------------------------------------------------- // define a window for displaying cell colors/icons: const int CELLSIZE = 16; // wd and ht of each cell const int NUMCOLS = 32; // number of columns const int NUMROWS = 8; // number of rows class CellPanel : public wxPanel { public: CellPanel(wxWindow* parent, wxWindowID id) : wxPanel(parent, id, wxPoint(0,0), wxSize(NUMCOLS*CELLSIZE+1,NUMROWS*CELLSIZE+1)) { } wxStaticText* statebox; // for showing state of cell under cursor wxStaticText* rgbbox; // for showing color of cell under cursor private: void OnEraseBackground(wxEraseEvent& event); void OnPaint(wxPaintEvent& event); void OnMouseDown(wxMouseEvent& event); void OnMouseMotion(wxMouseEvent& event); void OnMouseExit(wxMouseEvent& event); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(CellPanel, wxPanel) EVT_ERASE_BACKGROUND (CellPanel::OnEraseBackground) EVT_PAINT (CellPanel::OnPaint) EVT_LEFT_DOWN (CellPanel::OnMouseDown) EVT_LEFT_DCLICK (CellPanel::OnMouseDown) EVT_MOTION (CellPanel::OnMouseMotion) EVT_ENTER_WINDOW (CellPanel::OnMouseMotion) EVT_LEAVE_WINDOW (CellPanel::OnMouseExit) END_EVENT_TABLE() // ----------------------------------------------------------------------------- void CellPanel::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { // do nothing } // ----------------------------------------------------------------------------- void CellPanel::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); dc.SetPen(*wxBLACK_PEN); #ifdef __WXMSW__ // we have to use theme background color on Windows wxBrush bgbrush(GetBackgroundColour()); #else wxBrush bgbrush(*wxTRANSPARENT_BRUSH); #endif // draw cell boxes wxBitmap** iconmaps = currlayer->icons15x15; wxRect r = wxRect(0, 0, CELLSIZE+1, CELLSIZE+1); int col = 0; for (int state = 0; state < 256; state++) { if (state < currlayer->algo->NumCellStates()) { if (showicons && iconmaps && iconmaps[state]) { dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); DrawOneIcon(dc, r.x + 1, r.y + 1, iconmaps[state], currlayer->cellr[0], currlayer->cellg[0], currlayer->cellb[0], currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state], currlayer->multicoloricons); } else { wxColor color(currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state]); dc.SetBrush(wxBrush(color)); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } } else { // state >= currlayer->algo->NumCellStates() dc.SetBrush(bgbrush); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } col++; if (col < NUMCOLS) { r.x += CELLSIZE; } else { r.x = 0; r.y += CELLSIZE; col = 0; } } dc.SetPen(wxNullPen); } // ----------------------------------------------------------------------------- void CellPanel::OnMouseDown(wxMouseEvent& event) { int col = event.GetX() / CELLSIZE; int row = event.GetY() / CELLSIZE; int state = row * NUMCOLS + col; if (state >= 0 && state < currlayer->algo->NumCellStates()) { // let user change color of this cell state wxColour rgb(currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state]); wxColourData data; data.SetChooseFull(true); // for Windows data.SetColour(rgb); wxColourDialog dialog(this, &data); if ( dialog.ShowModal() == wxID_OK ) { wxColourData retData = dialog.GetColourData(); wxColour c = retData.GetColour(); if (rgb != c) { // change color currlayer->cellr[state] = c.Red(); currlayer->cellg[state] = c.Green(); currlayer->cellb[state] = c.Blue(); Refresh(false); } } } event.Skip(); } // ----------------------------------------------------------------------------- void CellPanel::OnMouseMotion(wxMouseEvent& event) { int col = event.GetX() / CELLSIZE; int row = event.GetY() / CELLSIZE; int state = row * NUMCOLS + col; if (state < 0 || state > 255) { statebox->SetLabel(_(" ")); rgbbox->SetLabel(_(" ")); } else { statebox->SetLabel(wxString::Format(_("%d"),state)); if (state < currlayer->algo->NumCellStates()) { rgbbox->SetLabel(wxString::Format(_("%d,%d,%d"), currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state])); } else { rgbbox->SetLabel(_(" ")); } } } // ----------------------------------------------------------------------------- void CellPanel::OnMouseExit(wxMouseEvent& WXUNUSED(event)) { statebox->SetLabel(_(" ")); rgbbox->SetLabel(_(" ")); } // ----------------------------------------------------------------------------- // define a modal dialog for changing colors class ColorDialog : public wxDialog { public: ColorDialog(wxWindow* parent); virtual bool TransferDataFromWindow(); // called when user hits OK enum { // control ids CELL_PANEL = wxID_HIGHEST + 1, ICON_CHECK, STATE_BOX, RGB_BOX, GRADIENT_BUTT, FROM_BUTT, TO_BUTT, DEFAULT_BUTT }; void CreateControls(); // initialize all the controls void AddColorButton(wxWindow* parent, wxBoxSizer* hbox, int id, wxColor* rgb); void ChangeButtonColor(int id, wxColor* rgb); void UpdateButtonColor(int id, wxColor* rgb); CellPanel* cellpanel; // for displaying cell colors/icons wxCheckBox* iconcheck; // show icons? private: // event handlers void OnCheckBoxClicked(wxCommandEvent& event); void OnButton(wxCommandEvent& event); #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) void OnCharHook(wxKeyEvent& event); #endif DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(ColorDialog, wxDialog) EVT_CHECKBOX (wxID_ANY, ColorDialog::OnCheckBoxClicked) EVT_BUTTON (wxID_ANY, ColorDialog::OnButton) #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) EVT_CHAR_HOOK (ColorDialog::OnCharHook) #endif END_EVENT_TABLE() // ----------------------------------------------------------------------------- // these consts are used to get nicely spaced controls on each platform: const int HGAP = 12; // space left and right of vertically stacked boxes // following ensures OK/Cancel buttons are better aligned #ifdef __WXMAC__ const int STDHGAP = 0; #elif defined(__WXMSW__) const int STDHGAP = 9; #else const int STDHGAP = 10; #endif const int BITMAP_WD = 60; // width of bitmap in color buttons const int BITMAP_HT = 20; // height of bitmap in color buttons // ----------------------------------------------------------------------------- ColorDialog::ColorDialog(wxWindow* parent) { Create(parent, wxID_ANY, _("Set Layer Colors"), wxDefaultPosition, wxDefaultSize); CreateControls(); Centre(); } // ----------------------------------------------------------------------------- void ColorDialog::CreateControls() { wxString note = _("NOTE: Changes made here are temporary and only affect the current layer and "); note += _("its clones. The colors will be reset to their default values if you open "); note += _("a pattern file or create a new pattern, or if you change the current algorithm "); note += _("or rule. If you want to change the default colors, use Preferences > Color."); wxStaticText* notebox = new wxStaticText(this, wxID_STATIC, note); notebox->Wrap(NUMCOLS * CELLSIZE + 1); // create bitmap buttons wxBoxSizer* frombox = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* tobox = new wxBoxSizer(wxHORIZONTAL); AddColorButton(this, frombox, FROM_BUTT, &currlayer->fromrgb); AddColorButton(this, tobox, TO_BUTT, &currlayer->torgb); wxButton* defbutt = new wxButton(this, DEFAULT_BUTT, _("Default Colors")); wxButton* gradbutt = new wxButton(this, GRADIENT_BUTT, _("Create Gradient")); wxBoxSizer* gradbox = new wxBoxSizer(wxHORIZONTAL); gradbox->Add(gradbutt, 0, wxALIGN_CENTER_VERTICAL, 0); gradbox->Add(new wxStaticText(this, wxID_STATIC, _(" from ")), 0, wxALIGN_CENTER_VERTICAL, 0); gradbox->Add(frombox, 0, wxALIGN_CENTER_VERTICAL, 0); gradbox->Add(new wxStaticText(this, wxID_STATIC, _(" to ")), 0, wxALIGN_CENTER_VERTICAL, 0); gradbox->Add(tobox, 0, wxALIGN_CENTER_VERTICAL, 0); // create child window for displaying cell colors/icons cellpanel = new CellPanel(this, CELL_PANEL); iconcheck = new wxCheckBox(this, ICON_CHECK, _("Show icons")); iconcheck->SetValue(showicons); wxStaticText* statebox = new wxStaticText(this, STATE_BOX, _("999")); cellpanel->statebox = statebox; wxBoxSizer* hbox1 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(statebox, 0, 0, 0); hbox1->SetMinSize( hbox1->GetMinSize() ); wxStaticText* rgbbox = new wxStaticText(this, RGB_BOX, _("999,999,999")); cellpanel->rgbbox = rgbbox; wxBoxSizer* hbox2 = new wxBoxSizer(wxHORIZONTAL); hbox2->Add(rgbbox, 0, 0, 0); hbox2->SetMinSize( hbox2->GetMinSize() ); statebox->SetLabel(_(" ")); rgbbox->SetLabel(_(" ")); wxBoxSizer* botbox = new wxBoxSizer(wxHORIZONTAL); botbox->Add(new wxStaticText(this, wxID_STATIC, _("State: ")), 0, wxALIGN_CENTER_VERTICAL, 0); botbox->Add(hbox1, 0, wxALIGN_CENTER_VERTICAL, 0); botbox->Add(20, 0, 0); botbox->Add(new wxStaticText(this, wxID_STATIC, _("RGB: ")), 0, wxALIGN_CENTER_VERTICAL, 0); botbox->Add(hbox2, 0, wxALIGN_CENTER_VERTICAL, 0); botbox->AddStretchSpacer(); botbox->Add(iconcheck, 0, wxALIGN_CENTER_VERTICAL, 0); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); vbox->Add(gradbox, 0, wxALIGN_CENTER, 0); vbox->AddSpacer(10); vbox->Add(cellpanel, 0, wxLEFT | wxRIGHT, 0); vbox->AddSpacer(5); vbox->Add(botbox, 1, wxGROW | wxLEFT | wxRIGHT, 0); wxSizer* stdbutts = CreateButtonSizer(wxOK | wxCANCEL); wxBoxSizer* stdhbox = new wxBoxSizer( wxHORIZONTAL ); stdhbox->Add(defbutt, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, HGAP); stdhbox->Add(stdbutts, 1, wxGROW | wxALIGN_CENTER_VERTICAL | wxRIGHT, STDHGAP); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); topSizer->AddSpacer(10); topSizer->Add(notebox, 0, wxLEFT | wxRIGHT, HGAP); topSizer->AddSpacer(20); topSizer->Add(vbox, 0, wxGROW | wxLEFT | wxRIGHT, HGAP); topSizer->AddSpacer(10); topSizer->Add(stdhbox, 1, wxGROW | wxTOP | wxBOTTOM, 10); SetSizer(topSizer); topSizer->SetSizeHints(this); // calls Fit } // ----------------------------------------------------------------------------- void ColorDialog::OnCheckBoxClicked(wxCommandEvent& event) { if ( event.GetId() == ICON_CHECK ) { showicons = iconcheck->GetValue() == 1; cellpanel->Refresh(false); } } // ----------------------------------------------------------------------------- void ColorDialog::AddColorButton(wxWindow* parent, wxBoxSizer* hbox, int id, wxColor* rgb) { wxBitmap bitmap(BITMAP_WD, BITMAP_HT); wxMemoryDC dc; dc.SelectObject(bitmap); wxRect rect(0, 0, BITMAP_WD, BITMAP_HT); wxBrush brush(*rgb); FillRect(dc, rect, brush); dc.SelectObject(wxNullBitmap); wxBitmapButton* bb = new wxBitmapButton(parent, id, bitmap, wxPoint(0,0), #if defined(__WXOSX_COCOA__) wxSize(BITMAP_WD + 12, BITMAP_HT + 12)); #else wxDefaultSize); #endif if (bb) hbox->Add(bb, 0, wxALIGN_CENTER_VERTICAL, 0); } // ----------------------------------------------------------------------------- void ColorDialog::UpdateButtonColor(int id, wxColor* rgb) { wxBitmapButton* bb = (wxBitmapButton*) FindWindow(id); if (bb) { wxBitmap bitmap(BITMAP_WD, BITMAP_HT); wxMemoryDC dc; dc.SelectObject(bitmap); wxRect rect(0, 0, BITMAP_WD, BITMAP_HT); wxBrush brush(*rgb); FillRect(dc, rect, brush); dc.SelectObject(wxNullBitmap); bb->SetBitmapLabel(bitmap); bb->Refresh(); } } // ----------------------------------------------------------------------------- void ColorDialog::ChangeButtonColor(int id, wxColor* rgb) { wxColourData data; data.SetChooseFull(true); // for Windows data.SetColour(*rgb); wxColourDialog dialog(this, &data); if ( dialog.ShowModal() == wxID_OK ) { wxColourData retData = dialog.GetColourData(); wxColour c = retData.GetColour(); if (*rgb != c) { // change given color rgb->Set(c.Red(), c.Green(), c.Blue()); // also change color of bitmap in corresponding button UpdateButtonColor(id, rgb); cellpanel->Refresh(false); } } } // ----------------------------------------------------------------------------- #if defined(__WXOSX_COCOA__) && wxCHECK_VERSION(3,0,0) void ColorDialog::OnCharHook(wxKeyEvent& event) { int key = event.GetKeyCode(); if (key == WXK_RETURN) { // fix wxOSX 3.x bug: allow return key to select OK button wxCommandEvent okevent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK); okevent.SetEventObject(this); GetEventHandler()->ProcessEvent(okevent); return; } event.Skip(); // process other keys, like escape } #endif // ----------------------------------------------------------------------------- void ColorDialog::OnButton(wxCommandEvent& event) { int id = event.GetId(); if ( id == FROM_BUTT ) { ChangeButtonColor(id, &currlayer->fromrgb); } else if ( id == TO_BUTT ) { ChangeButtonColor(id, &currlayer->torgb); } else if ( id == GRADIENT_BUTT ) { // use currlayer->fromrgb and currlayer->torgb CreateColorGradient(); cellpanel->Refresh(false); } else if ( id == DEFAULT_BUTT ) { // restore current layer's default colors, but don't call UpdateLayerColors // here because we don't want to change any clone layers at this stage // (in case user cancels dialog) UpdateCurrentColors(); UpdateButtonColor(FROM_BUTT, &currlayer->fromrgb); UpdateButtonColor(TO_BUTT, &currlayer->torgb); cellpanel->Refresh(false); } else { // process other buttons like Cancel and OK event.Skip(); } } // ----------------------------------------------------------------------------- bool ColorDialog::TransferDataFromWindow() { // if current layer has clones then update their colors UpdateCloneColors(); return true; } // ----------------------------------------------------------------------------- // class for saving and restoring layer colors class SaveData { public: SaveData() { fromrgb = currlayer->fromrgb; torgb = currlayer->torgb; for (int i = 0; i < currlayer->algo->NumCellStates(); i++) { cellr[i] = currlayer->cellr[i]; cellg[i] = currlayer->cellg[i]; cellb[i] = currlayer->cellb[i]; } deadbrushrgb = currlayer->deadbrush->GetColour(); gridpenrgb = currlayer->gridpen->GetColour(); boldpenrgb = currlayer->boldpen->GetColour(); saveshowicons = showicons; } void RestoreData() { currlayer->fromrgb = fromrgb; currlayer->torgb = torgb; for (int i = 0; i < currlayer->algo->NumCellStates(); i++) { currlayer->cellr[i] = cellr[i]; currlayer->cellg[i] = cellg[i]; currlayer->cellb[i] = cellb[i]; } currlayer->deadbrush->SetColour(deadbrushrgb); currlayer->gridpen->SetColour(gridpenrgb); currlayer->boldpen->SetColour(boldpenrgb); showicons = saveshowicons; } // this must match color info in Layer class wxColor fromrgb; wxColor torgb; unsigned char cellr[256]; unsigned char cellg[256]; unsigned char cellb[256]; wxColor deadbrushrgb; wxColor gridpenrgb; wxColor boldpenrgb; // we also save/restore showicons option bool saveshowicons; }; // ----------------------------------------------------------------------------- void SetLayerColors() { if (inscript || viewptr->waitingforclick) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_SET_COLORS); return; } bool wastoggled = swapcolors; if (swapcolors) viewptr->ToggleCellColors(); // save current color info so we can restore it if user cancels changes SaveData* save_info = new SaveData(); ColorDialog dialog( wxGetApp().GetTopWindow() ); if ( dialog.ShowModal() != wxID_OK ) { // user hit Cancel so restore color info saved above save_info->RestoreData(); } delete save_info; if (wastoggled) viewptr->ToggleCellColors(); mainptr->UpdateEverything(); } golly-2.7-src/gui-wx/wxinfo.h0000644000175000017500000000227012536111364013124 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXINFO_H_ #define _WXINFO_H_ // Routines for displaying comments in a pattern file: // Open a modeless window and display the comments in given file. void ShowInfo(const wxString& filepath); // Return a pointer to the info window. wxFrame* GetInfoFrame(); #endif golly-2.7-src/gui-wx/makefile-win0000755000175000017500000004367212536111364013752 00000000000000# Makefile for Windows version of Golly using wxWidgets. # # Use local-win-template.mk to create local-win.mk with paths to your installed libraries. # # Compile wxWidgets and Golly as below: # # On 32-bit Windows: (from a Visual Studio command prompt) # # Build wxWidgets: # cd \wxWidgets\build\msw # nmake -f makefile.vc BUILD=release RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=0 DEBUG_FLAG=0 # Build Golly: # cd \golly\src # nmake -f makefile-win BUILD=release RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=0 DEBUG_FLAG=0 # # On 64-bit Windows: (from a Visual Studio 64-bit command prompt) # # Build wxWidgets: # cd \wxWidgets\build\msw # nmake -f makefile.vc BUILD=release RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=0 DEBUG_FLAG=0 TARGET_CPU=AMD64 # Build Golly: # cd \golly\src # nmake -f makefile-win BUILD=release RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=0 DEBUG_FLAG=0 TARGET_CPU=AMD64 # # If you only build one wxWidgets configuration (e.g. 32-bit release) then you can edit # \wxWidgets\build\msw\config.vc with those options. Then you can build wxWidgets and Golly # simply with: # # Build wxWidgets: # cd \wxWidgets\build\msw # nmake -f makefile.vc # Build Golly: # cd \golly\src # nmake -f makefile-win # All system-dependent changes belong in local-win.mk !include local-win.mk ### Golly-related variables: ### APP_VERSION = 2.7 # these directory paths are relative to the location of this makefile: EXEDIR = .. DOCSDIR = ..\docs BASEDIR = ..\gollybase CMDDIR = ..\cmdline # for building binary and source distributions: RELEASENAME = $(EXEDIR)\golly-$(APP_VERSION) GUIFILES = CMakeLists.txt makefile-gtk makefile-mac makefile-win local-win-template.mk \ golly.rc Info.plist.in wx*.h wx*.cpp GUIDIRS = configure bitmaps icons BINFILES = $(EXEDIR)\Golly.exe $(EXEDIR)\bgolly.exe \ $(DOCSDIR)\ReadMe.html $(DOCSDIR)\License.html !if "$(TARGET_CPU)" == "AMD64" LIBDIRNAME = $(WX_DIR)\lib\vc_amd64_$(LIBTYPE_SUFFIX)$(CFG) WX_CPU_DEF = WX_CPU_AMD64 !else LIBDIRNAME = $(WX_DIR)\lib\vc_$(LIBTYPE_SUFFIX)$(CFG) WX_CPU_DEF = WX_CPU_X86 !endif SETUPHDIR = $(LIBDIRNAME)\$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG) ### note that /wd4100 turns off annoying warnings about "unreferenced formal parameter" ### in wx 2.9 when debugging assertions are disabled CXXFLAGS = /M$(__RUNTIME_LIBS_8)$(__DEBUGRUNTIME_3) /DWIN32 \ $(__DEBUGINFO_0) /Fdgolly.pdb $(____DEBUGRUNTIME_2_p) \ $(__OPTIMIZEFLAG_4) $(__NO_VC_CRTDBG_p) /D__WXMSW__ $(__WXUNIV_DEFINE_p) \ $(__DEBUG_DEFINE_p) $(__NDEBUG_DEFINE_p) $(__EXCEPTIONS_DEFINE_p) $(__RTTI_DEFINE_p) \ $(__THREAD_DEFINE_p) $(__UNICODE_DEFINE_p) /I$(WX_DIR)\include /I$(SETUPHDIR) \ /W4 /wd4100 /I. $(__DLLFLAG_p) /D_WINDOWS /I$(WX_DIR)\samples /DNOPCH $(__RTTIFLAG_9) \ $(__EXCEPTIONSFLAG_10) $(CPPFLAGS) \ /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS \ /EHsc /DVERSION=$(APP_VERSION) /DZLIB /I$(WX_DIR)\src\zlib /I$(BASEDIR) OBJDIR = ObjWin BASEH = $(BASEDIR)/bigint.h $(BASEDIR)/ghashbase.h $(BASEDIR)/hlifealgo.h $(BASEDIR)/jvnalgo.h \ $(BASEDIR)/lifealgo.h $(BASEDIR)/lifepoll.h $(BASEDIR)/liferender.h $(BASEDIR)/liferules.h \ $(BASEDIR)/platform.h $(BASEDIR)/qlifealgo.h $(BASEDIR)/readpattern.h $(BASEDIR)/util.h $(BASEDIR)/viewport.h \ $(BASEDIR)/writepattern.h $(BASEDIR)/ruletreealgo.h $(BASEDIR)/generationsalgo.h $(BASEDIR)/ruletable_algo.h \ $(BASEDIR)/ruleloaderalgo.h BASEOBJ = $(OBJDIR)/bigint.obj $(OBJDIR)/lifealgo.obj $(OBJDIR)/hlifealgo.obj \ $(OBJDIR)/hlifedraw.obj $(OBJDIR)/qlifealgo.obj $(OBJDIR)/qlifedraw.obj \ $(OBJDIR)/jvnalgo.obj $(OBJDIR)/ruletreealgo.obj \ $(OBJDIR)/ruletable_algo.obj $(OBJDIR)/ghashbase.obj $(OBJDIR)/ruleloaderalgo.obj \ $(OBJDIR)/ghashdraw.obj $(OBJDIR)/readpattern.obj \ $(OBJDIR)/writepattern.obj $(OBJDIR)/liferules.obj $(OBJDIR)/util.obj \ $(OBJDIR)/liferender.obj $(OBJDIR)/viewport.obj $(OBJDIR)/lifepoll.obj \ $(OBJDIR)/generationsalgo.obj WXH = wxalgos.h wxedit.h wxgolly.h wxhelp.h wxinfo.h wxlayer.h wxmain.h \ wxperl.h wxprefs.h wxpython.h wxrender.h wxrule.h wxscript.h wxselect.h wxstatus.h \ wxtimeline.h wxundo.h wxutils.h wxview.h WXOBJ = $(OBJDIR)/wxutils.obj $(OBJDIR)/wxprefs.obj $(OBJDIR)/wxalgos.obj \ $(OBJDIR)/wxrule.obj $(OBJDIR)/wxinfo.obj $(OBJDIR)/wxhelp.obj \ $(OBJDIR)/wxstatus.obj $(OBJDIR)/wxview.obj $(OBJDIR)/wxrender.obj \ $(OBJDIR)/wxscript.obj $(OBJDIR)/wxperl.obj $(OBJDIR)/wxpython.obj \ $(OBJDIR)/wxfile.obj $(OBJDIR)/wxedit.obj $(OBJDIR)/wxcontrol.obj \ $(OBJDIR)/wxtimeline.obj $(OBJDIR)/wxundo.obj $(OBJDIR)/wxlayer.obj \ $(OBJDIR)/wxmain.obj $(OBJDIR)/wxselect.obj $(OBJDIR)/wxgolly.obj ### Conditionally set variables: ### PORTNAME = msw !if "$(BUILD)" == "debug" && "$(DEBUG_FLAG)" == "default" WXDEBUGFLAG = d !endif !if "$(DEBUG_FLAG)" == "1" WXDEBUGFLAG = d !endif !if "$(UNICODE)" == "1" WXUNICODEFLAG = u !endif !if "$(WXUNIV)" == "1" WXUNIVNAME = univ !endif !if "$(SHARED)" == "1" WXDLLFLAG = dll !endif !if "$(SHARED)" == "0" LIBTYPE_SUFFIX = lib !endif !if "$(SHARED)" == "1" LIBTYPE_SUFFIX = dll !endif !if "$(BUILD)" == "debug" && "$(DEBUG_INFO)" == "default" __DEBUGINFO_0 = /Zi !endif !if "$(BUILD)" == "release" && "$(DEBUG_INFO)" == "default" __DEBUGINFO_0 = !endif !if "$(DEBUG_INFO)" == "0" __DEBUGINFO_0 = !endif !if "$(DEBUG_INFO)" == "1" __DEBUGINFO_0 = /Zi !endif !if "$(BUILD)" == "debug" && "$(DEBUG_INFO)" == "default" __DEBUGINFO_1 = /DEBUG !endif !if "$(BUILD)" == "release" && "$(DEBUG_INFO)" == "default" __DEBUGINFO_1 = !endif !if "$(DEBUG_INFO)" == "0" __DEBUGINFO_1 = !endif !if "$(DEBUG_INFO)" == "1" __DEBUGINFO_1 = /DEBUG !endif !if "$(BUILD)" == "debug" && "$(DEBUG_RUNTIME_LIBS)" == "default" ____DEBUGRUNTIME_2_p = /D_DEBUG !endif !if "$(BUILD)" == "release" && "$(DEBUG_RUNTIME_LIBS)" == "default" ____DEBUGRUNTIME_2_p = !endif !if "$(DEBUG_RUNTIME_LIBS)" == "0" ____DEBUGRUNTIME_2_p = !endif !if "$(DEBUG_RUNTIME_LIBS)" == "1" ____DEBUGRUNTIME_2_p = /D_DEBUG !endif !if "$(BUILD)" == "debug" && "$(DEBUG_RUNTIME_LIBS)" == "default" ____DEBUGRUNTIME_2_p_1 = /d _DEBUG !endif !if "$(BUILD)" == "release" && "$(DEBUG_RUNTIME_LIBS)" == "default" ____DEBUGRUNTIME_2_p_1 = !endif !if "$(DEBUG_RUNTIME_LIBS)" == "0" ____DEBUGRUNTIME_2_p_1 = !endif !if "$(DEBUG_RUNTIME_LIBS)" == "1" ____DEBUGRUNTIME_2_p_1 = /d _DEBUG !endif !if "$(BUILD)" == "debug" && "$(DEBUG_RUNTIME_LIBS)" == "default" __DEBUGRUNTIME_3 = d !endif !if "$(BUILD)" == "release" && "$(DEBUG_RUNTIME_LIBS)" == "default" __DEBUGRUNTIME_3 = !endif !if "$(DEBUG_RUNTIME_LIBS)" == "0" __DEBUGRUNTIME_3 = !endif !if "$(DEBUG_RUNTIME_LIBS)" == "1" __DEBUGRUNTIME_3 = d !endif !if "$(BUILD)" == "debug" __OPTIMIZEFLAG_4 = /Od !endif !if "$(BUILD)" == "release" __OPTIMIZEFLAG_4 = /O2 !endif !if "$(USE_THREADS)" == "0" __THREADSFLAG_7 = L !endif !if "$(USE_THREADS)" == "1" __THREADSFLAG_7 = T !endif !if "$(RUNTIME_LIBS)" == "dynamic" __RUNTIME_LIBS_8 = D !endif !if "$(RUNTIME_LIBS)" == "static" __RUNTIME_LIBS_8 = $(__THREADSFLAG_7) !endif !if "$(USE_RTTI)" == "0" __RTTIFLAG_9 = !endif !if "$(USE_RTTI)" == "1" __RTTIFLAG_9 = /GR !endif !if "$(USE_EXCEPTIONS)" == "0" __EXCEPTIONSFLAG_10 = !endif !if "$(USE_EXCEPTIONS)" == "1" __EXCEPTIONSFLAG_10 = /EHsc !endif !if "$(BUILD)" == "debug" && "$(DEBUG_RUNTIME_LIBS)" == "0" __NO_VC_CRTDBG_p = /D__NO_VC_CRTDBG__ !endif !if "$(BUILD)" == "release" && "$(DEBUG_FLAG)" == "1" __NO_VC_CRTDBG_p = /D__NO_VC_CRTDBG__ !endif !if "$(BUILD)" == "debug" && "$(DEBUG_RUNTIME_LIBS)" == "0" __NO_VC_CRTDBG_p_1 = /d __NO_VC_CRTDBG__ !endif !if "$(BUILD)" == "release" && "$(DEBUG_FLAG)" == "1" __NO_VC_CRTDBG_p_1 = /d __NO_VC_CRTDBG__ !endif !if "$(WXUNIV)" == "1" __WXUNIV_DEFINE_p = /D__WXUNIVERSAL__ !endif !if "$(WXUNIV)" == "1" __WXUNIV_DEFINE_p_1 = /d __WXUNIVERSAL__ !endif !if "$(BUILD)" == "debug" && "$(DEBUG_FLAG)" == "default" __DEBUG_DEFINE_p = /D__WXDEBUG__ !endif !if "$(DEBUG_FLAG)" == "1" __DEBUG_DEFINE_p = /D__WXDEBUG__ !endif !if "$(BUILD)" == "debug" && "$(DEBUG_FLAG)" == "default" __DEBUG_DEFINE_p_1 = /d __WXDEBUG__ !endif !if "$(DEBUG_FLAG)" == "1" __DEBUG_DEFINE_p_1 = /d __WXDEBUG__ !endif ### following is needed for wxMSW 2.9.x !if "$(DEBUG_FLAG)" == "0" __DEBUG_DEFINE_p = /DwxDEBUG_LEVEL=0 !endif !if "$(DEBUG_FLAG)" == "0" __DEBUG_DEFINE_p_1 = /d wxDEBUG_LEVEL=0 !endif !if "$(BUILD)" == "release" && "$(DEBUG_RUNTIME_LIBS)" == "default" __NDEBUG_DEFINE_p = /DNDEBUG !endif !if "$(DEBUG_RUNTIME_LIBS)" == "0" __NDEBUG_DEFINE_p = /DNDEBUG !endif !if "$(BUILD)" == "release" && "$(DEBUG_RUNTIME_LIBS)" == "default" __NDEBUG_DEFINE_p_1 = /d NDEBUG !endif !if "$(DEBUG_RUNTIME_LIBS)" == "0" __NDEBUG_DEFINE_p_1 = /d NDEBUG !endif !if "$(USE_EXCEPTIONS)" == "0" __EXCEPTIONS_DEFINE_p = /DwxNO_EXCEPTIONS !endif !if "$(USE_EXCEPTIONS)" == "0" __EXCEPTIONS_DEFINE_p_1 = /d wxNO_EXCEPTIONS !endif !if "$(USE_RTTI)" == "0" __RTTI_DEFINE_p = /DwxNO_RTTI !endif !if "$(USE_RTTI)" == "0" __RTTI_DEFINE_p_1 = /d wxNO_RTTI !endif !if "$(USE_THREADS)" == "0" __THREAD_DEFINE_p = /DwxNO_THREADS !endif !if "$(USE_THREADS)" == "0" __THREAD_DEFINE_p_1 = /d wxNO_THREADS !endif !if "$(UNICODE)" == "1" __UNICODE_DEFINE_p = /D_UNICODE !endif !if "$(UNICODE)" == "1" __UNICODE_DEFINE_p_1 = /d _UNICODE !endif !if "$(SHARED)" == "1" __DLLFLAG_p = /DWXUSINGDLL !endif !if "$(SHARED)" == "1" __DLLFLAG_p_1 = /d WXUSINGDLL !endif !if "$(MONOLITHIC)" == "0" __WXLIB_HTML_p = \ wx$(PORTNAME)$(WXUNIVNAME)$(WX_RELEASE)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_html.lib !endif !if "$(MONOLITHIC)" == "0" __WXLIB_ADV_p = \ wx$(PORTNAME)$(WXUNIVNAME)$(WX_RELEASE)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_adv.lib !endif !if "$(MONOLITHIC)" == "0" __WXLIB_CORE_p = \ wx$(PORTNAME)$(WXUNIVNAME)$(WX_RELEASE)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_core.lib !endif !if "$(MONOLITHIC)" == "0" __WXLIB_BASE_p = \ wxbase$(WX_RELEASE)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR).lib !endif !if "$(MONOLITHIC)" == "0" __WXLIB_NET_p = \ wxbase$(WX_RELEASE)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_net.lib !endif !if "$(MONOLITHIC)" == "1" __WXLIB_MONO_p = \ wx$(PORTNAME)$(WXUNIVNAME)$(WX_RELEASE)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR).lib !endif !if "$(MSLU)" == "1" __UNICOWS_LIB_p = unicows.lib !endif __LIB_TIFF_p = wxtiff$(WXDEBUGFLAG).lib __LIB_JPEG_p = wxjpeg$(WXDEBUGFLAG).lib __LIB_PNG_p = wxpng$(WXDEBUGFLAG).lib ### Targets: ### all: $(OBJDIR) $(EXEDIR)\Golly.exe $(EXEDIR)\bgolly.exe $(BASEOBJ): $(BASEH) $(WXOBJ): $(BASEH) $(WXH) icons/*.ico bitmaps/*.xpm $(OBJDIR): mkdir $(OBJDIR) clean: -if exist $(OBJDIR)\*.obj del $(OBJDIR)\*.obj -if exist *.res del *.res -if exist $(EXEDIR)\Golly.exe del $(EXEDIR)\Golly.exe -if exist $(EXEDIR)\bgolly.exe del $(EXEDIR)\bgolly.exe -if exist $(EXEDIR)\RuleTableToTree.exe del $(EXEDIR)\RuleTableToTree.exe -if exist golly.pdb del golly.pdb $(EXEDIR)\Golly.exe: $(BASEOBJ) $(WXOBJ) golly.res link /LARGEADDRESSAWARE /NOLOGO /OUT:$(EXEDIR)\Golly.exe $(LDFLAGS) $(__DEBUGINFO_1) /pdb:"golly.pdb" \ /LIBPATH:$(LIBDIRNAME) /SUBSYSTEM:WINDOWS $(BASEOBJ) $(WXOBJ) golly.res \ $(__WXLIB_HTML_p) $(__WXLIB_ADV_p) $(__WXLIB_CORE_p) $(__WXLIB_BASE_p) $(__WXLIB_NET_p) \ $(__WXLIB_MONO_p) $(__LIB_TIFF_p) $(__LIB_JPEG_p) $(__LIB_PNG_p) wxzlib$(WXDEBUGFLAG).lib \ wxregex$(WXUNICODEFLAG)$(WXDEBUGFLAG).lib wxexpat$(WXDEBUGFLAG).lib \ $(__UNICOWS_LIB_p) kernel32.lib user32.lib gdi32.lib comdlg32.lib \ winspool.lib winmm.lib shell32.lib comctl32.lib ole32.lib oleaut32.lib uuid.lib \ rpcrt4.lib advapi32.lib wsock32.lib wininet.lib golly.res: golly.rc rc /fo$@ /d $(WX_CPU_DEF) /d WIN32 $(____DEBUGRUNTIME_2_p_1) $(__NO_VC_CRTDBG_p_1) /d __WXMSW__ $(__WXUNIV_DEFINE_p_1) \ $(__DEBUG_DEFINE_p_1) $(__NDEBUG_DEFINE_p_1) $(__EXCEPTIONS_DEFINE_p_1) $(__RTTI_DEFINE_p_1) $(__THREAD_DEFINE_p_1) \ $(__UNICODE_DEFINE_p_1) /i $(WX_DIR)\include /i $(SETUPHDIR) /i . $(__DLLFLAG_p_1) /d _WINDOWS \ /i $(WX_DIR)\samples /d NOPCH golly.rc $(EXEDIR)\bgolly.exe: $(BASEOBJ) $(OBJDIR)/bgolly.obj link /LARGEADDRESSAWARE /NOLOGO /OUT:$(EXEDIR)\bgolly.exe $(LDFLAGS) /LIBPATH:$(LIBDIRNAME) \ $(OBJDIR)/bgolly.obj $(BASEOBJ) wxzlib$(WXDEBUGFLAG).lib $(EXEDIR)\RuleTableToTree.exe: $(BASEOBJ) $(OBJDIR)/RuleTableToTree.obj link /LARGEADDRESSAWARE /NOLOGO /OUT:$(EXEDIR)\RuleTableToTree.exe $(LDFLAGS) /LIBPATH:$(LIBDIRNAME) \ $(OBJDIR)/RuleTableToTree.obj $(BASEOBJ) wxzlib$(WXDEBUGFLAG).lib $(OBJDIR)/bgolly.obj: $(CMDDIR)/bgolly.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(CMDDIR)/bgolly.cpp $(OBJDIR)/RuleTableToTree.obj: $(CMDDIR)/RuleTableToTree.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(CMDDIR)/RuleTableToTree.cpp $(OBJDIR)/bigint.obj: $(BASEDIR)/bigint.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/bigint.cpp $(OBJDIR)/lifealgo.obj: $(BASEDIR)/lifealgo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/lifealgo.cpp $(OBJDIR)/hlifealgo.obj: $(BASEDIR)/hlifealgo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/hlifealgo.cpp $(OBJDIR)/hlifedraw.obj: $(BASEDIR)/hlifedraw.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/hlifedraw.cpp $(OBJDIR)/qlifealgo.obj: $(BASEDIR)/qlifealgo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/qlifealgo.cpp $(OBJDIR)/qlifedraw.obj: $(BASEDIR)/qlifedraw.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/qlifedraw.cpp $(OBJDIR)/jvnalgo.obj: $(BASEDIR)/jvnalgo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/jvnalgo.cpp $(OBJDIR)/ruleloaderalgo.obj: $(BASEDIR)/ruleloaderalgo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/ruleloaderalgo.cpp $(OBJDIR)/ruletable_algo.obj: $(BASEDIR)/ruletable_algo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/ruletable_algo.cpp $(OBJDIR)/ruletreealgo.obj: $(BASEDIR)/ruletreealgo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/ruletreealgo.cpp $(OBJDIR)/generationsalgo.obj: $(BASEDIR)/generationsalgo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/generationsalgo.cpp $(OBJDIR)/ghashbase.obj: $(BASEDIR)/ghashbase.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/ghashbase.cpp $(OBJDIR)/ghashdraw.obj: $(BASEDIR)/ghashdraw.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/ghashdraw.cpp $(OBJDIR)/liferules.obj: $(BASEDIR)/liferules.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/liferules.cpp $(OBJDIR)/liferender.obj: $(BASEDIR)/liferender.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/liferender.cpp $(OBJDIR)/readpattern.obj: $(BASEDIR)/readpattern.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/readpattern.cpp $(OBJDIR)/writepattern.obj: $(BASEDIR)/writepattern.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/writepattern.cpp $(OBJDIR)/util.obj: $(BASEDIR)/util.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/util.cpp $(OBJDIR)/viewport.obj: $(BASEDIR)/viewport.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/viewport.cpp $(OBJDIR)/lifepoll.obj: $(BASEDIR)/lifepoll.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(BASEDIR)/lifepoll.cpp $(OBJDIR)/wxutils.obj: wxutils.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxutils.cpp $(OBJDIR)/wxprefs.obj: wxprefs.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxprefs.cpp $(OBJDIR)/wxalgos.obj: wxalgos.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxalgos.cpp $(OBJDIR)/wxrule.obj: wxrule.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxrule.cpp $(OBJDIR)/wxinfo.obj: wxinfo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxinfo.cpp $(OBJDIR)/wxhelp.obj: wxhelp.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxhelp.cpp $(OBJDIR)/wxstatus.obj: wxstatus.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxstatus.cpp $(OBJDIR)/wxview.obj: wxview.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxview.cpp $(OBJDIR)/wxrender.obj: wxrender.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxrender.cpp $(OBJDIR)/wxperl.obj: wxperl.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(PERL_INCLUDE) wxperl.cpp $(OBJDIR)/wxpython.obj: wxpython.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(PYTHON_INCLUDE) wxpython.cpp $(OBJDIR)/wxscript.obj: wxscript.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxscript.cpp $(OBJDIR)/wxfile.obj: wxfile.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxfile.cpp $(OBJDIR)/wxedit.obj: wxedit.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxedit.cpp $(OBJDIR)/wxselect.obj: wxselect.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxselect.cpp $(OBJDIR)/wxcontrol.obj: wxcontrol.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxcontrol.cpp $(OBJDIR)/wxtimeline.obj: wxtimeline.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxtimeline.cpp $(OBJDIR)/wxundo.obj: wxundo.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxundo.cpp $(OBJDIR)/wxlayer.obj: wxlayer.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxlayer.cpp $(OBJDIR)/wxmain.obj: wxmain.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) wxmain.cpp $(OBJDIR)/wxgolly.obj: wxgolly.cpp $(CXX) /c /TP /nologo /Fo$@ $(CXXFLAGS) wxgolly.cpp srcdist: -rmdir /s /q $(RELEASENAME)-src mkdir $(RELEASENAME)-src mkdir $(RELEASENAME)-src\Help mkdir $(RELEASENAME)-src\Patterns mkdir $(RELEASENAME)-src\Rules mkdir $(RELEASENAME)-src\Scripts mkdir $(RELEASENAME)-src\docs mkdir $(RELEASENAME)-src\gollybase mkdir $(RELEASENAME)-src\cmdline xcopy /S /I $(EXEDIR)\Help $(RELEASENAME)-src\Help xcopy /S /I $(EXEDIR)\Patterns $(RELEASENAME)-src\Patterns xcopy /S /I $(EXEDIR)\Rules $(RELEASENAME)-src\Rules xcopy /S /I $(EXEDIR)\Scripts $(RELEASENAME)-src\Scripts xcopy /S /I $(EXEDIR)\docs $(RELEASENAME)-src\docs xcopy /S /I $(EXEDIR)\gollybase $(RELEASENAME)-src\gollybase xcopy /S /I $(EXEDIR)\cmdline $(RELEASENAME)-src\cmdline mkdir $(RELEASENAME)-src\gui-wx mkdir $(RELEASENAME)-src\gui-wx\configure mkdir $(RELEASENAME)-src\gui-wx\bitmaps mkdir $(RELEASENAME)-src\gui-wx\icons for %%F IN ($(GUIFILES)) do xcopy %F $(RELEASENAME)-src\gui-wx for %%F IN ($(GUIDIRS)) do xcopy /S /I %F $(RELEASENAME)-src\gui-wx\%F echo Now zip $(RELEASENAME)-src into $(RELEASENAME)-src.zip bindist: all -rmdir /s /q $(RELEASENAME)-win mkdir $(RELEASENAME)-win mkdir $(RELEASENAME)-win\Help mkdir $(RELEASENAME)-win\Patterns mkdir $(RELEASENAME)-win\Rules mkdir $(RELEASENAME)-win\Scripts xcopy /S /I $(EXEDIR)\Help $(RELEASENAME)-win\Help xcopy /S /I $(EXEDIR)\Patterns $(RELEASENAME)-win\Patterns xcopy /S /I $(EXEDIR)\Rules $(RELEASENAME)-win\Rules xcopy /S /I $(EXEDIR)\Scripts $(RELEASENAME)-win\Scripts for %%F IN ($(BINFILES)) do xcopy %F $(RELEASENAME)-win echo Now zip $(RELEASENAME)-win into $(RELEASENAME)-win.zip golly-2.7-src/gui-wx/wxrender.h0000755000175000017500000000734712536111364013465 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXRENDER_H_ #define _WXRENDER_H_ // Routines and data for rendering the viewport window: void InitDrawingData(); // Initialize drawing data (such as the image used to draw selections). // Must be called AFTER the viewport window has been created. void DestroyDrawingData(); // Call this when the main window is destroyed. void DrawView(wxDC& dc, int tileindex); // Draw the current pattern, grid lines, selection, etc. // The given tile index is only used when drawing tiled layers. void DrawOneIcon(wxDC& dc, int x, int y, wxBitmap* icon, unsigned char deadr, unsigned char deadg, unsigned char deadb, unsigned char liver, unsigned char liveg, unsigned char liveb, bool multicolor); // Draw the given icon using the given dead cell and live cell colors. void DrawSelection(wxDC &dc, wxRect& rect); // Draw the translucent selection image in the given rectangle. // We need to export this for drawing individual cells. void SetSelectionColor(); // Update the selection image's color. class lifealgo; void CreatePasteImage(lifealgo* pastealgo, wxRect& bbox); // Create an image used to draw the given paste pattern. // The given bounding box is not necessarily the *minimal* bounding box because // the paste pattern might have blank borders (in fact it could be empty). void DestroyPasteImage(); // Destroy the image created above (call when user clicks to end paste). void CreateTranslucentControls(); // Create the bitmap for translucent controls and set controlswd and // controlsht. Must be called BEFORE the viewport window is created. extern int controlswd; // width of translucent controls extern int controlsht; // height of translucent controls // control ids must match button order in controls bitmap typedef enum { NO_CONTROL = 0, // no current control (must be first) STEP1_CONTROL, // set step exponent to zero (ie. step by 1) SLOWER_CONTROL, // decrease step exponent FASTER_CONTROL, // increase step exponent FIT_CONTROL, // fit entire pattern in viewport ZOOMIN_CONTROL, // zoom in ZOOMOUT_CONTROL, // zoom out NW_CONTROL, // pan north west UP_CONTROL, // pan up NE_CONTROL, // pan north east LEFT_CONTROL, // pan left MIDDLE_CONTROL, // pan to 0,0 RIGHT_CONTROL, // pan right SW_CONTROL, // pan south west DOWN_CONTROL, // pan down SE_CONTROL // pan south east } control_id; extern control_id currcontrol; // currently clicked control control_id WhichControl(int x, int y); // Return the control at the given location in the controls bitmap. #endif golly-2.7-src/gui-wx/wxundo.h0000644000175000017500000001450212536111364013137 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXUNDO_H_ #define _WXUNDO_H_ #include "bigint.h" // for bigint class #include "wxselect.h" // for Selection class class Layer; // need this because wxlayer.h includes wxundo.h #include "wxlayer.h" // for Layer class #include "wxalgos.h" // for algo_type // This module implements unlimited undo/redo: typedef struct { int x; // cell's x position int y; // cell's y position int oldstate; // old state int newstate; // new state } cell_change; // stores a single cell change class UndoRedo { public: UndoRedo(); ~UndoRedo(); void SaveCellChange(int x, int y, int oldstate, int newstate); // cell at x,y has changed state void ForgetCellChanges(); // ignore cell changes made by any previous SaveCellChange calls bool RememberCellChanges(const wxString& action, bool olddirty); // remember cell changes made by any previous SaveCellChange calls, // and the state of the layer's dirty flag BEFORE the change; // the given action string will be appended to the Undo/Redo items; // return true if one or more cells changed state, false otherwise void RememberFlip(bool topbot, bool olddirty); // remember flip's direction void RememberRotation(bool clockwise, bool olddirty); // remember simple rotation (selection includes entire pattern) void RememberRotation(bool clockwise, Selection& oldsel, Selection& newsel, bool olddirty); // remember rotation's direction and old and new selections; // this variant assumes SaveCellChange may have been called void RememberSelection(const wxString& action); // remember selection change (no-op if selection hasn't changed) void RememberGenStart(); // remember info before generating the current pattern void RememberGenFinish(); // remember generating change after pattern has finished generating void AddGenChange(); // in some situations the undo list is empty but ResetPattern can still // be called because the gen count is > startgen, so this routine adds // a generating change to the undo list so the user can Undo or Reset // (and then Redo if they wish) void SyncUndoHistory(); // called by ResetPattern to synchronize the undo history void RememberSetGen(bigint& oldgen, bigint& newgen, bigint& oldstartgen, bool oldsave); // remember change of generation count void RememberNameChange(const wxString& oldname, const wxString& oldcurrfile, bool oldsave, bool olddirty); // remember change to current layer's name void DeletingClone(int index); // the given cloned layer is about to be deleted, so we must ignore // any later name changes involving this layer void RememberRuleChange(const wxString& oldrule); // remember rule change void RememberAlgoChange(algo_type oldalgo, const wxString& oldrule); // remember algorithm change, including a possible rule change // and possible cell changes (SaveCellChange may have been called) void RememberScriptStart(); // remember that script is about to start; this allows us to undo/redo // any changes made by the script all at once void RememberScriptFinish(); // remember that script has ended void DuplicateHistory(Layer* oldlayer, Layer* newlayer); // duplicate old layer's undo/redo history in new layer bool savecellchanges; // script's cell changes need to be remembered? bool savegenchanges; // script's gen changes need to be remembered? bool doingscriptchanges; // are script's changes being undone/redone? bool CanUndo(); // can a change be undone? bool CanRedo(); // can an undone change be redone? void UndoChange(); // undo a change void RedoChange(); // redo an undone change void UpdateUndoRedoItems(); // update Undo/Redo items in Edit menu void ClearUndoRedo(); // clear all undo/redo history private: wxList undolist; // list of undoable changes wxList redolist; // list of redoable changes cell_change* cellarray; // dynamic array of cell changes unsigned int numchanges; // number of cell changes unsigned int maxchanges; // number allocated bool badalloc; // malloc/realloc failed? wxString prevfile; // for saving pattern at start of gen change bigint prevgen; // generation count at start of gen change bigint prevx, prevy; // viewport position at start of gen change int prevmag; // scale at start of gen change int prevbase; // base step at start of gen change int prevexpo; // step exponent at start of gen change Selection prevsel; // selection at start of gen change int startcount; // unfinished RememberGenStart calls bool fixsetgen; // setgen node needs to be updated? void SaveCurrentPattern(const wxString& tempfile); // save current pattern to given temporary file void UpdateUndoItem(const wxString& action); void UpdateRedoItem(const wxString& action); // update the Undo/Redo items in the Edit menu }; #endif golly-2.7-src/gui-wx/makefile-gtk0000644000175000017500000002354212536111364013731 00000000000000# Makefile for GTK version of Golly using wxWidgets. # It assumes you've built and installed wxWidgets with commands like these: # # cd # mkdir buildgtk # cd buildgtk # ../configure --with-gtk --disable-shared --enable-unicode # (depending on your g++ version you might also need --disable-precomp-headers) # make # su # make install # ldconfig APP_VERSION = 2.7 # these directory paths are relative to the location of this makefile: EXEDIR = .. DOCSDIR = ../docs BASEDIR = ../gollybase CMDDIR = ../cmdline # for building binary and source distributions: RELEASENAME = $(EXEDIR)/golly-$(APP_VERSION) SHAREDFILES = $(EXEDIR)/Help $(EXEDIR)/Patterns $(EXEDIR)/Scripts $(EXEDIR)/Rules EXEFILES = $(EXEDIR)/golly $(EXEDIR)/bgolly DOCFILES = $(DOCSDIR)/ReadMe.html $(DOCSDIR)/License.html SRCFILES = $(DOCSDIR) $(BASEDIR) $(CMDDIR) GUIFILES = CMakeLists.txt makefile-gtk makefile-mac makefile-win local-win-template.mk \ golly.rc Info.plist.in wx*.h wx*.cpp configure bitmaps icons CXXC = g++ CXXFLAGS := -DVERSION=$(APP_VERSION) -DGOLLYDIR="$(GOLLYDIR)" \ -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -I$(BASEDIR) \ -O5 -Wall -Wno-non-virtual-dtor -fno-strict-aliasing $(CXXFLAGS) LDFLAGS := -Wl,--as-needed $(LDFLAGS) # for Perl script support PERL_INCLUDE = `perl -MExtUtils::Embed -e ccopts` # note that we must link in the Perl library if the Perl version is older # than 5.10 (this is necessary because boot_DynaLoader is in DynaLoader.a); # if using 5.10 or later we can dynamically load the Perl library because # it contains the boot_DynaLoader code PERL_LINK = `perl -MExtUtils::Embed -e '$$]<5.010 && ldopts'` PERL_SHLIB = libperl.so.5.10 # TODO: figure out how to do this dynamically PERL_PREFS = -DPERL_SHLIB="$(PERL_SHLIB)" # for Python script support PYTHON_INCLUDE = -I`python -c "import distutils.sysconfig; print distutils.sysconfig.get_python_inc()"` # we don't want to link against a specific library: PYTHON_LINK = -lpython2.3 # following generates "-Xlinker -export-dynamic" but doesn't seem to be needed # PYTHON_LINK = `python -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LINKFORSHARED')"` PYTHON_LINK = # the following determines the filename for the python dynamic library (e.g. libpython2.5.so) PYTHON_SHLIB = `python -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LDLIBRARY')"` PYTHON_PREFS = -DPYTHON_SHLIB="$(PYTHON_SHLIB)" # default settings for zlib support, so clear these to build without zlib ZLIB_CXXFLAGS = -DZLIB ZLIB_LDFLAGS = -lz # for wxGTK support (required for GUI) WX_CXXFLAGS = `wx-config --cxxflags` WX_LDFLAGS = `wx-config --libs` OBJDIR = ObjGTK BASEH = $(BASEDIR)/bigint.h $(BASEDIR)/ghashbase.h $(BASEDIR)/hlifealgo.h $(BASEDIR)/jvnalgo.h \ $(BASEDIR)/lifealgo.h $(BASEDIR)/lifepoll.h $(BASEDIR)/liferender.h $(BASEDIR)/liferules.h \ $(BASEDIR)/platform.h $(BASEDIR)/qlifealgo.h $(BASEDIR)/readpattern.h $(BASEDIR)/util.h $(BASEDIR)/viewport.h \ $(BASEDIR)/writepattern.h $(BASEDIR)/ruletreealgo.h $(BASEDIR)/generationsalgo.h $(BASEDIR)/ruletable_algo.h \ $(BASEDIR)/ruleloaderalgo.h BASEOBJ = $(OBJDIR)/bigint.o $(OBJDIR)/lifealgo.o $(OBJDIR)/hlifealgo.o \ $(OBJDIR)/hlifedraw.o $(OBJDIR)/qlifealgo.o $(OBJDIR)/qlifedraw.o \ $(OBJDIR)/jvnalgo.o $(OBJDIR)/ruletreealgo.o $(OBJDIR)/ruletable_algo.o $(OBJDIR)/ruleloaderalgo.o \ $(OBJDIR)/ghashbase.o $(OBJDIR)/ghashdraw.o $(OBJDIR)/readpattern.o \ $(OBJDIR)/writepattern.o $(OBJDIR)/liferules.o $(OBJDIR)/util.o \ $(OBJDIR)/liferender.o $(OBJDIR)/viewport.o $(OBJDIR)/lifepoll.o \ $(OBJDIR)/generationsalgo.o WXH = wxalgos.h wxedit.h wxgolly.h wxhelp.h wxinfo.h wxlayer.h wxmain.h \ wxperl.h wxprefs.h wxpython.h wxrender.h wxrule.h wxscript.h wxselect.h wxstatus.h \ wxtimeline.h wxundo.h wxutils.h wxview.h WXOBJ = $(OBJDIR)/wxutils.o $(OBJDIR)/wxprefs.o $(OBJDIR)/wxalgos.o $(OBJDIR)/wxrule.o \ $(OBJDIR)/wxinfo.o $(OBJDIR)/wxhelp.o $(OBJDIR)/wxstatus.o $(OBJDIR)/wxview.o \ $(OBJDIR)/wxrender.o $(OBJDIR)/wxscript.o $(OBJDIR)/wxperl.o $(OBJDIR)/wxpython.o \ $(OBJDIR)/wxfile.o $(OBJDIR)/wxedit.o $(OBJDIR)/wxcontrol.o $(OBJDIR)/wxtimeline.o \ $(OBJDIR)/wxundo.o $(OBJDIR)/wxselect.o $(OBJDIR)/wxlayer.o $(OBJDIR)/wxmain.o $(OBJDIR)/wxgolly.o all: $(OBJDIR) golly bgolly $(BASEOBJ): $(BASEH) $(WXOBJ): $(BASEH) $(WXH) icons/appicon.xpm bitmaps/*.xpm $(OBJDIR): mkdir -p $(OBJDIR) clean: rm -f $(OBJDIR)/*.o rm -f $(EXEDIR)/golly $(EXEDIR)/bgolly $(EXEDIR)/RuleTableToTree golly: $(OBJDIR) $(BASEOBJ) $(WXOBJ) $(CXXC) $(CXXFLAGS) -o $(EXEDIR)/golly $(BASEOBJ) $(WXOBJ) $(LDFLAGS) $(ZLIB_LDFLAGS) $(WX_LDFLAGS) $(PYTHON_LINK) $(PERL_LINK) bgolly: $(OBJDIR) $(BASEOBJ) $(OBJDIR)/bgolly.o $(CXXC) $(CXXFLAGS) -o $(EXEDIR)/bgolly $(BASEOBJ) $(OBJDIR)/bgolly.o $(LDFLAGS) $(ZLIB_LDFLAGS) RuleTableToTree: $(OBJDIR) $(BASEOBJ) $(OBJDIR)/RuleTableToTree.o $(CXXC) $(CXXFLAGS) -o $(EXEDIR)/RuleTableToTree $(BASEOBJ) $(OBJDIR)/RuleTableToTree.o $(LDFLAGS) $(ZLIB_LDFLAGS) $(OBJDIR)/bgolly.o: $(CMDDIR)/bgolly.cpp $(CXXC) $(CXXFLAGS) $(ZLIB_CXXFLAGS) -c -o $@ $(CMDDIR)/bgolly.cpp $(OBJDIR)/RuleTableToTree.o: $(CMDDIR)/RuleTableToTree.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(CMDDIR)/RuleTableToTree.cpp $(OBJDIR)/bigint.o: $(BASEDIR)/bigint.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/bigint.cpp $(OBJDIR)/lifealgo.o: $(BASEDIR)/lifealgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/lifealgo.cpp $(OBJDIR)/hlifealgo.o: $(BASEDIR)/hlifealgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/hlifealgo.cpp $(OBJDIR)/hlifedraw.o: $(BASEDIR)/hlifedraw.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/hlifedraw.cpp $(OBJDIR)/qlifealgo.o: $(BASEDIR)/qlifealgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/qlifealgo.cpp $(OBJDIR)/qlifedraw.o: $(BASEDIR)/qlifedraw.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/qlifedraw.cpp $(OBJDIR)/jvnalgo.o: $(BASEDIR)/jvnalgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/jvnalgo.cpp $(OBJDIR)/ruleloaderalgo.o: $(BASEDIR)/ruleloaderalgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ruleloaderalgo.cpp $(OBJDIR)/ruletable_algo.o: $(BASEDIR)/ruletable_algo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ruletable_algo.cpp $(OBJDIR)/ruletreealgo.o: $(BASEDIR)/ruletreealgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ruletreealgo.cpp $(OBJDIR)/generationsalgo.o: $(BASEDIR)/generationsalgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/generationsalgo.cpp $(OBJDIR)/ghashbase.o: $(BASEDIR)/ghashbase.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ghashbase.cpp $(OBJDIR)/ghashdraw.o: $(BASEDIR)/ghashdraw.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ghashdraw.cpp $(OBJDIR)/liferules.o: $(BASEDIR)/liferules.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/liferules.cpp $(OBJDIR)/liferender.o: $(BASEDIR)/liferender.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/liferender.cpp $(OBJDIR)/readpattern.o: $(BASEDIR)/readpattern.cpp $(CXXC) $(CXXFLAGS) $(ZLIB_CXXFLAGS) -c -o $@ $(BASEDIR)/readpattern.cpp $(OBJDIR)/writepattern.o: $(BASEDIR)/writepattern.cpp $(CXXC) $(CXXFLAGS) $(ZLIB_CXXFLAGS) -c -o $@ $(BASEDIR)/writepattern.cpp $(OBJDIR)/util.o: $(BASEDIR)/util.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/util.cpp $(OBJDIR)/viewport.o: $(BASEDIR)/viewport.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/viewport.cpp $(OBJDIR)/lifepoll.o: $(BASEDIR)/lifepoll.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/lifepoll.cpp $(OBJDIR)/wxutils.o: wxutils.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxutils.cpp $(OBJDIR)/wxprefs.o: wxprefs.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) $(PERL_PREFS) $(PYTHON_PREFS) -c -o $@ wxprefs.cpp $(OBJDIR)/wxalgos.o: wxalgos.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxalgos.cpp $(OBJDIR)/wxrule.o: wxrule.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxrule.cpp $(OBJDIR)/wxinfo.o: wxinfo.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxinfo.cpp $(OBJDIR)/wxhelp.o: wxhelp.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxhelp.cpp $(OBJDIR)/wxstatus.o: wxstatus.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxstatus.cpp $(OBJDIR)/wxview.o: wxview.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxview.cpp $(OBJDIR)/wxrender.o: wxrender.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxrender.cpp $(OBJDIR)/wxperl.o: wxperl.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) $(PERL_INCLUDE) -c -o $@ wxperl.cpp $(OBJDIR)/wxpython.o: wxpython.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) $(PYTHON_INCLUDE) -c -o $@ wxpython.cpp $(OBJDIR)/wxscript.o: wxscript.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxscript.cpp $(OBJDIR)/wxfile.o: wxfile.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxfile.cpp $(OBJDIR)/wxedit.o: wxedit.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxedit.cpp $(OBJDIR)/wxselect.o: wxselect.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxselect.cpp $(OBJDIR)/wxcontrol.o: wxcontrol.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxcontrol.cpp $(OBJDIR)/wxtimeline.o: wxtimeline.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxtimeline.cpp $(OBJDIR)/wxundo.o: wxundo.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxundo.cpp $(OBJDIR)/wxlayer.o: wxlayer.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxlayer.cpp $(OBJDIR)/wxmain.o: wxmain.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxmain.cpp $(OBJDIR)/wxgolly.o: wxgolly.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -c -o $@ wxgolly.cpp srcdist: -rm -rf $(RELEASENAME)-src mkdir $(RELEASENAME)-src mkdir $(RELEASENAME)-src/gui-wx cp -rp $(SRCFILES) $(SHAREDFILES) $(RELEASENAME)-src cp -rp $(GUIFILES) $(RELEASENAME)-src/gui-wx find $(RELEASENAME)-src -name '.[^.]*' -delete find $(RELEASENAME)-src/Scripts/Python -name '*.pyc' -delete tar -cf - ./$(RELEASENAME)-src | gzip > $(RELEASENAME)-src.tar.gz bindist: all -rm -rf $(RELEASENAME)-gtk mkdir $(RELEASENAME)-gtk install -s $(EXEFILES) $(RELEASENAME)-gtk cp -rp $(DOCFILES) $(SHAREDFILES) $(RELEASENAME)-gtk find $(RELEASENAME)-gtk -name '.[^.]*' -delete find $(RELEASENAME)-gtk/Scripts/Python -name '*.pyc' -delete tar -cf - ./$(RELEASENAME)-gtk | gzip > $(RELEASENAME)-gtk.tar.gz golly-2.7-src/gui-wx/wxcontrol.cpp0000644000175000017500000031216312536111364014211 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/dir.h" // for wxDir #include "wx/file.h" // for wxFile #include "wx/filename.h" // for wxFileName #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "util.h" // for linereader #include "wxgolly.h" // for wxGetApp, statusptr, viewptr, bigview #include "wxutils.h" // for BeginProgress, GetString, etc #include "wxprefs.h" // for allowundo, etc #include "wxrule.h" // for ChangeRule #include "wxhelp.h" // for LoadLexiconPattern #include "wxstatus.h" // for statusptr->... #include "wxselect.h" // for Selection #include "wxview.h" // for viewptr->... #include "wxscript.h" // for inscript, PassKeyToScript #include "wxmain.h" // for MainFrame #include "wxundo.h" // for undoredo->... #include "wxalgos.h" // for *_ALGO, algo_type, CreateNewUniverse, etc #include "wxlayer.h" // for currlayer, etc #include "wxrender.h" // for DrawView #include "wxtimeline.h" // for TimelineExists, UpdateTimelineBar, etc #include // for std::runtime_error and std::exception #include // for std::ostringstream #ifdef __WXMAC__ // we need to convert filepath to decomposed UTF8 so fopen will work #define OPENFILE(filepath) fopen(filepath.fn_str(),"r") #else #define OPENFILE(filepath) fopen(filepath.mb_str(wxConvLocal),"r") #endif // This module implements Control menu functions. // ----------------------------------------------------------------------------- bool MainFrame::SaveStartingPattern() { if ( currlayer->algo->getGeneration() > currlayer->startgen ) { // don't do anything if current gen count > starting gen return true; } // save current rule, dirty flag, scale, location, etc currlayer->startname = currlayer->currname; currlayer->startrule = wxString(currlayer->algo->getrule(), wxConvLocal); currlayer->startdirty = currlayer->dirty; currlayer->startmag = viewptr->GetMag(); viewptr->GetPos(currlayer->startx, currlayer->starty); currlayer->startbase = currlayer->currbase; currlayer->startexpo = currlayer->currexpo; currlayer->startalgo = currlayer->algtype; // if this layer is a clone then save some settings in other clones if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->startname = cloneptr->currname; cloneptr->startx = cloneptr->view->x; cloneptr->starty = cloneptr->view->y; cloneptr->startmag = cloneptr->view->getmag(); cloneptr->startbase = cloneptr->currbase; cloneptr->startexpo = cloneptr->currexpo; } } } // save current selection currlayer->startsel = currlayer->currsel; if ( !currlayer->savestart ) { // no need to save pattern; ResetPattern will load currfile currlayer->startfile.Clear(); return true; } // save starting pattern in tempstart file // use CanWriteFormat(MC_format)??? if ( currlayer->algo->hyperCapable() ) { // much faster to save pattern in a macrocell file const char* err = WritePattern(currlayer->tempstart, MC_format, no_compression, 0, 0, 0, 0); if (err) { statusptr->ErrorMessage(wxString(err,wxConvLocal)); // don't allow user to continue generating return false; } } else { // can only save as RLE if edges are within getcell/setcell limits bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Starting pattern is outside +/- 10^9 boundary.")); // don't allow user to continue generating return false; } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); // use XRLE format so the pattern's top left location and the current // generation count are stored in the file const char* err = WritePattern(currlayer->tempstart, XRLE_format, no_compression, itop, ileft, ibottom, iright); if (err) { statusptr->ErrorMessage(wxString(err,wxConvLocal)); // don't allow user to continue generating return false; } } currlayer->startfile = currlayer->tempstart; // ResetPattern will load tempstart return true; } // ----------------------------------------------------------------------------- void MainFrame::ResetPattern(bool resetundo) { if (currlayer->algo->getGeneration() == currlayer->startgen) return; if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_RESET); /* can't use wxPostEvent here because Yield processes all pending events: // send Reset command to event queue wxCommandEvent resetevt(wxEVT_COMMAND_MENU_SELECTED, ID_RESET); wxPostEvent(this->GetEventHandler(), resetevt); */ return; } if (inscript) stop_after_script = true; if (currlayer->algo->getGeneration() < currlayer->startgen) { // if this happens then startgen logic is wrong Warning(_("Current gen < starting gen!")); return; } if (currlayer->startfile.IsEmpty() && currlayer->currfile.IsEmpty()) { // if this happens then savestart logic is wrong Warning(_("Starting pattern cannot be restored!")); return; } if (allowundo && !currlayer->stayclean && inscript) { // script called reset() SavePendingChanges(); currlayer->undoredo->RememberGenStart(); } // save current algo and rule algo_type oldalgo = currlayer->algtype; wxString oldrule = wxString(currlayer->algo->getrule(), wxConvLocal); // restore pattern and settings saved by SaveStartingPattern; // first restore algorithm currlayer->algtype = currlayer->startalgo; // restore starting pattern if ( currlayer->startfile.IsEmpty() ) { // restore pattern from currfile LoadPattern(currlayer->currfile, wxEmptyString); } else { // restore pattern from startfile LoadPattern(currlayer->startfile, wxEmptyString); } if (currlayer->algo->getGeneration() != currlayer->startgen) { // LoadPattern failed to reset the gen count to startgen // (probably because the user deleted the starting pattern) // so best to clear the pattern and reset the gen count CreateUniverse(); currlayer->algo->setGeneration(currlayer->startgen); } // ensure savestart flag is correct currlayer->savestart = !currlayer->startfile.IsEmpty(); // restore settings saved by SaveStartingPattern RestoreRule(currlayer->startrule); currlayer->currname = currlayer->startname; currlayer->dirty = currlayer->startdirty; if (restoreview) { viewptr->SetPosMag(currlayer->startx, currlayer->starty, currlayer->startmag); } // restore step size and set increment currlayer->currbase = currlayer->startbase; currlayer->currexpo = currlayer->startexpo; SetGenIncrement(); // if this layer is a clone then restore some settings in other clones if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->currname = cloneptr->startname; if (restoreview) { cloneptr->view->setpositionmag(cloneptr->startx, cloneptr->starty, cloneptr->startmag); } cloneptr->currbase = cloneptr->startbase; cloneptr->currexpo = cloneptr->startexpo; // also synchronize dirty flags and update items in Layer menu cloneptr->dirty = currlayer->dirty; UpdateLayerItem(i); } } } // restore selection currlayer->currsel = currlayer->startsel; // switch to default colors if algo/rule changed wxString newrule = wxString(currlayer->algo->getrule(), wxConvLocal); if (oldalgo != currlayer->algtype || oldrule != newrule) { UpdateLayerColors(); } // update window title in case currname, rule or dirty flag changed; // note that UpdateLayerItem(currindex) gets called SetWindowTitle(currlayer->currname); UpdateEverything(); if (allowundo && !currlayer->stayclean) { if (inscript) { // script called reset() so remember gen change // (RememberGenStart was called above) currlayer->undoredo->RememberGenFinish(); } else if (resetundo) { // wind back the undo history to the starting pattern currlayer->undoredo->SyncUndoHistory(); } } } // ----------------------------------------------------------------------------- void MainFrame::RestorePattern(bigint& gen, const wxString& filename, bigint& x, bigint& y, int mag, int base, int expo) { // called to undo/redo a generating change if (gen == currlayer->startgen) { // restore starting pattern (false means don't call SyncUndoHistory) ResetPattern(false); } else { // restore pattern in given filename; // false means don't update status bar (algorithm should NOT change) LoadPattern(filename, wxEmptyString, false); if (currlayer->algo->getGeneration() != gen) { // filename could not be loaded for some reason, // so best to clear the pattern and set the expected gen count CreateUniverse(); currlayer->algo->setGeneration(gen); } // restore step size and set increment currlayer->currbase = base; currlayer->currexpo = expo; SetGenIncrement(); // restore position and scale, if allowed if (restoreview) viewptr->SetPosMag(x, y, mag); UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- const char* MainFrame::ChangeGenCount(const char* genstring, bool inundoredo) { // disallow alphabetic chars in genstring for (unsigned int i = 0; i < strlen(genstring); i++) if ( (genstring[i] >= 'a' && genstring[i] <= 'z') || (genstring[i] >= 'A' && genstring[i] <= 'Z') ) return "Alphabetic character is not allowed in generation string."; bigint oldgen = currlayer->algo->getGeneration(); bigint newgen(genstring); if (genstring[0] == '+' || genstring[0] == '-') { // leading +/- sign so make newgen relative to oldgen bigint relgen = newgen; newgen = oldgen; newgen += relgen; if (newgen < bigint::zero) newgen = bigint::zero; } // set stop_after_script BEFORE testing newgen == oldgen so scripts // can call setgen("+0") to prevent further generating if (inscript) stop_after_script = true; if (newgen == oldgen) return NULL; if (!inundoredo && allowundo && !currlayer->stayclean && inscript) { // script called setgen() SavePendingChanges(); } // need IsParityShifted() method??? if (currlayer->algtype == QLIFE_ALGO && newgen.odd() != oldgen.odd()) { // qlife stores pattern in different bits depending on gen parity, // so we need to create a new qlife universe, set its gen, copy the // current pattern to the new universe, then switch to that universe bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { return "Pattern is too big to copy."; } // create a new universe of same type and same rule lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); const char* err = newalgo->setrule(currlayer->algo->getrule()); if (err) { delete newalgo; return "Current rule is no longer valid!"; } newalgo->setGeneration(newgen); // copy pattern if ( !viewptr->CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, newalgo, false, _("Copying pattern")) ) { delete newalgo; return "Failed to copy pattern."; } // switch to new universe delete currlayer->algo; currlayer->algo = newalgo; SetGenIncrement(); } else { currlayer->algo->setGeneration(newgen); } if (!inundoredo) { // save some settings for RememberSetGen below bigint oldstartgen = currlayer->startgen; bool oldsave = currlayer->savestart; // may need to change startgen and savestart if (oldgen == currlayer->startgen || newgen <= currlayer->startgen) { currlayer->startgen = newgen; currlayer->savestart = true; } if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberSetGen(oldgen, newgen, oldstartgen, oldsave); } } UpdateStatus(); return NULL; } // ----------------------------------------------------------------------------- void MainFrame::SetGeneration() { if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_SETGEN); return; } bigint oldgen = currlayer->algo->getGeneration(); wxString result; wxString prompt = _("Enter a new generation count:"); prompt += _("\n(+n/-n is relative to current count)"); if ( GetString(_("Set Generation"), prompt, wxString(oldgen.tostring(), wxConvLocal), result) ) { const char* err = ChangeGenCount(result.mb_str(wxConvLocal)); if (err) { Warning(wxString(err,wxConvLocal)); } else { // Reset/Undo/Redo items might become enabled or disabled // (we need to do this if user clicked "Generation=..." text) UpdateMenuItems(); } } } // ----------------------------------------------------------------------------- void MainFrame::GoFaster() { if (TimelineExists()) { PlayTimelineFaster(); } else { currlayer->currexpo++; SetGenIncrement(); // only need to refresh status bar UpdateStatus(); if (generating && currlayer->currexpo < 0) { whentosee -= statusptr->GetCurrentDelay(); } } } // ----------------------------------------------------------------------------- void MainFrame::GoSlower() { if (TimelineExists()) { PlayTimelineSlower(); } else { if (currlayer->currexpo > minexpo) { currlayer->currexpo--; SetGenIncrement(); // only need to refresh status bar UpdateStatus(); if (generating && currlayer->currexpo < 0) { if (currlayer->currexpo == -1) { // need to initialize whentosee rather than increment it whentosee = stopwatch->Time() + statusptr->GetCurrentDelay(); } else { whentosee += statusptr->GetCurrentDelay(); } } } else { Beep(); } } } // ----------------------------------------------------------------------------- void MainFrame::SetBaseStep() { int i; if ( GetInteger(_("Set Base Step"), _("Temporarily change the current base step:"), currlayer->currbase, 2, MAX_BASESTEP, &i) ) { currlayer->currbase = i; SetGenIncrement(); UpdateStatus(); } } // ----------------------------------------------------------------------------- void MainFrame::DisplayPattern() { // this routine is similar to UpdatePatternAndStatus() but if tiled windows // exist it only updates the current tile if possible; ie. it's not a clone // and tile views aren't synchronized if (tilelayers && numlayers > 1 && !syncviews && currlayer->cloneid == 0) { // only update the current tile viewptr->Refresh(false); #ifdef __WXMAC__ if (!showstatus) viewptr->Update(); // else let statusptr->Update() update viewport #else viewptr->Update(); #endif } else { // update main viewport window, possibly including all tile windows // (tile windows are children of bigview) if (numlayers > 1 && (stacklayers || tilelayers)) { bigview->Refresh(false); #ifdef __WXMAC__ if (!showstatus) bigview->Update(); // else let statusptr->Update() update viewport #else bigview->Update(); #endif } else { viewptr->Refresh(false); #ifdef __WXMAC__ if (!showstatus) viewptr->Update(); // else let statusptr->Update() update viewport #else viewptr->Update(); #endif } } if (showstatus) { statusptr->CheckMouseLocation(infront); statusptr->Refresh(false); statusptr->Update(); } } // ----------------------------------------------------------------------------- static void JoinTwistedEdges(lifealgo* curralgo) { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; if (curralgo->htwist && curralgo->vtwist) { // cross-surface // eg. :C4,3 // a l k j i d // l A B C D i // h E F G H e // d I J K L a // i d c b a l for (int x = gl; x <= gr; x++) { int twistedx = gr - x + gl; int state = curralgo->getcell(twistedx, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(twistedx, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { int twistedy = gb - y + gt; int state = curralgo->getcell(gl, twistedy); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, twistedy); if (state > 0) curralgo->setcell(bl, y, state); } // copy grid's corner cells to SAME corners in border // (these cells are topologically different to non-corner cells) curralgo->setcell(bl, bt, curralgo->getcell(gl, gt)); curralgo->setcell(br, bt, curralgo->getcell(gr, gt)); curralgo->setcell(br, bb, curralgo->getcell(gr, gb)); curralgo->setcell(bl, bb, curralgo->getcell(gl, gb)); } else if (curralgo->htwist) { // Klein bottle with top and bottom edges twisted 180 degrees // eg. :K4*,3 // i l k j i l // d A B C D a // h E F G H e // l I J K L i // a d c b a d for (int x = gl; x <= gr; x++) { int twistedx = gr - x + gl; int state = curralgo->getcell(twistedx, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(twistedx, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no twist int state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(bl, y, state); } // do corner cells curralgo->setcell(bl, bt, curralgo->getcell(gl, gb)); curralgo->setcell(br, bt, curralgo->getcell(gr, gb)); curralgo->setcell(bl, bb, curralgo->getcell(gl, gt)); curralgo->setcell(br, bb, curralgo->getcell(gr, gt)); } else { // curralgo->vtwist // Klein bottle with left and right edges twisted 180 degrees // eg. :K4,3* // d i j k l a // l A B C D i // h E F G H e // d I J K L a // l a b c d i for (int x = gl; x <= gr; x++) { // join top and bottom edges with no twist int state = curralgo->getcell(x, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(x, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { int twistedy = gb - y + gt; int state = curralgo->getcell(gl, twistedy); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, twistedy); if (state > 0) curralgo->setcell(bl, y, state); } // do corner cells curralgo->setcell(bl, bt, curralgo->getcell(gr, gt)); curralgo->setcell(br, bt, curralgo->getcell(gl, gt)); curralgo->setcell(bl, bb, curralgo->getcell(gr, gb)); curralgo->setcell(br, bb, curralgo->getcell(gl, gb)); } } // ----------------------------------------------------------------------------- static void JoinTwistedAndShiftedEdges(lifealgo* curralgo) { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; if (curralgo->hshift != 0) { // Klein bottle with shift by 1 on twisted horizontal edge (with even number of cells) // eg. :K4*+1,3 // j i l k j i // d A B C D a // h E F G H e // l I J K L i // b a d c b a int state, twistedx, shiftedx; for (int x = gl; x <= gr; x++) { // join top and bottom edges with a twist and then shift by 1 twistedx = gr - x + gl; shiftedx = twistedx - 1; if (shiftedx < gl) shiftedx = gr; state = curralgo->getcell(shiftedx, gb); if (state > 0) curralgo->setcell(x, bt, state); state = curralgo->getcell(shiftedx, gt); if (state > 0) curralgo->setcell(x, bb, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no twist or shift state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(bl, y, state); } // do corner cells shiftedx = gl - 1; if (shiftedx < gl) shiftedx = gr; curralgo->setcell(bl, bt, curralgo->getcell(shiftedx, gb)); curralgo->setcell(bl, bb, curralgo->getcell(shiftedx, gt)); shiftedx = gr - 1; if (shiftedx < gl) shiftedx = gr; curralgo->setcell(br, bt, curralgo->getcell(shiftedx, gb)); curralgo->setcell(br, bb, curralgo->getcell(shiftedx, gt)); } else { // curralgo->vshift != 0 // Klein bottle with shift by 1 on twisted vertical edge (with even number of cells) // eg. :K3,4*+1 // f j k l d // c A B C a // l D E F j // i G H I g // f J K L d // c a b c a int state, twistedy, shiftedy; for (int x = gl; x <= gr; x++) { // join top and bottom edges with no twist or shift state = curralgo->getcell(x, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(x, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with a twist and then shift by 1 twistedy = gb - y + gt; shiftedy = twistedy - 1; if (shiftedy < gt) shiftedy = gb; state = curralgo->getcell(gr, shiftedy); if (state > 0) curralgo->setcell(bl, y, state); state = curralgo->getcell(gl, shiftedy); if (state > 0) curralgo->setcell(br, y, state); } // do corner cells shiftedy = gt - 1; if (shiftedy < gt) shiftedy = gb; curralgo->setcell(bl, bt, curralgo->getcell(gr, shiftedy)); curralgo->setcell(br, bt, curralgo->getcell(gl, shiftedy)); shiftedy = gb - 1; if (shiftedy < gt) shiftedy = gb; curralgo->setcell(bl, bb, curralgo->getcell(gr, shiftedy)); curralgo->setcell(br, bb, curralgo->getcell(gl, shiftedy)); } } // ----------------------------------------------------------------------------- static void JoinShiftedEdges(lifealgo* curralgo, int gwd, int ght, // grid wd and ht int hshift, int vshift) // horizontal and vertical shifts { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; if (hshift != 0) { // torus with horizontal shift // eg. :T4+1,3 // k l i j k l // d A B C D a // h E F G H e // l I J K L i // a b c d a b int state, shiftedx; for (int x = gl; x <= gr; x++) { // join top and bottom edges with a horizontal shift shiftedx = x - hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; state = curralgo->getcell(shiftedx, gb); if (state > 0) curralgo->setcell(x, bt, state); shiftedx = x + hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; state = curralgo->getcell(shiftedx, gt); if (state > 0) curralgo->setcell(x, bb, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no shift state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(bl, y, state); } // do corner cells shiftedx = gr - hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; curralgo->setcell(bl, bt, curralgo->getcell(shiftedx, gb)); shiftedx = gl - hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; curralgo->setcell(br, bt, curralgo->getcell(shiftedx, gb)); shiftedx = gr + hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; curralgo->setcell(bl, bb, curralgo->getcell(shiftedx, gt)); shiftedx = gl + hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; curralgo->setcell(br, bb, curralgo->getcell(shiftedx, gt)); } else { // vshift != 0 // torus with vertical shift // eg. :T4,3+1 // h i j k l a // l A B C D e // d E F G H i // h I J K L a // l a b c d e int state, shiftedy; for (int x = gl; x <= gr; x++) { // join top and bottom edges with no shift state = curralgo->getcell(x, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(x, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with a vertical shift shiftedy = y - vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; state = curralgo->getcell(gr, shiftedy); if (state > 0) curralgo->setcell(bl, y, state); shiftedy = y + vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; state = curralgo->getcell(gl, shiftedy); if (state > 0) curralgo->setcell(br, y, state); } // do corner cells shiftedy = gb - vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; curralgo->setcell(bl, bt, curralgo->getcell(gr, shiftedy)); shiftedy = gb + vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; curralgo->setcell(br, bt, curralgo->getcell(gl, shiftedy)); shiftedy = gt - vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; curralgo->setcell(bl, bb, curralgo->getcell(gr, shiftedy)); shiftedy = gt + vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; curralgo->setcell(br, bb, curralgo->getcell(gl, shiftedy)); } } // ----------------------------------------------------------------------------- static void JoinAdjacentEdges(lifealgo* curralgo, int pt, int pl, int pb, int pr) // pattern edges { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; // sphere // eg. :S3 // a a d g c // a A B C g // b D E F h // c G H I i // g c f i i // copy live cells in top edge to left border for (int x = pl; x <= pr; x++) { int state; int skip = curralgo->nextcell(x, gt, state); if (skip < 0) break; x += skip; if (state > 0) curralgo->setcell(bl, gt + (x - gl), state); } // copy live cells in left edge to top border for (int y = pt; y <= pb; y++) { // no point using nextcell() here -- edge is only 1 cell wide int state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(gl + (y - gt), bt, state); } // copy live cells in bottom edge to right border for (int x = pl; x <= pr; x++) { int state; int skip = curralgo->nextcell(x, gb, state); if (skip < 0) break; x += skip; if (state > 0) curralgo->setcell(br, gt + (x - gl), state); } // copy live cells in right edge to bottom border for (int y = pt; y <= pb; y++) { // no point using nextcell() here -- edge is only 1 cell wide int state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(gl + (y - gt), bb, state); } // copy grid's corner cells to SAME corners in border curralgo->setcell(bl, bt, curralgo->getcell(gl, gt)); curralgo->setcell(br, bt, curralgo->getcell(gr, gt)); curralgo->setcell(br, bb, curralgo->getcell(gr, gb)); curralgo->setcell(bl, bb, curralgo->getcell(gl, gb)); } // ----------------------------------------------------------------------------- static void JoinEdges(lifealgo* curralgo, int gwd, int ght, // grid wd and ht int pt, int pl, int pb, int pr) // pattern edges { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; if (ght > 0) { // copy live cells in top edge to bottom border for (int x = pl; x <= pr; x++) { int state; int skip = curralgo->nextcell(x, gt, state); if (skip < 0) break; x += skip; if (state > 0) curralgo->setcell(x, bb, state); } // copy live cells in bottom edge to top border for (int x = pl; x <= pr; x++) { int state; int skip = curralgo->nextcell(x, gb, state); if (skip < 0) break; x += skip; if (state > 0) curralgo->setcell(x, bt, state); } } if (gwd > 0) { // copy live cells in left edge to right border for (int y = pt; y <= pb; y++) { // no point using nextcell() here -- edge is only 1 cell wide int state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(br, y, state); } // copy live cells in right edge to left border for (int y = pt; y <= pb; y++) { // no point using nextcell() here -- edge is only 1 cell wide int state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(bl, y, state); } } if (gwd > 0 && ght > 0) { // copy grid's corner cells to opposite corners in border curralgo->setcell(bl, bt, curralgo->getcell(gr, gb)); curralgo->setcell(br, bt, curralgo->getcell(gl, gb)); curralgo->setcell(br, bb, curralgo->getcell(gl, gt)); curralgo->setcell(bl, bb, curralgo->getcell(gr, gt)); } } // ----------------------------------------------------------------------------- bool MainFrame::CreateBorderCells(lifealgo* curralgo) { // no need to do anything if there is no pattern or if the grid is a bounded plane if (curralgo->isEmpty() || curralgo->boundedplane) return true; int gwd = curralgo->gridwd; int ght = curralgo->gridht; bigint top, left, bottom, right; curralgo->findedges(&top, &left, &bottom, &right); // no need to do anything if pattern is completely inside grid edges if ( (gwd == 0 || (curralgo->gridleft < left && curralgo->gridright > right)) && (ght == 0 || (curralgo->gridtop < top && curralgo->gridbottom > bottom)) ) { return true; } // if grid has infinite width or height then pattern might be too big to use setcell/getcell if ( (gwd == 0 || ght == 0) && viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Pattern is too big!")); // return false so caller can exit step() loop return false; } if (curralgo->sphere) { // to get a sphere we join top edge with left edge, and right edge with bottom edge; // note that grid must be square (gwd == ght) int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); JoinAdjacentEdges(curralgo, pt, pl, pb, pr); } else if (curralgo->htwist || curralgo->vtwist) { // Klein bottle or cross-surface if ( (curralgo->htwist && curralgo->hshift != 0 && (gwd & 1) == 0) || (curralgo->vtwist && curralgo->vshift != 0 && (ght & 1) == 0) ) { // Klein bottle with shift is only possible if the shift is on the // twisted edge and that edge has an even number of cells JoinTwistedAndShiftedEdges(curralgo); } else { JoinTwistedEdges(curralgo); } } else if (curralgo->hshift != 0 || curralgo->vshift != 0) { // torus with horizontal or vertical shift JoinShiftedEdges(curralgo, gwd, ght, curralgo->hshift, curralgo->vshift); } else { // unshifted torus or infinite tube int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); JoinEdges(curralgo, gwd, ght, pt, pl, pb, pr); } curralgo->endofpattern(); return true; } // ----------------------------------------------------------------------------- void MainFrame::ClearRect(lifealgo* curralgo, int top, int left, int bottom, int right) { int cx, cy, v; for ( cy = top; cy <= bottom; cy++ ) { for ( cx = left; cx <= right; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > right) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell so delete it cx += skip; curralgo->setcell(cx, cy, 0); } else { cx = right + 1; // done this row } } } } // ----------------------------------------------------------------------------- bool MainFrame::DeleteBorderCells(lifealgo* curralgo) { // no need to do anything if there is no pattern if (curralgo->isEmpty()) return true; int gwd = curralgo->gridwd; int ght = curralgo->gridht; // need to find pattern edges because pattern may have expanded beyond grid // (typically by 2 cells, but could be more if rule allows births in empty space) bigint top, left, bottom, right; curralgo->findedges(&top, &left, &bottom, &right); // no need to do anything if grid encloses entire pattern if ( (gwd == 0 || (curralgo->gridleft <= left && curralgo->gridright >= right)) && (ght == 0 || (curralgo->gridtop <= top && curralgo->gridbottom >= bottom)) ) { return true; } if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Pattern is too big!")); // return false so caller can exit step() loop return false; } // set pattern edges int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); if (ght > 0 && pt < gt) { // delete live cells above grid ClearRect(curralgo, pt, pl, gt-1, pr); pt = gt; // reduce size of rect below } if (ght > 0 && pb > gb) { // delete live cells below grid ClearRect(curralgo, gb+1, pl, pb, pr); pb = gb; // reduce size of rect below } if (gwd > 0 && pl < gl) { // delete live cells left of grid ClearRect(curralgo, pt, pl, pb, gl-1); } if (gwd > 0 && pr > gr) { // delete live cells right of grid ClearRect(curralgo, pt, gr+1, pb, pr); } curralgo->endofpattern(); return true; } // ----------------------------------------------------------------------------- bool MainFrame::StepPattern() { lifealgo* curralgo = currlayer->algo; if (curralgo->gridwd > 0 || curralgo->gridht > 0) { // bounded grid, so temporarily set the increment to 1 so we can call // CreateBorderCells() and DeleteBorderCells() around each step() int savebase = currlayer->currbase; int saveexpo = currlayer->currexpo; bigint inc = curralgo->getIncrement(); curralgo->setIncrement(1); while (inc > 0) { if (wxGetApp().Poller()->checkevents()) { SetGenIncrement(); // restore correct increment return false; } if (savebase != currlayer->currbase || saveexpo != currlayer->currexpo) { // user changed step base/exponent, so best to simply exit loop break; } if (!CreateBorderCells(curralgo)) { SetGenIncrement(); // restore correct increment return false; } curralgo->step(); if (!DeleteBorderCells(curralgo)) { SetGenIncrement(); // restore correct increment return false; } inc -= 1; } // safe way to restore correct increment in case user altered step base/exponent SetGenIncrement(); } else { if (wxGetApp().Poller()->checkevents()) return false; curralgo->step(); } if (currlayer->autofit) viewptr->FitInView(0); if (!IsIconized()) DisplayPattern(); /*!!! enable this code if we ever implement isPeriodic() if (autostop) { int period = curralgo->isPeriodic(); if (period > 0) { if (period == 1) { if (curralgo->isEmpty()) { statusptr->DisplayMessage(_("Pattern is empty.")); } else { statusptr->DisplayMessage(_("Pattern is stable.")); } } else { wxString s; s.Printf(_("Pattern is oscillating (period = %d)."), period); statusptr->DisplayMessage(s); } return false; } } */ return true; } // ----------------------------------------------------------------------------- void MainFrame::GeneratePattern() { if (generating || viewptr->drawingcells || viewptr->waitingforclick) { Beep(); return; } if (currlayer->algo->isEmpty()) { statusptr->ErrorMessage(empty_pattern); return; } if (currlayer->algo->isrecording()) { // don't attempt to save starting pattern here (let DeleteTimeline do it) } else if (!SaveStartingPattern()) { return; } // GeneratePattern is never called while running a script so no need // to test inscript or currlayer->stayclean if (allowundo) currlayer->undoredo->RememberGenStart(); // for DisplayTimingInfo begintime = stopwatch->Time(); begingen = currlayer->algo->getGeneration().todouble(); // for hyperspeed int hypdown = 64; generating = true; // avoid re-entry wxGetApp().PollerReset(); UpdateUserInterface(); // only show hashing info while generating, otherwise Mac app can crash // after a paste due to hlifealgo::resize() calling lifestatus() which // then causes the viewport to be repainted for some inexplicable reason lifealgo::setVerbose( currlayer->showhashinfo ); if (currlayer->currexpo < 0) whentosee = stopwatch->Time() + statusptr->GetCurrentDelay(); while (true) { if (currlayer->currexpo < 0) { // slow down by only doing one gen every GetCurrentDelay() millisecs long currmsec = stopwatch->Time(); if (currmsec >= whentosee) { if (!StepPattern()) break; // add delay to current time rather than currmsec whentosee = stopwatch->Time() + statusptr->GetCurrentDelay(); } else { // process events while we wait if (wxGetApp().Poller()->checkevents()) break; // don't hog CPU but keep sleep duration short (ie. <= mindelay) wxMilliSleep(1); } } else { // currexpo >= 0 so advance pattern by currlayer->algo->getIncrement() gens if (!StepPattern()) break; if (currlayer->algo->isrecording()) { if (showtimeline) UpdateTimelineBar(); if (currlayer->algo->getframecount() == MAX_FRAME_COUNT) { wxString msg; msg.Printf(_("No more frames can be recorded (maximum = %d)."), MAX_FRAME_COUNT); Warning(msg); break; } } else if (currlayer->hyperspeed && currlayer->algo->hyperCapable()) { hypdown--; if (hypdown == 0) { hypdown = 64; GoFaster(); } } } } generating = false; lifealgo::setVerbose(0); // for DisplayTimingInfo endtime = stopwatch->Time(); endgen = currlayer->algo->getGeneration().todouble(); // display the final pattern if (currlayer->autofit) viewptr->FitInView(0); if (command_pending || draw_pending) { // let the pending command/draw do the update below } else { UpdateEverything(); } // GeneratePattern is never called while running a script so no need // to test inscript or currlayer->stayclean; note that we must call // RememberGenFinish BEFORE processing any pending command if (allowundo) currlayer->undoredo->RememberGenFinish(); // stop recording any timeline before processing any pending command if (currlayer->algo->isrecording()) { currlayer->algo->stoprecording(); if (currlayer->algo->getframecount() > 0) { // probably best to go to last frame currlayer->currframe = currlayer->algo->getframecount() - 1; currlayer->autoplay = 0; currlayer->tlspeed = 0; currlayer->algo->gotoframe(currlayer->currframe); if (currlayer->autofit) viewptr->FitInView(1); } if (!showtimeline) ToggleTimelineBar(); UpdateUserInterface(); } DoPendingAction(true); // true means we can restart generating loop } // ----------------------------------------------------------------------------- void MainFrame::DoPendingAction(bool restart) { if (command_pending) { command_pending = false; int id = cmdevent.GetId(); switch (id) { // don't restart the generating loop after some commands case wxID_NEW: NewPattern(); break; case wxID_OPEN: OpenPattern(); break; case ID_OPEN_CLIP: OpenClipboard(); break; case ID_RESET: ResetPattern(); break; case ID_SETGEN: SetGeneration(); break; case ID_UNDO: currlayer->undoredo->UndoChange(); break; case ID_ADD_LAYER: AddLayer(); break; case ID_DUPLICATE: DuplicateLayer(); break; case ID_LOAD_LEXICON: LoadLexiconPattern(); break; default: if ( id > ID_OPEN_RECENT && id <= ID_OPEN_RECENT + numpatterns ) { OpenRecentPattern(id); } else if ( id > ID_RUN_RECENT && id <= ID_RUN_RECENT + numscripts ) { OpenRecentScript(id); if (restart && !stop_after_script) { wxCommandEvent goevt(wxEVT_COMMAND_MENU_SELECTED, ID_START); wxPostEvent(this->GetEventHandler(), goevt); // avoid clearing status message due to script like density.py keepmessage = true; } } else if ( id == ID_RUN_SCRIPT ) { OpenScript(); if (restart && !stop_after_script) { wxCommandEvent goevt(wxEVT_COMMAND_MENU_SELECTED, ID_START); wxPostEvent(this->GetEventHandler(), goevt); // avoid clearing status message due to script like density.py keepmessage = true; } } else if ( id == ID_RUN_CLIP ) { RunClipboard(); if (restart && !stop_after_script) { wxCommandEvent goevt(wxEVT_COMMAND_MENU_SELECTED, ID_START); wxPostEvent(this->GetEventHandler(), goevt); // avoid clearing status message due to script like density.py keepmessage = true; } } else if ( id >= ID_LAYER0 && id <= ID_LAYERMAX ) { int oldcloneid = currlayer->cloneid; SetLayer(id - ID_LAYER0); // continue generating if new layer is a clone of old layer if (restart && currlayer->cloneid > 0 && currlayer->cloneid == oldcloneid) { wxCommandEvent goevt(wxEVT_COMMAND_MENU_SELECTED, ID_START); wxPostEvent(this->GetEventHandler(), goevt); } } else if ( id == ID_DEL_LAYER ) { int wasclone = currlayer->cloneid > 0 && ((currindex == 0 && currlayer->cloneid == GetLayer(1)->cloneid) || (currindex > 0 && currlayer->cloneid == GetLayer(currindex-1)->cloneid)); DeleteLayer(); // continue generating if new layer is/was a clone of old layer if (restart && wasclone) { wxCommandEvent goevt(wxEVT_COMMAND_MENU_SELECTED, ID_START); wxPostEvent(this->GetEventHandler(), goevt); } } else { // temporarily pretend the tool/layer/edit bars are not showing // to avoid Update[Tool/Layer/Edit]Bar changing button states bool saveshowtool = showtool; showtool = false; bool saveshowlayer = showlayer; showlayer = false; bool saveshowedit = showedit; showedit = false; // process the pending command cmdevent.SetEventType(wxEVT_COMMAND_MENU_SELECTED); cmdevent.SetEventObject(this); this->GetEventHandler()->ProcessEvent(cmdevent); // restore tool/layer/edit bar flags showtool = saveshowtool; showlayer = saveshowlayer; showedit = saveshowedit; if (restart) { // call GeneratePattern again wxCommandEvent goevt(wxEVT_COMMAND_MENU_SELECTED, ID_START); wxPostEvent(this->GetEventHandler(), goevt); } } } } if (draw_pending) { draw_pending = false; // temporarily pretend the tool/layer/edit bars are not showing // to avoid Update[Tool/Layer/Edit]Bar changing button states bool saveshowtool = showtool; showtool = false; bool saveshowlayer = showlayer; showlayer = false; bool saveshowedit = showedit; showedit = false; UpdateEverything(); // do the drawing mouseevent.SetEventType(wxEVT_LEFT_DOWN); mouseevent.SetEventObject(viewptr); viewptr->GetEventHandler()->ProcessEvent(mouseevent); while (viewptr->drawingcells) { wxGetApp().Yield(true); wxMilliSleep(5); // don't hog CPU } // restore tool/layer/edit bar flags showtool = saveshowtool; showlayer = saveshowlayer; showedit = saveshowedit; if (restart) { // call GeneratePattern again wxCommandEvent goevt(wxEVT_COMMAND_MENU_SELECTED, ID_START); wxPostEvent(this->GetEventHandler(), goevt); } } } // ----------------------------------------------------------------------------- void MainFrame::DisplayTimingInfo() { if (viewptr->waitingforclick) return; if (generating) { endtime = stopwatch->Time(); endgen = currlayer->algo->getGeneration().todouble(); } if (endtime > begintime) { double secs = (double)(endtime - begintime) / 1000.0; double gens = endgen - begingen; wxString s; s.Printf(_("%g gens in %g secs (%g gens/sec)."), gens, secs, gens/secs); statusptr->DisplayMessage(s); } } // ----------------------------------------------------------------------------- void MainFrame::Stop() { if (inscript) { PassKeyToScript(WXK_ESCAPE); } else if (generating) { wxGetApp().PollerInterrupt(); } } // ----------------------------------------------------------------------------- // this global flag is used to avoid re-entrancy in NextGeneration() // due to holding down the space/tab key static bool inNextGen = false; void MainFrame::NextGeneration(bool useinc) { if (inNextGen) return; inNextGen = true; if (!inscript && generating) { // we must be in GeneratePattern() loop, so abort it Stop(); inNextGen = false; return; } if (viewptr->drawingcells || viewptr->waitingforclick) { Beep(); inNextGen = false; return; } // best if generating stops after running a script like oscar.py or goto.py if (inscript) stop_after_script = true; lifealgo* curralgo = currlayer->algo; if (curralgo->isEmpty()) { statusptr->ErrorMessage(empty_pattern); inNextGen = false; return; } if (!SaveStartingPattern()) { inNextGen = false; return; } if (allowundo) { if (currlayer->stayclean) { // script has called run/step after a new/open command has set // stayclean true by calling MarkLayerClean if (curralgo->getGeneration() == currlayer->startgen) { // starting pattern has just been saved so we need to remember // this gen change in case user does a Reset after script ends // (RememberGenFinish will be called at the end of RunScript) if (currlayer->undoredo->savegenchanges) { // script must have called reset command, so we need to call // RememberGenFinish to match earlier RememberGenStart currlayer->undoredo->savegenchanges = false; currlayer->undoredo->RememberGenFinish(); } currlayer->undoredo->RememberGenStart(); } } else { // !currlayer->stayclean if (inscript) { // pass in false so we don't test savegenchanges flag; // ie. we only want to save pending cell changes here SavePendingChanges(false); } currlayer->undoredo->RememberGenStart(); } } // curralgo->step() calls checkevents() so set generating flag generating = true; // only show hashing info while generating lifealgo::setVerbose( currlayer->showhashinfo ); // avoid doing some things if NextGeneration is called from a script; // ie. by a run/step command if (!inscript) { if (useinc) { // for DisplayTimingInfo begintime = stopwatch->Time(); begingen = curralgo->getGeneration().todouble(); } wxGetApp().PollerReset(); viewptr->CheckCursor(infront); } bool boundedgrid = (curralgo->gridwd > 0 || curralgo->gridht > 0); if (useinc) { // step by current increment if (curralgo->getIncrement() > bigint::one && !inscript) { UpdateToolBar(); UpdateMenuItems(); } if (boundedgrid) { // temporarily set the increment to 1 so we can call CreateBorderCells() // and DeleteBorderCells() around each step() int savebase = currlayer->currbase; int saveexpo = currlayer->currexpo; bigint inc = curralgo->getIncrement(); curralgo->setIncrement(1); while (inc > 0) { if (wxGetApp().Poller()->checkevents()) break; if (savebase != currlayer->currbase || saveexpo != currlayer->currexpo) { // user changed step base/exponent, so reset increment to 1 inc = curralgo->getIncrement(); curralgo->setIncrement(1); } if (!CreateBorderCells(curralgo)) break; curralgo->step(); if (!DeleteBorderCells(curralgo)) break; inc -= 1; } // safe way to restore correct increment in case user altered base/expo in above loop SetGenIncrement(); } else { curralgo->step(); } } else { // step by 1 gen bigint saveinc = curralgo->getIncrement(); curralgo->setIncrement(1); if (boundedgrid) CreateBorderCells(curralgo); curralgo->step(); if (boundedgrid) DeleteBorderCells(curralgo); curralgo->setIncrement(saveinc); } generating = false; lifealgo::setVerbose(0); if (!inscript) { if (useinc) { // for DisplayTimingInfo (we add 1 millisec here in case it took < 1 millisec) endtime = stopwatch->Time() + 1; endgen = curralgo->getGeneration().todouble(); } // autofit is only used when doing many gens if (currlayer->autofit && useinc && curralgo->getIncrement() > bigint::one) viewptr->FitInView(0); UpdateEverything(); } // we must call RememberGenFinish BEFORE processing any pending command if (allowundo && !currlayer->stayclean) currlayer->undoredo->RememberGenFinish(); // process any pending command seen via checkevents() in curralgo->step() if (!inscript) DoPendingAction(false); // false means don't restart generating loop inNextGen = false; } // ----------------------------------------------------------------------------- void MainFrame::ToggleAutoFit() { currlayer->autofit = !currlayer->autofit; // we only use autofit when generating; that's why the Auto Fit item // is in the Control menu and not in the View menu if (generating && currlayer->autofit) { viewptr->FitInView(0); UpdateEverything(); } } // ----------------------------------------------------------------------------- void MainFrame::ToggleHyperspeed() { currlayer->hyperspeed = !currlayer->hyperspeed; } // ----------------------------------------------------------------------------- void MainFrame::ToggleHashInfo() { currlayer->showhashinfo = !currlayer->showhashinfo; // only show hashing info while generating if (generating) lifealgo::setVerbose( currlayer->showhashinfo ); } // ----------------------------------------------------------------------------- void MainFrame::ClearOutsideGrid() { // check current pattern and clear any live cells outside bounded grid bool patternchanged = false; bool savechanges = allowundo && !currlayer->stayclean; // might also need to truncate selection currlayer->currsel.CheckGridEdges(); if (currlayer->algo->isEmpty()) return; // check if current pattern is too big to use nextcell/setcell bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Pattern too big to check (outside +/- 10^9 boundary).")); return; } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); // no need to do anything if pattern is entirely within grid int gtop = currlayer->algo->gridtop.toint(); int gleft = currlayer->algo->gridleft.toint(); int gbottom = currlayer->algo->gridbottom.toint(); int gright = currlayer->algo->gridright.toint(); if (currlayer->algo->gridwd == 0) { // grid has infinite width gleft = INT_MIN; gright = INT_MAX; } if (currlayer->algo->gridht == 0) { // grid has infinite height gtop = INT_MIN; gbottom = INT_MAX; } if (itop >= gtop && ileft >= gleft && ibottom <= gbottom && iright <= gright) { return; } int ht = ibottom - itop + 1; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = currlayer->algo->getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; bool abort = false; int v = 0; BeginProgress(_("Checking cells outside grid")); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { currcount++; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (cx < gleft || cx > gright || cy < gtop || cy > gbottom) { // clear cell outside grid if (savechanges) currlayer->undoredo->SaveCellChange(cx, cy, v, 0); curralgo->setcell(cx, cy, 0); patternchanged = true; } currcount++; } else { cx = iright; // done this row } if (currcount > 1024) { accumcount += currcount; currcount = 0; abort = AbortProgress(accumcount / maxcount, wxEmptyString); if (abort) break; } } if (abort) break; } curralgo->endofpattern(); EndProgress(); if (patternchanged) { statusptr->ErrorMessage(_("Pattern was truncated (live cells were outside grid).")); } } // ----------------------------------------------------------------------------- void MainFrame::ReduceCellStates(int newmaxstate) { // check current pattern and reduce any cell states > newmaxstate bool patternchanged = false; bool savechanges = allowundo && !currlayer->stayclean; // check if current pattern is too big to use nextcell/setcell bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Pattern too big to check (outside +/- 10^9 boundary).")); return; } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int ht = ibottom - itop + 1; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = currlayer->algo->getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; bool abort = false; int v = 0; BeginProgress(_("Checking cell states")); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { currcount++; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (v > newmaxstate) { // reduce cell's current state to largest state if (savechanges) currlayer->undoredo->SaveCellChange(cx, cy, v, newmaxstate); curralgo->setcell(cx, cy, newmaxstate); patternchanged = true; } currcount++; } else { cx = iright; // done this row } if (currcount > 1024) { accumcount += currcount; currcount = 0; abort = AbortProgress(accumcount / maxcount, wxEmptyString); if (abort) break; } } if (abort) break; } curralgo->endofpattern(); EndProgress(); if (patternchanged) { statusptr->ErrorMessage(_("Pattern has changed (new rule has fewer states).")); } } // ----------------------------------------------------------------------------- void MainFrame::ShowRuleDialog() { if (inscript || viewptr->waitingforclick) return; if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_SETRULE); return; } algo_type oldalgo = currlayer->algtype; wxString oldrule = wxString(currlayer->algo->getrule(), wxConvLocal); int oldmaxstate = currlayer->algo->NumCellStates() - 1; // selection might change if grid becomes smaller, // so save current selection for RememberRuleChange/RememberAlgoChange viewptr->SaveCurrentSelection(); if (ChangeRule()) { // if ChangeAlgorithm was called then we're done if (currlayer->algtype != oldalgo) { // except we have to call UpdateEverything here now that the main window is active UpdateEverything(); return; } // show new rule in window title (but don't change file name); // even if the rule didn't change we still need to do this because // the user might have simply added/deleted a named rule SetWindowTitle(wxEmptyString); // check if the rule string changed, or the number of states changed // (the latter might happen if user edited a table/tree file) wxString newrule = wxString(currlayer->algo->getrule(), wxConvLocal); int newmaxstate = currlayer->algo->NumCellStates() - 1; if (oldrule != newrule || oldmaxstate != newmaxstate) { // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { ClearOutsideGrid(); } // rule change might have changed the number of cell states; // if there are fewer states then pattern might change if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { ReduceCellStates(newmaxstate); } if (allowundo) { currlayer->undoredo->RememberRuleChange(oldrule); } } // switch to default colors and icons for new rule (we need to do this even if // oldrule == newrule in case there's a new/changed .colors or .icons file) UpdateLayerColors(); // pattern or colors or icons might have changed UpdateEverything(); } } // ----------------------------------------------------------------------------- void MainFrame::ChangeAlgorithm(algo_type newalgotype, const wxString& newrule, bool inundoredo) { if (newalgotype == currlayer->algtype) return; // check if current pattern is too big to use nextcell/setcell bigint top, left, bottom, right; if ( !currlayer->algo->isEmpty() ) { currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Pattern cannot be converted (outside +/- 10^9 boundary).")); return; } } if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_ALGO0 + newalgotype); return; } // save changes if undo/redo is enabled and script isn't constructing a pattern // and we're not undoing/redoing an earlier algo change bool savechanges = allowundo && !currlayer->stayclean && !inundoredo; if (savechanges && inscript) { // note that we must save pending gen changes BEFORE changing algo type // otherwise temporary files won't be the correct type (mc or rle) SavePendingChanges(); } // selection might change if grid becomes smaller, // so save current selection for RememberAlgoChange if (savechanges) viewptr->SaveCurrentSelection(); bool rulechanged = false; wxString oldrule = wxString(currlayer->algo->getrule(), wxConvLocal); // change algorithm type, reset step size, and update status bar immediately algo_type oldalgo = currlayer->algtype; currlayer->algtype = newalgotype; currlayer->currbase = algoinfo[newalgotype]->defbase; currlayer->currexpo = 0; UpdateStatus(); // create a new universe of the requested flavor lifealgo* newalgo = CreateNewUniverse(newalgotype); if (inundoredo) { // switch to given newrule const char* err = newalgo->setrule( newrule.mb_str(wxConvLocal) ); if (err) newalgo->setrule( newalgo->DefaultRule() ); } else { const char* err; if (newrule.IsEmpty()) { // try to use same rule err = newalgo->setrule( currlayer->algo->getrule() ); } else { // switch to newrule err = newalgo->setrule( newrule.mb_str(wxConvLocal) ); rulechanged = true; } if (err) { wxString defrule = wxString(newalgo->DefaultRule(), wxConvLocal); if (newrule.IsEmpty() && oldrule.Find(':') >= 0) { // switch to new algo's default rule, but preserve the topology in oldrule // so we can do things like switch from "LifeHistory:T30,20" in RuleLoader // to "B3/S23:T30,20" in QuickLife if (defrule.Find(':') >= 0) { // default rule shouldn't have a suffix but play safe and remove it defrule = defrule.BeforeFirst(':'); } defrule += wxT(":"); defrule += oldrule.AfterFirst(':'); } err = newalgo->setrule( defrule.mb_str(wxConvLocal) ); // shouldn't ever fail but play safe if (err) newalgo->setrule( newalgo->DefaultRule() ); rulechanged = true; } } // set same gen count newalgo->setGeneration( currlayer->algo->getGeneration() ); bool patternchanged = false; if ( !currlayer->algo->isEmpty() ) { // copy pattern in current universe to new universe int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int ht = ibottom - itop + 1; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = currlayer->algo->getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; bool abort = false; int v = 0; BeginProgress(_("Converting pattern")); // set newalgo's grid edges so we can save cells that are outside grid int gtop = newalgo->gridtop.toint(); int gleft = newalgo->gridleft.toint(); int gbottom = newalgo->gridbottom.toint(); int gright = newalgo->gridright.toint(); if (newalgo->gridwd == 0) { // grid has infinite width gleft = INT_MIN; gright = INT_MAX; } if (newalgo->gridht == 0) { // grid has infinite height gtop = INT_MIN; gbottom = INT_MAX; } // need to check for state change if new algo has fewer states than old algo int newmaxstate = newalgo->NumCellStates() - 1; lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { currcount++; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (cx < gleft || cx > gright || cy < gtop || cy > gbottom) { // cx,cy is outside grid if (savechanges) currlayer->undoredo->SaveCellChange(cx, cy, v, 0); // no need to clear cell from curralgo (that universe will soon be deleted) patternchanged = true; } else { if (v > newmaxstate) { // reduce v to largest state in new algo if (savechanges) currlayer->undoredo->SaveCellChange(cx, cy, v, newmaxstate); v = newmaxstate; patternchanged = true; } newalgo->setcell(cx, cy, v); } currcount++; } else { cx = iright; // done this row } if (currcount > 1024) { accumcount += currcount; currcount = 0; abort = AbortProgress(accumcount / maxcount, wxEmptyString); if (abort) break; } } if (abort) break; } newalgo->endofpattern(); EndProgress(); } // delete old universe and point current universe to new universe delete currlayer->algo; currlayer->algo = newalgo; SetGenIncrement(); // if new grid is bounded then we might need to truncate the selection if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { currlayer->currsel.CheckGridEdges(); } // switch to default colors for new algo+rule UpdateLayerColors(); if (!inundoredo) { if (rulechanged) { // show new rule in window title (but don't change file name) SetWindowTitle(wxEmptyString); // if pattern exists and is at starting gen then set savestart true // so that SaveStartingPattern will save pattern to suitable file // (and thus ResetPattern will work correctly) if ( currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty() ) { currlayer->savestart = true; } if (newrule.IsEmpty()) { if (patternchanged) { statusptr->ErrorMessage(_("Rule has changed and pattern has changed.")); } else { // don't beep statusptr->DisplayMessage(_("Rule has changed.")); } } else { if (patternchanged) { statusptr->ErrorMessage(_("Algorithm has changed and pattern has changed.")); } else { // don't beep statusptr->DisplayMessage(_("Algorithm has changed.")); } } } else if (patternchanged) { statusptr->ErrorMessage(_("Pattern has changed.")); } if (!inscript) { UpdateEverything(); } } if (savechanges) { currlayer->undoredo->RememberAlgoChange(oldalgo, oldrule); } } // ----------------------------------------------------------------------------- static wxString CreateTABLE(const wxString& tablepath) { wxString contents = wxT("\n@TABLE\n\n"); // append contents of .table file FILE* f = OPENFILE(tablepath); if (f) { const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; linereader reader(f); while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; contents += wxString(linebuf, wxConvLocal); contents += wxT("\n"); } reader.close(); } else { std::ostringstream oss; oss << "Could not read .table file:\n" << tablepath.mb_str(wxConvLocal); throw std::runtime_error(oss.str().c_str()); } return contents; } // ----------------------------------------------------------------------------- static wxString CreateEmptyTABLE(const wxString& folder, const wxString& prefix, const wxSortedArrayString& allfiles) { // create a valid table that does nothing wxString contents = wxT("\nThis file contains colors and/or icons shared by "); contents += prefix; contents += wxT("-* rules.\n"); contents += wxT("\n@TABLE\n\n"); // search allfiles for 1st prefix-*.table/tree file and extract numstates and neighborhood wxString numstates, neighborhood; for (size_t n = 0; n < allfiles.GetCount(); n++) { wxString filename = allfiles[n]; if (filename.EndsWith(wxT(".table")) || filename.EndsWith(wxT(".tree"))) { if (prefix == filename.BeforeLast('-')) { wxString filepath = folder + filename; FILE* f = OPENFILE(filepath); if (f) { const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; linereader reader(f); while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; if (strncmp(linebuf, "n_states:", 9) == 0) { numstates = wxString(linebuf,wxConvLocal) + wxT("\n"); } else if (strncmp(linebuf, "num_states=", 11) == 0) { // convert to table syntax numstates = wxT("n_states:") + wxString(linebuf+11,wxConvLocal); numstates += wxT("\n"); } else if (strncmp(linebuf, "neighborhood:", 13) == 0) { neighborhood = wxString(linebuf,wxConvLocal) + wxT("\n"); break; } else if (strncmp(linebuf, "num_neighbors=", 14) == 0) { // convert to table syntax neighborhood = wxT("neighborhood:"); if (linebuf[14] == '4') neighborhood += wxT("vonNeumann\n"); else neighborhood += wxT("Moore\n"); break; } } reader.close(); } else { std::ostringstream oss; oss << "Could not read .table/tree file:\n" << filepath.mb_str(wxConvLocal); throw std::runtime_error(oss.str().c_str()); } } } } if (numstates.length() == 0) { numstates = wxT("n_states:256\n"); wxString msg = _("Could not find ") + prefix; msg += _("-*.table/tree to set n_states in "); msg += prefix; msg += _("-shared.rule."); Warning(msg); } contents += numstates; contents += neighborhood; contents += wxT("symmetries:none\n"); // anything valid would do contents += wxT("# do nothing\n"); // no transitions return contents; } // ----------------------------------------------------------------------------- static wxString CreateTREE(const wxString& treepath) { wxString contents = wxT("\n@TREE\n\n"); // append contents of .tree file FILE* f = OPENFILE(treepath); if (f) { const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; linereader reader(f); while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; contents += wxString(linebuf, wxConvLocal); contents += wxT("\n"); } reader.close(); } else { std::ostringstream oss; oss << "Could not read .tree file:\n" << treepath.mb_str(wxConvLocal); throw std::runtime_error(oss.str().c_str()); } return contents; } // ----------------------------------------------------------------------------- static wxString CreateCOLORS(const wxString& colorspath) { wxString contents = wxT("\n@COLORS\n\n"); FILE* f = OPENFILE(colorspath); if (f) { const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; linereader reader(f); while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; int skip = 0; if (strncmp(linebuf, "color", 5) == 0 || strncmp(linebuf, "gradient", 8) == 0) { // strip off everything before 1st digit while (linebuf[skip] && (linebuf[skip] < '0' || linebuf[skip] > '9')) { skip++; } } contents += wxString(linebuf + skip, wxConvLocal); contents += wxT("\n"); } reader.close(); } else { std::ostringstream oss; oss << "Could not read .colors file:\n" << colorspath.mb_str(wxConvLocal); throw std::runtime_error(oss.str().c_str()); } return contents; } // ----------------------------------------------------------------------------- static wxString CreateStateColors(wxImage image, int numicons) { wxString contents = wxT("\n@COLORS\n\n"); // if the last icon has only 1 color then assume it is the extra 15x15 icon // supplied to set the color of state 0 if (numicons > 1) { wxImage icon = image.GetSubImage(wxRect((numicons-1)*15, 0, 15, 15)); if (icon.CountColours(1) == 1) { unsigned char* idata = icon.GetData(); unsigned char R = idata[0]; unsigned char G = idata[1]; unsigned char B = idata[2]; contents += wxString::Format(wxT("0 %d %d %d\n"), R, G, B); numicons--; } } // set non-icon colors for each live state to the average of the non-black pixels // in each 15x15 icon (note we've skipped the extra icon detected above) for (int i = 0; i < numicons; i++) { wxImage icon = image.GetSubImage(wxRect(i*15, 0, 15, 15)); int nbcount = 0; // non-black pixels int totalR = 0; int totalG = 0; int totalB = 0; unsigned char* idata = icon.GetData(); for (int y = 0; y < 15; y++) { for (int x = 0; x < 15; x++) { long pos = (y * 15 + x) * 3; unsigned char R = idata[pos]; unsigned char G = idata[pos+1]; unsigned char B = idata[pos+2]; if (R > 0 || G > 0 || B > 0) { // non-black pixel nbcount++; totalR += R; totalG += G; totalB += B; } } } if (nbcount > 0) { contents += wxString::Format(wxT("%d %d %d %d\n"), i+1, totalR/nbcount, totalG/nbcount, totalB/nbcount); } else { // unlikely, but avoid div by zero contents += wxString::Format(wxT("%d 0 0 0\n"), i+1); } } return contents; } // ----------------------------------------------------------------------------- static wxString hex2(int i) { // convert given number from 0..255 into 2 hex digits wxString result = wxT("xx"); const char* hexdigit = "0123456789ABCDEF"; result[0] = hexdigit[i / 16]; result[1] = hexdigit[i % 16]; return result; } // ----------------------------------------------------------------------------- static wxString CreateXPM(const wxString& iconspath, wxImage image, int size, int numicons) { // create XPM data for given set of icons wxString contents = wxT("\nXPM\n"); int charsperpixel = 1; const char* cindex = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; wxImageHistogram histogram; int numcolors = image.ComputeHistogram(histogram); if (numcolors > 256) { std::ostringstream oss; oss << "Image in " << iconspath.mb_str(wxConvLocal) << " has more than 256 colors."; throw std::runtime_error(oss.str().c_str()); } if (numcolors > 26) charsperpixel = 2; // AABA..PA, ABBB..PB, ... , APBP..PP contents += wxT("/* width height num_colors chars_per_pixel */\n"); contents += wxString::Format(wxT("\"%d %d %d %d\"\n"), size, size*numicons, numcolors, charsperpixel); contents += wxT("/* colors */\n"); int n = 0; for (wxImageHistogram::iterator entry = histogram.begin(); entry != histogram.end(); ++entry) { unsigned long key = entry->first; unsigned char R = (key & 0xFF0000) >> 16; unsigned char G = (key & 0x00FF00) >> 8; unsigned char B = (key & 0x0000FF); if (R == 0 && G == 0 && B == 0) { // nicer to show . or .. for black pixels contents += wxT("\"."); if (charsperpixel == 2) contents += wxT("."); contents += wxT(" c #000000\"\n"); } else { wxString hexcolor = wxT("#"); hexcolor += hex2(R); hexcolor += hex2(G); hexcolor += hex2(B); contents += wxT("\""); if (charsperpixel == 1) { contents += cindex[n]; } else { contents += cindex[n % 16]; contents += cindex[n / 16]; } contents += wxT(" c "); contents += hexcolor; contents += wxT("\"\n"); } n++; } for (int i = 0; i < numicons; i++) { contents += wxString::Format(wxT("/* icon for state %d */\n"), i+1); wxImage icon = image.GetSubImage(wxRect(i*15, 0, size, size)); unsigned char* idata = icon.GetData(); for (int y = 0; y < size; y++) { contents += wxT("\""); for (int x = 0; x < size; x++) { long pos = (y * size + x) * 3; unsigned char R = idata[pos]; unsigned char G = idata[pos+1]; unsigned char B = idata[pos+2]; if (R == 0 && G == 0 && B == 0) { // nicer to show . or .. for black pixels contents += wxT("."); if (charsperpixel == 2) contents += wxT("."); } else { n = 0; unsigned long thisRGB = wxImageHistogram::MakeKey(R,G,B); for (wxImageHistogram::iterator entry = histogram.begin(); entry != histogram.end(); ++entry) { if (thisRGB == entry->first) break; n++; } if (charsperpixel == 1) { contents += cindex[n]; } else { contents += cindex[n % 16]; contents += cindex[n / 16]; } } } contents += wxT("\"\n"); } } return contents; } // ----------------------------------------------------------------------------- static wxString CreateICONS(const wxString& iconspath, bool nocolors) { wxString contents = wxT("\n@ICONS\n"); wxImage image; if (image.LoadFile(iconspath)) { int wd = image.GetWidth(); int ht = image.GetHeight(); if (ht != 15 && ht != 22) { std::ostringstream oss; oss << "Image in " << iconspath.mb_str(wxConvLocal) << " has incorrect height (should be 15 or 22)."; throw std::runtime_error(oss.str().c_str()); } if (wd % 15 > 0) { std::ostringstream oss; oss << "Image in " << iconspath.mb_str(wxConvLocal) << " has incorrect width (should be multiple of 15)."; throw std::runtime_error(oss.str().c_str()); } int numicons = wd / 15; // WARNING: MultiColorImage must be called 1st in the next test because // we want image to be converted to black-and-white if it only uses 2 colors // (for compatibility with Golly 2.4 and older) if (MultiColorImage(image) && nocolors) { // the .icons file is multi-color and there was no .colors file, // so prepend a @COLORS section that sets non-icon colors contents = CreateStateColors(image.GetSubImage(wxRect(0,0,wd,15)), numicons) + contents; } if (ht == 15) { contents += CreateXPM(iconspath, image, 15, numicons); } else { contents += CreateXPM(iconspath, image.GetSubImage(wxRect(0,0,wd,15)), 15, numicons); contents += CreateXPM(iconspath, image.GetSubImage(wxRect(0,15,wd,7)), 7, numicons); } } else { std::ostringstream oss; oss << "Could not load image from .icons file:\n" << iconspath.mb_str(wxConvLocal); throw std::runtime_error(oss.str().c_str()); } return contents; } // ----------------------------------------------------------------------------- static void CreateOneRule(const wxString& rulefile, const wxString& folder, const wxSortedArrayString& allfiles, wxString& htmlinfo) { wxString tabledata, treedata, colordata, icondata; wxString rulename = rulefile.BeforeLast('.'); if (rulename.EndsWith(wxT("-shared"))) { // create a .rule file with colors and/or icons shared by other .rule files wxString prefix = rulename.BeforeLast('-'); tabledata = CreateEmptyTABLE(folder, prefix, allfiles); wxString sharedcolors = prefix + wxT(".colors"); if (allfiles.Index(sharedcolors) != wxNOT_FOUND) colordata = CreateCOLORS(folder + sharedcolors); wxString sharedicons = prefix + wxT(".icons"); if (allfiles.Index(sharedicons) != wxNOT_FOUND) icondata = CreateICONS(folder + sharedicons, colordata.length() == 0); } else { wxString tablefile = rulename + wxT(".table"); wxString treefile = rulename + wxT(".tree"); wxString colorsfile = rulename + wxT(".colors"); wxString iconsfile = rulename + wxT(".icons"); if (allfiles.Index(tablefile) != wxNOT_FOUND) tabledata = CreateTABLE(folder + tablefile); if (allfiles.Index(treefile) != wxNOT_FOUND) treedata = CreateTREE(folder + treefile); if (allfiles.Index(colorsfile) != wxNOT_FOUND) colordata = CreateCOLORS(folder + colorsfile); if (allfiles.Index(iconsfile) != wxNOT_FOUND) icondata = CreateICONS(folder + iconsfile, colordata.length() == 0); } wxString contents = wxT("@RULE ") + rulename + wxT("\n"); contents += tabledata; contents += treedata; contents += colordata; contents += icondata; // write contents to .rule file wxString rulepath = folder + rulefile; wxFile outfile(rulepath, wxFile::write); if (outfile.IsOpened()) { outfile.Write(contents); outfile.Close(); } else { std::ostringstream oss; oss << "Could not create rule file:\n" << rulepath.mb_str(wxConvLocal); throw std::runtime_error(oss.str().c_str()); } // append created file to htmlinfo htmlinfo += _(""); htmlinfo += rulefile; htmlinfo += _("
\n"); } // ----------------------------------------------------------------------------- static bool SharedColorsIcons(const wxString& prefix, const wxSortedArrayString& allfiles) { // return true if prefix.colors/icons is shared by at least one prefix-*.table/tree file for (size_t n = 0; n < allfiles.GetCount(); n++) { wxString filename = allfiles[n]; if (filename.EndsWith(wxT(".table")) || filename.EndsWith(wxT(".tree"))) { if (prefix == filename.BeforeLast('-')) { return true; } } } // prefix-*.table/tree does not exist in allfiles return false; } // ----------------------------------------------------------------------------- static int ConvertRules(const wxString& folder, bool supplied, wxString& htmlinfo) { wxString filename, rulefile, rulename; int depcount = 0; if (!wxFileName::DirExists(folder)) { // this might happen if user deleted/renamed folder while Golly is running std::ostringstream oss; oss << "Directory does not exist:\n" << folder.mb_str(wxConvLocal); throw std::runtime_error(oss.str().c_str()); } wxDir dir(folder); if (!dir.IsOpened()) { std::ostringstream oss; oss << "Failed to open directory:\n" << folder.mb_str(wxConvLocal); throw std::runtime_error(oss.str().c_str()); } htmlinfo += wxT("

\n"); if (supplied) { htmlinfo += _("New .rule files created in the supplied Rules folder:
\n("); } else { htmlinfo += _("New .rule files created in your rules folder:
\n("); } htmlinfo += folder; htmlinfo += _(")

\n"); // build an array of all files in the given folder (using a sorted array speeds up Index calls) wxSortedArrayString allfiles; bool found = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN); while (found) { allfiles.Add(filename); found = dir.GetNext(&filename); } // create an array of candidate .rule files to be created wxSortedArrayString candidates; for (size_t n = 0; n < allfiles.GetCount(); n++) { filename = allfiles[n]; rulename = filename.BeforeLast('.'); bool colorsicons = filename.EndsWith(wxT(".colors")) || filename.EndsWith(wxT(".icons")); bool tabletree = filename.EndsWith(wxT(".table")) || filename.EndsWith(wxT(".tree")); if (colorsicons || tabletree) { depcount++; if (colorsicons) { if (SharedColorsIcons(rulename, allfiles)) { // colors and/or icons will be shared by one or more rulename-*.rule files rulefile = rulename + wxT("-shared.rule"); } else { rulefile = rulename + wxT(".rule"); } } else { // .table/tree file rulefile = rulename + wxT(".rule"); } // add .rule file to candidates if it hasn't been added yet // and if it doesn't already exist if (candidates.Index(rulefile) == wxNOT_FOUND && allfiles.Index(rulefile) == wxNOT_FOUND) { candidates.Add(rulefile); } } } // create the new .rule files for (size_t n = 0; n < candidates.GetCount(); n++) { CreateOneRule(candidates[n], folder, allfiles, htmlinfo); } if (candidates.GetCount() == 0) { htmlinfo += _("None.\n"); } return depcount; } // ----------------------------------------------------------------------------- static void ShowCreatedRules(wxString& htmlinfo) { wxString header = _("Converted Rules\n"); header += _("\n"); htmlinfo = header + htmlinfo; htmlinfo += _("\n"); wxString htmlfile = tempdir + _("converted-rules.html"); wxFile outfile(htmlfile, wxFile::write); if (outfile.IsOpened()) { outfile.Write(htmlinfo); outfile.Close(); ShowHelp(htmlfile); } else { Warning(_("Could not create html file:\n") + htmlfile); } } // ----------------------------------------------------------------------------- static void DeleteOldRules(const wxString& folder) { if (wxFileName::DirExists(folder)) { wxDir dir(folder); if (dir.IsOpened()) { // build an array of all files in the given folder wxArrayString allfiles; wxString filename; bool found = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN); while (found) { allfiles.Add(filename); found = dir.GetNext(&filename); } // delete all the .table/tree/colors/icons files for (size_t n = 0; n < allfiles.GetCount(); n++) { filename = allfiles[n]; if ( filename.EndsWith(wxT(".colors")) || filename.EndsWith(wxT(".icons")) || filename.EndsWith(wxT(".table")) || filename.EndsWith(wxT(".tree")) ) { wxRemoveFile(folder + filename); } } } } } // ----------------------------------------------------------------------------- void MainFrame::ConvertOldRules() { if (inscript || viewptr->waitingforclick) return; if (generating) { // terminate generating loop and set command_pending flag Stop(); command_pending = true; cmdevent.SetId(ID_CONVERT); return; } // look for deprecated .table/tree/colors/icons files and create corresponding .rule files wxString htmlinfo; bool aborted = false; int depcount = 0; // number of deprecated files try { // look in the supplied Rules folder first, then in the user's rules folder depcount += ConvertRules(rulesdir, true, htmlinfo); depcount += ConvertRules(userrules, false, htmlinfo); } catch(const std::exception& e) { // display message set by throw std::runtime_error(...) Warning(wxString(e.what(),wxConvLocal)); aborted = true; // nice to also show error message in help window htmlinfo += _("\n

*** CONVERSION ABORTED DUE TO ERROR ***\n

"); htmlinfo += wxString(e.what(),wxConvLocal); } // display the results in the help window ShowCreatedRules(htmlinfo); if (!aborted && depcount > 0) { // ask user if it's ok to delete all the deprecated files int answer = wxMessageBox(_("Do you want to delete all the old .table/tree/colors/icons files?"), _("Delete deprecated files?"), wxICON_QUESTION | wxYES_NO, wxGetActiveWindow()); if (answer == wxYES) { DeleteOldRules(rulesdir); DeleteOldRules(userrules); } } } // ----------------------------------------------------------------------------- wxString MainFrame::CreateRuleFiles(const wxSortedArrayString& deprecated, const wxSortedArrayString& ziprules) { // use the given list of deprecated .table/tree/colors/icons files // (recently extracted from a .zip file and installed in userrules) // to create new .rule files, except those in ziprules (they were in // the .zip file and have already been installed) wxString htmlinfo; bool aborted = false; try { // create an array of candidate .rule files to be created wxString rulefile, filename, rulename; wxSortedArrayString candidates; for (size_t n = 0; n < deprecated.GetCount(); n++) { filename = deprecated[n]; rulename = filename.BeforeLast('.'); if (filename.EndsWith(wxT(".colors")) || filename.EndsWith(wxT(".icons"))) { if (SharedColorsIcons(rulename, deprecated)) { // colors and/or icons will be shared by one or more rulename-*.rule files rulefile = rulename + wxT("-shared.rule"); } else { rulefile = rulename + wxT(".rule"); } } else { // .table/tree file rulefile = rulename + wxT(".rule"); } // add .rule file to candidates if it hasn't been added yet // and if it isn't in the zip file (ie. already installed) if (candidates.Index(rulefile) == wxNOT_FOUND && ziprules.Index(rulefile) == wxNOT_FOUND) { candidates.Add(rulefile); } } // create the new .rule files (unlike ConvertRules, here we overwrite any // existing .rule files in case the zip file's contents have changed) for (size_t n = 0; n < candidates.GetCount(); n++) { CreateOneRule(candidates[n], userrules, deprecated, htmlinfo); } } catch(const std::exception& e) { // display message set by throw std::runtime_error(...) Warning(wxString(e.what(),wxConvLocal)); aborted = true; // nice to also show error message in help window htmlinfo += _("\n

*** CONVERSION ABORTED DUE TO ERROR ***\n

"); htmlinfo += wxString(e.what(),wxConvLocal); } if (!aborted) { // delete all the deprecated files for (size_t n = 0; n < deprecated.GetCount(); n++) { wxRemoveFile(userrules + deprecated[n]); } } return htmlinfo; } golly-2.7-src/gui-wx/wxprefs.cpp0000644000175000017500000057204712536111364013661 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #if wxUSE_TOOLTIPS #include "wx/tooltip.h" // for wxToolTip #endif #include "wx/stdpaths.h" // for wxStandardPaths #include "wx/filename.h" // for wxFileName #include "wx/propdlg.h" // for wxPropertySheetDialog #include "wx/colordlg.h" // for wxColourDialog #include "wx/bookctrl.h" // for wxBookCtrlBase #include "wx/notebook.h" // for wxNotebookEvent #include "wx/spinctrl.h" // for wxSpinCtrl #include "wx/image.h" // for wxImage #include "lifealgo.h" #include "viewport.h" // for MAX_MAG #include "util.h" // for linereader #include "wxgolly.h" // for wxGetApp, mainptr, viewptr #include "wxmain.h" // for ID_*, mainptr->... #include "wxview.h" // for viewptr->... #include "wxutils.h" // for Warning, Fatal, Beep, FillRect #include "wxhelp.h" // for GetHelpFrame #include "wxinfo.h" // for GetInfoFrame #include "wxalgos.h" // for InitAlgorithms, NumAlgos, algoinfo, etc #include "wxrender.h" // for DrawOneIcon #include "wxlayer.h" // for currlayer, UpdateLayerColors #include "wxscript.h" // for inscript #include "wxprefs.h" // cursor bitmaps #include "bitmaps/pick_curs.xpm" #include "bitmaps/hand_curs.xpm" #include "bitmaps/zoomin_curs.xpm" #include "bitmaps/zoomout_curs.xpm" #ifdef __WXMSW__ #include "bitmaps/cross_curs.xpm" #endif // ----------------------------------------------------------------------------- // Golly's preferences file is a simple text file. It's initially created in // a user-specific data directory (datadir) but we look in the application // directory (gollydir) first because this makes uninstalling simple and allows // multiple copies/versions of the app to have separate preferences. const wxString PREFS_NAME = wxT("GollyPrefs"); wxString prefspath; // full path to prefs file // location of supplied pattern collection (relative to app) const wxString PATT_DIR = wxT("Patterns"); // location of supplied scripts (relative to app) const wxString SCRIPT_DIR = wxT("Scripts"); const int PREFS_VERSION = 4; // increment if necessary due to changes in syntax/semantics int currversion = PREFS_VERSION; // might be changed by prefs_version const int PREF_LINE_SIZE = 5000; // must be quite long for storing file paths // initialize exported preferences: wxString gollydir; // path of directory containing app wxString datadir; // path of directory for user-specific data wxString tempdir; // path of directory for temporary data wxString rulesdir; // path of directory for app's rule data wxString userrules; // path of directory for user's rule data wxString downloaddir; // path of directory for downloaded data int debuglevel = 0; // for displaying debug info if > 0 int mainx = 30; // main window's initial location int mainy = 40; int mainwd = 800; // main window's initial size int mainht = 600; bool maximize = false; // maximize main window? int helpx = 60; // help window's initial location int helpy = 60; int helpwd = 700; // help window's initial size int helpht = 500; #ifdef __WXMAC__ int helpfontsize = 12; // font size in help window #else int helpfontsize = 10; // font size in help window #endif int infox = 90; // info window's initial location int infoy = 90; int infowd = 700; // info window's initial size int infoht = 500; int rulex = 200; // rule dialog's initial location int ruley = 200; int ruleexwd = 500; // rule dialog's initial extra size int ruleexht = 200; bool showalgohelp = false; // show algorithm help in rule dialog? char initrule[256] = "B3/S23"; // initial rule bool initautofit = false; // initial autofit setting bool inithyperspeed = false; // initial hyperspeed setting bool initshowhashinfo = false; // initial showhashinfo setting bool savexrle = true; // save RLE file using XRLE format? bool showtips = true; // show button tips? bool showtool = true; // show tool bar? bool showlayer = false; // show layer bar? bool showedit = true; // show edit bar? bool showallstates = false; // show all cell states in edit bar? bool showstatus = true; // show status bar? bool showexact = false; // show exact numbers in status bar? bool showtimeline = false; // show timeline bar? bool showgridlines = true; // display grid lines? bool showicons = false; // display icons for cell states? bool swapcolors = false; // swap colors used for cell states? bool buffered = true; // use wxWdgets buffering to avoid flicker? bool scrollpencil = true; // scroll if pencil cursor is dragged outside view? bool scrollcross = true; // scroll if cross cursor is dragged outside view? bool scrollhand = true; // scroll if hand cursor is dragged outside view? bool allowundo = true; // allow undo/redo? bool allowbeep = true; // okay to play beep sound? bool restoreview = true; // should reset/undo restore view? int controlspos = 1; // position of translucent controls (1 is top left corner) int canchangerule = 0; // if > 0 then paste can change rule int randomfill = 50; // random fill percentage (1..100) int opacity = 80; // percentage opacity of live cells in overlays (1..100) int tileborder = 3; // thickness of tiled window borders int mingridmag = 2; // minimum mag to draw grid lines int boldspacing = 10; // spacing of bold grid lines bool showboldlines = true; // show bold grid lines? bool mathcoords = false; // show Y values increasing upwards? bool syncviews = false; // synchronize viewports? bool synccursors = true; // synchronize cursors? bool stacklayers = false; // stack all layers? bool tilelayers = false; // tile all layers? bool askonnew = true; // ask to save changes before creating new pattern? bool askonload = true; // ask to save changes before loading pattern file? bool askondelete = true; // ask to save changes before deleting layer? bool askonquit = true; // ask to save changes before quitting app? bool warn_on_save = true; // warn if saving non-starting generation? int newmag = MAX_MAG; // mag setting for new pattern bool newremovesel = true; // new pattern removes selection? bool openremovesel = true; // opening pattern removes selection? wxCursor* newcurs = NULL; // cursor after creating new pattern (if not NULL) wxCursor* opencurs = NULL; // cursor after opening pattern (if not NULL) int mousewheelmode = 2; // 0:Ignore, 1:forward=ZoomOut, 2:forward=ZoomIn int thumbrange = 10; // thumb box scrolling range in terms of view wd/ht int mindelay = 250; // minimum millisec delay int maxdelay = 2000; // maximum millisec delay wxString opensavedir; // directory for Open and Save dialogs wxString rundir; // directory for Run Script dialog wxString icondir; // directory used by Load Icon File button wxString choosedir; // directory used by Choose File button wxString patterndir; // directory used by Show Patterns wxString scriptdir; // directory used by Show Scripts wxString texteditor; // path of user's preferred text editor wxString perllib; // name of Perl library (loaded at runtime) wxString pythonlib; // name of Python library (loaded at runtime) int dirwinwd = 180; // width of directory window bool showpatterns = true; // show pattern directory? bool showscripts = false; // show script directory? wxMenu* patternSubMenu = NULL; // submenu of recent pattern files wxMenu* scriptSubMenu = NULL; // submenu of recent script files int numpatterns = 0; // current number of recent pattern files int numscripts = 0; // current number of recent script files int maxpatterns = 20; // maximum number of recent pattern files (1..MAX_RECENT) int maxscripts = 20; // maximum number of recent script files (1..MAX_RECENT) wxArrayString namedrules; // initialized in GetPrefs wxColor* borderrgb; // color for border around bounded grid wxColor* selectrgb; // color for selected cells wxColor* pastergb; // color for pasted pattern wxBrush* borderbrush; // brush for filling grid border wxPen* pastepen; // for drawing paste rect // these settings must be global -- they are changed by GetPrefs *before* the // view window is created paste_location plocation = TopLeft; paste_mode pmode = Or; // these must be global -- they are created before the view window is created wxCursor* curs_pencil; // for drawing cells wxCursor* curs_pick; // for picking cell states wxCursor* curs_cross; // for selecting cells wxCursor* curs_hand; // for moving view by dragging wxCursor* curs_zoomin; // for zooming in to a clicked cell wxCursor* curs_zoomout; // for zooming out from a clicked cell // local (ie. non-exported) globals: int mingridindex; // mingridmag - 2 int newcursindex; int opencursindex; #if defined(__WXMAC__) && wxCHECK_VERSION(2,9,0) // wxMOD_CONTROL has been changed to mean Command key down (sheesh!) #define wxMOD_CONTROL wxMOD_RAW_CONTROL #define ControlDown RawControlDown #endif // set of modifier keys (note that MSVC didn't like MK_*) const int mk_CMD = 1; // command key on Mac, control key on Win/Linux const int mk_ALT = 2; // option key on Mac const int mk_SHIFT = 4; #ifdef __WXMAC__ const int mk_CTRL = 8; // control key is separate modifier on Mac const int MAX_MODS = 16; #else const int MAX_MODS = 8; #endif // WXK_* key codes like WXK_F1 have values > 300, so to minimize the // size of the keyaction table (see below) we use our own internal // key codes for function keys and other special keys const int IK_HOME = 1; const int IK_END = 2; const int IK_PAGEUP = 3; const int IK_PAGEDOWN = 4; const int IK_HELP = 5; const int IK_INSERT = 6; const int IK_DELETE = 8; // treat delete like backspace (consistent with GSF_dokey) const int IK_TAB = 9; const int IK_RETURN = 13; const int IK_LEFT = 28; const int IK_RIGHT = 29; const int IK_UP = 30; const int IK_DOWN = 31; const int IK_F1 = 'A'; // we use shift+a for the real A, etc const int IK_F24 = 'X'; const int MAX_KEYCODES = 128; // names of the non-displayable keys we currently support; // note that these names can be used in menu item accelerator strings // so they must match legal wx names (listed in wxMenu::Append docs) const char NK_HOME[] = "Home"; const char NK_END[] = "End"; const char NK_PGUP[] = "PgUp"; const char NK_PGDN[] = "PgDn"; const char NK_HELP[] = "Help"; const char NK_INSERT[] = "Insert"; const char NK_DELETE[] = "Delete"; const char NK_TAB[] = "Tab"; #ifdef __WXMSW__ const char NK_RETURN[] = "Enter"; #else const char NK_RETURN[] = "Return"; #endif const char NK_LEFT[] = "Left"; const char NK_RIGHT[] = "Right"; const char NK_UP[] = "Up"; const char NK_DOWN[] = "Down"; const char NK_SPACE[] = "Space"; const action_info nullaction = { DO_NOTHING, wxEmptyString }; // table for converting key combinations into actions action_info keyaction[MAX_KEYCODES][MAX_MODS] = {{ nullaction }}; // strings for setting menu item accelerators wxString accelerator[MAX_ACTIONS]; // ----------------------------------------------------------------------------- bool ConvertKeyAndModifiers(int wxkey, int wxmods, int* newkey, int* newmods) { // first convert given wx modifiers (set by wxKeyEvent::GetModifiers) // to a corresponding set of mk_* values int ourmods = 0; if (wxmods & wxMOD_CMD) ourmods |= mk_CMD; if (wxmods & wxMOD_ALT) ourmods |= mk_ALT; if (wxmods & wxMOD_SHIFT) ourmods |= mk_SHIFT; #ifdef __WXMAC__ if (wxmods & wxMOD_CONTROL) ourmods |= mk_CTRL; #endif // now convert given wx key code to corresponding IK_* code int ourkey; if (wxkey >= 'A' && wxkey <= 'Z') { // convert A..Z to shift+a..shift+z so we can use A..X // for our internal function keys (IK_F1 to IK_F24) ourkey = wxkey + 32; ourmods |= mk_SHIFT; } else if (wxkey >= WXK_F1 && wxkey <= WXK_F24) { // convert wx function key code to IK_F1..IK_F24 ourkey = IK_F1 + (wxkey - WXK_F1); } else if (wxkey >= WXK_NUMPAD0 && wxkey <= WXK_NUMPAD9) { // treat numpad digits like ordinary digits ourkey = '0' + (wxkey - WXK_NUMPAD0); } else { switch (wxkey) { case WXK_HOME: ourkey = IK_HOME; break; case WXK_END: ourkey = IK_END; break; case WXK_PAGEUP: ourkey = IK_PAGEUP; break; case WXK_PAGEDOWN: ourkey = IK_PAGEDOWN; break; case WXK_HELP: ourkey = IK_HELP; break; case WXK_INSERT: ourkey = IK_INSERT; break; case WXK_BACK: // treat backspace like delete case WXK_DELETE: ourkey = IK_DELETE; break; case WXK_TAB: ourkey = IK_TAB; break; case WXK_NUMPAD_ENTER: // treat enter like return case WXK_RETURN: ourkey = IK_RETURN; break; case WXK_LEFT: ourkey = IK_LEFT; break; case WXK_RIGHT: ourkey = IK_RIGHT; break; case WXK_UP: ourkey = IK_UP; break; case WXK_DOWN: ourkey = IK_DOWN; break; case WXK_ADD: ourkey = '+'; break; case WXK_SUBTRACT: ourkey = '-'; break; case WXK_DIVIDE: ourkey = '/'; break; case WXK_MULTIPLY: ourkey = '*'; break; default: ourkey = wxkey; } } if (ourkey < 0 || ourkey >= MAX_KEYCODES) return false; *newkey = ourkey; *newmods = ourmods; return true; } // ----------------------------------------------------------------------------- action_info FindAction(int wxkey, int wxmods) { // convert given wx key code and modifier set to our internal values // and return the corresponding action int ourkey, ourmods; if ( ConvertKeyAndModifiers(wxkey, wxmods, &ourkey, &ourmods) ) { return keyaction[ourkey][ourmods]; } else { return nullaction; } } // ----------------------------------------------------------------------------- void AddDefaultKeyActions() { // these default shortcuts are similar to the hard-wired shortcuts in v1.2 // include some examples of DO_OPENFILE keyaction[(int)'s'][mk_SHIFT].id = DO_OPENFILE; keyaction[(int)'s'][mk_SHIFT].file = wxT("Scripts/Python/shift.py"); keyaction[(int)'l'][mk_ALT].id = DO_OPENFILE; keyaction[(int)'l'][mk_ALT].file = wxT("Help/Lexicon/lex.htm"); // File menu keyaction[(int)'n'][mk_CMD].id = DO_NEWPATT; keyaction[(int)'o'][mk_CMD].id = DO_OPENPATT; keyaction[(int)'o'][mk_SHIFT+mk_CMD].id = DO_OPENCLIP; keyaction[(int)'s'][mk_CMD].id = DO_SAVE; keyaction[(int)'p'][0].id = DO_PATTERNS; keyaction[(int)'p'][mk_CMD].id = DO_PATTERNS; keyaction[(int)'p'][mk_SHIFT].id = DO_SCRIPTS; keyaction[(int)'p'][mk_SHIFT+mk_CMD].id = DO_SCRIPTS; #ifdef __WXMSW__ // Windows does not support ctrl+non-alphanumeric #else keyaction[(int)','][mk_CMD].id = DO_PREFS; #endif keyaction[(int)','][0].id = DO_PREFS; keyaction[(int)'q'][mk_CMD].id = DO_QUIT; // Edit menu keyaction[(int)'z'][0].id = DO_UNDO; keyaction[(int)'z'][mk_CMD].id = DO_UNDO; keyaction[(int)'z'][mk_SHIFT].id = DO_REDO; keyaction[(int)'z'][mk_SHIFT+mk_CMD].id = DO_REDO; keyaction[(int)'x'][mk_CMD].id = DO_CUT; keyaction[(int)'c'][mk_CMD].id = DO_COPY; keyaction[IK_DELETE][0].id = DO_CLEAR; keyaction[IK_DELETE][mk_SHIFT].id = DO_CLEAROUT; keyaction[(int)'v'][0].id = DO_PASTE; keyaction[(int)'v'][mk_CMD].id = DO_PASTE; keyaction[(int)'m'][mk_SHIFT].id = DO_PASTEMODE; keyaction[(int)'l'][mk_SHIFT].id = DO_PASTELOC; keyaction[(int)'a'][0].id = DO_SELALL; keyaction[(int)'a'][mk_CMD].id = DO_SELALL; keyaction[(int)'k'][0].id = DO_REMOVESEL; keyaction[(int)'k'][mk_CMD].id = DO_REMOVESEL; keyaction[(int)'s'][0].id = DO_SHRINKFIT; keyaction[(int)'5'][mk_CMD].id = DO_RANDFILL; keyaction[(int)'y'][0].id = DO_FLIPTB; keyaction[(int)'x'][0].id = DO_FLIPLR; keyaction[(int)'>'][0].id = DO_ROTATECW; keyaction[(int)'<'][0].id = DO_ROTATEACW; keyaction[IK_F1+1][0].id = DO_CURSDRAW; keyaction[IK_F1+2][0].id = DO_CURSPICK; keyaction[IK_F1+3][0].id = DO_CURSSEL; keyaction[IK_F1+4][0].id = DO_CURSMOVE; keyaction[IK_F1+5][0].id = DO_CURSIN; keyaction[IK_F1+6][0].id = DO_CURSOUT; keyaction[(int)'c'][0].id = DO_CURSCYCLE; // Control menu keyaction[IK_RETURN][0].id = DO_STARTSTOP; keyaction[(int)' '][0].id = DO_NEXTGEN; keyaction[IK_TAB][0].id = DO_NEXTSTEP; keyaction[(int)'r'][mk_CMD].id = DO_RESET; keyaction[(int)'+'][0].id = DO_FASTER; keyaction[(int)'+'][mk_SHIFT].id = DO_FASTER; keyaction[(int)'='][0].id = DO_FASTER; keyaction[(int)'_'][0].id = DO_SLOWER; keyaction[(int)'_'][mk_SHIFT].id = DO_SLOWER; keyaction[(int)'-'][0].id = DO_SLOWER; keyaction[(int)'t'][0].id = DO_AUTOFIT; keyaction[(int)'t'][mk_CMD].id = DO_AUTOFIT; keyaction[(int)'u'][mk_CMD].id = DO_HASHING; #ifdef __WXMAC__ keyaction[(int)' '][mk_CTRL].id = DO_ADVANCE; #else // on Windows/Linux mk_CMD is control key keyaction[(int)' '][mk_CMD].id = DO_ADVANCE; #endif keyaction[(int)' '][mk_SHIFT].id = DO_ADVANCEOUT; keyaction[(int)'t'][mk_SHIFT].id = DO_TIMING; // View menu keyaction[IK_LEFT][0].id = DO_LEFT; keyaction[IK_RIGHT][0].id = DO_RIGHT; keyaction[IK_UP][0].id = DO_UP; keyaction[IK_DOWN][0].id = DO_DOWN; keyaction[IK_F1+10][0].id = DO_FULLSCREEN; keyaction[(int)'f'][0].id = DO_FIT; keyaction[(int)'f'][mk_CMD].id = DO_FIT; keyaction[(int)'f'][mk_SHIFT].id = DO_FITSEL; keyaction[(int)'f'][mk_SHIFT+mk_CMD].id = DO_FITSEL; keyaction[(int)'m'][0].id = DO_MIDDLE; keyaction[(int)'m'][mk_CMD].id = DO_MIDDLE; keyaction[(int)'0'][0].id = DO_CHANGE00; keyaction[(int)'9'][0].id = DO_RESTORE00; keyaction[(int)'9'][mk_CMD].id = DO_RESTORE00; keyaction[(int)']'][0].id = DO_ZOOMIN; keyaction[(int)'['][0].id = DO_ZOOMOUT; #ifdef __WXMSW__ // Windows does not support ctrl+non-alphanumeric #else keyaction[(int)']'][mk_CMD].id = DO_ZOOMIN; keyaction[(int)'['][mk_CMD].id = DO_ZOOMOUT; #endif keyaction[(int)'1'][0].id = DO_SCALE1; keyaction[(int)'2'][0].id = DO_SCALE2; keyaction[(int)'4'][0].id = DO_SCALE4; keyaction[(int)'8'][0].id = DO_SCALE8; keyaction[(int)'6'][0].id = DO_SCALE16; keyaction[(int)'3'][0].id = DO_SCALE32; keyaction[(int)'\''][0].id = DO_SHOWTOOL; keyaction[(int)'\\'][0].id = DO_SHOWLAYER; keyaction[(int)'/'][0].id = DO_SHOWEDIT; keyaction[(int)'.'][0].id = DO_SHOWSTATES; keyaction[(int)';'][0].id = DO_SHOWSTATUS; #ifdef __WXMSW__ // Windows does not support ctrl+non-alphanumeric #else keyaction[(int)'\''][mk_CMD].id = DO_SHOWTOOL; keyaction[(int)'\\'][mk_CMD].id = DO_SHOWLAYER; keyaction[(int)'/'][mk_CMD].id = DO_SHOWEDIT; keyaction[(int)'.'][mk_CMD].id = DO_SHOWSTATES; keyaction[(int)';'][mk_CMD].id = DO_SHOWSTATUS; #endif keyaction[(int)'e'][0].id = DO_SHOWEXACT; keyaction[(int)'e'][mk_CMD].id = DO_SHOWEXACT; keyaction[(int)'l'][0].id = DO_SHOWGRID; keyaction[(int)'l'][mk_CMD].id = DO_SHOWGRID; keyaction[(int)'b'][0].id = DO_INVERT; keyaction[(int)'b'][mk_CMD].id = DO_INVERT; keyaction[(int)'i'][0].id = DO_INFO; keyaction[(int)'i'][mk_CMD].id = DO_INFO; // Layer menu // none // Help menu keyaction[(int)'h'][0].id = DO_HELP; keyaction[(int)'?'][0].id = DO_HELP; keyaction[IK_HELP][0].id = DO_HELP; #ifdef __WXMAC__ // cmd-? is the usual shortcut in Mac apps keyaction[(int)'?'][mk_CMD].id = DO_HELP; // we can only detect shift+cmd+/ so we have to assume '?' is above '/' -- yuk keyaction[(int)'/'][mk_SHIFT+mk_CMD].id = DO_HELP; #else // F1 is the usual shortcut in Win/Linux apps keyaction[IK_F1][0].id = DO_HELP; #endif } // ----------------------------------------------------------------------------- const char* GetActionName(action_id action) { switch (action) { case DO_NOTHING: return "NONE"; case DO_OPENFILE: return "Open:"; // File menu case DO_NEWPATT: return "New Pattern"; case DO_OPENPATT: return "Open Pattern..."; case DO_OPENCLIP: return "Open Clipboard"; case DO_PATTERNS: return "Show Patterns"; case DO_PATTDIR: return "Set Pattern Folder..."; case DO_SAVE: return "Save Pattern..."; case DO_SAVEXRLE: return "Save Extended RLE"; case DO_RUNSCRIPT: return "Run Script..."; case DO_RUNCLIP: return "Run Clipboard"; case DO_SCRIPTS: return "Show Scripts"; case DO_SCRIPTDIR: return "Set Script Folder..."; case DO_PREFS: return "Preferences..."; case DO_QUIT: return "Quit Golly"; // Edit menu case DO_UNDO: return "Undo"; case DO_REDO: return "Redo"; case DO_DISABLE: return "Disable Undo/Redo"; case DO_CUT: return "Cut Selection"; case DO_COPY: return "Copy Selection"; case DO_CLEAR: return "Clear Selection"; case DO_CLEAROUT: return "Clear Outside"; case DO_PASTE: return "Paste"; case DO_PASTEMODE: return "Cycle Paste Mode"; case DO_PASTELOC: return "Cycle Paste Location"; case DO_PASTESEL: return "Paste to Selection"; case DO_SELALL: return "Select All"; case DO_REMOVESEL: return "Remove Selection"; case DO_SHRINK: return "Shrink Selection"; case DO_SHRINKFIT: return "Shrink and Fit"; case DO_RANDFILL: return "Random Fill"; case DO_FLIPTB: return "Flip Top-Bottom"; case DO_FLIPLR: return "Flip Left-Right"; case DO_ROTATECW: return "Rotate Clockwise"; case DO_ROTATEACW: return "Rotate Anticlockwise"; case DO_CURSDRAW: return "Cursor Mode: Draw"; case DO_CURSPICK: return "Cursor Mode: Pick"; case DO_CURSSEL: return "Cursor Mode: Select"; case DO_CURSMOVE: return "Cursor Mode: Move"; case DO_CURSIN: return "Cursor Mode: Zoom In"; case DO_CURSOUT: return "Cursor Mode: Zoom Out"; case DO_CURSCYCLE: return "Cycle Cursor Mode"; // Control menu case DO_STARTSTOP: return "Start/Stop Generating"; case DO_NEXTGEN: return "Next Generation"; case DO_NEXTSTEP: return "Next Step"; case DO_NEXTHIGHER: return "Next Higher State"; case DO_NEXTLOWER: return "Next Lower State"; case DO_RESET: return "Reset"; case DO_SETGEN: return "Set Generation..."; case DO_FASTER: return "Faster"; case DO_SLOWER: return "Slower"; case DO_SETBASE: return "Set Base Step..."; case DO_AUTOFIT: return "Auto Fit"; case DO_HASHING: return "Use Hashing"; case DO_HYPER: return "Hyperspeed"; case DO_HASHINFO: return "Show Hash Info"; case DO_RECORD: return "Start/Stop Recording"; case DO_DELTIME: return "Delete Timeline"; case DO_PLAYBACK: return "Play Timeline Backwards"; case DO_SETRULE: return "Set Rule..."; case DO_ADVANCE: return "Advance Selection"; case DO_ADVANCEOUT: return "Advance Outside"; case DO_TIMING: return "Show Timing"; // View menu case DO_LEFT: return "Scroll Left"; case DO_RIGHT: return "Scroll Right"; case DO_UP: return "Scroll Up"; case DO_DOWN: return "Scroll Down"; case DO_NE: return "Scroll NE"; case DO_NW: return "Scroll NW"; case DO_SE: return "Scroll SE"; case DO_SW: return "Scroll SW"; case DO_FULLSCREEN: return "Full Screen"; case DO_FIT: return "Fit Pattern"; case DO_FITSEL: return "Fit Selection"; case DO_MIDDLE: return "Middle"; case DO_CHANGE00: return "Change Origin"; case DO_RESTORE00: return "Restore Origin"; case DO_ZOOMIN: return "Zoom In"; case DO_ZOOMOUT: return "Zoom Out"; case DO_SCALE1: return "Set Scale 1:1"; case DO_SCALE2: return "Set Scale 1:2"; case DO_SCALE4: return "Set Scale 1:4"; case DO_SCALE8: return "Set Scale 1:8"; case DO_SCALE16: return "Set Scale 1:16"; case DO_SCALE32: return "Set Scale 1:32"; case DO_SHOWTOOL: return "Show Tool Bar"; case DO_SHOWLAYER: return "Show Layer Bar"; case DO_SHOWEDIT: return "Show Edit Bar"; case DO_SHOWSTATES: return "Show All States"; case DO_SHOWSTATUS: return "Show Status Bar"; case DO_SHOWEXACT: return "Show Exact Numbers"; case DO_SETCOLORS: return "Set Layer Colors..."; case DO_SHOWICONS: return "Show Cell Icons"; case DO_INVERT: return "Invert Colors"; case DO_SHOWGRID: return "Show Grid Lines"; case DO_BUFFERED: return "Buffered"; case DO_SHOWTIME: return "Show Timeline"; case DO_INFO: return "Pattern Info"; // Layer menu case DO_ADD: return "Add Layer"; case DO_CLONE: return "Clone Layer"; case DO_DUPLICATE: return "Duplicate Layer"; case DO_DELETE: return "Delete Layer"; case DO_DELOTHERS: return "Delete Other Layers"; case DO_MOVELAYER: return "Move Layer..."; case DO_NAMELAYER: return "Name Layer..."; case DO_SYNCVIEWS: return "Synchronize Views"; case DO_SYNCCURS: return "Synchronize Cursors"; case DO_STACK: return "Stack Layers"; case DO_TILE: return "Tile Layers"; // Help menu case DO_HELP: return "Show Help"; case DO_ABOUT: return "About Golly"; default: Warning(_("Bug detected in GetActionName!")); } return "BUG"; } // ----------------------------------------------------------------------------- // for case-insensitive string comparison #ifdef __WXMSW__ #define ISTRCMP stricmp #else #define ISTRCMP strcasecmp #endif void GetKeyAction(char* value) { // parse strings like "z undo" or "space+ctrl advance selection"; // note that some errors detected here can be Fatal because the user // has to quit Golly anyway to edit the prefs file char* start = value; char* p = start; int modset = 0; int key = -1; // extract key, skipping first char in case it's '+' if (*p > 0) p++; while (1) { if (*p == 0) { Fatal(wxString::Format(_("Bad key_action value: %s"), wxString(value,wxConvLocal).c_str())); } if (*p == ' ' || *p == '+') { // we found end of key char oldp = *p; *p = 0; int len = (int)strlen(start); if (len == 1) { key = start[0]; if (key < ' ' || key > '~') { // this can happen if the user's language setting is not English, // so change key and continue rather than call Fatal Warning(wxString::Format(_("Non-displayable key in key_action: %s"), wxString(start,wxConvLocal).c_str())); key = '!'; } if (key >= 'A' && key <= 'Z') { // convert A..Z to shift+a..shift+z so we can use A..X // for our internal function keys (IK_F1 to IK_F24) key += 32; modset |= mk_SHIFT; } } else if (len > 1) { if ((start[0] == 'f' || start[0] == 'F') && start[1] >= '1' && start[1] <= '9') { // we have a function key char* p = &start[1]; int num; sscanf(p, "%d", &num); if (num >= 1 && num <= 24) key = IK_F1 + num - 1; } else { if (ISTRCMP(start, NK_HOME) == 0) key = IK_HOME; else if (ISTRCMP(start, NK_END) == 0) key = IK_END; else if (ISTRCMP(start, NK_PGUP) == 0) key = IK_PAGEUP; else if (ISTRCMP(start, NK_PGDN) == 0) key = IK_PAGEDOWN; else if (ISTRCMP(start, NK_HELP) == 0) key = IK_HELP; else if (ISTRCMP(start, NK_INSERT) == 0) key = IK_INSERT; else if (ISTRCMP(start, NK_DELETE) == 0) key = IK_DELETE; else if (ISTRCMP(start, NK_TAB) == 0) key = IK_TAB; else if (ISTRCMP(start, NK_RETURN) == 0) key = IK_RETURN; else if (ISTRCMP(start, NK_LEFT) == 0) key = IK_LEFT; else if (ISTRCMP(start, NK_RIGHT) == 0) key = IK_RIGHT; else if (ISTRCMP(start, NK_UP) == 0) key = IK_UP; else if (ISTRCMP(start, NK_DOWN) == 0) key = IK_DOWN; else if (ISTRCMP(start, NK_SPACE) == 0) key = ' '; } if (key < 0) Fatal(wxString::Format(_("Unknown key in key_action: %s"), wxString(start,wxConvLocal).c_str())); } *p = oldp; // restore ' ' or '+' start = p; start++; break; } p++; } // *p is ' ' or '+' so extract zero or more modifiers while (*p != ' ') { p++; if (*p == 0) { Fatal(wxString::Format(_("No action in key_action value: %s"), wxString(value,wxConvLocal).c_str())); } if (*p == ' ' || *p == '+') { // we found end of modifier char oldp = *p; *p = 0; #ifdef __WXMAC__ if (ISTRCMP(start, "cmd") == 0) modset |= mk_CMD; else if (ISTRCMP(start, "opt") == 0) modset |= mk_ALT; else if (ISTRCMP(start, "ctrl") == 0) modset |= mk_CTRL; #else if (ISTRCMP(start, "ctrl") == 0) modset |= mk_CMD; else if (ISTRCMP(start, "alt") == 0) modset |= mk_ALT; #endif else if (ISTRCMP(start, "shift") == 0) modset |= mk_SHIFT; else Fatal(wxString::Format(_("Unknown modifier in key_action: %s"), wxString(start,wxConvLocal).c_str())); *p = oldp; // restore ' ' or '+' start = p; start++; } } // *p is ' ' so skip and check the action string p++; action_info action = nullaction; // first look for "Open:" followed by file path if (strncmp(p, "Open:", 5) == 0) { action.id = DO_OPENFILE; action.file = wxString(&p[5], wxConvLocal); } else { // assume DO_NOTHING is 0 and start with action 1 for (int i = 1; i < MAX_ACTIONS; i++) { if (strcmp(p, GetActionName((action_id) i)) == 0) { action.id = (action_id) i; break; } } } // test for some deprecated actions if (action.id == DO_NOTHING) { if (strcmp(p, "Swap Cell Colors") == 0) action.id = DO_INVERT; } keyaction[key][modset] = action; } // ----------------------------------------------------------------------------- wxString GetKeyCombo(int key, int modset) { // build a key combo string for display in prefs dialog and help window wxString result = wxEmptyString; #ifdef __WXMAC__ if (mk_ALT & modset) result += wxT("Option-"); if (mk_SHIFT & modset) result += wxT("Shift-"); if (mk_CTRL & modset) result += wxT("Control-"); if (mk_CMD & modset) result += wxT("Command-"); #else if (mk_ALT & modset) result += wxT("Alt+"); if (mk_SHIFT & modset) result += wxT("Shift+"); if (mk_CMD & modset) result += wxT("Control+"); #endif if (key >= IK_F1 && key <= IK_F24) { // function key result += wxString::Format(wxT("F%d"), key - IK_F1 + 1); } else if (key >= 'a' && key <= 'z') { // display A..Z rather than a..z result += wxChar(key - 32); } else if (key > ' ' && key <= '~') { // displayable char, but excluding space (that's handled below) result += wxChar(key); } else { // non-displayable char switch (key) { // these strings can be more descriptive than the NK_* strings case IK_HOME: result += _("Home"); break; case IK_END: result += _("End"); break; case IK_PAGEUP: result += _("PageUp"); break; case IK_PAGEDOWN: result += _("PageDown"); break; case IK_HELP: result += _("Help"); break; case IK_INSERT: result += _("Insert"); break; case IK_DELETE: result += _("Delete"); break; case IK_TAB: result += _("Tab"); break; #ifdef __WXMSW__ case IK_RETURN: result += _("Enter"); break; #else case IK_RETURN: result += _("Return"); break; #endif case IK_LEFT: result += _("Left"); break; case IK_RIGHT: result += _("Right"); break; case IK_UP: result += _("Up"); break; case IK_DOWN: result += _("Down"); break; case ' ': result += _("Space"); break; default: result = wxEmptyString; } } return result; } // ----------------------------------------------------------------------------- wxString GetShortcutTable() { // return HTML data to display current keyboard shortcuts in help window wxString result; result += _("Golly Help: Keyboard Shortcuts"); result += _(""); result += _("

Keyboard shortcuts"); result += _("

Use Preferences > Keyboard"); result += _(" to change the following keyboard shortcuts:"); result += _("

"); result += _(""); result += _(""); bool assigned[MAX_ACTIONS] = {false}; for (int key = 0; key < MAX_KEYCODES; key++) { for (int modset = 0; modset < MAX_MODS; modset++) { action_info action = keyaction[key][modset]; if ( action.id != DO_NOTHING ) { assigned[action.id] = true; wxString keystring = GetKeyCombo(key, modset); if (key == '<') { keystring.Replace(_("<"), _("<")); } result += _(""); } } } result += _("
Key CombinationAction
"); result += keystring; result += _("  "); result += wxString(GetActionName(action.id), wxConvLocal); if (action.id == DO_OPENFILE) { result += _(" "); result += action.file; } result += _("
"); // also list unassigned actions result += _("

The following actions currently have no keyboard shortcuts:

"); for (int i = 1; i < MAX_ACTIONS; i++) { if (!assigned[i]) { wxString name = wxString(GetActionName((action_id) i),wxConvLocal); result += wxString::Format(_("

%s
"), name.c_str()); } } result += _(""); return result; } // ----------------------------------------------------------------------------- wxString GetModifiers(int modset) { wxString modkeys = wxEmptyString; #ifdef __WXMAC__ if (mk_ALT & modset) modkeys += wxT("+opt"); if (mk_SHIFT & modset) modkeys += wxT("+shift"); if (mk_CTRL & modset) modkeys += wxT("+ctrl"); if (mk_CMD & modset) modkeys += wxT("+cmd"); #else if (mk_ALT & modset) modkeys += wxT("+alt"); if (mk_SHIFT & modset) modkeys += wxT("+shift"); if (mk_CMD & modset) modkeys += wxT("+ctrl"); #endif return modkeys; } // ----------------------------------------------------------------------------- wxString GetKeyName(int key) { wxString result; if (key >= IK_F1 && key <= IK_F24) { // function key result.Printf(wxT("F%d"), key - IK_F1 + 1); } else if (key > ' ' && key <= '~') { // displayable char, but excluding space (that's handled below) result = wxChar(key); } else { // non-displayable char switch (key) { case IK_HOME: result = wxString(NK_HOME, wxConvLocal); break; case IK_END: result = wxString(NK_END, wxConvLocal); break; case IK_PAGEUP: result = wxString(NK_PGUP, wxConvLocal); break; case IK_PAGEDOWN: result = wxString(NK_PGDN, wxConvLocal); break; case IK_HELP: result = wxString(NK_HELP, wxConvLocal); break; case IK_INSERT: result = wxString(NK_INSERT, wxConvLocal); break; case IK_DELETE: result = wxString(NK_DELETE, wxConvLocal); break; case IK_TAB: result = wxString(NK_TAB, wxConvLocal); break; case IK_RETURN: result = wxString(NK_RETURN, wxConvLocal); break; case IK_LEFT: result = wxString(NK_LEFT, wxConvLocal); break; case IK_RIGHT: result = wxString(NK_RIGHT, wxConvLocal); break; case IK_UP: result = wxString(NK_UP, wxConvLocal); break; case IK_DOWN: result = wxString(NK_DOWN, wxConvLocal); break; case ' ': result = wxString(NK_SPACE, wxConvLocal); break; default: result = wxEmptyString; } } return result; } // ----------------------------------------------------------------------------- void SaveKeyActions(FILE* f) { bool assigned[MAX_ACTIONS] = {false}; fputs("\n", f); for (int key = 0; key < MAX_KEYCODES; key++) { for (int modset = 0; modset < MAX_MODS; modset++) { action_info action = keyaction[key][modset]; if ( action.id != DO_NOTHING ) { assigned[action.id] = true; fprintf(f, "key_action=%s%s %s%s\n", (const char*) GetKeyName(key).mb_str(wxConvLocal), (const char*) GetModifiers(modset).mb_str(wxConvLocal), GetActionName(action.id), (const char*) action.file.mb_str(wxConvLocal)); } } } // list all unassigned actions in comment lines fputs("# unassigned actions:\n", f); for (int i = 1; i < MAX_ACTIONS; i++) { if ( !assigned[i] ) { fprintf(f, "# key_action=key+mods %s", GetActionName((action_id) i)); if ( i == DO_OPENFILE ) fputs("file", f); fputs("\n", f); } } fputs("\n", f); } // ----------------------------------------------------------------------------- void CreateAccelerator(action_id action, int modset, int key) { accelerator[action] = wxT("\t"); #ifdef __WXMAC__ if (modset & mk_CTRL) accelerator[action] += wxT("RawCtrl+"); #endif if (modset & mk_CMD) accelerator[action] += wxT("Ctrl+"); if (modset & mk_ALT) accelerator[action] += wxT("Alt+"); if (modset & mk_SHIFT) accelerator[action] += wxT("Shift+"); if (key >= 'a' && key <= 'z') { // convert a..z to A..Z accelerator[action] += wxChar(key - 32); #ifdef __WXMAC__ } else if (key == IK_DELETE) { // must use "Back" to get correct symbol (<+ rather than +>) accelerator[action] += wxT("Back"); #endif } else { accelerator[action] += GetKeyName(key); } } // ----------------------------------------------------------------------------- void UpdateAcceleratorStrings() { for (int i = 0; i < MAX_ACTIONS; i++) accelerator[i] = wxEmptyString; // go thru keyaction table looking for key combos that are valid menu item // accelerators and construct suitable strings like "\tCtrl+Alt+Shift+K" // or "\tF12" or "\tReturn" etc for (int key = 0; key < MAX_KEYCODES; key++) { for (int modset = 0; modset < MAX_MODS; modset++) { action_info info = keyaction[key][modset]; action_id action = info.id; if (action != DO_NOTHING && accelerator[action].IsEmpty()) { // check if key can be used as an accelerator if ((key >= ' ' && key <= '~') || (key >= IK_F1 && key <= IK_F24) || (key >= IK_LEFT && key <= IK_DOWN) || key == IK_HOME || key == IK_END || key == IK_PAGEUP || key == IK_PAGEDOWN || key == IK_DELETE || key == IK_TAB || key == IK_RETURN ) { CreateAccelerator(action, modset, key); } } } } // go thru keyaction table again looking only for key combos containing Ctrl; // we do this so that the Paste menu item will have the standard Ctrl+V // shortcut rather than a plain V if both those shortcuts are assigned for (int key = 0; key < MAX_KEYCODES; key++) { for (int modset = 0; modset < MAX_MODS; modset++) { action_info info = keyaction[key][modset]; action_id action = info.id; if (action != DO_NOTHING && (modset & mk_CMD)) { CreateAccelerator(action, modset, key); } } } } // ----------------------------------------------------------------------------- wxString GetAccelerator(action_id action) { return accelerator[action]; } // ----------------------------------------------------------------------------- // some method names have changed in wx 2.9 #if wxCHECK_VERSION(2,9,0) #define GetLabelFromText GetLabelText #endif void RemoveAccelerator(wxMenuBar* mbar, int item, action_id action) { if (!accelerator[action].IsEmpty()) { // remove accelerator from given menu item mbar->SetLabel(item, wxMenuItem::GetLabelFromText(mbar->GetLabel(item))); } } // ----------------------------------------------------------------------------- void SetAccelerator(wxMenuBar* mbar, int item, action_id action) { wxString accel = accelerator[action]; if (inscript) { // RunScript has called mainptr->UpdateMenuAccelerators() // so remove accelerator from menu item to allow keyboard shortcuts // to be passed to script if (accel.IsEmpty()) return; if (action == DO_STARTSTOP) { // don't remove Escape from "Stop Script" menu item return; } else { accel = wxEmptyString; } } else if (viewptr->waitingforclick) { // PatternView::PasteTemporaryToCurrent has called mainptr->UpdateMenuAccelerators() // so remove accelerator to allow keyboard shortcuts while waiting for paste click if (accel.IsEmpty()) return; accel = wxEmptyString; } // we need to remove old accelerator string from GetLabel text mbar->SetLabel(item, wxMenuItem::GetLabelFromText(mbar->GetLabel(item)) + accel); } // ----------------------------------------------------------------------------- void CreateCursors() { curs_pencil = new wxCursor(wxCURSOR_PENCIL); if (curs_pencil == NULL) Fatal(_("Failed to create pencil cursor!")); wxBitmap bitmap_pick = XPM_BITMAP(pick_curs); wxImage image_pick = bitmap_pick.ConvertToImage(); image_pick.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 0); image_pick.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 15); curs_pick = new wxCursor(image_pick); if (curs_pick == NULL) Fatal(_("Failed to create pick cursor!")); #ifdef __WXMSW__ // don't use wxCURSOR_CROSS because it disappears on black background wxBitmap bitmap_cross = XPM_BITMAP(cross_curs); wxImage image_cross = bitmap_cross.ConvertToImage(); image_cross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 8); image_cross.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 8); curs_cross = new wxCursor(image_cross); #else curs_cross = new wxCursor(wxCURSOR_CROSS); #endif if (curs_cross == NULL) Fatal(_("Failed to create cross cursor!")); wxBitmap bitmap_hand = XPM_BITMAP(hand_curs); wxImage image_hand = bitmap_hand.ConvertToImage(); image_hand.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 8); image_hand.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 8); curs_hand = new wxCursor(image_hand); if (curs_hand == NULL) Fatal(_("Failed to create hand cursor!")); wxBitmap bitmap_zoomin = XPM_BITMAP(zoomin_curs); wxImage image_zoomin = bitmap_zoomin.ConvertToImage(); image_zoomin.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 6); image_zoomin.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 6); curs_zoomin = new wxCursor(image_zoomin); if (curs_zoomin == NULL) Fatal(_("Failed to create zoomin cursor!")); wxBitmap bitmap_zoomout = XPM_BITMAP(zoomout_curs); wxImage image_zoomout = bitmap_zoomout.ConvertToImage(); image_zoomout.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, 6); image_zoomout.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, 6); curs_zoomout = new wxCursor(image_zoomout); if (curs_zoomout == NULL) Fatal(_("Failed to create zoomout cursor!")); // default cursors for new pattern or after opening pattern newcurs = curs_pencil; opencurs = curs_zoomin; } // ----------------------------------------------------------------------------- void FreeCursors() { delete curs_pencil; delete curs_pick; delete curs_cross; delete curs_hand; delete curs_zoomin; delete curs_zoomout; } // ----------------------------------------------------------------------------- const char* CursorToString(wxCursor* curs) { if (curs == curs_pencil) return "Draw"; if (curs == curs_pick) return "Pick"; if (curs == curs_cross) return "Select"; if (curs == curs_hand) return "Move"; if (curs == curs_zoomin) return "Zoom In"; if (curs == curs_zoomout) return "Zoom Out"; return "No Change"; // curs is NULL } // ----------------------------------------------------------------------------- wxCursor* StringToCursor(const char* s) { if (strcmp(s, "Draw") == 0) return curs_pencil; if (strcmp(s, "Pick") == 0) return curs_pick; if (strcmp(s, "Select") == 0) return curs_cross; if (strcmp(s, "Move") == 0) return curs_hand; if (strcmp(s, "Zoom In") == 0) return curs_zoomin; if (strcmp(s, "Zoom Out") == 0) return curs_zoomout; return NULL; // "No Change" } // ----------------------------------------------------------------------------- int CursorToIndex(wxCursor* curs) { if (curs == curs_pencil) return 0; if (curs == curs_pick) return 1; if (curs == curs_cross) return 2; if (curs == curs_hand) return 3; if (curs == curs_zoomin) return 4; if (curs == curs_zoomout) return 5; return 6; // curs is NULL } // ----------------------------------------------------------------------------- wxCursor* IndexToCursor(int i) { if (i == 0) return curs_pencil; if (i == 1) return curs_pick; if (i == 2) return curs_cross; if (i == 3) return curs_hand; if (i == 4) return curs_zoomin; if (i == 5) return curs_zoomout; return NULL; // "No Change" } // ----------------------------------------------------------------------------- // following routines cannot be PatternView methods -- they are called by // GetPrefs() before the view window is created const char* GetPasteLocation() { switch (plocation) { case TopLeft: return "TopLeft"; case TopRight: return "TopRight"; case BottomRight: return "BottomRight"; case BottomLeft: return "BottomLeft"; case Middle: return "Middle"; default: return "unknown"; } } // ----------------------------------------------------------------------------- void SetPasteLocation(const char* s) { if (strcmp(s, "TopLeft") == 0) { plocation = TopLeft; } else if (strcmp(s, "TopRight") == 0) { plocation = TopRight; } else if (strcmp(s, "BottomRight") == 0) { plocation = BottomRight; } else if (strcmp(s, "BottomLeft") == 0) { plocation = BottomLeft; } else { plocation = Middle; } } // ----------------------------------------------------------------------------- const char* GetPasteMode() { switch (pmode) { case And: return "And"; case Copy: return "Copy"; case Or: return "Or"; case Xor: return "Xor"; default: return "unknown"; } } // ----------------------------------------------------------------------------- void SetPasteMode(const char* s) { if (strcmp(s, "And") == 0) { pmode = And; } else if (strcmp(s, "Copy") == 0) { pmode = Copy; } else if (strcmp(s, "Or") == 0) { pmode = Or; } else { pmode = Xor; } } // ----------------------------------------------------------------------------- void SetBrushesAndPens() { for (int i = 0; i < NumAlgos(); i++) { algoinfo[i]->statusbrush->SetColour(algoinfo[i]->statusrgb); } borderbrush->SetColour(*borderrgb); pastepen->SetColour(*pastergb); } // ----------------------------------------------------------------------------- void CreateDefaultColors() { borderrgb = new wxColor(128, 128, 128); // 50% gray selectrgb = new wxColor( 75, 175, 0); // dark green (will be 50% transparent) pastergb = new wxColor(255, 0, 0); // red borderbrush = new wxBrush(*wxBLACK); pastepen = new wxPen(*wxBLACK); // set their default colors (in case prefs file doesn't exist) SetBrushesAndPens(); } // ----------------------------------------------------------------------------- void FreeDefaultColors() { delete borderrgb; delete selectrgb; delete pastergb; delete borderbrush; delete pastepen; } // ----------------------------------------------------------------------------- void GetColor(const char* value, wxColor* rgb) { unsigned int r, g, b; sscanf(value, "%u,%u,%u", &r, &g, &b); rgb->Set(r, g, b); } // ----------------------------------------------------------------------------- void SaveColor(FILE* f, const char* name, const wxColor* rgb) { fprintf(f, "%s=%d,%d,%d\n", name, rgb->Red(), rgb->Green(), rgb->Blue()); } // ----------------------------------------------------------------------------- void GetRelPath(const char* value, wxString& path, const wxString& defdir = wxEmptyString, bool isdir = true) { path = wxString(value, wxConvLocal); wxFileName fname(path); if (currversion < 4 && fname.IsAbsolute() && defdir.length() > 0) { // if old version's absolute path ends with defdir then update // path so new version will see correct dir wxString suffix = wxFILE_SEP_PATH + defdir; if (path.EndsWith(suffix)) { path = gollydir + defdir; // nicer if directory path ends with separator if (isdir && path.Last() != wxFILE_SEP_PATH) path += wxFILE_SEP_PATH; return; } } // if path isn't absolute then prepend Golly directory if (!fname.IsAbsolute()) path = gollydir + path; if (defdir.length() > 0) { // if path doesn't exist then reset to default directory if (!wxFileName::DirExists(path)) path = gollydir + defdir; } // nicer if directory path ends with separator if (isdir && path.Last() != wxFILE_SEP_PATH) path += wxFILE_SEP_PATH; } // ----------------------------------------------------------------------------- void SaveRelPath(FILE* f, const char* name, wxString path) { // if given path is inside Golly directory then save as a relative path if (path.StartsWith(gollydir)) { // remove gollydir from start of path path.erase(0, gollydir.length()); } fprintf(f, "%s=%s\n", name, (const char*)path.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- #define STRINGIFY(arg) STR2(arg) #define STR2(arg) #arg const char* GOLLY_VERSION = STRINGIFY(VERSION); void SavePrefs() { if (mainptr == NULL || currlayer == NULL) { // should never happen but play safe return; } #ifdef __WXMAC__ // we need to convert prefspath to decomposed UTF8 so fopen will work FILE* f = fopen(prefspath.fn_str(), "w"); #else FILE* f = fopen(prefspath.mb_str(wxConvLocal), "w"); #endif if (f == NULL) { Warning(_("Could not save preferences file!")); return; } fprintf(f, "# NOTE: If you edit this file then do so when Golly isn't running\n"); fprintf(f, "# otherwise all your changes will be clobbered when Golly quits.\n\n"); fprintf(f, "prefs_version=%d\n", PREFS_VERSION); fprintf(f, "golly_version=%s\n", GOLLY_VERSION); wxString wxversion = wxVERSION_STRING; fprintf(f, "wx_version=%s\n", (const char*)wxversion.mb_str(wxConvLocal)); #if defined(__WXMAC__) fprintf(f, "platform=Mac\n"); #elif defined(__WXMSW__) fprintf(f, "platform=Windows\n"); #elif defined(__WXGTK__) fprintf(f, "platform=Linux\n"); #else fprintf(f, "platform=unknown\n"); #endif fprintf(f, "debug_level=%d\n", debuglevel); SaveKeyActions(f); // save main window's location and size #ifdef __WXMSW__ if (mainptr->fullscreen || mainptr->IsIconized()) { // use mainx, mainy, mainwd, mainht set by mainptr->ToggleFullScreen() // or by mainptr->OnSize } #else if (mainptr->fullscreen) { // use mainx, mainy, mainwd, mainht set by mainptr->ToggleFullScreen() } #endif else { wxRect r = mainptr->GetRect(); mainx = r.x; mainy = r.y; mainwd = r.width; mainht = r.height; } fprintf(f, "main_window=%d,%d,%d,%d\n", mainx, mainy, mainwd, mainht); fprintf(f, "maximize=%d\n", mainptr->IsMaximized() ? 1 : 0); #ifdef __WXMSW__ if (GetHelpFrame() && !GetHelpFrame()->IsIconized()) #else if (GetHelpFrame()) #endif { wxRect r = GetHelpFrame()->GetRect(); helpx = r.x; helpy = r.y; helpwd = r.width; helpht = r.height; } fprintf(f, "help_window=%d,%d,%d,%d\n", helpx, helpy, helpwd, helpht); fprintf(f, "help_font_size=%d (%d..%d)\n", helpfontsize, minfontsize, maxfontsize); #ifdef __WXMSW__ if (GetInfoFrame() && !GetInfoFrame()->IsIconized()) #else if (GetInfoFrame()) #endif { wxRect r = GetInfoFrame()->GetRect(); infox = r.x; infoy = r.y; infowd = r.width; infoht = r.height; } fprintf(f, "info_window=%d,%d,%d,%d\n", infox, infoy, infowd, infoht); fprintf(f, "rule_dialog=%d,%d,%d,%d\n", rulex, ruley, ruleexwd, ruleexht); fprintf(f, "show_algo_help=%d\n", showalgohelp ? 1 : 0); fprintf(f, "allow_undo=%d\n", allowundo ? 1 : 0); fprintf(f, "allow_beep=%d\n", allowbeep ? 1 : 0); fprintf(f, "restore_view=%d\n", restoreview ? 1 : 0); fprintf(f, "paste_location=%s\n", GetPasteLocation()); fprintf(f, "paste_mode=%s\n", GetPasteMode()); fprintf(f, "scroll_pencil=%d\n", scrollpencil ? 1 : 0); fprintf(f, "scroll_cross=%d\n", scrollcross ? 1 : 0); fprintf(f, "scroll_hand=%d\n", scrollhand ? 1 : 0); fprintf(f, "controls_pos=%d (0..4)\n", controlspos); fprintf(f, "can_change_rule=%d (0..2)\n", canchangerule); fprintf(f, "random_fill=%d (1..100)\n", randomfill); fprintf(f, "min_delay=%d (0..%d millisecs)\n", mindelay, MAX_DELAY); fprintf(f, "max_delay=%d (0..%d millisecs)\n", maxdelay, MAX_DELAY); fprintf(f, "auto_fit=%d\n", currlayer->autofit ? 1 : 0); fprintf(f, "hyperspeed=%d\n", currlayer->hyperspeed ? 1 : 0); fprintf(f, "hash_info=%d\n", currlayer->showhashinfo ? 1 : 0); fputs("\n", f); fprintf(f, "init_algo=%s\n", GetAlgoName(currlayer->algtype)); for (int i = 0; i < NumAlgos(); i++) { fputs("\n", f); fprintf(f, "algorithm=%s\n", GetAlgoName(i)); fprintf(f, "max_mem=%d\n", algoinfo[i]->algomem); fprintf(f, "base_step=%d\n", algoinfo[i]->defbase); SaveColor(f, "status_rgb", &algoinfo[i]->statusrgb); SaveColor(f, "from_rgb", &algoinfo[i]->fromrgb); SaveColor(f, "to_rgb", &algoinfo[i]->torgb); fprintf(f, "use_gradient=%d\n", algoinfo[i]->gradient ? 1 : 0); fputs("colors=", f); for (int state = 0; state < algoinfo[i]->maxstates; state++) { // only write out state,r,g,b tuple if color is different to default if (algoinfo[i]->algor[state] != algoinfo[i]->defr[state] || algoinfo[i]->algog[state] != algoinfo[i]->defg[state] || algoinfo[i]->algob[state] != algoinfo[i]->defb[state] ) { fprintf(f, "%d,%d,%d,%d,", state, algoinfo[i]->algor[state], algoinfo[i]->algog[state], algoinfo[i]->algob[state]); } } fputs("\n", f); } fputs("\n", f); fprintf(f, "rule=%s\n", currlayer->algo->getrule()); if (namedrules.GetCount() > 1) { size_t i; for (i=1; i 0) { fputs("\n", f); int i; for (i = 0; i < numpatterns; i++) { wxMenuItem* item = patternSubMenu->FindItemByPosition(i); if (item) { #if wxCHECK_VERSION(2,9,0) wxString path = item->GetItemLabel(); #else wxString path = item->GetText(); #endif #ifdef __WXGTK__ // remove duplicate underscores path.Replace(wxT("__"), wxT("_")); #endif // remove duplicate ampersands path.Replace(wxT("&&"), wxT("&")); fprintf(f, "recent_pattern=%s\n", (const char*)path.mb_str(wxConvLocal)); } } } if (numscripts > 0) { fputs("\n", f); int i; for (i = 0; i < numscripts; i++) { wxMenuItem* item = scriptSubMenu->FindItemByPosition(i); if (item) { #if wxCHECK_VERSION(2,9,0) wxString path = item->GetItemLabel(); #else wxString path = item->GetText(); #endif #ifdef __WXGTK__ // remove duplicate underscores path.Replace(wxT("__"), wxT("_")); #endif // remove duplicate ampersands path.Replace(wxT("&&"), wxT("&")); fprintf(f, "recent_script=%s\n", (const char*)path.mb_str(wxConvLocal)); } } } fclose(f); } // ----------------------------------------------------------------------------- void AddDefaultRules() { namedrules.Add(wxT("LifeHistory|LifeHistory")); namedrules.Add(wxT("3-4 Life|B34/S34")); namedrules.Add(wxT("HighLife|B36/S23")); namedrules.Add(wxT("AntiLife|B0123478/S01234678")); namedrules.Add(wxT("Life without Death|B3/S012345678")); namedrules.Add(wxT("Plow World|B378/S012345678")); namedrules.Add(wxT("Day and Night|B3678/S34678")); namedrules.Add(wxT("Diamoeba|B35678/S5678")); namedrules.Add(wxT("LongLife|B345/S5")); namedrules.Add(wxT("Seeds|B2")); namedrules.Add(wxT("Persian Rug|B234")); namedrules.Add(wxT("Replicator|B1357/S1357")); namedrules.Add(wxT("Fredkin|B1357/S02468")); namedrules.Add(wxT("Morley|B368/S245")); namedrules.Add(wxT("Wolfram 22|W22")); namedrules.Add(wxT("Wolfram 30|W30")); namedrules.Add(wxT("Wolfram 110|W110")); namedrules.Add(wxT("WireWorld|WireWorld")); namedrules.Add(wxT("JvN29|JvN29")); namedrules.Add(wxT("Nobili32|Nobili32")); namedrules.Add(wxT("Hutton32|Hutton32")); } // ----------------------------------------------------------------------------- bool GetKeywordAndValue(linereader& lr, char* line, char** keyword, char** value) { // the linereader class handles all line endings (CR, CR+LF, LF) // and terminates line buffer with \0 while ( lr.fgets(line, PREF_LINE_SIZE) != 0 ) { if ( line[0] == '#' || line[0] == 0 ) { // skip comment line or empty line } else { // line should have format keyword=value *keyword = line; *value = line; while ( **value != '=' && **value != 0 ) *value += 1; **value = 0; // terminate keyword *value += 1; return true; } } return false; } // ----------------------------------------------------------------------------- void CheckVisibility(int* x, int* y, int* wd, int* ht) { wxRect maxrect = wxGetClientDisplayRect(); // reset x,y if title bar isn't clearly visible if ( *y + 10 < maxrect.y || *y + 10 > maxrect.GetBottom() || *x + 10 > maxrect.GetRight() || *x + *wd - 10 < maxrect.x ) { *x = wxDefaultCoord; *y = wxDefaultCoord; } // reduce wd,ht if too big for screen if (*wd > maxrect.width) *wd = maxrect.width; if (*ht > maxrect.height) *ht = maxrect.height; } // ----------------------------------------------------------------------------- char* ReplaceDeprecatedAlgo(char* algoname) { if (strcmp(algoname, "RuleTable") == 0 || strcmp(algoname, "RuleTree") == 0) { // RuleTable and RuleTree algos have been replaced by RuleLoader return (char*)"RuleLoader"; } else { return algoname; } } // ----------------------------------------------------------------------------- void InitPaths() { #ifdef __WXGTK__ // on Linux we want datadir to be "~/.golly" rather than "~/.Golly" wxGetApp().SetAppName(_("golly")); #endif // init datadir and create the directory if it doesn't exist; // the directory will probably be: // Win: C:\Documents and Settings\username\Application Data\Golly // Mac: ~/Library/Application Support/Golly // Unix: ~/.golly datadir = wxStandardPaths::Get().GetUserDataDir(); if ( !wxFileName::DirExists(datadir) ) { if ( !wxFileName::Mkdir(datadir, 0777, wxPATH_MKDIR_FULL) ) { Warning(_("Could not create a user-specific data directory!\nWill try to use the application directory instead.")); datadir = gollydir; } } if (datadir.Last() != wxFILE_SEP_PATH) datadir += wxFILE_SEP_PATH; // init tempdir to a temporary directory unique to this process tempdir = wxFileName::CreateTempFileName(wxT("golly_")); // on Linux the file is in /tmp; // on my Mac the file is in /private/var/tmp/folders.502/TemporaryItems; // on WinXP the file is in C:\Documents and Settings\Andy\Local Settings\Temp // (or shorter equivalent C:\DOCUME~1\Andy\LOCALS~1\Temp) but the file name // is gol*.tmp (ie. only 1st 3 chars of the prefix are used, and .tmp is added) wxRemoveFile(tempdir); if ( !wxFileName::Mkdir(tempdir, 0777, wxPATH_MKDIR_FULL) ) { Warning(_("Could not create temporary directory:\n") + tempdir); // use standard directory for temp files tempdir = wxStandardPaths::Get().GetTempDir(); if ( !wxFileName::DirExists(tempdir) ) { // should never happen, but play safe Fatal(_("Sorry, temporary directory does not exist:\n") + tempdir); } } if (tempdir.Last() != wxFILE_SEP_PATH) tempdir += wxFILE_SEP_PATH; #ifdef __WXGTK__ // "Golly" is nicer for warning dialogs etc wxGetApp().SetAppName(_("Golly")); #endif // init prefspath -- look in gollydir first, then in datadir prefspath = gollydir + PREFS_NAME; if ( !wxFileExists(prefspath) ) { prefspath = datadir + PREFS_NAME; } } // ----------------------------------------------------------------------------- void CreateMissingFolders() { // create userrules and downloaddir if they don't exist if ( !wxFileName::DirExists(userrules) ) { if ( !wxFileName::Mkdir(userrules, 0777, wxPATH_MKDIR_FULL) ) { Warning(_("Could not create your rules directory:\n") + userrules); } } if ( !wxFileName::DirExists(downloaddir) ) { if ( !wxFileName::Mkdir(downloaddir, 0777, wxPATH_MKDIR_FULL) ) { Warning(_("Could not create your download directory:\n") + downloaddir); } } } // ----------------------------------------------------------------------------- void GetPrefs() { int algoindex = -1; // unknown algorithm bool sawkeyaction = false; // saw at least one key_action entry? MAX_MAG = 5; // maximum cell size = 32x32 InitPaths(); // init datadir, tempdir and prefspath InitAlgorithms(); // init algoinfo data rulesdir = gollydir + wxT("Rules"); rulesdir += wxFILE_SEP_PATH; userrules = datadir + wxT("Rules"); userrules += wxFILE_SEP_PATH; downloaddir = datadir + wxT("Downloads"); downloaddir += wxFILE_SEP_PATH; opensavedir = gollydir + PATT_DIR; rundir = gollydir + SCRIPT_DIR; icondir = gollydir; choosedir = gollydir; patterndir = gollydir + PATT_DIR; scriptdir = gollydir + SCRIPT_DIR; // init the text editor to something reasonable #ifdef __WXMSW__ texteditor = wxT("Notepad"); #elif defined(__WXMAC__) texteditor = wxT("/Applications/TextEdit.app"); #else // assume Linux // don't attempt to guess which editor might be available; // set the string empty so the user is asked to choose their // preferred editor the first time texteditor is used texteditor = wxEmptyString; #endif // init names of Perl and Python libraries #ifdef __WXMSW__ perllib = wxT("perl510.dll"); pythonlib = wxT("python27.dll"); #elif defined(__WXMAC__) // not used (Perl & Python are loaded at link time) perllib = wxEmptyString; pythonlib = wxEmptyString; #else // assume Linux perllib = wxT(STRINGIFY(PERL_SHLIB)); pythonlib = wxT(STRINGIFY(PYTHON_SHLIB)); #endif // create curs_* and initialize newcurs and opencurs CreateCursors(); CreateDefaultColors(); // initialize Open Recent submenu patternSubMenu = new wxMenu(); patternSubMenu->AppendSeparator(); patternSubMenu->Append(ID_CLEAR_MISSING_PATTERNS, _("Clear Missing Files")); patternSubMenu->Append(ID_CLEAR_ALL_PATTERNS, _("Clear All Files")); // initialize Run Recent submenu scriptSubMenu = new wxMenu(); scriptSubMenu->AppendSeparator(); scriptSubMenu->Append(ID_CLEAR_MISSING_SCRIPTS, _("Clear Missing Files")); scriptSubMenu->Append(ID_CLEAR_ALL_SCRIPTS, _("Clear All Files")); namedrules.Add(wxT("Life|B3/S23")); // must be 1st entry if ( !wxFileExists(prefspath) ) { AddDefaultRules(); AddDefaultKeyActions(); UpdateAcceleratorStrings(); CreateMissingFolders(); return; } #ifdef __WXMAC__ // we need to convert prefspath to decomposed UTF8 so fopen will work FILE* f = fopen(prefspath.fn_str(), "r"); #else FILE* f = fopen(prefspath.mb_str(wxConvLocal), "r"); #endif if (f == NULL) { Warning(_("Could not read preferences file!")); return; } linereader reader(f); char line[PREF_LINE_SIZE]; char* keyword; char* value; while ( GetKeywordAndValue(reader, line, &keyword, &value) ) { if (strcmp(keyword, "prefs_version") == 0) { sscanf(value, "%d", &currversion); } else if (strcmp(keyword, "debug_level") == 0) { sscanf(value, "%d", &debuglevel); } else if (strcmp(keyword, "key_action") == 0) { GetKeyAction(value); sawkeyaction = true; } else if (strcmp(keyword, "main_window") == 0) { sscanf(value, "%d,%d,%d,%d", &mainx, &mainy, &mainwd, &mainht); // avoid very small window if (mainwd < minmainwd) mainwd = minmainwd; if (mainht < minmainht) mainht = minmainht; CheckVisibility(&mainx, &mainy, &mainwd, &mainht); } else if (strcmp(keyword, "maximize") == 0) { maximize = value[0] == '1'; } else if (strcmp(keyword, "help_window") == 0) { sscanf(value, "%d,%d,%d,%d", &helpx, &helpy, &helpwd, &helpht); if (helpwd < minhelpwd) helpwd = minhelpwd; if (helpht < minhelpht) helpht = minhelpht; CheckVisibility(&helpx, &helpy, &helpwd, &helpht); } else if (strcmp(keyword, "help_font_size") == 0) { sscanf(value, "%d", &helpfontsize); if (helpfontsize < minfontsize) helpfontsize = minfontsize; if (helpfontsize > maxfontsize) helpfontsize = maxfontsize; } else if (strcmp(keyword, "info_window") == 0) { sscanf(value, "%d,%d,%d,%d", &infox, &infoy, &infowd, &infoht); if (infowd < mininfowd) infowd = mininfowd; if (infoht < mininfoht) infoht = mininfoht; CheckVisibility(&infox, &infoy, &infowd, &infoht); } else if (strcmp(keyword, "rule_dialog") == 0) { sscanf(value, "%d,%d,%d,%d", &rulex, &ruley, &ruleexwd, &ruleexht); if (ruleexwd < 100) ruleexwd = 100; if (ruleexht < 0) ruleexht = 0; CheckVisibility(&rulex, &ruley, &ruleexwd, &ruleexht); } else if (strcmp(keyword, "show_algo_help") == 0) { showalgohelp = value[0] == '1'; } else if (strcmp(keyword, "allow_undo") == 0) { allowundo = value[0] == '1'; } else if (strcmp(keyword, "allow_beep") == 0) { allowbeep = value[0] == '1'; } else if (strcmp(keyword, "restore_view") == 0) { restoreview = value[0] == '1'; } else if (strcmp(keyword, "paste_location") == 0) { SetPasteLocation(value); } else if (strcmp(keyword, "paste_mode") == 0) { SetPasteMode(value); } else if (strcmp(keyword, "scroll_pencil") == 0) { scrollpencil = value[0] == '1'; } else if (strcmp(keyword, "scroll_cross") == 0) { scrollcross = value[0] == '1'; } else if (strcmp(keyword, "scroll_hand") == 0) { scrollhand = value[0] == '1'; } else if (strcmp(keyword, "controls_pos") == 0) { sscanf(value, "%d", &controlspos); if (controlspos < 0) controlspos = 0; if (controlspos > 4) controlspos = 4; } else if (strcmp(keyword, "can_change_rule") == 0) { sscanf(value, "%d", &canchangerule); if (canchangerule < 0) canchangerule = 0; if (canchangerule > 2) canchangerule = 2; } else if (strcmp(keyword, "random_fill") == 0) { sscanf(value, "%d", &randomfill); if (randomfill < 1) randomfill = 1; if (randomfill > 100) randomfill = 100; } else if (strcmp(keyword, "q_base_step") == 0) { // deprecated int base; sscanf(value, "%d", &base); if (base < 2) base = 2; if (base > MAX_BASESTEP) base = MAX_BASESTEP; algoinfo[QLIFE_ALGO]->defbase = base; } else if (strcmp(keyword, "h_base_step") == 0) { // deprecated int base; sscanf(value, "%d", &base); if (base < 2) base = 2; if (base > MAX_BASESTEP) base = MAX_BASESTEP; algoinfo[HLIFE_ALGO]->defbase = base; } else if (strcmp(keyword, "algorithm") == 0) { if (strcmp(value, "RuleTable") == 0) { // use deprecated RuleTable settings for RuleLoader // (deprecated RuleTree settings will simply be ignored) value = (char*)"RuleLoader"; } algoindex = -1; for (int i = 0; i < NumAlgos(); i++) { if (strcmp(value, GetAlgoName(i)) == 0) { algoindex = i; break; } } } else if (strcmp(keyword, "max_mem") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) { int maxmem; sscanf(value, "%d", &maxmem); if (maxmem < MIN_MEM_MB) maxmem = MIN_MEM_MB; if (maxmem > MAX_MEM_MB) maxmem = MAX_MEM_MB; algoinfo[algoindex]->algomem = maxmem; } } else if (strcmp(keyword, "base_step") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) { int base; sscanf(value, "%d", &base); if (base < 2) base = 2; if (base > MAX_BASESTEP) base = MAX_BASESTEP; algoinfo[algoindex]->defbase = base; } } else if (strcmp(keyword, "status_rgb") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) GetColor(value, &algoinfo[algoindex]->statusrgb); } else if (strcmp(keyword, "from_rgb") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) GetColor(value, &algoinfo[algoindex]->fromrgb); } else if (strcmp(keyword, "to_rgb") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) GetColor(value, &algoinfo[algoindex]->torgb); } else if (strcmp(keyword, "use_gradient") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) algoinfo[algoindex]->gradient = value[0] == '1'; } else if (strcmp(keyword, "colors") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) { int state, r, g, b; while (sscanf(value, "%d,%d,%d,%d,", &state, &r, &g, &b) == 4) { if (state >= 0 && state < algoinfo[algoindex]->maxstates) { algoinfo[algoindex]->algor[state] = r; algoinfo[algoindex]->algog[state] = g; algoinfo[algoindex]->algob[state] = b; } while (*value != ',') value++; value++; while (*value != ',') value++; value++; while (*value != ',') value++; value++; while (*value != ',') value++; value++; } } } else if (strcmp(keyword, "min_delay") == 0) { sscanf(value, "%d", &mindelay); if (mindelay < 0) mindelay = 0; if (mindelay > MAX_DELAY) mindelay = MAX_DELAY; } else if (strcmp(keyword, "max_delay") == 0) { sscanf(value, "%d", &maxdelay); if (maxdelay < 0) maxdelay = 0; if (maxdelay > MAX_DELAY) maxdelay = MAX_DELAY; } else if (strcmp(keyword, "auto_fit") == 0) { initautofit = value[0] == '1'; } else if (strcmp(keyword, "hashing") == 0) { // deprecated initalgo = value[0] == '1' ? HLIFE_ALGO : QLIFE_ALGO; } else if (strcmp(keyword, "init_algo") == 0) { value = ReplaceDeprecatedAlgo(value); int i = staticAlgoInfo::nameToIndex(value); if (i >= 0 && i < NumAlgos()) initalgo = i; } else if (strcmp(keyword, "hyperspeed") == 0) { inithyperspeed = value[0] == '1'; } else if (strcmp(keyword, "hash_info") == 0) { initshowhashinfo = value[0] == '1'; } else if (strcmp(keyword, "max_hash_mem") == 0) { // deprecated int maxmem; sscanf(value, "%d", &maxmem); if (maxmem < MIN_MEM_MB) maxmem = MIN_MEM_MB; if (maxmem > MAX_MEM_MB) maxmem = MAX_MEM_MB; // change all except QLIFE_ALGO for (int i = 0; i < NumAlgos(); i++) if (i != QLIFE_ALGO) algoinfo[i]->algomem = maxmem; } else if (strcmp(keyword, "rule") == 0) { strncpy(initrule, value, sizeof(initrule)); } else if (strcmp(keyword, "named_rule") == 0) { // value must have format "name|rule" with name and rule non-empty wxString str(value,wxConvLocal); int barcount = str.Freq('|'); if (barcount == 0) { Fatal(_("Missing \"|\" separator in named_rule entry: ") + str); } else if (barcount > 1) { Fatal(_("Too many \"|\" separators in named_rule entry: ") + str); } else { wxString name = str.BeforeFirst('|'); wxString rule = str.AfterFirst('|'); if (name.IsEmpty()) { Fatal(_("Empty name in named_rule entry: ") + str); } else if (rule.IsEmpty()) { Fatal(_("Empty rule in named_rule entry: ") + str); } else { namedrules.Add(str); } } } else if (strcmp(keyword, "show_tips") == 0) { showtips = value[0] == '1'; } else if (strcmp(keyword, "show_tool") == 0) { showtool = value[0] == '1'; } else if (strcmp(keyword, "show_layer") == 0) { showlayer = value[0] == '1'; } else if (strcmp(keyword, "show_edit") == 0) { showedit = value[0] == '1'; } else if (strcmp(keyword, "show_states") == 0) { showallstates = value[0] == '1'; } else if (strcmp(keyword, "show_status") == 0) { showstatus = value[0] == '1'; } else if (strcmp(keyword, "show_exact") == 0) { showexact = value[0] == '1'; } else if (strcmp(keyword, "show_timeline") == 0) { showtimeline = value[0] == '1'; } else if (strcmp(keyword, "grid_lines") == 0) { showgridlines = value[0] == '1'; } else if (strcmp(keyword, "min_grid_mag") == 0) { sscanf(value, "%d", &mingridmag); if (mingridmag < 2) mingridmag = 2; if (mingridmag > MAX_MAG) mingridmag = MAX_MAG; } else if (strcmp(keyword, "bold_spacing") == 0) { sscanf(value, "%d", &boldspacing); if (boldspacing < 2) boldspacing = 2; if (boldspacing > MAX_SPACING) boldspacing = MAX_SPACING; } else if (strcmp(keyword, "show_bold_lines") == 0) { showboldlines = value[0] == '1'; } else if (strcmp(keyword, "math_coords") == 0) { mathcoords = value[0] == '1'; } else if (strcmp(keyword, "sync_views") == 0) { syncviews = value[0] == '1'; } else if (strcmp(keyword, "sync_cursors") == 0) { synccursors = value[0] == '1'; } else if (strcmp(keyword, "stack_layers") == 0) { stacklayers = value[0] == '1'; } else if (strcmp(keyword, "tile_layers") == 0) { tilelayers = value[0] == '1'; } else if (strcmp(keyword, "tile_border") == 0) { sscanf(value, "%d", &tileborder); if (tileborder < 1) tileborder = 1; if (tileborder > 10) tileborder = 10; } else if (strcmp(keyword, "ask_on_new") == 0) { askonnew = value[0] == '1'; } else if (strcmp(keyword, "ask_on_load") == 0) { askonload = value[0] == '1'; } else if (strcmp(keyword, "ask_on_delete") == 0) { askondelete = value[0] == '1'; } else if (strcmp(keyword, "ask_on_quit") == 0) { askonquit = value[0] == '1'; } else if (strcmp(keyword, "warn_on_save") == 0) { warn_on_save = value[0] == '1'; } else if (strcmp(keyword, "show_icons") == 0) { showicons = value[0] == '1'; } else if (strcmp(keyword, "swap_colors") == 0) { swapcolors = value[0] == '1'; } else if (strcmp(keyword, "opacity") == 0) { sscanf(value, "%d", &opacity); if (opacity < 1) opacity = 1; if (opacity > 100) opacity = 100; } else if (strcmp(keyword, "border_rgb") == 0) { GetColor(value, borderrgb); } else if (strcmp(keyword, "select_rgb") == 0) { GetColor(value, selectrgb); } else if (strcmp(keyword, "paste_rgb") == 0) { GetColor(value, pastergb); } else if (strcmp(keyword, "dead_rgb") == 0) { // use deprecated value to set color of state 0 in all algos // (only done once because dead_rgb is no longer saved in prefs file) wxColor color; GetColor(value, &color); for (int i = 0; i < NumAlgos(); i++) { algoinfo[i]->algor[0] = color.Red(); algoinfo[i]->algog[0] = color.Green(); algoinfo[i]->algob[0] = color.Blue(); } } else if (strcmp(keyword, "qlife_rgb") == 0) { // deprecated GetColor(value, &algoinfo[QLIFE_ALGO]->statusrgb); } else if (strcmp(keyword, "hlife_rgb") == 0) { // deprecated GetColor(value, &algoinfo[HLIFE_ALGO]->statusrgb); } else if (strcmp(keyword, "buffered") == 0) { buffered = value[0] == '1'; } else if (strcmp(keyword, "mouse_wheel_mode") == 0) { sscanf(value, "%d", &mousewheelmode); if (mousewheelmode < 0) mousewheelmode = 0; if (mousewheelmode > 2) mousewheelmode = 2; } else if (strcmp(keyword, "thumb_range") == 0) { sscanf(value, "%d", &thumbrange); if (thumbrange < 2) thumbrange = 2; if (thumbrange > MAX_THUMBRANGE) thumbrange = MAX_THUMBRANGE; } else if (strcmp(keyword, "new_mag") == 0) { sscanf(value, "%d", &newmag); if (newmag < 0) newmag = 0; if (newmag > MAX_MAG) newmag = MAX_MAG; } else if (strcmp(keyword, "new_remove_sel") == 0) { newremovesel = value[0] == '1'; } else if (strcmp(keyword, "new_cursor") == 0) { newcurs = StringToCursor(value); } else if (strcmp(keyword, "open_remove_sel") == 0) { openremovesel = value[0] == '1'; } else if (strcmp(keyword, "open_cursor") == 0) { opencurs = StringToCursor(value); } else if (strcmp(keyword, "save_xrle") == 0) { savexrle = value[0] == '1'; } else if (strcmp(keyword, "open_save_dir") == 0) { GetRelPath(value, opensavedir, PATT_DIR); } else if (strcmp(keyword, "run_dir") == 0) { GetRelPath(value, rundir, SCRIPT_DIR); } else if (strcmp(keyword, "icon_dir") == 0) { GetRelPath(value, icondir); } else if (strcmp(keyword, "choose_dir") == 0) { GetRelPath(value, choosedir); } else if (strcmp(keyword, "pattern_dir") == 0) { GetRelPath(value, patterndir, PATT_DIR); } else if (strcmp(keyword, "script_dir") == 0) { GetRelPath(value, scriptdir, SCRIPT_DIR); } else if (strcmp(keyword, "user_rules") == 0) { GetRelPath(value, userrules); } else if (strcmp(keyword, "download_dir") == 0) { GetRelPath(value, downloaddir); } else if (strcmp(keyword, "text_editor") == 0) { texteditor = wxString(value,wxConvLocal); } else if (strcmp(keyword, "perl_lib") == 0) { perllib = wxString(value,wxConvLocal); } else if (strcmp(keyword, "python_lib") == 0) { pythonlib = wxString(value,wxConvLocal); } else if (strcmp(keyword, "dir_width") == 0) { sscanf(value, "%d", &dirwinwd); if (dirwinwd < MIN_DIRWD) dirwinwd = MIN_DIRWD; } else if (strcmp(keyword, "show_patterns") == 0) { showpatterns = value[0] == '1'; } else if (strcmp(keyword, "show_scripts") == 0) { showscripts = value[0] == '1'; } else if (strcmp(keyword, "max_patterns") == 0) { sscanf(value, "%d", &maxpatterns); if (maxpatterns < 1) maxpatterns = 1; if (maxpatterns > MAX_RECENT) maxpatterns = MAX_RECENT; } else if (strcmp(keyword, "max_scripts") == 0) { sscanf(value, "%d", &maxscripts); if (maxscripts < 1) maxscripts = 1; if (maxscripts > MAX_RECENT) maxscripts = MAX_RECENT; } else if (strcmp(keyword, "recent_pattern") == 0) { // append path to Open Recent submenu if (numpatterns < maxpatterns && value[0]) { numpatterns++; wxString path(value, wxConvLocal); if (currversion < 2 && path.StartsWith(gollydir)) { // remove gollydir from start of path path.erase(0, gollydir.length()); } // duplicate ampersands so they appear in menu path.Replace(wxT("&"), wxT("&&")); patternSubMenu->Insert(numpatterns - 1, ID_OPEN_RECENT + numpatterns, path); } } else if (strcmp(keyword, "recent_script") == 0) { // append path to Run Recent submenu if (numscripts < maxscripts && value[0]) { numscripts++; wxString path(value, wxConvLocal); if (currversion < 2 && path.StartsWith(gollydir)) { // remove gollydir from start of path path.erase(0, gollydir.length()); } // duplicate ampersands so they appear in menu path.Replace(wxT("&"), wxT("&&")); scriptSubMenu->Insert(numscripts - 1, ID_RUN_RECENT + numscripts, path); } } } reader.close(); // colors for brushes and pens may have changed SetBrushesAndPens(); // showpatterns and showscripts must not both be true if (showpatterns && showscripts) showscripts = false; // stacklayers and tilelayers must not both be true if (stacklayers && tilelayers) tilelayers = false; // if no named_rule entries then add default names if (namedrules.GetCount() == 1) AddDefaultRules(); // if no key_action entries then use default shortcuts if (!sawkeyaction) AddDefaultKeyActions(); // initialize accelerator array UpdateAcceleratorStrings(); // create some important directories if they don't exist CreateMissingFolders(); } // ----------------------------------------------------------------------------- // global data used in CellBoxes and PrefsDialog methods: static int coloralgo; // currently selected algorithm in Color pane static int gradstates; // current number of gradient states const int CELLSIZE = 16; // wd and ht of each cell in CellBoxes const int NUMCOLS = 32; // number of columns in CellBoxes const int NUMROWS = 8; // number of rows in CellBoxes // ----------------------------------------------------------------------------- // define a window for displaying cell colors/icons: class CellBoxes : public wxPanel { public: CellBoxes(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size) : wxPanel(parent, id, pos, size) { } wxStaticText* statebox; // for showing state of cell under cursor wxStaticText* rgbbox; // for showing color of cell under cursor private: void GetGradientColor(int state, unsigned char* r, unsigned char* g, unsigned char* b); void OnEraseBackground(wxEraseEvent& event); void OnPaint(wxPaintEvent& event); void OnMouseDown(wxMouseEvent& event); void OnMouseMotion(wxMouseEvent& event); void OnMouseExit(wxMouseEvent& event); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(CellBoxes, wxPanel) EVT_ERASE_BACKGROUND (CellBoxes::OnEraseBackground) EVT_PAINT (CellBoxes::OnPaint) EVT_LEFT_DOWN (CellBoxes::OnMouseDown) EVT_LEFT_DCLICK (CellBoxes::OnMouseDown) EVT_MOTION (CellBoxes::OnMouseMotion) EVT_ENTER_WINDOW (CellBoxes::OnMouseMotion) EVT_LEAVE_WINDOW (CellBoxes::OnMouseExit) END_EVENT_TABLE() // ----------------------------------------------------------------------------- void CellBoxes::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { // do nothing } // ----------------------------------------------------------------------------- void CellBoxes::GetGradientColor(int state, unsigned char* r, unsigned char* g, unsigned char* b) { // calculate gradient color for given state (> 0 and < gradstates) AlgoData* ad = algoinfo[coloralgo]; if (state == 1) { *r = ad->fromrgb.Red(); *g = ad->fromrgb.Green(); *b = ad->fromrgb.Blue(); } else if (state == gradstates - 1) { *r = ad->torgb.Red(); *g = ad->torgb.Green(); *b = ad->torgb.Blue(); } else { unsigned char r1 = ad->fromrgb.Red(); unsigned char g1 = ad->fromrgb.Green(); unsigned char b1 = ad->fromrgb.Blue(); unsigned char r2 = ad->torgb.Red(); unsigned char g2 = ad->torgb.Green(); unsigned char b2 = ad->torgb.Blue(); int N = gradstates - 2; double rfrac = (double)(r2 - r1) / (double)N; double gfrac = (double)(g2 - g1) / (double)N; double bfrac = (double)(b2 - b1) / (double)N; *r = (int)(r1 + (state-1) * rfrac + 0.5); *g = (int)(g1 + (state-1) * gfrac + 0.5); *b = (int)(b1 + (state-1) * bfrac + 0.5); } } // ----------------------------------------------------------------------------- void CellBoxes::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(this); dc.SetPen(*wxBLACK_PEN); #ifdef __WXMSW__ // we have to use theme background color on Windows wxBrush bgbrush(GetBackgroundColour()); #else wxBrush bgbrush(*wxTRANSPARENT_BRUSH); #endif // draw cell boxes wxRect r = wxRect(0, 0, CELLSIZE+1, CELLSIZE+1); int col = 0; for (int state = 0; state < 256; state++) { if (state < algoinfo[coloralgo]->maxstates) { if (state == 0) { wxColor color(algoinfo[coloralgo]->algor[0], algoinfo[coloralgo]->algog[0], algoinfo[coloralgo]->algob[0]); dc.SetBrush(wxBrush(color)); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } else if (showicons) { wxBitmap** iconmaps = algoinfo[coloralgo]->icons15x15; if (iconmaps && iconmaps[state]) { dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); if (algoinfo[coloralgo]->gradient) { if (state > 0 && state < gradstates) { unsigned char red, green, blue; GetGradientColor(state, &red, &green, &blue); DrawOneIcon(dc, r.x + 1, r.y + 1, iconmaps[state], algoinfo[coloralgo]->algor[0], algoinfo[coloralgo]->algog[0], algoinfo[coloralgo]->algob[0], red, green, blue, false); // default icons are grayscale } else { dc.SetBrush(bgbrush); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } } else { DrawOneIcon(dc, r.x + 1, r.y + 1, iconmaps[state], algoinfo[coloralgo]->algor[0], algoinfo[coloralgo]->algog[0], algoinfo[coloralgo]->algob[0], algoinfo[coloralgo]->algor[state], algoinfo[coloralgo]->algog[state], algoinfo[coloralgo]->algob[state], false); // default icons are grayscale } } else { dc.SetBrush(bgbrush); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } } else if (algoinfo[coloralgo]->gradient) { if (state > 0 && state < gradstates) { unsigned char red, green, blue; GetGradientColor(state, &red, &green, &blue); wxColor color(red, green, blue); dc.SetBrush(wxBrush(color)); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } else { dc.SetBrush(bgbrush); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } } else { wxColor color(algoinfo[coloralgo]->algor[state], algoinfo[coloralgo]->algog[state], algoinfo[coloralgo]->algob[state]); dc.SetBrush(wxBrush(color)); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } } else { // state >= maxstates dc.SetBrush(bgbrush); dc.DrawRectangle(r); dc.SetBrush(wxNullBrush); } col++; if (col < NUMCOLS) { r.x += CELLSIZE; } else { r.x = 0; r.y += CELLSIZE; col = 0; } } dc.SetPen(wxNullPen); } // ----------------------------------------------------------------------------- void CellBoxes::OnMouseDown(wxMouseEvent& event) { int col = event.GetX() / CELLSIZE; int row = event.GetY() / CELLSIZE; int state = row * NUMCOLS + col; if (state >= 0 && state < algoinfo[coloralgo]->maxstates) { if (algoinfo[coloralgo]->gradient && state > 0) { Beep(); } else { // let user change color of this cell state wxColour rgb(algoinfo[coloralgo]->algor[state], algoinfo[coloralgo]->algog[state], algoinfo[coloralgo]->algob[state]); wxColourData data; data.SetChooseFull(true); // for Windows data.SetColour(rgb); wxColourDialog dialog(this, &data); if ( dialog.ShowModal() == wxID_OK ) { wxColourData retData = dialog.GetColourData(); wxColour c = retData.GetColour(); if (rgb != c) { // change color algoinfo[coloralgo]->algor[state] = c.Red(); algoinfo[coloralgo]->algog[state] = c.Green(); algoinfo[coloralgo]->algob[state] = c.Blue(); Refresh(false); } } } } event.Skip(); } // ----------------------------------------------------------------------------- void CellBoxes::OnMouseMotion(wxMouseEvent& event) { int col = event.GetX() / CELLSIZE; int row = event.GetY() / CELLSIZE; int state = row * NUMCOLS + col; if (state < 0 || state > 255) { statebox->SetLabel(_(" ")); rgbbox->SetLabel(_(" ")); } else { statebox->SetLabel(wxString::Format(_("%d"),state)); if (state < algoinfo[coloralgo]->maxstates) { unsigned char r, g, b; if (algoinfo[coloralgo]->gradient && state > 0) { GetGradientColor(state, &r, &g, &b); } else { r = algoinfo[coloralgo]->algor[state]; g = algoinfo[coloralgo]->algog[state]; b = algoinfo[coloralgo]->algob[state]; } rgbbox->SetLabel(wxString::Format(_("%d,%d,%d"),r,g,b)); } else { rgbbox->SetLabel(_(" ")); } } } // ----------------------------------------------------------------------------- void CellBoxes::OnMouseExit(wxMouseEvent& WXUNUSED(event)) { statebox->SetLabel(_(" ")); rgbbox->SetLabel(_(" ")); } // ----------------------------------------------------------------------------- #if defined(__WXMAC__) && wxCHECK_VERSION(2,7,2) // fix wxMac 2.7.2+ bug in wxTextCtrl::SetSelection #define ALL_TEXT 0,999 #else #define ALL_TEXT -1,-1 #endif #if defined(__WXMAC__) && wxCHECK_VERSION(2,8,0) && !wxCHECK_VERSION(2,9,0) // fix wxALIGN_CENTER_VERTICAL bug in wxMac 2.8.x; // eg. when a wxStaticText box is next to a wxChoice box #define FIX_ALIGN_BUG wxBOTTOM,4 #else #define FIX_ALIGN_BUG wxALL,0 #endif #ifdef __WXMSW__ // Vista needs more RAM for itself const wxString HASH_MEM_NOTE = _("MB (best if ~70% of RAM)"); #else const wxString HASH_MEM_NOTE = _("MB (best if ~80% of RAM)"); #endif const wxString HASH_STEP_NOTE = _("(best if power of 2)"); const wxString NONHASH_MEM_NOTE = _("MB (0 means no limit)"); const wxString NONHASH_STEP_NOTE = _(" "); const int BITMAP_WD = 60; // width of bitmap in color buttons const int BITMAP_HT = 20; // height of bitmap in color buttons const int PAGESIZE = 10; // scroll amount when paging static size_t currpage = 0; // current page in PrefsDialog // these are global so we can remember current key combination static int currkey = ' '; static int currmods = mk_ALT + mk_SHIFT + mk_CMD; // ----------------------------------------------------------------------------- enum { // these *_PAGE values must correspond to currpage values FILE_PAGE = 0, EDIT_PAGE, CONTROL_PAGE, VIEW_PAGE, LAYER_PAGE, COLOR_PAGE, KEYBOARD_PAGE }; enum { // File prefs PREF_NEW_REM_SEL = wxID_HIGHEST + 1, // avoid problems with FindWindowById PREF_NEW_CURSOR, PREF_NEW_SCALE, PREF_OPEN_REM_SEL, PREF_OPEN_CURSOR, PREF_MAX_PATTERNS, PREF_MAX_SCRIPTS, PREF_EDITOR_BUTT, PREF_EDITOR_BOX, PREF_DOWNLOAD_BUTT, PREF_DOWNLOAD_BOX, // Edit prefs PREF_RANDOM_FILL, PREF_PASTE_0, PREF_PASTE_1, PREF_PASTE_2, PREF_SCROLL_PENCIL, PREF_SCROLL_CROSS, PREF_SCROLL_HAND, PREF_BEEP, // Control prefs PREF_ALGO_MENU1, PREF_MAX_MEM, PREF_MEM_NOTE, PREF_BASE_STEP, PREF_STEP_NOTE, PREF_MIN_DELAY, PREF_MAX_DELAY, PREF_RULES_BUTT, PREF_RULES_BOX, // View prefs PREF_SHOW_TIPS, PREF_RESTORE, PREF_Y_UP, PREF_SHOW_BOLD, PREF_BOLD_SPACING, PREF_MIN_GRID_SCALE, PREF_MOUSE_WHEEL, PREF_THUMB_RANGE, PREF_NO_CONTROLS, PREF_TL_CONTROLS, PREF_TR_CONTROLS, PREF_BR_CONTROLS, PREF_BL_CONTROLS, // Layer prefs PREF_OPACITY, PREF_TILE_BORDER, PREF_ASK_NEW, PREF_ASK_LOAD, PREF_ASK_DELETE, PREF_ASK_QUIT, PREF_WARN_SAVE, // Color prefs PREF_ALGO_MENU2, PREF_GRADIENT_CHECK, PREF_ICON_CHECK, PREF_CELL_PANEL, PREF_SCROLL_BAR, PREF_STATE_BOX, PREF_RGB_BOX, PREF_STATUS_BUTT, PREF_FROM_BUTT, PREF_TO_BUTT, PREF_SELECT_BUTT, PREF_PASTE_BUTT, PREF_BORDER_BUTT, // Keyboard prefs PREF_KEYCOMBO, PREF_ACTION, PREF_CHOOSE, PREF_FILE_BOX }; // define a multi-page dialog for changing various preferences class PrefsDialog : public wxPropertySheetDialog { public: PrefsDialog(wxWindow* parent, const wxString& page); ~PrefsDialog() { delete onetimer; } wxPanel* CreateFilePrefs(wxWindow* parent); wxPanel* CreateEditPrefs(wxWindow* parent); wxPanel* CreateControlPrefs(wxWindow* parent); wxPanel* CreateViewPrefs(wxWindow* parent); wxPanel* CreateLayerPrefs(wxWindow* parent); wxPanel* CreateColorPrefs(wxWindow* parent); wxPanel* CreateKeyboardPrefs(wxWindow* parent); virtual bool TransferDataFromWindow(); // called when user hits OK #ifdef __WXMAC__ void OnSpinCtrlChar(wxKeyEvent& event); #endif static void UpdateChosenFile(); private: bool GetCheckVal(long id); int GetChoiceVal(long id); int GetSpinVal(long id); int GetRadioVal(long firstid, int numbuttons); bool BadSpinVal(int id, int minval, int maxval, const wxString& prefix); bool ValidatePage(); wxBitmapButton* AddColorButton(wxWindow* parent, wxBoxSizer* hbox, int id, wxColor* rgb, const wxString& text); void ChangeButtonColor(int id, wxColor& rgb); void UpdateButtonColor(int id, wxColor& rgb); void UpdateScrollBar(); void OnCheckBoxClicked(wxCommandEvent& event); void OnColorButton(wxCommandEvent& event); void OnPageChanging(wxNotebookEvent& event); void OnPageChanged(wxNotebookEvent& event); void OnChoice(wxCommandEvent& event); void OnButton(wxCommandEvent& event); void OnScroll(wxScrollEvent& event); void OnOneTimer(wxTimerEvent& event); bool ignore_page_event; // used to prevent currpage being changed int algopos1; // selected algorithm in PREF_ALGO_MENU1 int new_algomem[MAX_ALGOS]; // new max mem values for each algorithm int new_defbase[MAX_ALGOS]; // new default base step values for each algorithm CellBoxes* cellboxes; // for displaying cell colors/icons wxCheckBox* gradcheck; // use gradient? wxCheckBox* iconcheck; // show icons? wxBitmapButton* frombutt; // button to set gradient's start color wxBitmapButton* tobutt; // button to set gradient's end color wxScrollBar* scrollbar; // for changing number of gradient states wxString neweditor; // new text editor wxString newdownloaddir; // new directory for downloaded files wxString newuserrules; // new directory for user's rules wxTimer* onetimer; // one shot timer (see OnOneTimer) DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(PrefsDialog, wxPropertySheetDialog) EVT_CHECKBOX (wxID_ANY, PrefsDialog::OnCheckBoxClicked) EVT_BUTTON (wxID_ANY, PrefsDialog::OnColorButton) EVT_NOTEBOOK_PAGE_CHANGING (wxID_ANY, PrefsDialog::OnPageChanging) EVT_NOTEBOOK_PAGE_CHANGED (wxID_ANY, PrefsDialog::OnPageChanged) EVT_CHOICE (wxID_ANY, PrefsDialog::OnChoice) EVT_BUTTON (wxID_ANY, PrefsDialog::OnButton) EVT_COMMAND_SCROLL (PREF_SCROLL_BAR, PrefsDialog::OnScroll) EVT_TIMER (wxID_ANY, PrefsDialog::OnOneTimer) END_EVENT_TABLE() // ----------------------------------------------------------------------------- // define a text control for showing current key combination class KeyComboCtrl : public wxTextCtrl { public: KeyComboCtrl(wxWindow* parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, int style = 0) : wxTextCtrl(parent, id, value, pos, size, style) {} ~KeyComboCtrl() {} // handlers to intercept keyboard events void OnKeyDown(wxKeyEvent& event); void OnChar(wxKeyEvent& event); private: int realkey; // key code set by OnKeyDown wxString debugkey; // display debug info for OnKeyDown and OnChar DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(KeyComboCtrl, wxTextCtrl) EVT_KEY_DOWN (KeyComboCtrl::OnKeyDown) EVT_CHAR (KeyComboCtrl::OnChar) END_EVENT_TABLE() // ----------------------------------------------------------------------------- void KeyComboCtrl::OnKeyDown(wxKeyEvent& event) { realkey = event.GetKeyCode(); int mods = event.GetModifiers(); if (debuglevel == 1) { // set debugkey now but don't show it until OnChar debugkey = wxString::Format(_("OnKeyDown: key=%d (%c) mods=%d"), realkey, realkey < 128 ? wxChar(realkey) : wxChar('?'), mods); } if (realkey == WXK_ESCAPE) { // escape key is reserved for other uses Beep(); return; } #ifdef __WXOSX__ // pass arrow key or function key or delete key directly to OnChar if ( (realkey >= WXK_LEFT && realkey <= WXK_DOWN) || (realkey >= WXK_F1 && realkey <= WXK_F24) || realkey == WXK_BACK ) { OnChar(event); return; } #endif // WARNING: logic must match that in PatternView::OnKeyDown if (mods == wxMOD_NONE || realkey > 127) { // tell OnChar handler to ignore realkey realkey = 0; } #ifdef __WXOSX__ // pass ctrl/cmd-key combos directly to OnChar if (realkey > 0 && ((mods & wxMOD_CONTROL) || (mods & wxMOD_CMD))) { OnChar(event); return; } #endif #ifdef __WXMAC__ // prevent ctrl-[ cancelling dialog (it translates to escape) if (realkey == '[' && (mods & wxMOD_CONTROL)) { OnChar(event); return; } // avoid translating option-E/I/N/U/` if (mods == wxMOD_ALT && (realkey == 'E' || realkey == 'I' || realkey == 'N' || realkey == 'U' || realkey == '`')) { OnChar(event); return; } #endif #ifdef __WXMSW__ // on Windows, OnChar is NOT called for some ctrl-key combos like // ctrl-0..9 or ctrl-alt-key, so we call OnChar ourselves if (realkey > 0 && (mods & wxMOD_CONTROL)) { OnChar(event); return; } #endif /* this didn't work!!! -- OnKeyDown is not getting called #ifdef __WXGTK__ // on Linux we need to avoid alt-C/O selecting Cancel/OK button if ((realkey == 'C' || realkey == 'O') && mods == wxMOD_ALT) { OnChar(event); return; } #endif */ event.Skip(); } // ----------------------------------------------------------------------------- #ifdef __WXOSX__ static bool inonchar = false; #endif void KeyComboCtrl::OnChar(wxKeyEvent& event) { #ifdef __WXOSX__ // avoid infinite recursion in wxOSX due to ChangeValue call below if (inonchar) { event.Skip(); return; } inonchar = true; #endif int key = event.GetKeyCode(); int mods = event.GetModifiers(); if (debuglevel == 1) { debugkey += wxString::Format(_("\nOnChar: key=%d (%c) mods=%d"), key, key < 128 ? wxChar(key) : wxChar('?'), mods); Warning(debugkey); } // WARNING: logic must match that in PatternView::OnChar if (realkey > 0 && mods != wxMOD_NONE) { #ifdef __WXGTK__ // sigh... wxGTK returns inconsistent results for shift-comma combos // so we assume that '<' is produced by pressing shift-comma // (which might only be true for US keyboards) if (key == '<' && (mods & wxMOD_SHIFT)) realkey = ','; #endif #ifdef __WXMSW__ // sigh... wxMSW returns inconsistent results for some shift-key combos // so again we assume we're using a US keyboard if (key == '~' && (mods & wxMOD_SHIFT)) realkey = '`'; if (key == '+' && (mods & wxMOD_SHIFT)) realkey = '='; #endif if (mods == wxMOD_SHIFT && key != realkey) { // use translated key code but remove shift key; // eg. we want shift-'/' to be seen as '?' mods = wxMOD_NONE; } else { // use key code seen by OnKeyDown key = realkey; if (key >= 'A' && key <= 'Z') key += 32; // convert A..Z to a..z } } // convert wx key and mods to our internal key code and modifiers // and, if they are valid, display the key combo and update the action if ( ConvertKeyAndModifiers(key, mods, &currkey, &currmods) ) { wxChoice* actionmenu = (wxChoice*) FindWindowById(PREF_ACTION); if (actionmenu) { wxString keystring = GetKeyCombo(currkey, currmods); if (!keystring.IsEmpty()) { ChangeValue(keystring); } else { currkey = 0; currmods = 0; ChangeValue(_("UNKNOWN KEY")); } actionmenu->SetSelection(keyaction[currkey][currmods].id); PrefsDialog::UpdateChosenFile(); SetFocus(); SetSelection(ALL_TEXT); } else { Warning(_("Failed to find wxChoice control!")); } } else { // unsupported key combo Beep(); } // do NOT pass event on to next handler // event.Skip(); #ifdef __WXOSX__ inonchar = false; #endif } // ----------------------------------------------------------------------------- #ifdef __WXMAC__ // override key event handler for wxSpinCtrl to allow key checking // and to get tab key navigation to work correctly class MySpinCtrl : public wxSpinCtrl { public: MySpinCtrl(wxWindow* parent, wxWindowID id, const wxString& str, const wxPoint& pos, const wxSize& size) : wxSpinCtrl(parent, id, str, pos, size) { // create a dynamic event handler for the underlying wxTextCtrl wxTextCtrl* textctrl = GetText(); if (textctrl) { textctrl->Connect(wxID_ANY, wxEVT_CHAR, wxKeyEventHandler(PrefsDialog::OnSpinCtrlChar)); } } }; void PrefsDialog::OnSpinCtrlChar(wxKeyEvent& event) { int key = event.GetKeyCode(); if (event.CmdDown()) { // allow handling of cmd-x/v/etc event.Skip(); } else if ( key == WXK_TAB ) { // note that FindFocus() returns pointer to wxTextCtrl window in wxSpinCtrl if ( currpage == FILE_PAGE ) { wxSpinCtrl* s1 = (wxSpinCtrl*) FindWindowById(PREF_MAX_PATTERNS); wxSpinCtrl* s2 = (wxSpinCtrl*) FindWindowById(PREF_MAX_SCRIPTS); wxTextCtrl* t1 = s1->GetText(); wxTextCtrl* t2 = s2->GetText(); wxWindow* focus = FindFocus(); if ( focus == t1 ) { s2->SetFocus(); s2->SetSelection(ALL_TEXT); } if ( focus == t2 ) { s1->SetFocus(); s1->SetSelection(ALL_TEXT); } } else if ( currpage == EDIT_PAGE ) { // only one spin ctrl on this page wxSpinCtrl* s1 = (wxSpinCtrl*) FindWindowById(PREF_RANDOM_FILL); if ( s1 ) { s1->SetFocus(); s1->SetSelection(ALL_TEXT); } } else if ( currpage == CONTROL_PAGE ) { wxSpinCtrl* s1 = (wxSpinCtrl*) FindWindowById(PREF_MAX_MEM); wxSpinCtrl* s2 = (wxSpinCtrl*) FindWindowById(PREF_BASE_STEP); wxSpinCtrl* s3 = (wxSpinCtrl*) FindWindowById(PREF_MIN_DELAY); wxSpinCtrl* s4 = (wxSpinCtrl*) FindWindowById(PREF_MAX_DELAY); wxTextCtrl* t1 = s1->GetText(); wxTextCtrl* t2 = s2->GetText(); wxTextCtrl* t3 = s3->GetText(); wxTextCtrl* t4 = s4->GetText(); wxWindow* focus = FindFocus(); if ( focus == t1 ) { s2->SetFocus(); s2->SetSelection(ALL_TEXT); } if ( focus == t2 ) { s3->SetFocus(); s3->SetSelection(ALL_TEXT); } if ( focus == t3 ) { s4->SetFocus(); s4->SetSelection(ALL_TEXT); } if ( focus == t4 ) { s1->SetFocus(); s1->SetSelection(ALL_TEXT); } } else if ( currpage == VIEW_PAGE ) { wxSpinCtrl* s1 = (wxSpinCtrl*) FindWindowById(PREF_BOLD_SPACING); wxSpinCtrl* s2 = (wxSpinCtrl*) FindWindowById(PREF_THUMB_RANGE); wxTextCtrl* t1 = s1->GetText(); wxTextCtrl* t2 = s2->GetText(); wxWindow* focus = FindFocus(); wxCheckBox* checkbox = (wxCheckBox*) FindWindowById(PREF_SHOW_BOLD); if (checkbox) { if (checkbox->GetValue()) { if ( focus == t1 ) { s2->SetFocus(); s2->SetSelection(ALL_TEXT); } if ( focus == t2 ) { s1->SetFocus(); s1->SetSelection(ALL_TEXT); } } else { if ( s2 ) { s2->SetFocus(); s2->SetSelection(ALL_TEXT); } } } else { Beep(); } } else if ( currpage == LAYER_PAGE ) { wxSpinCtrl* s1 = (wxSpinCtrl*) FindWindowById(PREF_OPACITY); wxSpinCtrl* s2 = (wxSpinCtrl*) FindWindowById(PREF_TILE_BORDER); wxTextCtrl* t1 = s1->GetText(); wxTextCtrl* t2 = s2->GetText(); wxWindow* focus = FindFocus(); if ( focus == t1 ) { s2->SetFocus(); s2->SetSelection(ALL_TEXT); } if ( focus == t2 ) { s1->SetFocus(); s1->SetSelection(ALL_TEXT); } } else if ( currpage == COLOR_PAGE ) { // no spin ctrls on this page } else if ( currpage == KEYBOARD_PAGE ) { // no spin ctrls on this page } } else if ( key >= ' ' && key <= '~' ) { if ( key >= '0' && key <= '9' ) { // allow digits event.Skip(); } else { // disallow any other displayable ascii char Beep(); } } else { event.Skip(); } } #else #define MySpinCtrl wxSpinCtrl #endif // !__WXMAC__ // ----------------------------------------------------------------------------- PrefsDialog::PrefsDialog(wxWindow* parent, const wxString& page) { // not using validators so no need for this: // SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY); Create(parent, wxID_ANY, _("Preferences")); CreateButtons(wxOK | wxCANCEL); wxBookCtrlBase* notebook = GetBookCtrl(); wxPanel* filePrefs = CreateFilePrefs(notebook); wxPanel* editPrefs = CreateEditPrefs(notebook); wxPanel* ctrlPrefs = CreateControlPrefs(notebook); wxPanel* viewPrefs = CreateViewPrefs(notebook); wxPanel* layerPrefs = CreateLayerPrefs(notebook); wxPanel* colorPrefs = CreateColorPrefs(notebook); wxPanel* keyboardPrefs = CreateKeyboardPrefs(notebook); // AddPage and SetSelection cause OnPageChanging and OnPageChanged to be called // so we use a flag to prevent currpage being changed (and unnecessary validation) ignore_page_event = true; notebook->AddPage(filePrefs, _("File")); notebook->AddPage(editPrefs, _("Edit")); notebook->AddPage(ctrlPrefs, _("Control")); notebook->AddPage(viewPrefs, _("View")); notebook->AddPage(layerPrefs, _("Layer")); notebook->AddPage(colorPrefs, _("Color")); notebook->AddPage(keyboardPrefs, _("Keyboard")); if (!page.IsEmpty()) { if (page == wxT("file")) currpage = FILE_PAGE; else if (page == wxT("edit")) currpage = EDIT_PAGE; else if (page == wxT("control")) currpage = CONTROL_PAGE; else if (page == wxT("view")) currpage = VIEW_PAGE; else if (page == wxT("layer")) currpage = LAYER_PAGE; else if (page == wxT("color")) currpage = COLOR_PAGE; else if (page == wxT("keyboard")) currpage = KEYBOARD_PAGE; } // show the desired page notebook->SetSelection(currpage); ignore_page_event = false; LayoutDialog(); // ensure top text box has focus and text is selected by creating // a one-shot timer which will call OnOneTimer after short delay onetimer = new wxTimer(this, wxID_ANY); if (onetimer) onetimer->Start(10, wxTIMER_ONE_SHOT); } // ----------------------------------------------------------------------------- void PrefsDialog::OnOneTimer(wxTimerEvent& WXUNUSED(event)) { MySpinCtrl* s1 = NULL; if (currpage == FILE_PAGE) { s1 = (MySpinCtrl*) FindWindowById(PREF_MAX_PATTERNS); } else if (currpage == EDIT_PAGE) { s1 = (MySpinCtrl*) FindWindowById(PREF_RANDOM_FILL); } else if (currpage == CONTROL_PAGE) { s1 = (MySpinCtrl*) FindWindowById(PREF_MAX_MEM); } else if (currpage == VIEW_PAGE) { s1 = (MySpinCtrl*) FindWindowById(showgridlines ? PREF_BOLD_SPACING : PREF_THUMB_RANGE); } else if (currpage == LAYER_PAGE) { s1 = (MySpinCtrl*) FindWindowById(PREF_OPACITY); } else if (currpage == COLOR_PAGE) { // no spin ctrls on this page return; } else if (currpage == KEYBOARD_PAGE) { KeyComboCtrl* k = (KeyComboCtrl*) FindWindowById(PREF_KEYCOMBO); if (k) { k->SetFocus(); k->SetSelection(ALL_TEXT); } return; } if (s1) { s1->SetFocus(); s1->SetSelection(ALL_TEXT); } } // ----------------------------------------------------------------------------- // these consts are used to get nicely spaced controls on each platform: #ifdef __WXMAC__ #define GROUPGAP (12) // vertical gap between a group of controls #define SBTOPGAP (2) // vertical gap before first item in wxStaticBoxSizer #define SBBOTGAP (2) // vertical gap after last item in wxStaticBoxSizer #if wxCHECK_VERSION(3,0,0) #define SVGAP (8) // vertical gap above wxSpinCtrl box #define S2VGAP (6) // vertical gap between 2 wxSpinCtrl boxes #define SPINGAP (6) // horizontal gap around each wxSpinCtrl box #else #define SVGAP (4) // vertical gap above wxSpinCtrl box #define S2VGAP (0) // vertical gap between 2 wxSpinCtrl boxes #define SPINGAP (3) // horizontal gap around each wxSpinCtrl box #endif #define CH2VGAP (6) // vertical gap between 2 check/radio boxes #define CVGAP (9) // vertical gap above wxChoice box #define LRGAP (5) // space left and right of vertically stacked boxes #define CHOICEGAP (6) // horizontal gap to left of wxChoice box #elif defined(__WXMSW__) #define GROUPGAP (10) #define SBTOPGAP (7) #define SBBOTGAP (7) #define SVGAP (7) #define S2VGAP (5) #define CH2VGAP (8) #define CVGAP (7) #define LRGAP (5) #define SPINGAP (6) #define CHOICEGAP (6) #else // assume Linux #define GROUPGAP (10) #define SBTOPGAP (12) #define SBBOTGAP (7) #define SVGAP (7) #define S2VGAP (5) #define CH2VGAP (8) #define CVGAP (7) #define LRGAP (5) #define SPINGAP (6) #define CHOICEGAP (6) #endif // ----------------------------------------------------------------------------- wxPanel* PrefsDialog::CreateFilePrefs(wxWindow* parent) { wxPanel* panel = new wxPanel(parent, wxID_ANY); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); wxArrayString newcursorChoices; newcursorChoices.Add(wxT("Draw")); newcursorChoices.Add(wxT("Pick")); newcursorChoices.Add(wxT("Select")); newcursorChoices.Add(wxT("Move")); newcursorChoices.Add(wxT("Zoom In")); newcursorChoices.Add(wxT("Zoom Out")); newcursorChoices.Add(wxT("No Change")); wxArrayString opencursorChoices = newcursorChoices; wxArrayString newscaleChoices; newscaleChoices.Add(wxT("1:1")); newscaleChoices.Add(wxT("1:2")); newscaleChoices.Add(wxT("1:4")); newscaleChoices.Add(wxT("1:8")); newscaleChoices.Add(wxT("1:16")); newscaleChoices.Add(wxT("1:32")); // on new pattern wxStaticBox* sbox1 = new wxStaticBox(panel, wxID_ANY, _("On creating a new pattern:")); wxBoxSizer* ssizer1 = new wxStaticBoxSizer(sbox1, wxVERTICAL); wxCheckBox* check1 = new wxCheckBox(panel, PREF_NEW_REM_SEL, _("Remove selection")); wxBoxSizer* check1box = new wxBoxSizer(wxHORIZONTAL); check1box->Add(check1, 0, FIX_ALIGN_BUG); wxBoxSizer* setcurs1 = new wxBoxSizer(wxHORIZONTAL); setcurs1->Add(new wxStaticText(panel, wxID_STATIC, _("Set cursor:")), 0, FIX_ALIGN_BUG); wxBoxSizer* setscalebox = new wxBoxSizer(wxHORIZONTAL); setscalebox->Add(new wxStaticText(panel, wxID_STATIC, _("Set scale:")), 0, FIX_ALIGN_BUG); wxChoice* choice3 = new wxChoice(panel, PREF_NEW_CURSOR, wxDefaultPosition, wxDefaultSize, newcursorChoices); wxChoice* choice1 = new wxChoice(panel, PREF_NEW_SCALE, wxDefaultPosition, wxDefaultSize, newscaleChoices); wxBoxSizer* hbox1 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(check1box, 0, wxALIGN_CENTER_VERTICAL, 0); hbox1->AddStretchSpacer(20); hbox1->Add(setcurs1, 0, wxALIGN_CENTER_VERTICAL, 0); hbox1->Add(choice3, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, CHOICEGAP); hbox1->AddStretchSpacer(20); wxBoxSizer* hbox2 = new wxBoxSizer(wxHORIZONTAL); hbox2->Add(setscalebox, 0, wxALIGN_CENTER_VERTICAL, 0); hbox2->Add(choice1, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, CHOICEGAP); ssizer1->AddSpacer(SBTOPGAP); ssizer1->Add(hbox1, 1, wxGROW | wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(CVGAP); ssizer1->Add(hbox2, 0, wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(SBBOTGAP); // on opening pattern wxStaticBox* sbox2 = new wxStaticBox(panel, wxID_ANY, _("On opening a pattern file or the clipboard:")); wxBoxSizer* ssizer2 = new wxStaticBoxSizer(sbox2, wxVERTICAL); wxCheckBox* check2 = new wxCheckBox(panel, PREF_OPEN_REM_SEL, _("Remove selection")); wxBoxSizer* check2box = new wxBoxSizer(wxHORIZONTAL); check2box->Add(check2, 0, FIX_ALIGN_BUG); wxChoice* choice4 = new wxChoice(panel, PREF_OPEN_CURSOR, wxDefaultPosition, wxDefaultSize, opencursorChoices); wxBoxSizer* setcurs2 = new wxBoxSizer(wxHORIZONTAL); setcurs2->Add(new wxStaticText(panel, wxID_STATIC, _("Set cursor:")), 0, FIX_ALIGN_BUG); wxBoxSizer* hbox4 = new wxBoxSizer(wxHORIZONTAL); hbox4->Add(check2box, 0, wxALIGN_CENTER_VERTICAL, 0); hbox4->AddStretchSpacer(20); hbox4->Add(setcurs2, 0, wxALIGN_CENTER_VERTICAL, 0); hbox4->Add(choice4, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, CHOICEGAP); hbox4->AddStretchSpacer(20); ssizer2->AddSpacer(SBTOPGAP); ssizer2->Add(hbox4, 1, wxGROW | wxLEFT | wxRIGHT, LRGAP); ssizer2->AddSpacer(SBBOTGAP); // max_patterns and max_scripts wxBoxSizer* maxbox = new wxBoxSizer(wxHORIZONTAL); maxbox->Add(new wxStaticText(panel, wxID_STATIC, _("Maximum number of recent patterns:")), 0, wxALL, 0); wxBoxSizer* minbox = new wxBoxSizer(wxHORIZONTAL); minbox->Add(new wxStaticText(panel, wxID_STATIC, _("Maximum number of recent scripts:")), 0, wxALL, 0); // align spin controls by setting minbox same width as maxbox minbox->SetMinSize( maxbox->GetMinSize() ); wxSpinCtrl* spin1 = new MySpinCtrl(panel, PREF_MAX_PATTERNS, wxEmptyString, wxDefaultPosition, wxSize(70, wxDefaultCoord)); wxSpinCtrl* spin2 = new MySpinCtrl(panel, PREF_MAX_SCRIPTS, wxEmptyString, wxDefaultPosition, wxSize(70, wxDefaultCoord)); wxBoxSizer* hpbox = new wxBoxSizer(wxHORIZONTAL); hpbox->Add(maxbox, 0, wxALIGN_CENTER_VERTICAL, 0); hpbox->Add(spin1, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); wxBoxSizer* hsbox = new wxBoxSizer(wxHORIZONTAL); hsbox->Add(minbox, 0, wxALIGN_CENTER_VERTICAL, 0); hsbox->Add(spin2, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); wxButton* editorbutt = new wxButton(panel, PREF_EDITOR_BUTT, _("Text Editor...")); wxStaticText* editorbox = new wxStaticText(panel, PREF_EDITOR_BOX, texteditor); neweditor = texteditor; wxButton* downloadbutt = new wxButton(panel, PREF_DOWNLOAD_BUTT, _("Downloads...")); wxStaticText* downloadbox = new wxStaticText(panel, PREF_DOWNLOAD_BOX, downloaddir); newdownloaddir = downloaddir; wxBoxSizer* hebox = new wxBoxSizer(wxHORIZONTAL); hebox->Add(editorbutt, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 0); hebox->Add(editorbox, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, LRGAP); wxBoxSizer* hdbox = new wxBoxSizer(wxHORIZONTAL); hdbox->Add(downloadbutt, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 0); hdbox->Add(downloadbox, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, LRGAP); vbox->Add(ssizer1, 0, wxGROW | wxALL, 2); vbox->AddSpacer(10); vbox->Add(ssizer2, 0, wxGROW | wxALL, 2); vbox->AddSpacer(10); vbox->Add(hpbox, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(S2VGAP); vbox->Add(hsbox, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(10); vbox->Add(hebox, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(10); vbox->Add(hdbox, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(5); // init control values check1->SetValue(newremovesel); check2->SetValue(openremovesel); choice1->SetSelection(newmag); newcursindex = CursorToIndex(newcurs); opencursindex = CursorToIndex(opencurs); choice3->SetSelection(newcursindex); choice4->SetSelection(opencursindex); spin1->SetRange(1, MAX_RECENT); spin1->SetValue(maxpatterns); spin2->SetRange(1, MAX_RECENT); spin2->SetValue(maxscripts); spin1->SetFocus(); spin1->SetSelection(ALL_TEXT); topSizer->Add(vbox, 1, wxGROW | wxALIGN_CENTER | wxALL, 5); panel->SetSizer(topSizer); topSizer->Fit(panel); return panel; } // ----------------------------------------------------------------------------- wxPanel* PrefsDialog::CreateEditPrefs(wxWindow* parent) { wxPanel* panel = new wxPanel(parent, wxID_ANY); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); // random_fill wxBoxSizer* hbox1 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(new wxStaticText(panel, wxID_STATIC, _("Random fill percentage:")), 0, wxALIGN_CENTER_VERTICAL, 0); wxSpinCtrl* spin1 = new MySpinCtrl(panel, PREF_RANDOM_FILL, wxEmptyString, wxDefaultPosition, wxSize(70, wxDefaultCoord)); hbox1->Add(spin1, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); // can_change_rule wxStaticBox* sbox1 = new wxStaticBox(panel, wxID_ANY, _("When pasting a clipboard pattern:")); wxBoxSizer* ssizer1 = new wxStaticBoxSizer(sbox1, wxVERTICAL); wxRadioButton* radio0 = new wxRadioButton(panel, PREF_PASTE_0, _("Never change rule"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP); wxRadioButton* radio1 = new wxRadioButton(panel, PREF_PASTE_1, _("Only change rule if one is specified and the universe is empty")); wxRadioButton* radio2 = new wxRadioButton(panel, PREF_PASTE_2, _("Always change rule if one is specified")); ssizer1->AddSpacer(SBTOPGAP); ssizer1->Add(radio0, 0, wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(CH2VGAP); ssizer1->Add(radio1, 0, wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(CH2VGAP); ssizer1->Add(radio2, 0, wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(SBBOTGAP); // scroll_pencil, scroll_cross, scroll_hand wxStaticBox* sbox2 = new wxStaticBox(panel, wxID_ANY, _("If the cursor is dragged outside the viewport:")); wxBoxSizer* ssizer2 = new wxStaticBoxSizer(sbox2, wxVERTICAL); wxCheckBox* check1 = new wxCheckBox(panel, PREF_SCROLL_PENCIL, _("Scroll when drawing cells (using the pencil cursor)")); wxCheckBox* check2 = new wxCheckBox(panel, PREF_SCROLL_CROSS, _("Scroll when selecting cells (using the cross cursor)")); wxCheckBox* check3 = new wxCheckBox(panel, PREF_SCROLL_HAND, _("Scroll when moving view (using the hand cursor)")); ssizer2->AddSpacer(SBTOPGAP); ssizer2->Add(check1, 0, wxLEFT | wxRIGHT, LRGAP); ssizer2->AddSpacer(CH2VGAP); ssizer2->Add(check2, 0, wxLEFT | wxRIGHT, LRGAP); ssizer2->AddSpacer(CH2VGAP); ssizer2->Add(check3, 0, wxLEFT | wxRIGHT, LRGAP); ssizer2->AddSpacer(SBBOTGAP); // allow_beep wxCheckBox* check4 = new wxCheckBox(panel, PREF_BEEP, _("Allow beep sound")); vbox->AddSpacer(SVGAP); vbox->Add(hbox1, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(GROUPGAP); vbox->Add(ssizer1, 0, wxGROW | wxALL, 2); vbox->AddSpacer(GROUPGAP); vbox->Add(ssizer2, 0, wxGROW | wxALL, 2); vbox->AddSpacer(GROUPGAP); vbox->Add(check4, 0, wxLEFT | wxRIGHT, LRGAP); // init control values spin1->SetRange(1, 100); spin1->SetValue(randomfill); spin1->SetFocus(); spin1->SetSelection(ALL_TEXT); radio0->SetValue(canchangerule == 0); radio1->SetValue(canchangerule == 1); radio2->SetValue(canchangerule == 2); check1->SetValue(scrollpencil); check2->SetValue(scrollcross); check3->SetValue(scrollhand); check4->SetValue(allowbeep); topSizer->Add(vbox, 1, wxGROW | wxALIGN_CENTER | wxALL, 5); panel->SetSizer(topSizer); topSizer->Fit(panel); return panel; } // ----------------------------------------------------------------------------- wxPanel* PrefsDialog::CreateControlPrefs(wxWindow* parent) { wxPanel* panel = new wxPanel(parent, wxID_ANY); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); // create a choice menu to select algo wxArrayString algoChoices; for (int i = 0; i < NumAlgos(); i++) { algoChoices.Add( wxString(GetAlgoName(i), wxConvLocal) ); } wxChoice* algomenu = new wxChoice(panel, PREF_ALGO_MENU1, wxDefaultPosition, wxDefaultSize, algoChoices); algopos1 = currlayer->algtype; wxBoxSizer* longbox = new wxBoxSizer(wxHORIZONTAL); longbox->Add(new wxStaticText(panel, wxID_STATIC, _("Settings for this algorithm:")), 0, FIX_ALIGN_BUG); wxBoxSizer* menubox = new wxBoxSizer(wxHORIZONTAL); menubox->Add(longbox, 0, wxALIGN_CENTER_VERTICAL, 0); menubox->Add(algomenu, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, CHOICEGAP); // maximum memory and base step wxBoxSizer* membox = new wxBoxSizer(wxHORIZONTAL); membox->Add(new wxStaticText(panel, wxID_STATIC, _("Maximum memory:")), 0, wxALL, 0); wxBoxSizer* basebox = new wxBoxSizer(wxHORIZONTAL); basebox->Add(new wxStaticText(panel, wxID_STATIC, _("Default base step:")), 0, wxALL, 0); // align spin controls membox->SetMinSize( longbox->GetMinSize() ); basebox->SetMinSize( longbox->GetMinSize() ); wxBoxSizer* hbox1 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(membox, 0, wxALIGN_CENTER_VERTICAL, 0); wxSpinCtrl* spin1 = new MySpinCtrl(panel, PREF_MAX_MEM, wxEmptyString, wxDefaultPosition, wxSize(80, wxDefaultCoord)); hbox1->Add(spin1, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); wxString memnote = algoinfo[algopos1]->canhash ? HASH_MEM_NOTE : NONHASH_MEM_NOTE; hbox1->Add(new wxStaticText(panel, PREF_MEM_NOTE, memnote), 0, wxALIGN_CENTER_VERTICAL, 0); wxBoxSizer* hbox2 = new wxBoxSizer(wxHORIZONTAL); hbox2->Add(basebox, 0, wxALIGN_CENTER_VERTICAL, 0); wxSpinCtrl* spin2 = new MySpinCtrl(panel, PREF_BASE_STEP, wxEmptyString, wxDefaultPosition, wxSize(80, wxDefaultCoord)); hbox2->Add(spin2, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); wxString stepnote = algoinfo[algopos1]->canhash ? HASH_STEP_NOTE : NONHASH_STEP_NOTE; hbox2->Add(new wxStaticText(panel, PREF_STEP_NOTE, stepnote), 0, wxALIGN_CENTER_VERTICAL, 0); // min_delay and max_delay wxBoxSizer* minbox = new wxBoxSizer(wxHORIZONTAL); minbox->Add(new wxStaticText(panel, wxID_STATIC, _("Minimum delay:")), 0, wxALL, 0); wxBoxSizer* maxbox = new wxBoxSizer(wxHORIZONTAL); maxbox->Add(new wxStaticText(panel, wxID_STATIC, _("Maximum delay:")), 0, wxALL, 0); // align spin controls minbox->SetMinSize( maxbox->GetMinSize() ); wxBoxSizer* hbox3 = new wxBoxSizer(wxHORIZONTAL); hbox3->Add(minbox, 0, wxALIGN_CENTER_VERTICAL, 0); wxSpinCtrl* spin3 = new MySpinCtrl(panel, PREF_MIN_DELAY, wxEmptyString, wxDefaultPosition, wxSize(80, wxDefaultCoord)); hbox3->Add(spin3, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); hbox3->Add(new wxStaticText(panel, wxID_STATIC, _("millisecs")), 0, wxALIGN_CENTER_VERTICAL, 0); wxBoxSizer* hbox4 = new wxBoxSizer(wxHORIZONTAL); hbox4->Add(maxbox, 0, wxALIGN_CENTER_VERTICAL, 0); wxSpinCtrl* spin4 = new MySpinCtrl(panel, PREF_MAX_DELAY, wxEmptyString, wxDefaultPosition, wxSize(80, wxDefaultCoord)); hbox4->Add(spin4, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); hbox4->Add(new wxStaticText(panel, wxID_STATIC, _("millisecs")), 0, wxALIGN_CENTER_VERTICAL, 0); // user_rules wxButton* rulesbutt = new wxButton(panel, PREF_RULES_BUTT, _("Your Rules...")); wxStaticText* rulesbox = new wxStaticText(panel, PREF_RULES_BOX, userrules); newuserrules = userrules; wxBoxSizer* hrbox = new wxBoxSizer(wxHORIZONTAL); hrbox->Add(rulesbutt, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 0); hrbox->Add(rulesbox, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, LRGAP); wxString note = _("Golly looks for .rule files in the above folder before looking in the Rules folder."); wxBoxSizer* notebox = new wxBoxSizer(wxHORIZONTAL); notebox->Add(new wxStaticText(panel, wxID_STATIC, note)); // position things vbox->AddSpacer(5); vbox->Add(menubox, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(SVGAP); vbox->Add(hbox1, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(S2VGAP); vbox->Add(hbox2, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(5); vbox->AddSpacer(GROUPGAP); vbox->Add(hbox3, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(S2VGAP); vbox->Add(hbox4, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(15); vbox->AddSpacer(GROUPGAP); vbox->Add(hrbox, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(15); vbox->Add(notebox, 0, wxLEFT, LRGAP); // init control values; // to avoid a wxGTK bug we use SetRange and SetValue rather than specifying // the min,max,init values in the wxSpinCtrl constructor spin1->SetRange(MIN_MEM_MB, MAX_MEM_MB); spin1->SetValue(algoinfo[algopos1]->algomem); spin2->SetRange(2, MAX_BASESTEP); spin2->SetValue(algoinfo[algopos1]->defbase); spin3->SetRange(0, MAX_DELAY); spin3->SetValue(mindelay); spin4->SetRange(0, MAX_DELAY); spin4->SetValue(maxdelay); spin1->SetFocus(); spin1->SetSelection(ALL_TEXT); algomenu->SetSelection(algopos1); for (int i = 0; i < NumAlgos(); i++) { new_algomem[i] = algoinfo[i]->algomem; new_defbase[i] = algoinfo[i]->defbase; } topSizer->Add(vbox, 1, wxGROW | wxALIGN_CENTER | wxALL, 5); panel->SetSizer(topSizer); topSizer->Fit(panel); return panel; } // ----------------------------------------------------------------------------- wxPanel* PrefsDialog::CreateViewPrefs(wxWindow* parent) { wxPanel* panel = new wxPanel(parent, wxID_ANY); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); // show_tips #if wxUSE_TOOLTIPS wxCheckBox* check3 = new wxCheckBox(panel, PREF_SHOW_TIPS, _("Show button tips")); #endif // restore_view wxCheckBox* check4 = new wxCheckBox(panel, PREF_RESTORE, _("Reset/Undo will restore view")); // math_coords wxCheckBox* check1 = new wxCheckBox(panel, PREF_Y_UP, _("Y coordinates increase upwards")); // show_bold_lines and bold_spacing wxBoxSizer* hbox2 = new wxBoxSizer(wxHORIZONTAL); wxCheckBox* check2 = new wxCheckBox(panel, PREF_SHOW_BOLD, _("Show bold grid lines every")); wxSpinCtrl* spin2 = new MySpinCtrl(panel, PREF_BOLD_SPACING, wxEmptyString, wxDefaultPosition, wxSize(70, wxDefaultCoord)); hbox2->Add(check2, 0, wxALIGN_CENTER_VERTICAL, 0); hbox2->Add(spin2, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); hbox2->Add(new wxStaticText(panel, wxID_STATIC, _("cells")), 0, wxALIGN_CENTER_VERTICAL, 0); // min_grid_mag (2..MAX_MAG) wxBoxSizer* hbox3 = new wxBoxSizer(wxHORIZONTAL); wxArrayString mingridChoices; mingridChoices.Add(wxT("1:4")); mingridChoices.Add(wxT("1:8")); mingridChoices.Add(wxT("1:16")); mingridChoices.Add(wxT("1:32")); wxChoice* choice3 = new wxChoice(panel, PREF_MIN_GRID_SCALE, wxDefaultPosition, wxDefaultSize, mingridChoices); wxBoxSizer* longbox = new wxBoxSizer(wxHORIZONTAL); longbox->Add(new wxStaticText(panel, wxID_STATIC, _("Minimum scale for grid:")), 0, FIX_ALIGN_BUG); wxBoxSizer* shortbox = new wxBoxSizer(wxHORIZONTAL); shortbox->Add(new wxStaticText(panel, wxID_STATIC, _("Mouse wheel action:")), 0, FIX_ALIGN_BUG); // align controls by setting shortbox same width as longbox shortbox->SetMinSize( longbox->GetMinSize() ); hbox3->Add(longbox, 0, wxALIGN_CENTER_VERTICAL, 0); hbox3->Add(choice3, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, CHOICEGAP); // mouse_wheel_mode wxBoxSizer* hbox4 = new wxBoxSizer(wxHORIZONTAL); wxArrayString mousewheelChoices; mousewheelChoices.Add(wxT("Disabled")); mousewheelChoices.Add(wxT("Forward zooms out")); mousewheelChoices.Add(wxT("Forward zooms in")); wxChoice* choice4 = new wxChoice(panel, PREF_MOUSE_WHEEL, wxDefaultPosition, wxDefaultSize, mousewheelChoices); hbox4->Add(shortbox, 0, wxALIGN_CENTER_VERTICAL, 0); hbox4->Add(choice4, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, CHOICEGAP); // thumb_range wxBoxSizer* thumblabel = new wxBoxSizer(wxHORIZONTAL); thumblabel->Add(new wxStaticText(panel, wxID_STATIC, _("Thumb scroll range:")), 0, wxALIGN_CENTER_VERTICAL, 0); thumblabel->SetMinSize( longbox->GetMinSize() ); wxBoxSizer* hbox5 = new wxBoxSizer(wxHORIZONTAL); hbox5->Add(thumblabel, 0, wxALIGN_CENTER_VERTICAL, 0); wxSpinCtrl* spin5 = new MySpinCtrl(panel, PREF_THUMB_RANGE, wxEmptyString, wxDefaultPosition, wxSize(70, wxDefaultCoord)); hbox5->Add(spin5, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); hbox5->Add(new wxStaticText(panel, wxID_STATIC, _("times view size")), 0, wxALIGN_CENTER_VERTICAL, 0); // controls_pos wxStaticBox* sbox1 = new wxStaticBox(panel, wxID_ANY, _("Position of translucent buttons:")); wxBoxSizer* ssizer1 = new wxStaticBoxSizer(sbox1, wxVERTICAL); wxRadioButton* radio0 = new wxRadioButton(panel, PREF_NO_CONTROLS, _("Disabled"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP); wxRadioButton* radio1 = new wxRadioButton(panel, PREF_TL_CONTROLS, _("Top left corner")); wxRadioButton* radio2 = new wxRadioButton(panel, PREF_TR_CONTROLS, _("Top right corner")); wxRadioButton* radio3 = new wxRadioButton(panel, PREF_BR_CONTROLS, _("Bottom right corner")); wxRadioButton* radio4 = new wxRadioButton(panel, PREF_BL_CONTROLS, _("Bottom left corner")); wxBoxSizer* b1 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* b4 = new wxBoxSizer(wxHORIZONTAL); b1->Add(radio1, 0, wxALL, 0); b4->Add(radio4, 0, wxALL, 0); wxSize wd1 = b1->GetMinSize(); wxSize wd4 = b4->GetMinSize(); if (wd1.GetWidth() > wd4.GetWidth()) b4->SetMinSize(wd1); else b1->SetMinSize(wd4); wxBoxSizer* toprow = new wxBoxSizer(wxHORIZONTAL); toprow->Add(b1, 0, wxLEFT | wxRIGHT, LRGAP); // don't use AddSpacer(20) because that will also add 20 *vertical* units! toprow->AddSpacer(10); toprow->AddSpacer(10); toprow->Add(radio2, 0, wxLEFT | wxRIGHT, LRGAP); toprow->AddStretchSpacer(20); toprow->Add(radio0, 0, wxLEFT | wxRIGHT, 0); toprow->AddStretchSpacer(10); wxBoxSizer* botrow = new wxBoxSizer(wxHORIZONTAL); botrow->Add(b4, 0, wxLEFT | wxRIGHT, LRGAP); // don't use AddSpacer(20) because that will also add 20 *vertical* units! botrow->AddSpacer(10); botrow->AddSpacer(10); botrow->Add(radio3, 0, wxLEFT | wxRIGHT, LRGAP); botrow->AddStretchSpacer(10); ssizer1->AddSpacer(SBTOPGAP); ssizer1->Add(toprow, 1, wxGROW | wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(CH2VGAP); ssizer1->Add(botrow, 1, wxGROW | wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(SBBOTGAP); // position things vbox->AddSpacer(5); #if wxUSE_TOOLTIPS vbox->Add(check3, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(CH2VGAP + 3); #endif vbox->Add(check4, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(CH2VGAP + 3); vbox->Add(check1, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(SVGAP); vbox->Add(hbox2, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(SVGAP); #ifdef __WXMAC__ vbox->AddSpacer(10); #endif vbox->Add(hbox3, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(CVGAP); vbox->Add(hbox4, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(SVGAP); vbox->Add(hbox5, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(GROUPGAP); vbox->Add(ssizer1, 0, wxGROW | wxALL, 2); // init control values #if wxUSE_TOOLTIPS check3->SetValue(showtips); #endif check4->SetValue(restoreview); check1->SetValue(mathcoords); check2->SetValue(showboldlines); spin5->SetRange(2, MAX_THUMBRANGE); spin5->SetValue(thumbrange); spin2->SetRange(2, MAX_SPACING); spin2->SetValue(boldspacing); spin2->Enable(showboldlines); if (showboldlines) { spin2->SetFocus(); spin2->SetSelection(ALL_TEXT); } else { spin5->SetFocus(); spin5->SetSelection(ALL_TEXT); } mingridindex = mingridmag - 2; choice3->SetSelection(mingridindex); choice4->SetSelection(mousewheelmode); radio0->SetValue(controlspos == 0); radio1->SetValue(controlspos == 1); radio2->SetValue(controlspos == 2); radio3->SetValue(controlspos == 3); radio4->SetValue(controlspos == 4); topSizer->Add(vbox, 1, wxGROW | wxALIGN_CENTER | wxALL, 5); panel->SetSizer(topSizer); topSizer->Fit(panel); return panel; } // ----------------------------------------------------------------------------- wxPanel* PrefsDialog::CreateLayerPrefs(wxWindow* parent) { wxPanel* panel = new wxPanel(parent, wxID_ANY); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); // opacity wxBoxSizer* opacitybox = new wxBoxSizer(wxHORIZONTAL); opacitybox->Add(new wxStaticText(panel, wxID_STATIC, _("Opacity percentage when drawing stacked layers:")), 0, wxALIGN_CENTER_VERTICAL, 0); wxSpinCtrl* spin1 = new MySpinCtrl(panel, PREF_OPACITY, wxEmptyString, wxDefaultPosition, wxSize(70, wxDefaultCoord)); opacitybox->Add(spin1, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); // tile_border wxBoxSizer* borderbox = new wxBoxSizer(wxHORIZONTAL); borderbox->Add(new wxStaticText(panel, wxID_STATIC, _("Border thickness for tiled layers:")), 0, wxALIGN_CENTER_VERTICAL, 0); wxSpinCtrl* spin2 = new MySpinCtrl(panel, PREF_TILE_BORDER, wxEmptyString, wxDefaultPosition, wxSize(70, wxDefaultCoord)); borderbox->Add(spin2, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, SPINGAP); // ask_on_new, ask_on_load, ask_on_delete, ask_on_quit, warn_on_save wxStaticBox* sbox1 = new wxStaticBox(panel, wxID_ANY, _("Ask to save changes to layer before:")); wxBoxSizer* ssizer1 = new wxStaticBoxSizer(sbox1, wxVERTICAL); wxCheckBox* check1 = new wxCheckBox(panel, PREF_ASK_NEW, _("Creating a new pattern")); wxCheckBox* check2 = new wxCheckBox(panel, PREF_ASK_LOAD, _("Opening a pattern file")); wxCheckBox* check3 = new wxCheckBox(panel, PREF_ASK_DELETE, _("Deleting layer")); wxCheckBox* check4 = new wxCheckBox(panel, PREF_ASK_QUIT, _("Quitting application")); wxCheckBox* check5 = new wxCheckBox(panel, PREF_WARN_SAVE, _("Warn if saving non-starting generation")); wxBoxSizer* b1 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* b2 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* b3 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* b4 = new wxBoxSizer(wxHORIZONTAL); b1->Add(check1, 0, wxALL, 0); b2->Add(check2, 0, wxALL, 0); b3->Add(check3, 0, wxALL, 0); b4->Add(check4, 0, wxALL, 0); wxSize wd1 = b1->GetMinSize(); wxSize wd2 = b2->GetMinSize(); wxSize wd3 = b3->GetMinSize(); wxSize wd4 = b4->GetMinSize(); if (wd1.GetWidth() > wd2.GetWidth()) b2->SetMinSize(wd1); else b1->SetMinSize(wd2); if (wd3.GetWidth() > wd4.GetWidth()) b4->SetMinSize(wd3); else b3->SetMinSize(wd4); wxBoxSizer* hbox1 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(b1, 0, wxLEFT | wxRIGHT, LRGAP); hbox1->AddStretchSpacer(20); hbox1->Add(b3, 0, wxLEFT | wxRIGHT, LRGAP); hbox1->AddStretchSpacer(20); wxBoxSizer* hbox2 = new wxBoxSizer(wxHORIZONTAL); hbox2->Add(b2, 0, wxLEFT | wxRIGHT, LRGAP); hbox2->AddStretchSpacer(20); hbox2->Add(b4, 0, wxLEFT | wxRIGHT, LRGAP); hbox2->AddStretchSpacer(20); ssizer1->AddSpacer(SBTOPGAP); ssizer1->Add(hbox1, 1, wxGROW | wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(CH2VGAP); ssizer1->Add(hbox2, 1, wxGROW | wxLEFT | wxRIGHT, LRGAP); ssizer1->AddSpacer(SBBOTGAP); // position things vbox->AddSpacer(SVGAP); vbox->Add(opacitybox, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(S2VGAP); vbox->Add(borderbox, 0, wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(GROUPGAP); vbox->Add(ssizer1, 0, wxGROW | wxALL, 2); vbox->AddSpacer(GROUPGAP); vbox->Add(check5, 0, wxLEFT | wxRIGHT, LRGAP); // init control values spin1->SetRange(1, 100); spin1->SetValue(opacity); spin2->SetRange(1, 10); spin2->SetValue(tileborder); spin1->SetFocus(); spin1->SetSelection(ALL_TEXT); check1->SetValue(askonnew); check2->SetValue(askonload); check3->SetValue(askondelete); check4->SetValue(askonquit); check5->SetValue(warn_on_save); topSizer->Add(vbox, 1, wxGROW | wxALIGN_CENTER | wxALL, 5); panel->SetSizer(topSizer); topSizer->Fit(panel); return panel; } // ----------------------------------------------------------------------------- wxBitmapButton* PrefsDialog::AddColorButton(wxWindow* parent, wxBoxSizer* hbox, int id, wxColor* rgb, const wxString& text) { wxBitmap bitmap(BITMAP_WD, BITMAP_HT); wxMemoryDC dc; dc.SelectObject(bitmap); wxRect rect(0, 0, BITMAP_WD, BITMAP_HT); wxBrush brush(*rgb); FillRect(dc, rect, brush); dc.SelectObject(wxNullBitmap); wxBitmapButton* bb = new wxBitmapButton(parent, id, bitmap, wxPoint(0,0), #if defined(__WXOSX_COCOA__) wxSize(BITMAP_WD + 12, BITMAP_HT + 12)); #else wxDefaultSize); #endif if (bb) { hbox->Add(new wxStaticText(parent, wxID_STATIC, text), 0, wxALIGN_CENTER_VERTICAL, 0); hbox->Add(bb, 0, wxALIGN_CENTER_VERTICAL, 0); } return bb; } // ----------------------------------------------------------------------------- wxPanel* PrefsDialog::CreateColorPrefs(wxWindow* parent) { wxPanel* panel = new wxPanel(parent, wxID_ANY); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); // create a choice menu to select algo wxArrayString algoChoices; for (int i = 0; i < NumAlgos(); i++) { algoChoices.Add( wxString(GetAlgoName(i), wxConvLocal) ); } wxChoice* algomenu = new wxChoice(panel, PREF_ALGO_MENU2, wxDefaultPosition, wxDefaultSize, algoChoices); coloralgo = currlayer->algtype; algomenu->SetSelection(coloralgo); // create bitmap buttons wxBoxSizer* statusbox = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* frombox = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* tobox = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* colorbox = new wxBoxSizer(wxHORIZONTAL); AddColorButton(panel, statusbox, PREF_STATUS_BUTT, &algoinfo[coloralgo]->statusrgb, _("Status bar: ")); frombutt = AddColorButton(panel, frombox, PREF_FROM_BUTT, &algoinfo[coloralgo]->fromrgb, _("")); tobutt = AddColorButton(panel, tobox, PREF_TO_BUTT, &algoinfo[coloralgo]->torgb, _(" to ")); AddColorButton(panel, colorbox, PREF_SELECT_BUTT, selectrgb, _("Selection: ")); // don't use AddSpacer(20) because that will also add 20 *vertical* units! colorbox->AddSpacer(10); colorbox->AddSpacer(10); AddColorButton(panel, colorbox, PREF_PASTE_BUTT, pastergb, _("Paste: ")); // don't use AddSpacer(20) because that will also add 20 *vertical* units! colorbox->AddSpacer(10); colorbox->AddSpacer(10); AddColorButton(panel, colorbox, PREF_BORDER_BUTT, borderrgb, _("Grid border: ")); wxBoxSizer* algobox = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* algolabel = new wxBoxSizer(wxHORIZONTAL); algolabel->Add(new wxStaticText(panel, wxID_STATIC, _("Default colors for:")), 0, FIX_ALIGN_BUG); algobox->Add(algolabel, 0, wxALIGN_CENTER_VERTICAL, 0); algobox->Add(algomenu, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 6); algobox->AddStretchSpacer(); algobox->Add(statusbox, 0, wxALIGN_CENTER_VERTICAL | FIX_ALIGN_BUG); algobox->AddStretchSpacer(); gradcheck = new wxCheckBox(panel, PREF_GRADIENT_CHECK, _("Use gradient from ")); gradcheck->SetValue(algoinfo[coloralgo]->gradient); wxBoxSizer* gradbox = new wxBoxSizer(wxHORIZONTAL); gradbox->Add(gradcheck, 0, wxALIGN_CENTER_VERTICAL, 0); gradbox->Add(frombox, 0, wxALIGN_CENTER_VERTICAL, 0); gradbox->Add(tobox, 0, wxALIGN_CENTER_VERTICAL, 0); gradbox->AddSpacer(10); // create scroll bar filling right part of gradbox wxSize minsize = gradbox->GetMinSize(); int scrollbarwd = NUMCOLS*CELLSIZE+1 - minsize.GetWidth(); #ifdef __WXMAC__ int scrollbarht = 15; // must be this height on Mac #else int scrollbarht = 16; #endif scrollbar = new wxScrollBar(panel, PREF_SCROLL_BAR, wxDefaultPosition, wxSize(scrollbarwd, scrollbarht), wxSB_HORIZONTAL); if (scrollbar == NULL) Fatal(_("Failed to create scroll bar!")); gradbox->Add(scrollbar, 0, wxALIGN_CENTER_VERTICAL, 0); gradstates = algoinfo[coloralgo]->maxstates; UpdateScrollBar(); scrollbar->Enable(algoinfo[coloralgo]->gradient); frombutt->Enable(algoinfo[coloralgo]->gradient); tobutt->Enable(algoinfo[coloralgo]->gradient); // create child window for displaying cell colors/icons cellboxes = new CellBoxes(panel, PREF_CELL_PANEL, wxPoint(0,0), wxSize(NUMCOLS*CELLSIZE+1,NUMROWS*CELLSIZE+1)); iconcheck = new wxCheckBox(panel, PREF_ICON_CHECK, _("Show icons")); iconcheck->SetValue(showicons); wxStaticText* statebox = new wxStaticText(panel, PREF_STATE_BOX, _("999")); cellboxes->statebox = statebox; wxBoxSizer* hbox1 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(statebox, 0, 0, 0); hbox1->SetMinSize( hbox1->GetMinSize() ); wxStaticText* rgbbox = new wxStaticText(panel, PREF_RGB_BOX, _("999,999,999")); cellboxes->rgbbox = rgbbox; wxBoxSizer* hbox2 = new wxBoxSizer(wxHORIZONTAL); hbox2->Add(rgbbox, 0, 0, 0); hbox2->SetMinSize( hbox2->GetMinSize() ); statebox->SetLabel(_(" ")); rgbbox->SetLabel(_(" ")); wxBoxSizer* botbox = new wxBoxSizer(wxHORIZONTAL); botbox->Add(new wxStaticText(panel, wxID_STATIC, _("State: ")), 0, wxALIGN_CENTER_VERTICAL, 0); botbox->Add(hbox1, 0, wxALIGN_CENTER_VERTICAL, 0); botbox->Add(20, 0, 0); botbox->Add(new wxStaticText(panel, wxID_STATIC, _("RGB: ")), 0, wxALIGN_CENTER_VERTICAL, 0); botbox->Add(hbox2, 0, wxALIGN_CENTER_VERTICAL, 0); botbox->AddStretchSpacer(); botbox->Add(iconcheck, 0, wxALIGN_CENTER_VERTICAL, 0); //!!! avoid wxMac bug -- can't click on bitmap buttons inside wxStaticBoxSizer //!!! wxStaticBox* sbox1 = new wxStaticBox(panel, wxID_ANY, _("Cell colors:")); //!!! wxBoxSizer* ssizer1 = new wxStaticBoxSizer(sbox1, wxVERTICAL); wxBoxSizer* ssizer1 = new wxBoxSizer(wxVERTICAL); ssizer1->AddSpacer(10); ssizer1->Add(gradbox, 0, wxLEFT | wxRIGHT, 0); ssizer1->AddSpacer(8); ssizer1->Add(cellboxes, 0, wxLEFT | wxRIGHT, 0); ssizer1->AddSpacer(8); ssizer1->Add(botbox, 1, wxGROW | wxLEFT | wxRIGHT, 0); ssizer1->AddSpacer(SBBOTGAP); wxStaticText* sbox2 = new wxStaticText(panel, wxID_STATIC, _("Global colors used by all algorithms:")); wxBoxSizer* ssizer2 = new wxBoxSizer(wxVERTICAL); ssizer2->Add(sbox2, 0, 0, 0); ssizer2->AddSpacer(10); ssizer2->Add(colorbox, 1, wxGROW | wxLEFT | wxRIGHT, 0); vbox->AddSpacer(5); vbox->Add(algobox, 1, wxGROW | wxLEFT | wxRIGHT, LRGAP); vbox->Add(ssizer1, 0, wxGROW | wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(15); vbox->Add(ssizer2, 0, wxGROW | wxLEFT | wxRIGHT, LRGAP); vbox->AddSpacer(2); topSizer->Add(vbox, 1, wxGROW | wxALIGN_CENTER | wxALL, 5); panel->SetSizer(topSizer); topSizer->Fit(panel); return panel; } // ----------------------------------------------------------------------------- wxPanel* PrefsDialog::CreateKeyboardPrefs(wxWindow* parent) { wxPanel* panel = new wxPanel(parent, wxID_ANY); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); // make sure this is the first control added so it gets focus on a page change KeyComboCtrl* keycombo = new KeyComboCtrl(panel, PREF_KEYCOMBO, wxEmptyString, wxDefaultPosition, wxSize(230, wxDefaultCoord), wxTE_CENTER | wxTE_PROCESS_TAB | wxTE_PROCESS_ENTER // so enter key won't select OK on Windows #ifdef __WXOSX__ // avoid wxTE_RICH2 otherwise we see scroll bar ); #else | wxTE_RICH2 ); // better for Windows #endif wxArrayString actionChoices; for (int i = 0; i < MAX_ACTIONS; i++) { actionChoices.Add( wxString(GetActionName((action_id) i), wxConvLocal) ); } actionChoices[DO_OPENFILE] = _("Open Chosen File"); wxChoice* actionmenu = new wxChoice(panel, PREF_ACTION, wxDefaultPosition, wxDefaultSize, actionChoices); wxBoxSizer* hbox0 = new wxBoxSizer(wxHORIZONTAL); hbox0->Add(new wxStaticText(panel, wxID_STATIC, _("Type a key combination, then select the desired action:"))); wxBoxSizer* keybox = new wxBoxSizer(wxVERTICAL); keybox->Add(new wxStaticText(panel, wxID_STATIC, _("Key Combination")), 0, wxALIGN_CENTER, 0); keybox->AddSpacer(5); keybox->Add(keycombo, 0, wxALIGN_CENTER, 0); wxBoxSizer* actbox = new wxBoxSizer(wxVERTICAL); #if defined(__WXMAC__) && wxCHECK_VERSION(2,8,0) && !wxCHECK_VERSION(2,9,0) actbox->AddSpacer(2); #endif actbox->Add(new wxStaticText(panel, wxID_STATIC, _("Action")), 0, wxALIGN_CENTER, 0); actbox->AddSpacer(5); actbox->Add(actionmenu, 0, wxALIGN_CENTER, 0); wxBoxSizer* hbox1 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(keybox, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, LRGAP); hbox1->AddSpacer(15); hbox1->Add(actbox, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, LRGAP); wxButton* choose = new wxButton(panel, PREF_CHOOSE, _("Choose File...")); wxStaticText* filebox = new wxStaticText(panel, PREF_FILE_BOX, wxEmptyString); wxBoxSizer* hbox2 = new wxBoxSizer(wxHORIZONTAL); hbox2->Add(choose, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, LRGAP); hbox2->Add(filebox, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, LRGAP); wxBoxSizer* midbox = new wxBoxSizer(wxVERTICAL); midbox->Add(hbox1, 0, wxLEFT | wxRIGHT, LRGAP); midbox->AddSpacer(15); midbox->Add(hbox2, 0, wxLEFT, LRGAP); wxString notes = _("Note:"); notes += _("\n- Different key combinations can be assigned to the same action."); notes += _("\n- The Escape key is reserved for hard-wired actions."); wxBoxSizer* hbox3 = new wxBoxSizer(wxHORIZONTAL); hbox3->Add(new wxStaticText(panel, wxID_STATIC, notes)); vbox->AddSpacer(5); vbox->Add(hbox0, 0, wxLEFT, LRGAP); vbox->AddSpacer(15); vbox->Add(midbox, 0, wxALIGN_CENTER, 0); vbox->AddSpacer(30); vbox->Add(hbox3, 0, wxLEFT, LRGAP); // initialize controls keycombo->ChangeValue( GetKeyCombo(currkey, currmods) ); actionmenu->SetSelection( keyaction[currkey][currmods].id ); UpdateChosenFile(); keycombo->SetFocus(); keycombo->SetSelection(ALL_TEXT); topSizer->Add(vbox, 1, wxGROW | wxALIGN_CENTER | wxALL, 5); panel->SetSizer(topSizer); topSizer->Fit(panel); return panel; } // ----------------------------------------------------------------------------- void PrefsDialog::UpdateChosenFile() { wxStaticText* filebox = (wxStaticText*) FindWindowById(PREF_FILE_BOX); if (filebox) { action_id action = keyaction[currkey][currmods].id; if (action == DO_OPENFILE) { // display current file name filebox->SetLabel(keyaction[currkey][currmods].file); } else { // clear file name; don't set keyaction[currkey][currmods].file empty // here because user might change their mind (TransferDataFromWindow // will eventually set the file empty) filebox->SetLabel(wxEmptyString); } } } // ----------------------------------------------------------------------------- void PrefsDialog::OnChoice(wxCommandEvent& event) { int id = event.GetId(); if ( id == PREF_ACTION ) { int i = event.GetSelection(); if (i >= 0 && i < MAX_ACTIONS) { action_id action = (action_id) i; keyaction[currkey][currmods].id = action; if ( action == DO_OPENFILE && keyaction[currkey][currmods].file.IsEmpty() ) { // call OnButton (which will call UpdateChosenFile) wxCommandEvent buttevt(wxEVT_COMMAND_BUTTON_CLICKED, PREF_CHOOSE); OnButton(buttevt); } else { UpdateChosenFile(); } } } else if ( id == PREF_ALGO_MENU1 ) { int i = event.GetSelection(); if (i >= 0 && i < NumAlgos() && i != algopos1) { // first update values for previous selection new_algomem[algopos1] = GetSpinVal(PREF_MAX_MEM); new_defbase[algopos1] = GetSpinVal(PREF_BASE_STEP); algopos1 = i; // show values for new selection wxSpinCtrl* s1 = (wxSpinCtrl*) FindWindowById(PREF_MAX_MEM); wxSpinCtrl* s2 = (wxSpinCtrl*) FindWindowById(PREF_BASE_STEP); if (s1 && s2) { s1->SetValue(new_algomem[algopos1]); s2->SetValue(new_defbase[algopos1]); wxWindow* focus = FindFocus(); #ifdef __WXMAC__ // FindFocus returns pointer to text ctrl wxTextCtrl* t1 = s1->GetText(); wxTextCtrl* t2 = s2->GetText(); if (focus == t1) { s1->SetFocus(); s1->SetSelection(ALL_TEXT); } if (focus == t2) { s2->SetFocus(); s2->SetSelection(ALL_TEXT); } #else // probably pointless -- pop-up menu has focus on Win & Linux??? if (focus == s1) { s1->SetFocus(); s1->SetSelection(ALL_TEXT); } if (focus == s2) { s2->SetFocus(); s2->SetSelection(ALL_TEXT); } #endif } // change comments depending on whether or not algo uses hashing wxStaticText* membox = (wxStaticText*) FindWindowById(PREF_MEM_NOTE); wxStaticText* stepbox = (wxStaticText*) FindWindowById(PREF_STEP_NOTE); if (membox && stepbox) { if (algoinfo[algopos1]->canhash) { membox->SetLabel(HASH_MEM_NOTE); stepbox->SetLabel(HASH_STEP_NOTE); } else { membox->SetLabel(NONHASH_MEM_NOTE); stepbox->SetLabel(NONHASH_STEP_NOTE); } } } } else if ( id == PREF_ALGO_MENU2 ) { int i = event.GetSelection(); if (i >= 0 && i < NumAlgos() && i != coloralgo) { coloralgo = i; AlgoData* ad = algoinfo[coloralgo]; // update colors in some bitmap buttons UpdateButtonColor(PREF_STATUS_BUTT, ad->statusrgb); UpdateButtonColor(PREF_FROM_BUTT, ad->fromrgb); UpdateButtonColor(PREF_TO_BUTT, ad->torgb); gradstates = ad->maxstates; UpdateScrollBar(); gradcheck->SetValue(ad->gradient); scrollbar->Enable(ad->gradient); frombutt->Enable(ad->gradient); tobutt->Enable(ad->gradient); cellboxes->Refresh(false); } } } // ----------------------------------------------------------------------------- void ChooseTextEditor(wxWindow* parent, wxString& result) { #ifdef __WXMSW__ wxString filetypes = _("Applications (*.exe)|*.exe"); #elif defined(__WXMAC__) wxString filetypes = _("Applications (*.app)|*.app"); #else // assume Linux wxString filetypes = _("All files (*)|*"); #endif wxFileDialog opendlg(parent, _("Choose a text editor"), wxEmptyString, wxEmptyString, filetypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST); #ifdef __WXMSW__ opendlg.SetDirectory(_("C:\\Program Files")); #elif defined(__WXMAC__) opendlg.SetDirectory(_("/Applications")); #else // assume Linux opendlg.SetDirectory(_("/usr/bin")); #endif if ( opendlg.ShowModal() == wxID_OK ) { result = opendlg.GetPath(); } else { result = wxEmptyString; } } // ----------------------------------------------------------------------------- void PrefsDialog::OnButton(wxCommandEvent& event) { int id = event.GetId(); if ( id == PREF_CHOOSE ) { // ask user to choose an appropriate file wxString filetypes = _("All files (*)|*"); filetypes += _("|Pattern (*.rle;*.mc;*.lif)|*.rle;*.mc;*.lif"); filetypes += _("|Script (*.pl;*.py)|*.pl;*.py"); filetypes += _("|HTML (*.html;*.htm)|*.html;*.htm"); wxFileDialog opendlg(this, _("Choose a pattern, script or HTML file"), choosedir, wxEmptyString, filetypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST); #ifdef __WXGTK__ // choosedir is ignored above (bug in wxGTK 2.8.0???) opendlg.SetDirectory(choosedir); #endif if ( opendlg.ShowModal() == wxID_OK ) { wxFileName fullpath( opendlg.GetPath() ); choosedir = fullpath.GetPath(); wxString path = opendlg.GetPath(); if (path.StartsWith(gollydir)) { // remove gollydir from start of path path.erase(0, gollydir.length()); } keyaction[currkey][currmods].file = path; keyaction[currkey][currmods].id = DO_OPENFILE; wxChoice* actionmenu = (wxChoice*) FindWindowById(PREF_ACTION); if (actionmenu) { actionmenu->SetSelection(DO_OPENFILE); } } UpdateChosenFile(); } else if ( id == PREF_EDITOR_BUTT ) { // ask user to choose a text editor wxString result; ChooseTextEditor(this, result); if ( !result.IsEmpty() ) { neweditor = result; wxStaticText* editorbox = (wxStaticText*) FindWindowById(PREF_EDITOR_BOX); if (editorbox) { editorbox->SetLabel(neweditor); } } } else if ( id == PREF_DOWNLOAD_BUTT ) { // ask user to choose folder for downloaded files wxDirDialog dirdlg(this, _("Choose a folder for downloaded files"), newdownloaddir, wxDD_NEW_DIR_BUTTON); if ( dirdlg.ShowModal() == wxID_OK ) { wxString newdir = dirdlg.GetPath(); if (newdir.Last() != wxFILE_SEP_PATH) newdir += wxFILE_SEP_PATH; if (newdownloaddir != newdir) { newdownloaddir = newdir; wxStaticText* dirbox = (wxStaticText*) FindWindowById(PREF_DOWNLOAD_BOX); if (dirbox) { dirbox->SetLabel(newdownloaddir); } } } } else if ( id == PREF_RULES_BUTT ) { // ask user to choose folder for their rules wxDirDialog dirdlg(this, _("Choose a folder for your rules"), newuserrules, wxDD_NEW_DIR_BUTTON); if ( dirdlg.ShowModal() == wxID_OK ) { wxString newdir = dirdlg.GetPath(); if (newdir.Last() != wxFILE_SEP_PATH) newdir += wxFILE_SEP_PATH; if (newuserrules != newdir) { newuserrules = newdir; wxStaticText* dirbox = (wxStaticText*) FindWindowById(PREF_RULES_BOX); if (dirbox) { dirbox->SetLabel(newuserrules); } } } } event.Skip(); // need this so other buttons work correctly } // ----------------------------------------------------------------------------- void PrefsDialog::OnCheckBoxClicked(wxCommandEvent& event) { int id = event.GetId(); if ( id == PREF_SHOW_BOLD ) { // enable/disable PREF_BOLD_SPACING spin control wxCheckBox* checkbox = (wxCheckBox*) FindWindow(PREF_SHOW_BOLD); wxSpinCtrl* spinctrl = (wxSpinCtrl*) FindWindow(PREF_BOLD_SPACING); if (checkbox && spinctrl) { bool ticked = checkbox->GetValue(); spinctrl->Enable(ticked); if (ticked) spinctrl->SetFocus(); } } else if ( id == PREF_GRADIENT_CHECK ) { AlgoData* ad = algoinfo[coloralgo]; ad->gradient = gradcheck->GetValue() == 1; scrollbar->Enable(ad->gradient); frombutt->Enable(ad->gradient); tobutt->Enable(ad->gradient); cellboxes->Refresh(false); } else if ( id == PREF_ICON_CHECK ) { showicons = iconcheck->GetValue() == 1; cellboxes->Refresh(false); } } // ----------------------------------------------------------------------------- void PrefsDialog::UpdateButtonColor(int id, wxColor& rgb) { wxBitmapButton* bb = (wxBitmapButton*) FindWindow(id); if (bb) { wxBitmap bitmap(BITMAP_WD, BITMAP_HT); wxMemoryDC dc; dc.SelectObject(bitmap); wxRect rect(0, 0, BITMAP_WD, BITMAP_HT); wxBrush brush(rgb); FillRect(dc, rect, brush); dc.SelectObject(wxNullBitmap); bb->SetBitmapLabel(bitmap); bb->Refresh(); } } // ----------------------------------------------------------------------------- void PrefsDialog::ChangeButtonColor(int id, wxColor& rgb) { wxColourData data; data.SetChooseFull(true); // for Windows data.SetColour(rgb); wxColourDialog dialog(this, &data); if ( dialog.ShowModal() == wxID_OK ) { wxColourData retData = dialog.GetColourData(); wxColour c = retData.GetColour(); if (rgb != c) { // change given color rgb.Set(c.Red(), c.Green(), c.Blue()); // also change color of bitmap in corresponding button UpdateButtonColor(id, rgb); if (id == PREF_FROM_BUTT || id == PREF_TO_BUTT) { cellboxes->Refresh(false); } } } } // ----------------------------------------------------------------------------- void PrefsDialog::OnColorButton(wxCommandEvent& event) { int id = event.GetId(); if ( id == PREF_STATUS_BUTT ) { ChangeButtonColor(id, algoinfo[coloralgo]->statusrgb); } else if ( id == PREF_FROM_BUTT ) { ChangeButtonColor(id, algoinfo[coloralgo]->fromrgb); } else if ( id == PREF_TO_BUTT ) { ChangeButtonColor(id, algoinfo[coloralgo]->torgb); } else if ( id == PREF_SELECT_BUTT ) { ChangeButtonColor(id, *selectrgb); } else if ( id == PREF_PASTE_BUTT ) { ChangeButtonColor(id, *pastergb); } else if ( id == PREF_BORDER_BUTT ) { ChangeButtonColor(id, *borderrgb); } else { // process other buttons like Cancel and OK event.Skip(); } } // ----------------------------------------------------------------------------- void PrefsDialog::UpdateScrollBar() { AlgoData* ad = algoinfo[coloralgo]; scrollbar->SetScrollbar(gradstates - ad->minstates, 1, ad->maxstates - ad->minstates + 1, // range PAGESIZE, true); } // ----------------------------------------------------------------------------- void PrefsDialog::OnScroll(wxScrollEvent& event) { WXTYPE type = event.GetEventType(); if (type == wxEVT_SCROLL_LINEUP) { gradstates--; if (gradstates < algoinfo[coloralgo]->minstates) gradstates = algoinfo[coloralgo]->minstates; cellboxes->Refresh(false); } else if (type == wxEVT_SCROLL_LINEDOWN) { gradstates++; if (gradstates > algoinfo[coloralgo]->maxstates) gradstates = algoinfo[coloralgo]->maxstates; cellboxes->Refresh(false); } else if (type == wxEVT_SCROLL_PAGEUP) { gradstates -= PAGESIZE; if (gradstates < algoinfo[coloralgo]->minstates) gradstates = algoinfo[coloralgo]->minstates; cellboxes->Refresh(false); } else if (type == wxEVT_SCROLL_PAGEDOWN) { gradstates += PAGESIZE; if (gradstates > algoinfo[coloralgo]->maxstates) gradstates = algoinfo[coloralgo]->maxstates; cellboxes->Refresh(false); } else if (type == wxEVT_SCROLL_THUMBTRACK) { gradstates = algoinfo[coloralgo]->minstates + event.GetPosition(); if (gradstates < algoinfo[coloralgo]->minstates) gradstates = algoinfo[coloralgo]->minstates; if (gradstates > algoinfo[coloralgo]->maxstates) gradstates = algoinfo[coloralgo]->maxstates; cellboxes->Refresh(false); } else if (type == wxEVT_SCROLL_THUMBRELEASE) { UpdateScrollBar(); } } // ----------------------------------------------------------------------------- bool PrefsDialog::GetCheckVal(long id) { wxCheckBox* checkbox = (wxCheckBox*) FindWindow(id); if (checkbox) { return checkbox->GetValue(); } else { Warning(_("Bug in GetCheckVal!")); return false; } } // ----------------------------------------------------------------------------- int PrefsDialog::GetChoiceVal(long id) { wxChoice* choice = (wxChoice*) FindWindow(id); if (choice) { return choice->GetSelection(); } else { Warning(_("Bug in GetChoiceVal!")); return 0; } } // ----------------------------------------------------------------------------- int PrefsDialog::GetRadioVal(long firstid, int numbuttons) { for (int i = 0; i < numbuttons; i++) { wxRadioButton* radio = (wxRadioButton*) FindWindow(firstid + i); if (radio->GetValue()) return i; } Warning(_("Bug in GetRadioVal!")); return 0; } // ----------------------------------------------------------------------------- int PrefsDialog::GetSpinVal(long id) { wxSpinCtrl* spinctrl = (wxSpinCtrl*) FindWindow(id); if (spinctrl) { return spinctrl->GetValue(); } else { Warning(_("Bug in GetSpinVal!")); return 0; } } // ----------------------------------------------------------------------------- bool PrefsDialog::BadSpinVal(int id, int minval, int maxval, const wxString& prefix) { wxSpinCtrl* spinctrl = (wxSpinCtrl*) FindWindow(id); // spinctrl->GetValue() always returns a value within range even if // the text ctrl doesn't contain a valid number -- yuk! int i = spinctrl->GetValue(); if (i < minval || i > maxval) { wxString msg; msg.Printf(_("%s must be from %d to %d."), prefix.c_str(), minval, maxval); Warning(msg); spinctrl->SetFocus(); spinctrl->SetSelection(ALL_TEXT); return true; } else { return false; } } // ----------------------------------------------------------------------------- bool PrefsDialog::ValidatePage() { // validate all spin control values on current page if (currpage == FILE_PAGE) { if ( BadSpinVal(PREF_MAX_PATTERNS, 1, MAX_RECENT, _("Maximum number of recent patterns")) ) return false; if ( BadSpinVal(PREF_MAX_SCRIPTS, 1, MAX_RECENT, _("Maximum number of recent scripts")) ) return false; } else if (currpage == EDIT_PAGE) { if ( BadSpinVal(PREF_RANDOM_FILL, 1, 100, _("Random fill percentage")) ) return false; } else if (currpage == CONTROL_PAGE) { if ( BadSpinVal(PREF_MAX_MEM, MIN_MEM_MB, MAX_MEM_MB, _("Maximum memory")) ) return false; if ( BadSpinVal(PREF_BASE_STEP, 2, MAX_BASESTEP, _("Default base step")) ) return false; if ( BadSpinVal(PREF_MIN_DELAY, 0, MAX_DELAY, _("Minimum delay")) ) return false; if ( BadSpinVal(PREF_MAX_DELAY, 0, MAX_DELAY, _("Maximum delay")) ) return false; } else if (currpage == VIEW_PAGE) { if ( BadSpinVal(PREF_BOLD_SPACING, 2, MAX_SPACING, _("Spacing of bold grid lines")) ) return false; if ( BadSpinVal(PREF_THUMB_RANGE, 2, MAX_THUMBRANGE, _("Thumb scrolling range")) ) return false; } else if (currpage == LAYER_PAGE) { if ( BadSpinVal(PREF_OPACITY, 1, 100, _("Percentage opacity")) ) return false; if ( BadSpinVal(PREF_TILE_BORDER, 1, 10, _("Tile border thickness")) ) return false; } else if (currpage == COLOR_PAGE) { // no spin ctrls on this page } else if (currpage == KEYBOARD_PAGE) { // no spin ctrls on this page } else { Warning(_("Bug in ValidatePage!")); return false; } return true; } // ----------------------------------------------------------------------------- void PrefsDialog::OnPageChanging(wxNotebookEvent& event) { if (ignore_page_event) return; // validate current page and veto change if invalid if (!ValidatePage()) event.Veto(); } // ----------------------------------------------------------------------------- void PrefsDialog::OnPageChanged(wxNotebookEvent& event) { if (ignore_page_event) return; currpage = event.GetSelection(); #ifdef __WXMSW__ // ensure key combo box has focus if (currpage == KEYBOARD_PAGE) { KeyComboCtrl* keycombo = (KeyComboCtrl*) FindWindowById(PREF_KEYCOMBO); if (keycombo) { keycombo->SetFocus(); keycombo->SetSelection(ALL_TEXT); } } #endif } // ----------------------------------------------------------------------------- bool PrefsDialog::TransferDataFromWindow() { if (!ValidatePage()) return false; // set global prefs to current control values // FILE_PAGE newremovesel = GetCheckVal(PREF_NEW_REM_SEL); newcursindex = GetChoiceVal(PREF_NEW_CURSOR); newmag = GetChoiceVal(PREF_NEW_SCALE); openremovesel = GetCheckVal(PREF_OPEN_REM_SEL); opencursindex = GetChoiceVal(PREF_OPEN_CURSOR); maxpatterns = GetSpinVal(PREF_MAX_PATTERNS); maxscripts = GetSpinVal(PREF_MAX_SCRIPTS); texteditor = neweditor; downloaddir = newdownloaddir; // EDIT_PAGE randomfill = GetSpinVal(PREF_RANDOM_FILL); canchangerule = GetRadioVal(PREF_PASTE_0, 3); scrollpencil = GetCheckVal(PREF_SCROLL_PENCIL); scrollcross = GetCheckVal(PREF_SCROLL_CROSS); scrollhand = GetCheckVal(PREF_SCROLL_HAND); allowbeep = GetCheckVal(PREF_BEEP); // CONTROL_PAGE new_algomem[algopos1] = GetSpinVal(PREF_MAX_MEM); new_defbase[algopos1] = GetSpinVal(PREF_BASE_STEP); for (int i = 0; i < NumAlgos(); i++) { algoinfo[i]->algomem = new_algomem[i]; algoinfo[i]->defbase = new_defbase[i]; } mindelay = GetSpinVal(PREF_MIN_DELAY); maxdelay = GetSpinVal(PREF_MAX_DELAY); userrules = newuserrules; // VIEW_PAGE #if wxUSE_TOOLTIPS showtips = GetCheckVal(PREF_SHOW_TIPS); wxToolTip::Enable(showtips); #endif restoreview = GetCheckVal(PREF_RESTORE); mathcoords = GetCheckVal(PREF_Y_UP); showboldlines = GetCheckVal(PREF_SHOW_BOLD); boldspacing = GetSpinVal(PREF_BOLD_SPACING); mingridindex = GetChoiceVal(PREF_MIN_GRID_SCALE); mousewheelmode = GetChoiceVal(PREF_MOUSE_WHEEL); thumbrange = GetSpinVal(PREF_THUMB_RANGE); controlspos = GetRadioVal(PREF_NO_CONTROLS, 5); // LAYER_PAGE opacity = GetSpinVal(PREF_OPACITY); tileborder = GetSpinVal(PREF_TILE_BORDER); askonnew = GetCheckVal(PREF_ASK_NEW); askonload = GetCheckVal(PREF_ASK_LOAD); askondelete = GetCheckVal(PREF_ASK_DELETE); askonquit = GetCheckVal(PREF_ASK_QUIT); warn_on_save = GetCheckVal(PREF_WARN_SAVE); // COLOR_PAGE // no need to validate anything // KEYBOARD_PAGE // go thru keyaction table and make sure the file field is empty // if the action isn't DO_OPENFILE for (int key = 0; key < MAX_KEYCODES; key++) for (int modset = 0; modset < MAX_MODS; modset++) if ( keyaction[key][modset].id != DO_OPENFILE && !keyaction[key][modset].file.IsEmpty() ) keyaction[key][modset].file = wxEmptyString; // update globals corresponding to some wxChoice menu selections mingridmag = mingridindex + 2; newcurs = IndexToCursor(newcursindex); opencurs = IndexToCursor(opencursindex); return true; } // ----------------------------------------------------------------------------- // class for saving and restoring AlgoData color info in ChangePrefs() class SaveColorInfo { public: SaveColorInfo(int algo) { AlgoData* ad = algoinfo[algo]; statusrgb = ad->statusrgb; gradient = ad->gradient; fromrgb = ad->fromrgb; torgb = ad->torgb; for (int i = 0; i < ad->maxstates; i++) { algor[i] = ad->algor[i]; algog[i] = ad->algog[i]; algob[i] = ad->algob[i]; } } void RestoreColorInfo(int algo) { AlgoData* ad = algoinfo[algo]; ad->statusrgb = statusrgb; ad->gradient = gradient; ad->fromrgb = fromrgb; ad->torgb = torgb; for (int i = 0; i < ad->maxstates; i++) { ad->algor[i] = algor[i]; ad->algog[i] = algog[i]; ad->algob[i] = algob[i]; } } bool ColorInfoChanged(int algo) { AlgoData* ad = algoinfo[algo]; // ignore ad->statusrgb if (ad->gradient != gradient) return true; if (gradient && ad->fromrgb != fromrgb) return true; if (gradient && ad->torgb != torgb) return true; for (int i = 0; i < ad->maxstates; i++) { if (ad->algor[i] != algor[i]) return true; if (ad->algog[i] != algog[i]) return true; if (ad->algob[i] != algob[i]) return true; } // get here if there was no change return false; } // this must match color info in AlgoData wxColor statusrgb; bool gradient; wxColor fromrgb; wxColor torgb; unsigned char algor[256]; unsigned char algog[256]; unsigned char algob[256]; }; // ----------------------------------------------------------------------------- bool ChangePrefs(const wxString& page) { // save current keyboard shortcuts so we can restore them or detect a change action_info savekeyaction[MAX_KEYCODES][MAX_MODS]; for (int key = 0; key < MAX_KEYCODES; key++) for (int modset = 0; modset < MAX_MODS; modset++) savekeyaction[key][modset] = keyaction[key][modset]; bool wasswapped = swapcolors; if (swapcolors) { swapcolors = false; InvertCellColors(); mainptr->UpdateEverything(); } // save current color info so we can restore it if user cancels changes wxColor save_selectrgb = *selectrgb; wxColor save_pastergb = *pastergb; wxColor save_borderrgb = *borderrgb; SaveColorInfo* save_info[MAX_ALGOS]; for (int i = 0; i < NumAlgos(); i++) { save_info[i] = new SaveColorInfo(i); } // save showicons option in case user cancels dialog bool saveshowicons = showicons; // save the default base step for the current layer's algo so we can detect a change int old_defbase = algoinfo[currlayer->algtype]->defbase; PrefsDialog dialog(mainptr, page); bool result; if (dialog.ShowModal() == wxID_OK) { // TransferDataFromWindow has validated and updated all global prefs; // if a keyboard shortcut changed then update menu item accelerators for (int key = 0; key < MAX_KEYCODES; key++) for (int modset = 0; modset < MAX_MODS; modset++) if (savekeyaction[key][modset].id != keyaction[key][modset].id) { // first update accelerator array UpdateAcceleratorStrings(); mainptr->UpdateMenuAccelerators(); goto done; } done: // if the default base step for the current layer's algo changed // then reset the current base step (this should result in less confusion) if (old_defbase != algoinfo[currlayer->algtype]->defbase) { currlayer->currbase = algoinfo[currlayer->algtype]->defbase; mainptr->SetGenIncrement(); } // if the default colors/icons for the current layer's algo changed // then reset the current layer's colors (and any clones) if (save_info[currlayer->algtype]->ColorInfoChanged(currlayer->algtype)) { UpdateLayerColors(); } result = true; } else { // user hit Cancel, so restore keyaction array in case it was changed for (int key = 0; key < MAX_KEYCODES; key++) for (int modset = 0; modset < MAX_MODS; modset++) keyaction[key][modset] = savekeyaction[key][modset]; // restore color info saved above *selectrgb = save_selectrgb; *pastergb = save_pastergb; *borderrgb = save_borderrgb; for (int i = 0; i < NumAlgos(); i++) { save_info[i]->RestoreColorInfo(i); } // restore showicons option showicons = saveshowicons; result = false; } // update colors for global brushes and pens SetBrushesAndPens(); for (int i = 0; i < NumAlgos(); i++) { delete save_info[i]; } if (wasswapped) { swapcolors = true; InvertCellColors(); // let caller do this // mainptr->UpdateEverything(); } return result; } golly-2.7-src/gui-wx/wxalgos.cpp0000644000175000017500000010307312536111364013634 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/filename.h" // for wxFileName #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "generationsalgo.h" #include "jvnalgo.h" #include "ruleloaderalgo.h" #include "wxgolly.h" // for wxGetApp #include "wxmain.h" // for ID_ALGO0 #include "wxutils.h" // for Fatal, Warning #include "wxprefs.h" // for gollydir #include "wxlayer.h" // for currlayer #include "wxalgos.h" // ----------------------------------------------------------------------------- // exported data: wxMenu* algomenu; // menu of algorithm names wxMenu* algomenupop; // copy of algomenu for PopupMenu calls algo_type initalgo = QLIFE_ALGO; // initial layer's algorithm AlgoData* algoinfo[MAX_ALGOS]; // static info for each algorithm wxBitmap** circles7x7; // circular icons for scale 1:8 wxBitmap** circles15x15; // circular icons for scale 1:16 wxBitmap** circles31x31; // circular icons for scale 1:32 wxBitmap** diamonds7x7; // diamond-shaped icons for scale 1:8 wxBitmap** diamonds15x15; // diamond-shaped icons for scale 1:16 wxBitmap** diamonds31x31; // diamond-shaped icons for scale 1:32 wxBitmap** hexagons7x7; // hexagonal icons for scale 1:8 wxBitmap** hexagons15x15; // hexagonal icons for scale 1:16 wxBitmap** hexagons31x31; // hexagonal icons for scale 1:32 wxBitmap** triangles7x7; // triangular icons for scale 1:8 wxBitmap** triangles15x15; // triangular icons for scale 1:16 wxBitmap** triangles31x31; // triangular icons for scale 1:32 // ----------------------------------------------------------------------------- // These default cell colors were generated by continuously finding the // color furthest in rgb space from the closest of the already selected // colors, black, and white. static unsigned char default_colors[] = { 48,48,48, // better if state 0 is dark gray (was 255,127,0) 0,255,127,127,0,255,148,148,148,128,255,0,255,0,128, 0,128,255,1,159,0,159,0,1,255,254,96,0,1,159,96,255,254, 254,96,255,126,125,21,21,126,125,125,21,126,255,116,116,116,255,116, 116,116,255,228,227,0,28,255,27,255,27,28,0,228,227,227,0,228, 27,28,255,59,59,59,234,195,176,175,196,255,171,194,68,194,68,171, 68,171,194,72,184,71,184,71,72,71,72,184,169,255,188,252,179,63, 63,252,179,179,63,252,80,9,0,0,80,9,9,0,80,255,175,250, 199,134,213,115,100,95,188,163,0,0,188,163,163,0,188,203,73,0, 0,203,73,73,0,203,94,189,0,189,0,94,0,94,189,187,243,119, 55,125,32,125,32,55,32,55,125,255,102,185,102,185,255,120,209,168, 208,166,119,135,96,192,182,255,41,83,153,130,247,88,55,89,247,55, 88,55,247,87,75,0,0,87,75,75,0,87,200,135,59,51,213,127, 255,255,162,255,37,182,37,182,255,228,57,117,142,163,210,57,117,228, 193,255,246,188,107,123,123,194,107,145,59,5,5,145,59,59,5,145, 119,39,198,40,197,23,197,23,40,23,40,197,178,199,158,255,201,121, 134,223,223,39,253,84,149,203,15,203,15,149,15,149,203,152,144,90, 143,75,139,71,97,132,224,65,219,65,219,224,255,255,40,218,223,69, 74,241,0,241,0,74,0,74,241,122,171,51,220,211,227,61,127,87, 90,124,176,36,39,13,165,142,255,255,38,255,38,255,255,83,50,107, 224,142,165,255,181,9,9,255,181,181,9,255,140,238,70,255,74,5, 74,5,255,138,84,51,31,172,101,177,115,17,221,0,0,0,221,0, 0,0,221,220,255,200,0,41,50,255,150,205,178,45,116,113,255,189, 47,0,44,40,119,171,205,107,255,177,115,172,133,73,236,109,0,168, 168,46,207,188,181,203,212,188,35,90,97,52,39,209,184,41,164,152, 227,46,70,46,70,227,211,156,255,98,146,222,136,56,95,102,54,152, 86,142,0,142,0,86,0,86,142,86,223,96,246,135,46,4,208,120, 212,233,158,177,92,214,104,147,88,149,240,147,227,93,148,72,255,133, 209,27,194,147,255,255,44,93,0,160,36,158,182,233,0,96,94,217, 218,103,88,163,154,38,118,114,139,94,0,43,113,164,174,168,188,114, 0,23,119,42,86,93,255,226,202,80,191,155,255,158,136,0,247,62, 234,146,88,0,183,229,110,212,36,0,143,161,105,191,210,133,164,0, 41,30,89,164,0,132,30,89,42,178,222,217,121,22,11,221,107,22, 69,151,255,45,158,3,158,3,45,3,45,158,86,42,29,9,122,22, 213,209,110,53,221,57,159,101,91,93,140,45,247,213,37,185,34,0, 0,185,34,34,0,185,236,0,172,210,180,78,231,107,221,162,49,43, 43,162,49,49,43,162,36,248,213,114,0,214,213,36,248,149,34,243, 185,158,167,144,122,224,34,245,149,255,31,98,31,98,255,152,200,193, 255,80,95,128,123,63,102,62,72,255,62,148,151,226,108,159,99,255, 226,255,126,98,223,136,80,95,255,225,153,15,73,41,211,212,71,41, 83,217,187,180,235,79,0,166,127,251,135,243,229,41,0,41,0,229, 82,255,216,141,174,249,249,215,255,167,31,79,31,79,167,213,102,185, 255,215,83,4,2,40,224,171,220,41,0,4,6,50,90,221,15,113, 15,113,221,33,0,115,108,23,90,182,215,36 }; // ----------------------------------------------------------------------------- // Note that all the default icons are grayscale bitmaps. // These icons are used for lots of different rules with different numbers // of states, and at rendering time we will replace the white pixels in each // icon with the cell's state color to avoid "color shock" when switching // between icon and non-icon view. Gray pixels are used to do anti-aliasing. // XPM data for default 7x7 icon static const char* default7x7[] = { // width height ncolors chars_per_pixel "7 7 4 1", // colors ". c #000000", // black will be transparent "D c #404040", "E c #E0E0E0", "W c #FFFFFF", // white // pixels ".DEWED.", "DWWWWWD", "EWWWWWE", "WWWWWWW", "EWWWWWE", "DWWWWWD", ".DEWED." }; // XPM data for default 15x15 icon static const char* default15x15[] = { // width height ncolors chars_per_pixel "15 15 5 1", // colors ". c #000000", // black will be transparent "D c #404040", "C c #808080", "B c #C0C0C0", "W c #FFFFFF", // white // pixels "...............", "....DBWWWBD....", "...BWWWWWWWB...", "..BWWWWWWWWWB..", ".DWWWWWWWWWWWD.", ".BWWWWWWWWWWWB.", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", ".BWWWWWWWWWWWB.", ".DWWWWWWWWWWWD.", "..BWWWWWWWWWB..", "...BWWWWWWWB...", "....DBWWWBD....", "..............." }; // XPM data for default 31x31 icon static const char* default31x31[] = { // width height ncolors chars_per_pixel "31 31 5 1", // colors ". c #000000", // black will be transparent "D c #404040", "C c #808080", "B c #C0C0C0", "W c #FFFFFF", // white // pixels "...............................", "...............................", "..........DCBWWWWWBCD..........", ".........CWWWWWWWWWWWC.........", ".......DWWWWWWWWWWWWWWWD.......", "......BWWWWWWWWWWWWWWWWWB......", ".....BWWWWWWWWWWWWWWWWWWWB.....", "....DWWWWWWWWWWWWWWWWWWWWWD....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...CWWWWWWWWWWWWWWWWWWWWWWWC...", "..DWWWWWWWWWWWWWWWWWWWWWWWWWD..", "..CWWWWWWWWWWWWWWWWWWWWWWWWWC..", "..BWWWWWWWWWWWWWWWWWWWWWWWWWB..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..BWWWWWWWWWWWWWWWWWWWWWWWWWB..", "..CWWWWWWWWWWWWWWWWWWWWWWWWWC..", "..DWWWWWWWWWWWWWWWWWWWWWWWWWD..", "...CWWWWWWWWWWWWWWWWWWWWWWWC...", "....WWWWWWWWWWWWWWWWWWWWWWW....", "....DWWWWWWWWWWWWWWWWWWWWWD....", ".....BWWWWWWWWWWWWWWWWWWWB.....", "......BWWWWWWWWWWWWWWWWWB......", ".......DWWWWWWWWWWWWWWWD.......", ".........CWWWWWWWWWWWC.........", "..........DCBWWWWWBCD..........", "...............................", "..............................." }; // XPM data for the 7x7 icon used for hexagonal CA static const char* hex7x7[] = { // width height ncolors chars_per_pixel "7 7 3 1", // colors ". c #000000", // black will be transparent "C c #808080", "W c #FFFFFF", // white // pixels ".WWC...", "WWWWW..", "WWWWWW.", "CWWWWWC", ".WWWWWW", "..WWWWW", "...CWW."}; // XPM data for the 15x15 icon used for hexagonal CA static const char* hex15x15[] = { // width height ncolors chars_per_pixel "15 15 3 1", // colors ". c #000000", // black will be transparent "C c #808080", "W c #FFFFFF", // white // pixels "...WWC.........", "..WWWWWC.......", ".WWWWWWWWC.....", "WWWWWWWWWWW....", "WWWWWWWWWWWW...", "CWWWWWWWWWWWC..", ".WWWWWWWWWWWW..", ".CWWWWWWWWWWWC.", "..WWWWWWWWWWWW.", "..CWWWWWWWWWWWC", "...WWWWWWWWWWWW", "....WWWWWWWWWWW", ".....CWWWWWWWW.", ".......CWWWWW..", ".........CWW..."}; // XPM data for 31x31 icon used for hexagonal CA static const char* hex31x31[] = { // width height ncolors chars_per_pixel "31 31 3 1", // colors ". c #000000", // black will be transparent "C c #808080", "W c #FFFFFF", // white // pixels ".....WWC.......................", "....WWWWWC.....................", "...WWWWWWWWC...................", "..WWWWWWWWWWWC.................", ".WWWWWWWWWWWWWWC...............", "WWWWWWWWWWWWWWWWWC.............", "WWWWWWWWWWWWWWWWWWWC...........", "CWWWWWWWWWWWWWWWWWWWWC.........", ".WWWWWWWWWWWWWWWWWWWWWW........", ".CWWWWWWWWWWWWWWWWWWWWWC.......", "..WWWWWWWWWWWWWWWWWWWWWW.......", "..CWWWWWWWWWWWWWWWWWWWWWC......", "...WWWWWWWWWWWWWWWWWWWWWW......", "...CWWWWWWWWWWWWWWWWWWWWWC.....", "....WWWWWWWWWWWWWWWWWWWWWW.....", "....CWWWWWWWWWWWWWWWWWWWWWC....", ".....WWWWWWWWWWWWWWWWWWWWWW....", ".....CWWWWWWWWWWWWWWWWWWWWWC...", "......WWWWWWWWWWWWWWWWWWWWWW...", "......CWWWWWWWWWWWWWWWWWWWWWC..", ".......WWWWWWWWWWWWWWWWWWWWWW..", ".......CWWWWWWWWWWWWWWWWWWWWWC.", "........WWWWWWWWWWWWWWWWWWWWWW.", ".........CWWWWWWWWWWWWWWWWWWWWC", "...........CWWWWWWWWWWWWWWWWWWW", ".............CWWWWWWWWWWWWWWWWW", "...............CWWWWWWWWWWWWWW.", ".................CWWWWWWWWWWW..", "...................CWWWWWWWW...", ".....................CWWWWW....", ".......................CWW....." }; // XPM data for the 7x7 icon used for von Neumann CA static const char* vn7x7[] = { // width height ncolors chars_per_pixel "7 7 2 1", // colors ". c #000000", // black will be transparent "W c #FFFFFF", // white // pixels "...W...", "..WWW..", ".WWWWW.", "WWWWWWW", ".WWWWW.", "..WWW..", "...W..." }; // XPM data for the 15x15 icon used for von Neumann CA static const char* vn15x15[] = { // width height ncolors chars_per_pixel "15 15 2 1", // colors ". c #000000", // black will be transparent "W c #FFFFFF", // white // pixels "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWWWWWWWWW..", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "..............." }; // XPM data for 31x31 icon used for von Neumann CA static const char* vn31x31[] = { // width height ncolors chars_per_pixel "31 31 2 1", // colors ". c #000000", // black will be transparent "W c #FFFFFF", // white // pixels "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "....WWWWWWWWWWWWWWWWWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "..............................." }; // XPM data for the 7x7 icons used by 4-state rules emulating a triangular neighborhood static const char* tri7x7[] = { // width height ncolors chars_per_pixel "7 21 2 1", // colors ". c #000000", // black will be transparent "W c #FFFFFF", // white // pixels for state 1 ".......", "W......", "WW.....", "WWW....", "WWWW...", "WWWWW..", "WWWWWW.", // pixels for state 2 ".WWWWWW", "..WWWWW", "...WWWW", "....WWW", ".....WW", "......W", ".......", // pixels for state 3 ".WWWWWW", "W.WWWWW", "WW.WWWW", "WWW.WWW", "WWWW.WW", "WWWWW.W", "WWWWWW." }; // XPM data for the 15x15 icons used by 4-state rules emulating a triangular neighborhood static const char* tri15x15[] = { // width height ncolors chars_per_pixel "15 45 2 1", // colors ". c #000000", "W c #FFFFFF", // pixels for state 1 "...............", "W..............", "WW.............", "WWW............", "WWWW...........", "WWWWW..........", "WWWWWW.........", "WWWWWWW........", "WWWWWWWW.......", "WWWWWWWWW......", "WWWWWWWWWW.....", "WWWWWWWWWWW....", "WWWWWWWWWWWW...", "WWWWWWWWWWWWW..", "WWWWWWWWWWWWWW.", // pixels for state 2 ".WWWWWWWWWWWWWW", "..WWWWWWWWWWWWW", "...WWWWWWWWWWWW", "....WWWWWWWWWWW", ".....WWWWWWWWWW", "......WWWWWWWWW", ".......WWWWWWWW", "........WWWWWWW", ".........WWWWWW", "..........WWWWW", "...........WWWW", "............WWW", ".............WW", "..............W", "...............", // pixels for state 3 ".WWWWWWWWWWWWWW", "W.WWWWWWWWWWWWW", "WW.WWWWWWWWWWWW", "WWW.WWWWWWWWWWW", "WWWW.WWWWWWWWWW", "WWWWW.WWWWWWWWW", "WWWWWW.WWWWWWWW", "WWWWWWW.WWWWWWW", "WWWWWWWW.WWWWWW", "WWWWWWWWW.WWWWW", "WWWWWWWWWW.WWWW", "WWWWWWWWWWW.WWW", "WWWWWWWWWWWW.WW", "WWWWWWWWWWWWW.W", "WWWWWWWWWWWWWW." }; // XPM data for the 31x31 icons used by 4-state rules emulating a triangular neighborhood static const char* tri31x31[] = { // width height ncolors chars_per_pixel "31 93 2 1", // colors ". c #000000", "W c #FFFFFF", // pixels for state 1 "...............................", "W..............................", "WW.............................", "WWW............................", "WWWW...........................", "WWWWW..........................", "WWWWWW.........................", "WWWWWWW........................", "WWWWWWWW.......................", "WWWWWWWWW......................", "WWWWWWWWWW.....................", "WWWWWWWWWWW....................", "WWWWWWWWWWWW...................", "WWWWWWWWWWWWW..................", "WWWWWWWWWWWWWW.................", "WWWWWWWWWWWWWWW................", "WWWWWWWWWWWWWWWW...............", "WWWWWWWWWWWWWWWWW..............", "WWWWWWWWWWWWWWWWWW.............", "WWWWWWWWWWWWWWWWWWW............", "WWWWWWWWWWWWWWWWWWWW...........", "WWWWWWWWWWWWWWWWWWWWW..........", "WWWWWWWWWWWWWWWWWWWWWW.........", "WWWWWWWWWWWWWWWWWWWWWWW........", "WWWWWWWWWWWWWWWWWWWWWWWW.......", "WWWWWWWWWWWWWWWWWWWWWWWWW......", "WWWWWWWWWWWWWWWWWWWWWWWWWW.....", "WWWWWWWWWWWWWWWWWWWWWWWWWWW....", "WWWWWWWWWWWWWWWWWWWWWWWWWWWW...", "WWWWWWWWWWWWWWWWWWWWWWWWWWWWW..", "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW.", // pixels for state 2 ".WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "..WWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "...WWWWWWWWWWWWWWWWWWWWWWWWWWWW", "....WWWWWWWWWWWWWWWWWWWWWWWWWWW", ".....WWWWWWWWWWWWWWWWWWWWWWWWWW", "......WWWWWWWWWWWWWWWWWWWWWWWWW", ".......WWWWWWWWWWWWWWWWWWWWWWWW", "........WWWWWWWWWWWWWWWWWWWWWWW", ".........WWWWWWWWWWWWWWWWWWWWWW", "..........WWWWWWWWWWWWWWWWWWWWW", "...........WWWWWWWWWWWWWWWWWWWW", "............WWWWWWWWWWWWWWWWWWW", ".............WWWWWWWWWWWWWWWWWW", "..............WWWWWWWWWWWWWWWWW", "...............WWWWWWWWWWWWWWWW", "................WWWWWWWWWWWWWWW", ".................WWWWWWWWWWWWWW", "..................WWWWWWWWWWWWW", "...................WWWWWWWWWWWW", "....................WWWWWWWWWWW", ".....................WWWWWWWWWW", "......................WWWWWWWWW", ".......................WWWWWWWW", "........................WWWWWWW", ".........................WWWWWW", "..........................WWWWW", "...........................WWWW", "............................WWW", ".............................WW", "..............................W", "...............................", // pixels for state 3 ".WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "W.WWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "WW.WWWWWWWWWWWWWWWWWWWWWWWWWWWW", "WWW.WWWWWWWWWWWWWWWWWWWWWWWWWWW", "WWWW.WWWWWWWWWWWWWWWWWWWWWWWWWW", "WWWWW.WWWWWWWWWWWWWWWWWWWWWWWWW", "WWWWWW.WWWWWWWWWWWWWWWWWWWWWWWW", "WWWWWWW.WWWWWWWWWWWWWWWWWWWWWWW", "WWWWWWWW.WWWWWWWWWWWWWWWWWWWWWW", "WWWWWWWWW.WWWWWWWWWWWWWWWWWWWWW", "WWWWWWWWWW.WWWWWWWWWWWWWWWWWWWW", "WWWWWWWWWWW.WWWWWWWWWWWWWWWWWWW", "WWWWWWWWWWWW.WWWWWWWWWWWWWWWWWW", "WWWWWWWWWWWWW.WWWWWWWWWWWWWWWWW", "WWWWWWWWWWWWWW.WWWWWWWWWWWWWWWW", "WWWWWWWWWWWWWWW.WWWWWWWWWWWWWWW", "WWWWWWWWWWWWWWWW.WWWWWWWWWWWWWW", "WWWWWWWWWWWWWWWWW.WWWWWWWWWWWWW", "WWWWWWWWWWWWWWWWWW.WWWWWWWWWWWW", "WWWWWWWWWWWWWWWWWWW.WWWWWWWWWWW", "WWWWWWWWWWWWWWWWWWWW.WWWWWWWWWW", "WWWWWWWWWWWWWWWWWWWWW.WWWWWWWWW", "WWWWWWWWWWWWWWWWWWWWWW.WWWWWWWW", "WWWWWWWWWWWWWWWWWWWWWWW.WWWWWWW", "WWWWWWWWWWWWWWWWWWWWWWWW.WWWWWW", "WWWWWWWWWWWWWWWWWWWWWWWWW.WWWWW", "WWWWWWWWWWWWWWWWWWWWWWWWWW.WWWW", "WWWWWWWWWWWWWWWWWWWWWWWWWWW.WWW", "WWWWWWWWWWWWWWWWWWWWWWWWWWWW.WW", "WWWWWWWWWWWWWWWWWWWWWWWWWWWWW.W", "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW." }; // ----------------------------------------------------------------------------- wxBitmap** CreateIconBitmaps(const char** xpmdata, int maxstates) { if (xpmdata == NULL) return NULL; wxImage image(xpmdata); #ifdef __WXMSW__ if (!image.HasAlpha()) { // add alpha channel and set to opaque image.InitAlpha(); } #endif #ifdef __WXGTK__ // need alpha channel on Linux image.SetMaskColour(0, 0, 0); // make black transparent #endif wxBitmap allicons(image, -1); // RGBA int wd = allicons.GetWidth(); int numicons = allicons.GetHeight() / wd; if (numicons > 255) numicons = 255; // play safe wxBitmap** iconptr = (wxBitmap**) malloc(256 * sizeof(wxBitmap*)); if (iconptr) { // initialize all pointers (not just those < maxstates) for (int i = 0; i < 256; i++) iconptr[i] = NULL; for (int i = 0; i < numicons; i++) { wxRect rect(0, i*wd, wd, wd); // add 1 to skip iconptr[0] (ie. dead state) iconptr[i+1] = new wxBitmap(allicons.GetSubBitmap(rect)); } if (numicons < maxstates-1 && iconptr[numicons]) { // duplicate last icon wxRect rect(0, (numicons-1)*wd, wd, wd); for (int i = numicons; i < maxstates-1; i++) { iconptr[i+1] = new wxBitmap(allicons.GetSubBitmap(rect)); } } } return iconptr; } // ----------------------------------------------------------------------------- void FreeIconBitmaps(wxBitmap** icons) { if (icons) { for (int i = 0; i < 256; i++) delete icons[i]; free(icons); } } // ----------------------------------------------------------------------------- wxBitmap** ScaleIconBitmaps(wxBitmap** srcicons, int size) { if (srcicons == NULL) return NULL; wxBitmap** iconptr = (wxBitmap**) malloc(256 * sizeof(wxBitmap*)); if (iconptr) { for (int i = 0; i < 256; i++) { if (srcicons[i] == NULL) { iconptr[i] = NULL; } else { wxImage image = srcicons[i]->ConvertToImage(); #ifdef __WXGTK__ // fix wxGTK bug when converting black-and-white bitmap (black pixels are 1,2,3 not 0,0,0) if (image.CountColours(2) <= 2) { int numpixels = image.GetWidth() * image.GetHeight(); unsigned char* newdata = (unsigned char*) malloc(numpixels * 3); if (newdata) { unsigned char* p = image.GetData(); unsigned char* n = newdata; for (int j = 0; j < numpixels; j++) { unsigned char r = *p++; unsigned char g = *p++; unsigned char b = *p++; if (r == 1 && g == 2 && b == 3) { // change to black *n++ = 0; *n++ = 0; *n++ = 0; } else { // probably white *n++ = r; *n++ = g; *n++ = b; } } image.SetData(newdata); // image now owns pointer } } #endif // do NOT scale using wxIMAGE_QUALITY_HIGH (thin lines can disappear) image.Rescale(size, size, wxIMAGE_QUALITY_NORMAL); #ifdef __WXMSW__ if (!image.HasAlpha()) { // add alpha channel and set to opaque image.InitAlpha(); } #endif iconptr[i] = new wxBitmap(image, -1); } } } return iconptr; } // ----------------------------------------------------------------------------- static void CreateDefaultIcons(AlgoData* ad) { if (ad->defxpm7x7 || ad->defxpm15x15 || ad->defxpm31x31) { // create icons using given algo's default XPM data ad->icons7x7 = CreateIconBitmaps(ad->defxpm7x7, ad->maxstates); ad->icons15x15 = CreateIconBitmaps(ad->defxpm15x15, ad->maxstates); ad->icons31x31 = CreateIconBitmaps(ad->defxpm31x31, ad->maxstates); // create scaled bitmaps if size(s) not supplied if (!ad->icons7x7) { if (ad->icons15x15) // scale down 15x15 bitmaps ad->icons7x7 = ScaleIconBitmaps(ad->icons15x15, 7); else // scale down 31x31 bitmaps ad->icons7x7 = ScaleIconBitmaps(ad->icons31x31, 7); } if (!ad->icons15x15) { if (ad->icons31x31) // scale down 31x31 bitmaps ad->icons15x15 = ScaleIconBitmaps(ad->icons31x31, 15); else // scale up 7x7 bitmaps ad->icons15x15 = ScaleIconBitmaps(ad->icons7x7, 15); } if (!ad->icons31x31) { if (ad->icons15x15) // scale up 15x15 bitmaps ad->icons31x31 = ScaleIconBitmaps(ad->icons15x15, 31); else // scale up 7x7 bitmaps ad->icons31x31 = ScaleIconBitmaps(ad->icons7x7, 31); } } else { // algo didn't supply any icons so use static XPM data defined above ad->icons7x7 = CreateIconBitmaps(default7x7, ad->maxstates); ad->icons15x15 = CreateIconBitmaps(default15x15, ad->maxstates); ad->icons31x31 = CreateIconBitmaps(default31x31, ad->maxstates); } } // ----------------------------------------------------------------------------- AlgoData::AlgoData() { algomem = defbase = 0; statusbrush = NULL; icons7x7 = NULL; icons15x15 = NULL; icons31x31 = NULL; } // ----------------------------------------------------------------------------- AlgoData::~AlgoData() { FreeIconBitmaps(icons7x7); FreeIconBitmaps(icons15x15); FreeIconBitmaps(icons31x31); delete statusbrush; } // ----------------------------------------------------------------------------- AlgoData& AlgoData::tick() { AlgoData* r = new AlgoData(); algoinfo[r->id] = r; return *r; } // ----------------------------------------------------------------------------- void InitAlgorithms() { // qlife must be 1st and hlife must be 2nd qlifealgo::doInitializeAlgoInfo(AlgoData::tick()); hlifealgo::doInitializeAlgoInfo(AlgoData::tick()); // nicer if the rest are in alphabetical order generationsalgo::doInitializeAlgoInfo(AlgoData::tick()); jvnalgo::doInitializeAlgoInfo(AlgoData::tick()); ruleloaderalgo::doInitializeAlgoInfo(AlgoData::tick()); // algomenu is used for the Control > Set Algorithm submenu; // algomenupop is used when the tool bar's algo button is pressed // (we can't share a single menu for both purposes because we get // assert messages with wxOSX and wxGTK 2.9+) algomenu = new wxMenu(); algomenupop = new wxMenu(); // init algoinfo array for (int i = 0; i < NumAlgos(); i++) { AlgoData* ad = algoinfo[i]; if (ad->algoName == 0 || ad->creator == 0) Fatal(_("Algorithm did not set name and/or creator")); wxString name = wxString(ad->algoName, wxConvLocal); algomenu->AppendCheckItem(ID_ALGO0 + i, name); algomenupop->AppendCheckItem(ID_ALGO0 + i, name); // does algo use hashing? ad->canhash = ad->defbase == 8; //!!! safer method needed??? // set status bar background by cycling thru a few pale colors switch (i % 9) { case 0: ad->statusrgb.Set(255, 255, 206); break; // pale yellow case 1: ad->statusrgb.Set(226, 250, 248); break; // pale blue case 2: ad->statusrgb.Set(255, 233, 233); break; // pale pink case 3: ad->statusrgb.Set(225, 255, 225); break; // pale green case 4: ad->statusrgb.Set(243, 225, 255); break; // pale purple case 5: ad->statusrgb.Set(255, 220, 180); break; // pale orange case 6: ad->statusrgb.Set(200, 255, 255); break; // pale aqua case 7: ad->statusrgb.Set(200, 200, 200); break; // pale gray case 8: ad->statusrgb.Set(255, 255, 255); break; // white } ad->statusbrush = new wxBrush(ad->statusrgb); // initialize default color scheme if (ad->defr[0] == ad->defr[1] && ad->defg[0] == ad->defg[1] && ad->defb[0] == ad->defb[1]) { // colors are nonsensical, probably unset, so use above defaults unsigned char* rgbptr = default_colors; for (int c = 0; c < ad->maxstates; c++) { ad->defr[c] = *rgbptr++; ad->defg[c] = *rgbptr++; ad->defb[c] = *rgbptr++; } } ad->gradient = ad->defgradient; ad->fromrgb.Set(ad->defr1, ad->defg1, ad->defb1); ad->torgb.Set(ad->defr2, ad->defg2, ad->defb2); for (int c = 0; c < ad->maxstates; c++) { ad->algor[c] = ad->defr[c]; ad->algog[c] = ad->defg[c]; ad->algob[c] = ad->defb[c]; } CreateDefaultIcons(ad); } circles7x7 = CreateIconBitmaps(default7x7,256); circles15x15 = CreateIconBitmaps(default15x15,256); circles31x31 = CreateIconBitmaps(default31x31,256); diamonds7x7 = CreateIconBitmaps(vn7x7,256); diamonds15x15 = CreateIconBitmaps(vn15x15,256); diamonds31x31 = CreateIconBitmaps(vn31x31,256); hexagons7x7 = CreateIconBitmaps(hex7x7,256); hexagons15x15 = CreateIconBitmaps(hex15x15,256); hexagons31x31 = CreateIconBitmaps(hex31x31,256); // these icons can only be used with 4-state rules triangles7x7 = CreateIconBitmaps(tri7x7,4); triangles15x15 = CreateIconBitmaps(tri15x15,4); triangles31x31 = CreateIconBitmaps(tri31x31,4); } // ----------------------------------------------------------------------------- void DeleteAlgorithms() { for (int i = 0; i < NumAlgos(); i++) delete algoinfo[i]; FreeIconBitmaps(circles7x7); FreeIconBitmaps(circles15x15); FreeIconBitmaps(circles31x31); FreeIconBitmaps(diamonds7x7); FreeIconBitmaps(diamonds15x15); FreeIconBitmaps(diamonds31x31); FreeIconBitmaps(hexagons7x7); FreeIconBitmaps(hexagons15x15); FreeIconBitmaps(hexagons31x31); FreeIconBitmaps(triangles7x7); FreeIconBitmaps(triangles15x15); FreeIconBitmaps(triangles31x31); delete algomenupop; } // ----------------------------------------------------------------------------- lifealgo* CreateNewUniverse(algo_type algotype, bool allowcheck) { lifealgo* newalgo = algoinfo[algotype]->creator(); if (newalgo == NULL) Fatal(_("Failed to create new universe!")); if (algoinfo[algotype]->algomem >= 0) newalgo->setMaxMemory(algoinfo[algotype]->algomem); if (allowcheck) newalgo->setpoll(wxGetApp().Poller()); return newalgo; } // ----------------------------------------------------------------------------- const char* GetAlgoName(algo_type algotype) { return algoinfo[algotype]->algoName; } // ----------------------------------------------------------------------------- int NumAlgos() { return staticAlgoInfo::getNumAlgos(); } // ----------------------------------------------------------------------------- bool MultiColorImage(wxImage& image) { // return true if image contains at least one color that isn't a shade of gray int numpixels = image.GetWidth() * image.GetHeight(); unsigned char* p = image.GetData(); // p points to RGBRGB... (ie. no alpha data) for (int i = 0; i < numpixels; i++) { unsigned char r = *p++; unsigned char g = *p++; unsigned char b = *p++; if (r != g || g != b) { if (image.CountColours(2) <= 2) { // Golly 2.4 and older treated two-color icons as monochrome // so we need to convert the image to black-and-white image = image.ConvertToMono(r, g, b); return false; // grayscale image } else { return true; // multi-color image } } } return false; // grayscale image } // ----------------------------------------------------------------------------- bool LoadIconFile(const wxString& path, int maxstate, wxBitmap*** out7x7, wxBitmap*** out15x15, wxBitmap*** out31x31) { wxImage image; if (!image.LoadFile(path)) { Warning(_("Could not load icon bitmaps from file:\n") + path); return false; } // check for multi-color icons currlayer->multicoloricons = MultiColorImage(image); #ifdef __WXMSW__ if (!image.HasAlpha()) { // add alpha channel and set to opaque image.InitAlpha(); } #endif #ifdef __WXGTK__ // need alpha channel on Linux image.SetMaskColour(0, 0, 0); // make black transparent #endif wxBitmap allicons(image, -1); // RGBA int wd = allicons.GetWidth(); int ht = allicons.GetHeight(); // check dimensions if (ht != 15 && ht != 22) { Warning(_("Wrong bitmap height in icon file (must be 15 or 22):\n") + path); return false; } if (wd % 15 != 0) { Warning(_("Wrong bitmap width in icon file (must be multiple of 15):\n") + path); return false; } // first extract 15x15 icons int numicons = wd / 15; if (numicons > 255) numicons = 255; // play safe wxBitmap** iconptr = (wxBitmap**) malloc(256 * sizeof(wxBitmap*)); if (iconptr) { for (int i = 0; i < 256; i++) iconptr[i] = NULL; for (int i = 0; i < numicons; i++) { wxRect rect(i*15, 0, 15, 15); // add 1 to skip iconptr[0] (ie. dead state) iconptr[i+1] = new wxBitmap(allicons.GetSubBitmap(rect)); } if (numicons < maxstate && iconptr[numicons]) { // duplicate last icon wxRect rect((numicons-1)*15, 0, 15, 15); for (int i = numicons; i < maxstate; i++) { iconptr[i+1] = new wxBitmap(allicons.GetSubBitmap(rect)); } } // if there is an extra icon at the right end of the multi-color icons then // store it in iconptr[0] -- it will be used later in UpdateCurrentColors() // to set the color of state 0 if (currlayer->multicoloricons && (wd / 15) > maxstate) { wxRect rect(maxstate*15, 0, 15, 15); iconptr[0] = new wxBitmap(allicons.GetSubBitmap(rect)); } } *out15x15 = iconptr; if (ht == 22) { // extract 7x7 icons (at bottom left corner of each 15x15 icon) iconptr = (wxBitmap**) malloc(256 * sizeof(wxBitmap*)); if (iconptr) { for (int i = 0; i < 256; i++) iconptr[i] = NULL; for (int i = 0; i < numicons; i++) { wxRect rect(i*15, 15, 7, 7); // add 1 to skip iconptr[0] (ie. dead state) iconptr[i+1] = new wxBitmap(allicons.GetSubBitmap(rect)); } if (numicons < maxstate && iconptr[numicons]) { // duplicate last icon wxRect rect((numicons-1)*15, 15, 7, 7); for (int i = numicons; i < maxstate; i++) { iconptr[i+1] = new wxBitmap(allicons.GetSubBitmap(rect)); } } } *out7x7 = iconptr; } else { // create 7x7 icons by scaling down 15x15 icons *out7x7 = ScaleIconBitmaps(*out15x15, 7); } // create 31x31 icons by scaling up 15x15 icons *out31x31 = ScaleIconBitmaps(*out15x15, 31); return true; } golly-2.7-src/gui-wx/configure/0000755000175000017500000000000012536111546013503 500000000000000golly-2.7-src/gui-wx/configure/m4/0000755000175000017500000000000012536111545014022 500000000000000golly-2.7-src/gui-wx/configure/m4/shlib.m40000644000175000017500000000147312536111364015311 00000000000000dnl Hackish check to determine the exact name of a dynamic library required to dnl run a specific executable. dnl dnl Usage: dnl CHECK_SHLIB_USED(variable,exec-path,lib-name,value-if-not-found) dnl Where: dnl `variable' is the name of the variable to be set to the full library name dnl `exec-path' is the full (absolute or relative) path to the executable dnl `lib-name' is the basename of the library (e.g. `perl' for `libperl.so') dnl `value-if-not-found' is the value set when the library is not found. AC_DEFUN([CHECK_SHLIB_USED], [ AC_MSG_CHECKING([for $3 shared library used by $2]) [$1=`$OBJDUMP -p "$2" \ | $EGREP -i 'NEEDED +lib$3[0-9.]*[.]so|DLL Name: +$3[0-9.]*[.]dll' \ | $SED 's/^.* //'`] AS_IF([test "x$]$1[" != x], [ AC_MSG_RESULT([$]$1) ], [ AC_MSG_RESULT([not found]) $1=$4 ]) ]) golly-2.7-src/gui-wx/configure/m4/wxwin.m40000644000175000017500000011730712536111364015370 00000000000000dnl --------------------------------------------------------------------------- dnl Author: wxWidgets development team, dnl Francesco Montorsi, dnl Bob McCown (Mac-testing) dnl Creation date: 24/11/2001 dnl RCS-ID: $Id$ dnl --------------------------------------------------------------------------- dnl =========================================================================== dnl Table of Contents of this macro file: dnl ------------------------------------- dnl dnl SECTION A: wxWidgets main macros dnl - WX_CONFIG_OPTIONS dnl - WX_CONFIG_CHECK dnl - WXRC_CHECK dnl - WX_STANDARD_OPTIONS dnl - WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS dnl - WX_DETECT_STANDARD_OPTION_VALUES dnl dnl SECTION B: wxWidgets-related utilities dnl - WX_LIKE_LIBNAME dnl - WX_ARG_ENABLE_YESNOAUTO dnl - WX_ARG_WITH_YESNOAUTO dnl dnl SECTION C: messages to the user dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG_END dnl - WX_BOOLOPT_SUMMARY dnl dnl The special "WX_DEBUG_CONFIGURE" variable can be set to 1 to enable extra dnl debug output on stdout from these macros. dnl =========================================================================== dnl --------------------------------------------------------------------------- dnl Macros for wxWidgets detection. Typically used in configure.in as: dnl dnl AC_ARG_ENABLE(...) dnl AC_ARG_WITH(...) dnl ... dnl WX_CONFIG_OPTIONS dnl ... dnl ... dnl WX_CONFIG_CHECK([2.6.0], [wxWin=1]) dnl if test "$wxWin" != 1; then dnl AC_MSG_ERROR([ dnl wxWidgets must be installed on your system dnl but wx-config script couldn't be found. dnl dnl Please check that wx-config is in path, the directory dnl where wxWidgets libraries are installed (returned by dnl 'wx-config --libs' command) is in LD_LIBRARY_PATH or dnl equivalent variable and wxWidgets version is 2.3.4 or above. dnl ]) dnl fi dnl CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS" dnl CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY" dnl CFLAGS="$CFLAGS $WX_CFLAGS_ONLY" dnl dnl LIBS="$LIBS $WX_LIBS" dnl dnl If you want to support standard --enable-debug/unicode/shared options, you dnl may do the following: dnl dnl ... dnl AC_CANONICAL_SYSTEM dnl dnl # define configure options dnl WX_CONFIG_OPTIONS dnl WX_STANDARD_OPTIONS([debug,unicode,shared,toolkit,wxshared]) dnl dnl # basic configure checks dnl ... dnl dnl # we want to always have DEBUG==WX_DEBUG and UNICODE==WX_UNICODE dnl WX_DEBUG=$DEBUG dnl WX_UNICODE=$UNICODE dnl dnl WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS dnl WX_CONFIG_CHECK([2.8.0], [wxWin=1],,[html,core,net,base],[$WXCONFIG_FLAGS]) dnl WX_DETECT_STANDARD_OPTION_VALUES dnl dnl # write the output files dnl AC_CONFIG_FILES([Makefile ...]) dnl AC_OUTPUT dnl dnl # optional: just to show a message to the user dnl WX_STANDARD_OPTIONS_SUMMARY_MSG dnl dnl --------------------------------------------------------------------------- dnl --------------------------------------------------------------------------- dnl WX_CONFIG_OPTIONS dnl dnl adds support for --wx-prefix, --wx-exec-prefix, --with-wxdir and dnl --wx-config command line options dnl --------------------------------------------------------------------------- AC_DEFUN([WX_CONFIG_OPTIONS], [ AC_ARG_WITH(wxdir, [ --with-wxdir=PATH Use uninstalled version of wxWidgets in PATH], [ wx_config_name="$withval/wx-config" wx_config_args="--inplace"]) AC_ARG_WITH(wx-config, [ --with-wx-config=CONFIG wx-config script to use (optional)], wx_config_name="$withval" ) AC_ARG_WITH(wx-prefix, [ --with-wx-prefix=PREFIX Prefix where wxWidgets is installed (optional)], wx_config_prefix="$withval", wx_config_prefix="") AC_ARG_WITH(wx-exec-prefix, [ --with-wx-exec-prefix=PREFIX Exec prefix where wxWidgets is installed (optional)], wx_config_exec_prefix="$withval", wx_config_exec_prefix="") ]) dnl Helper macro for checking if wx version is at least $1.$2.$3, set's dnl wx_ver_ok=yes if it is: AC_DEFUN([_WX_PRIVATE_CHECK_VERSION], [ wx_ver_ok="" if test "x$WX_VERSION" != x ; then if test $wx_config_major_version -gt $1; then wx_ver_ok=yes else if test $wx_config_major_version -eq $1; then if test $wx_config_minor_version -gt $2; then wx_ver_ok=yes else if test $wx_config_minor_version -eq $2; then if test $wx_config_micro_version -ge $3; then wx_ver_ok=yes fi fi fi fi fi fi ]) dnl --------------------------------------------------------------------------- dnl WX_CONFIG_CHECK(VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND dnl [, WX-LIBS [, ADDITIONAL-WX-CONFIG-FLAGS]]]]) dnl dnl Test for wxWidgets, and define WX_C*FLAGS, WX_LIBS and WX_LIBS_STATIC dnl (the latter is for static linking against wxWidgets). Set WX_CONFIG_NAME dnl environment variable to override the default name of the wx-config script dnl to use. Set WX_CONFIG_PATH to specify the full path to wx-config - in this dnl case the macro won't even waste time on tests for its existence. dnl dnl Optional WX-LIBS argument contains comma- or space-separated list of dnl wxWidgets libraries to link against. If it is not specified then WX_LIBS dnl and WX_LIBS_STATIC will contain flags to link with all of the core dnl wxWidgets libraries. dnl dnl Optional ADDITIONAL-WX-CONFIG-FLAGS argument is appended to wx-config dnl invocation command in present. It can be used to fine-tune lookup of dnl best wxWidgets build available. dnl dnl Example use: dnl WX_CONFIG_CHECK([2.6.0], [wxWin=1], [wxWin=0], [html,core,net] dnl [--unicode --debug]) dnl --------------------------------------------------------------------------- dnl dnl Get the cflags and libraries from the wx-config script dnl AC_DEFUN([WX_CONFIG_CHECK], [ dnl do we have wx-config name: it can be wx-config or wxd-config or ... if test x${WX_CONFIG_NAME+set} != xset ; then WX_CONFIG_NAME=wx-config fi if test "x$wx_config_name" != x ; then WX_CONFIG_NAME="$wx_config_name" fi dnl deal with optional prefixes if test x$wx_config_exec_prefix != x ; then wx_config_args="$wx_config_args --exec-prefix=$wx_config_exec_prefix" WX_LOOKUP_PATH="$wx_config_exec_prefix/bin" fi if test x$wx_config_prefix != x ; then wx_config_args="$wx_config_args --prefix=$wx_config_prefix" WX_LOOKUP_PATH="$WX_LOOKUP_PATH:$wx_config_prefix/bin" fi if test "$cross_compiling" = "yes"; then wx_config_args="$wx_config_args --host=$host_alias" fi dnl don't search the PATH if WX_CONFIG_NAME is absolute filename if test -x "$WX_CONFIG_NAME" ; then AC_MSG_CHECKING(for wx-config) WX_CONFIG_PATH="$WX_CONFIG_NAME" AC_MSG_RESULT($WX_CONFIG_PATH) else AC_PATH_PROG(WX_CONFIG_PATH, $WX_CONFIG_NAME, no, "$WX_LOOKUP_PATH:$PATH") fi if test "$WX_CONFIG_PATH" != "no" ; then WX_VERSION="" min_wx_version=ifelse([$1], ,2.2.1,$1) if test -z "$5" ; then AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version]) else AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version ($5)]) fi dnl don't add the libraries ($4) to this variable as this would result in dnl an error when it's used with --version below WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args $5" WX_VERSION=`$WX_CONFIG_WITH_ARGS --version 2>/dev/null` wx_config_major_version=`echo $WX_VERSION | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` wx_config_minor_version=`echo $WX_VERSION | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` wx_config_micro_version=`echo $WX_VERSION | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` wx_requested_major_version=`echo $min_wx_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` wx_requested_minor_version=`echo $min_wx_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` wx_requested_micro_version=`echo $min_wx_version | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` _WX_PRIVATE_CHECK_VERSION([$wx_requested_major_version], [$wx_requested_minor_version], [$wx_requested_micro_version]) if test -n "$wx_ver_ok"; then AC_MSG_RESULT(yes (version $WX_VERSION)) WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs $4` dnl is this even still appropriate? --static is a real option now dnl and WX_CONFIG_WITH_ARGS is likely to contain it if that is dnl what the user actually wants, making this redundant at best. dnl For now keep it in case anyone actually used it in the past. AC_MSG_CHECKING([for wxWidgets static library]) WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs $4 2>/dev/null` if test "x$WX_LIBS_STATIC" = "x"; then AC_MSG_RESULT(no) else AC_MSG_RESULT(yes) fi dnl starting with version 2.2.6 wx-config has --cppflags argument wx_has_cppflags="" if test $wx_config_major_version -gt 2; then wx_has_cppflags=yes else if test $wx_config_major_version -eq 2; then if test $wx_config_minor_version -gt 2; then wx_has_cppflags=yes else if test $wx_config_minor_version -eq 2; then if test $wx_config_micro_version -ge 6; then wx_has_cppflags=yes fi fi fi fi fi dnl starting with version 2.7.0 wx-config has --rescomp option wx_has_rescomp="" if test $wx_config_major_version -gt 2; then wx_has_rescomp=yes else if test $wx_config_major_version -eq 2; then if test $wx_config_minor_version -ge 7; then wx_has_rescomp=yes fi fi fi if test "x$wx_has_rescomp" = x ; then dnl cannot give any useful info for resource compiler WX_RESCOMP= else WX_RESCOMP=`$WX_CONFIG_WITH_ARGS --rescomp` fi if test "x$wx_has_cppflags" = x ; then dnl no choice but to define all flags like CFLAGS WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags $4` WX_CPPFLAGS=$WX_CFLAGS WX_CXXFLAGS=$WX_CFLAGS WX_CFLAGS_ONLY=$WX_CFLAGS WX_CXXFLAGS_ONLY=$WX_CFLAGS else dnl we have CPPFLAGS included in CFLAGS included in CXXFLAGS WX_CPPFLAGS=`$WX_CONFIG_WITH_ARGS --cppflags $4` WX_CXXFLAGS=`$WX_CONFIG_WITH_ARGS --cxxflags $4` WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags $4` WX_CFLAGS_ONLY=`echo $WX_CFLAGS | sed "s@^$WX_CPPFLAGS *@@"` WX_CXXFLAGS_ONLY=`echo $WX_CXXFLAGS | sed "s@^$WX_CFLAGS *@@"` fi ifelse([$2], , :, [$2]) else if test "x$WX_VERSION" = x; then dnl no wx-config at all AC_MSG_RESULT(no) else AC_MSG_RESULT(no (version $WX_VERSION is not new enough)) fi WX_CFLAGS="" WX_CPPFLAGS="" WX_CXXFLAGS="" WX_LIBS="" WX_LIBS_STATIC="" WX_RESCOMP="" if test ! -z "$5"; then wx_error_message=" The configuration you asked for $PACKAGE_NAME requires a wxWidgets build with the following settings: $5 but such build is not available. To see the wxWidgets builds available on this system, please use 'wx-config --list' command. To use the default build, returned by 'wx-config --selected-config', use the options with their 'auto' default values." fi wx_error_message=" The requested wxWidgets build couldn't be found. $wx_error_message If you still get this error, then check that 'wx-config' is in path, the directory where wxWidgets libraries are installed (returned by 'wx-config --libs' command) is in LD_LIBRARY_PATH or equivalent variable and wxWidgets version is $1 or above." ifelse([$3], , AC_MSG_ERROR([$wx_error_message]), [$3]) fi else WX_CFLAGS="" WX_CPPFLAGS="" WX_CXXFLAGS="" WX_LIBS="" WX_LIBS_STATIC="" WX_RESCOMP="" ifelse([$3], , :, [$3]) fi AC_SUBST(WX_CPPFLAGS) AC_SUBST(WX_CFLAGS) AC_SUBST(WX_CXXFLAGS) AC_SUBST(WX_CFLAGS_ONLY) AC_SUBST(WX_CXXFLAGS_ONLY) AC_SUBST(WX_LIBS) AC_SUBST(WX_LIBS_STATIC) AC_SUBST(WX_VERSION) AC_SUBST(WX_RESCOMP) dnl need to export also WX_VERSION_MINOR and WX_VERSION_MAJOR symbols dnl to support wxpresets bakefiles (we export also WX_VERSION_MICRO for completeness): WX_VERSION_MAJOR="$wx_config_major_version" WX_VERSION_MINOR="$wx_config_minor_version" WX_VERSION_MICRO="$wx_config_micro_version" AC_SUBST(WX_VERSION_MAJOR) AC_SUBST(WX_VERSION_MINOR) AC_SUBST(WX_VERSION_MICRO) ]) dnl --------------------------------------------------------------------------- dnl Get information on the wxrc program for making C++, Python and xrs dnl resource files. dnl dnl AC_ARG_ENABLE(...) dnl AC_ARG_WITH(...) dnl ... dnl WX_CONFIG_OPTIONS dnl ... dnl WX_CONFIG_CHECK(2.6.0, wxWin=1) dnl if test "$wxWin" != 1; then dnl AC_MSG_ERROR([ dnl wxWidgets must be installed on your system dnl but wx-config script couldn't be found. dnl dnl Please check that wx-config is in path, the directory dnl where wxWidgets libraries are installed (returned by dnl 'wx-config --libs' command) is in LD_LIBRARY_PATH or dnl equivalent variable and wxWidgets version is 2.6.0 or above. dnl ]) dnl fi dnl dnl WXRC_CHECK([HAVE_WXRC=1], [HAVE_WXRC=0]) dnl if test "x$HAVE_WXRC" != x1; then dnl AC_MSG_ERROR([ dnl The wxrc program was not installed or not found. dnl dnl Please check the wxWidgets installation. dnl ]) dnl fi dnl dnl CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS" dnl CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY" dnl CFLAGS="$CFLAGS $WX_CFLAGS_ONLY" dnl dnl LDFLAGS="$LDFLAGS $WX_LIBS" dnl --------------------------------------------------------------------------- dnl --------------------------------------------------------------------------- dnl WXRC_CHECK([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) dnl dnl Test for wxWidgets' wxrc program for creating either C++, Python or XRS dnl resources. The variable WXRC will be set and substituted in the configure dnl script and Makefiles. dnl dnl Example use: dnl WXRC_CHECK([wxrc=1], [wxrc=0]) dnl --------------------------------------------------------------------------- dnl dnl wxrc program from the wx-config script dnl AC_DEFUN([WXRC_CHECK], [ AC_ARG_VAR([WXRC], [Path to wxWidget's wxrc resource compiler]) if test "x$WX_CONFIG_NAME" = x; then AC_MSG_ERROR([The wxrc tests must run after wxWidgets test.]) else AC_MSG_CHECKING([for wxrc]) if test "x$WXRC" = x ; then dnl wx-config --utility is a new addition to wxWidgets: _WX_PRIVATE_CHECK_VERSION(2,5,3) if test -n "$wx_ver_ok"; then WXRC=`$WX_CONFIG_WITH_ARGS --utility=wxrc` fi fi if test "x$WXRC" = x ; then AC_MSG_RESULT([not found]) ifelse([$2], , :, [$2]) else AC_MSG_RESULT([$WXRC]) ifelse([$1], , :, [$1]) fi AC_SUBST(WXRC) fi ]) dnl --------------------------------------------------------------------------- dnl WX_LIKE_LIBNAME([output-var] [prefix], [name]) dnl dnl Sets the "output-var" variable to the name of a library named with same dnl wxWidgets rule. dnl E.g. for output-var=='lib', name=='test', prefix='mine', sets dnl the $lib variable to: dnl 'mine_gtk2ud_test-2.8' dnl if WX_PORT=gtk2, WX_UNICODE=1, WX_DEBUG=1 and WX_RELEASE=28 dnl --------------------------------------------------------------------------- AC_DEFUN([WX_LIKE_LIBNAME], [ wx_temp="$2""_""$WX_PORT" dnl add the [u][d] string if test "$WX_UNICODE" = "1"; then wx_temp="$wx_temp""u" fi if test "$WX_DEBUG" = "1"; then wx_temp="$wx_temp""d" fi dnl complete the name of the lib wx_temp="$wx_temp""_""$3""-$WX_VERSION_MAJOR.$WX_VERSION_MINOR" dnl save it in the user's variable $1=$wx_temp ]) dnl --------------------------------------------------------------------------- dnl WX_ARG_ENABLE_YESNOAUTO/WX_ARG_WITH_YESNOAUTO dnl dnl Two little custom macros which define the ENABLE/WITH configure arguments. dnl Macro arguments: dnl $1 = the name of the --enable / --with feature dnl $2 = the name of the variable associated dnl $3 = the description of that feature dnl $4 = the default value for that feature dnl $5 = additional action to do in case option is given with "yes" value dnl --------------------------------------------------------------------------- AC_DEFUN([WX_ARG_ENABLE_YESNOAUTO], [AC_ARG_ENABLE($1, AC_HELP_STRING([--enable-$1], [$3 (default is $4)]), [], [enableval="$4"]) dnl Show a message to the user about this option AC_MSG_CHECKING([for the --enable-$1 option]) if test "$enableval" = "yes" ; then AC_MSG_RESULT([yes]) $2=1 $5 elif test "$enableval" = "no" ; then AC_MSG_RESULT([no]) $2=0 elif test "$enableval" = "auto" ; then AC_MSG_RESULT([will be automatically detected]) $2="auto" else AC_MSG_ERROR([ Unrecognized option value (allowed values: yes, no, auto) ]) fi ]) AC_DEFUN([WX_ARG_WITH_YESNOAUTO], [AC_ARG_WITH($1, AC_HELP_STRING([--with-$1], [$3 (default is $4)]), [], [withval="$4"]) dnl Show a message to the user about this option AC_MSG_CHECKING([for the --with-$1 option]) if test "$withval" = "yes" ; then AC_MSG_RESULT([yes]) $2=1 $5 dnl NB: by default we don't allow --with-$1=no option dnl since it does not make much sense ! elif test "$6" = "1" -a "$withval" = "no" ; then AC_MSG_RESULT([no]) $2=0 elif test "$withval" = "auto" ; then AC_MSG_RESULT([will be automatically detected]) $2="auto" else AC_MSG_ERROR([ Unrecognized option value (allowed values: yes, auto) ]) fi ]) dnl --------------------------------------------------------------------------- dnl WX_STANDARD_OPTIONS([options-to-add]) dnl dnl Adds to the configure script one or more of the following options: dnl --enable-[debug|unicode|shared|wxshared|wxdebug] dnl --with-[gtk|msw|motif|x11|mac|mgl|dfb] dnl --with-wxversion dnl Then checks for their presence and eventually set the DEBUG, UNICODE, SHARED, dnl PORT, WX_SHARED, WX_DEBUG, variables to one of the "yes", "no", "auto" values. dnl dnl Note that e.g. UNICODE != WX_UNICODE; the first is the value of the dnl --enable-unicode option (in boolean format) while the second indicates dnl if wxWidgets was built in Unicode mode (and still is in boolean format). dnl --------------------------------------------------------------------------- AC_DEFUN([WX_STANDARD_OPTIONS], [ dnl the following lines will expand to WX_ARG_ENABLE_YESNOAUTO calls if and only if dnl the $1 argument contains respectively the debug,unicode or shared options. dnl be careful here not to set debug flag if only "wxdebug" was specified ifelse(regexp([$1], [\bdebug]), [-1],, [WX_ARG_ENABLE_YESNOAUTO([debug], [DEBUG], [Build in debug mode], [auto])]) ifelse(index([$1], [unicode]), [-1],, [WX_ARG_ENABLE_YESNOAUTO([unicode], [UNICODE], [Build in Unicode mode], [auto])]) ifelse(regexp([$1], [\bshared]), [-1],, [WX_ARG_ENABLE_YESNOAUTO([shared], [SHARED], [Build as shared library], [auto])]) dnl WX_ARG_WITH_YESNOAUTO cannot be used for --with-toolkit since it's an option dnl which must be able to accept the auto|gtk1|gtk2|msw|... values ifelse(index([$1], [toolkit]), [-1],, [ AC_ARG_WITH([toolkit], AC_HELP_STRING([--with-toolkit], [Build against a specific wxWidgets toolkit (default is auto)]), [], [withval="auto"]) dnl Show a message to the user about this option AC_MSG_CHECKING([for the --with-toolkit option]) if test "$withval" = "auto" ; then AC_MSG_RESULT([will be automatically detected]) TOOLKIT="auto" else TOOLKIT="$withval" dnl PORT must be one of the allowed values if test "$TOOLKIT" != "gtk1" -a "$TOOLKIT" != "gtk2" -a \ "$TOOLKIT" != "msw" -a "$TOOLKIT" != "motif" -a \ "$TOOLKIT" != "x11" -a "$TOOLKIT" != "mac" -a \ "$TOOLKIT" != "mgl" -a "$TOOLKIT" != "dfb" ; then AC_MSG_ERROR([ Unrecognized option value (allowed values: auto, gtk1, gtk2, msw, motif, x11, mac, mgl, dfb) ]) fi AC_MSG_RESULT([$TOOLKIT]) fi ]) dnl ****** IMPORTANT ******* dnl Unlike for the UNICODE setting, you can build your program in dnl shared mode against a static build of wxWidgets. Thus we have the dnl following option which allows these mixtures. E.g. dnl dnl ./configure --disable-shared --with-wxshared dnl dnl will build your library in static mode against the first available dnl shared build of wxWidgets. dnl dnl Note that's not possible to do the viceversa: dnl dnl ./configure --enable-shared --without-wxshared dnl dnl Doing so you would try to build your library in shared mode against a static dnl build of wxWidgets. This is not possible (you would mix PIC and non PIC code) ! dnl A check for this combination of options is in WX_DETECT_STANDARD_OPTION_VALUES dnl (where we know what 'auto' should be expanded to). dnl dnl If you try to build something in ANSI mode against a UNICODE build dnl of wxWidgets or in RELEASE mode against a DEBUG build of wxWidgets, dnl then at best you'll get ton of linking errors ! dnl ************************ ifelse(index([$1], [wxshared]), [-1],, [ WX_ARG_WITH_YESNOAUTO( [wxshared], [WX_SHARED], [Force building against a shared build of wxWidgets, even if --disable-shared is given], [auto], [], [1]) ]) dnl Just like for SHARED and WX_SHARED it may happen that some adventurous dnl peoples will want to mix a wxWidgets release build with a debug build of dnl his app/lib. So, we have both DEBUG and WX_DEBUG variables. ifelse(index([$1], [wxdebug]), [-1],, [ WX_ARG_WITH_YESNOAUTO( [wxdebug], [WX_DEBUG], [Force building against a debug build of wxWidgets, even if --disable-debug is given], [auto], [], [1]) ]) dnl WX_ARG_WITH_YESNOAUTO cannot be used for --with-wxversion since it's an option dnl which accepts the "auto|2.6|2.7|2.8|2.9|3.0" etc etc values ifelse(index([$1], [wxversion]), [-1],, [ AC_ARG_WITH([wxversion], AC_HELP_STRING([--with-wxversion], [Build against a specific version of wxWidgets (default is auto)]), [], [withval="auto"]) dnl Show a message to the user about this option AC_MSG_CHECKING([for the --with-wxversion option]) if test "$withval" = "auto" ; then AC_MSG_RESULT([will be automatically detected]) WX_RELEASE="auto" else wx_requested_major_version=`echo $withval | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).*/\1/'` wx_requested_minor_version=`echo $withval | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).*/\2/'` dnl both vars above must be exactly 1 digit if test "${#wx_requested_major_version}" != "1" -o \ "${#wx_requested_minor_version}" != "1" ; then AC_MSG_ERROR([ Unrecognized option value (allowed values: auto, 2.6, 2.7, 2.8, 2.9, 3.0) ]) fi WX_RELEASE="$wx_requested_major_version"".""$wx_requested_minor_version" AC_MSG_RESULT([$WX_RELEASE]) fi ]) if test "$WX_DEBUG_CONFIGURE" = "1"; then echo "[[dbg]] DEBUG: $DEBUG, WX_DEBUG: $WX_DEBUG" echo "[[dbg]] UNICODE: $UNICODE, WX_UNICODE: $WX_UNICODE" echo "[[dbg]] SHARED: $SHARED, WX_SHARED: $WX_SHARED" echo "[[dbg]] TOOLKIT: $TOOLKIT, WX_TOOLKIT: $WX_TOOLKIT" echo "[[dbg]] VERSION: $VERSION, WX_RELEASE: $WX_RELEASE" fi ]) dnl --------------------------------------------------------------------------- dnl WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS dnl dnl Sets the WXCONFIG_FLAGS string using the SHARED,DEBUG,UNICODE variable values dnl which are different from "auto". dnl Thus this macro needs to be called only once all options have been set. dnl --------------------------------------------------------------------------- AC_DEFUN([WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS], [ if test "$WX_SHARED" = "1" ; then WXCONFIG_FLAGS="--static=no " elif test "$WX_SHARED" = "0" ; then WXCONFIG_FLAGS="--static=yes " fi if test "$WX_DEBUG" = "1" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--debug=yes " elif test "$WX_DEBUG" = "0" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--debug=no " fi dnl The user should have set WX_UNICODE=UNICODE if test "$WX_UNICODE" = "1" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=yes " elif test "$WX_UNICODE" = "0" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=no " fi if test "$TOOLKIT" != "auto" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--toolkit=$TOOLKIT " fi if test "$WX_RELEASE" != "auto" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--version=$WX_RELEASE " fi dnl strip out the last space of the string WXCONFIG_FLAGS=${WXCONFIG_FLAGS% } if test "$WX_DEBUG_CONFIGURE" = "1"; then echo "[[dbg]] WXCONFIG_FLAGS: $WXCONFIG_FLAGS" fi ]) dnl --------------------------------------------------------------------------- dnl _WX_SELECTEDCONFIG_CHECKFOR([RESULTVAR], [STRING], [MSG] dnl [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) dnl dnl Outputs the given MSG. Then searches the given STRING in the wxWidgets dnl additional CPP flags and put the result of the search in WX_$RESULTVAR dnl also adding the "yes" or "no" message result to MSG. dnl --------------------------------------------------------------------------- AC_DEFUN([_WX_SELECTEDCONFIG_CHECKFOR], [ if test "$$1" = "auto" ; then dnl The user does not have particular preferences for this option; dnl so we will detect the wxWidgets relative build setting and use it AC_MSG_CHECKING([$3]) dnl set WX_$1 variable to 1 if the $WX_SELECTEDCONFIG contains the $2 dnl string or to 0 otherwise. dnl NOTE: 'expr match STRING REGEXP' cannot be used since on Mac it dnl doesn't work; we use 'expr STRING : REGEXP' instead WX_$1=$(expr "$WX_SELECTEDCONFIG" : ".*$2.*") if test "$WX_$1" != "0"; then WX_$1=1 AC_MSG_RESULT([yes]) ifelse([$4], , :, [$4]) else WX_$1=0 AC_MSG_RESULT([no]) ifelse([$5], , :, [$5]) fi else dnl Use the setting given by the user WX_$1=$$1 fi ]) dnl --------------------------------------------------------------------------- dnl WX_DETECT_STANDARD_OPTION_VALUES dnl dnl Detects the values of the following variables: dnl 1) WX_RELEASE dnl 2) WX_UNICODE dnl 3) WX_DEBUG dnl 4) WX_SHARED (and also WX_STATIC) dnl 5) WX_PORT dnl from the previously selected wxWidgets build; this macro in fact must be dnl called *after* calling the WX_CONFIG_CHECK macro. dnl dnl Note that the WX_VERSION_MAJOR, WX_VERSION_MINOR symbols are already set dnl by WX_CONFIG_CHECK macro dnl --------------------------------------------------------------------------- AC_DEFUN([WX_DETECT_STANDARD_OPTION_VALUES], [ dnl IMPORTANT: WX_VERSION contains all three major.minor.micro digits, dnl while WX_RELEASE only the major.minor ones. WX_RELEASE="$WX_VERSION_MAJOR""$WX_VERSION_MINOR" if test $WX_RELEASE -lt 26 ; then AC_MSG_ERROR([ Cannot detect the wxWidgets configuration for the selected wxWidgets build since its version is $WX_VERSION < 2.6.0; please install a newer version of wxWidgets. ]) fi dnl The wx-config we are using understands the "--selected_config" dnl option which returns an easy-parseable string ! WX_SELECTEDCONFIG=$($WX_CONFIG_WITH_ARGS --selected_config) if test "$WX_DEBUG_CONFIGURE" = "1"; then echo "[[dbg]] Using wx-config --selected-config" echo "[[dbg]] WX_SELECTEDCONFIG: $WX_SELECTEDCONFIG" fi dnl we could test directly for WX_SHARED with a line like: dnl _WX_SELECTEDCONFIG_CHECKFOR([SHARED], [shared], dnl [if wxWidgets was built in SHARED mode]) dnl but wx-config --selected-config DOES NOT outputs the 'shared' dnl word when wx was built in shared mode; it rather outputs the dnl 'static' word when built in static mode. if test $WX_SHARED = "1"; then STATIC=0 elif test $WX_SHARED = "0"; then STATIC=1 elif test $WX_SHARED = "auto"; then STATIC="auto" fi dnl Now set the WX_UNICODE, WX_DEBUG, WX_STATIC variables _WX_SELECTEDCONFIG_CHECKFOR([UNICODE], [unicode], [if wxWidgets was built with UNICODE enabled]) _WX_SELECTEDCONFIG_CHECKFOR([DEBUG], [debug], [if wxWidgets was built in DEBUG mode]) _WX_SELECTEDCONFIG_CHECKFOR([STATIC], [static], [if wxWidgets was built in STATIC mode]) dnl init WX_SHARED from WX_STATIC if test "$WX_STATIC" != "0"; then WX_SHARED=0 else WX_SHARED=1 fi AC_SUBST(WX_UNICODE) AC_SUBST(WX_DEBUG) AC_SUBST(WX_SHARED) dnl detect the WX_PORT to use if test "$TOOLKIT" = "auto" ; then dnl The user does not have particular preferences for this option; dnl so we will detect the wxWidgets relative build setting and use it AC_MSG_CHECKING([which wxWidgets toolkit was selected]) WX_GTKPORT1=$(expr "$WX_SELECTEDCONFIG" : ".*gtk1.*") WX_GTKPORT2=$(expr "$WX_SELECTEDCONFIG" : ".*gtk2.*") WX_MSWPORT=$(expr "$WX_SELECTEDCONFIG" : ".*msw.*") WX_MOTIFPORT=$(expr "$WX_SELECTEDCONFIG" : ".*motif.*") WX_OSXCOCOAPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_cocoa.*") WX_OSXCARBONPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_carbon.*") WX_X11PORT=$(expr "$WX_SELECTEDCONFIG" : ".*x11.*") WX_MGLPORT=$(expr "$WX_SELECTEDCONFIG" : ".*mgl.*") WX_DFBPORT=$(expr "$WX_SELECTEDCONFIG" : ".*dfb.*") WX_PORT="unknown" if test "$WX_GTKPORT1" != "0"; then WX_PORT="gtk1"; fi if test "$WX_GTKPORT2" != "0"; then WX_PORT="gtk2"; fi if test "$WX_MSWPORT" != "0"; then WX_PORT="msw"; fi if test "$WX_MOTIFPORT" != "0"; then WX_PORT="motif"; fi if test "$WX_OSXCOCOAPORT" != "0"; then WX_PORT="osx_cocoa"; fi if test "$WX_OSXCARBONPORT" != "0"; then WX_PORT="osx_carbon"; fi if test "$WX_X11PORT" != "0"; then WX_PORT="x11"; fi if test "$WX_MGLPORT" != "0"; then WX_PORT="mgl"; fi if test "$WX_DFBPORT" != "0"; then WX_PORT="dfb"; fi dnl NOTE: backward-compatible check for wx2.8; in wx2.9 the mac dnl ports are called 'osx_cocoa' and 'osx_carbon' (see above) WX_MACPORT=$(expr "$WX_SELECTEDCONFIG" : ".*mac.*") if test "$WX_MACPORT" != "0"; then WX_PORT="mac"; fi dnl check at least one of the WX_*PORT has been set ! if test "$WX_PORT" = "unknown" ; then AC_MSG_ERROR([ Cannot detect the currently installed wxWidgets port ! Please check your 'wx-config --cxxflags'... ]) fi AC_MSG_RESULT([$WX_PORT]) else dnl Use the setting given by the user if test -z "$TOOLKIT" ; then WX_PORT=$TOOLKIT else dnl try with PORT WX_PORT=$PORT fi fi AC_SUBST(WX_PORT) if test "$WX_DEBUG_CONFIGURE" = "1"; then echo "[[dbg]] Values of all WX_* options after final detection:" echo "[[dbg]] WX_DEBUG: $WX_DEBUG" echo "[[dbg]] WX_UNICODE: $WX_UNICODE" echo "[[dbg]] WX_SHARED: $WX_SHARED" echo "[[dbg]] WX_RELEASE: $WX_RELEASE" echo "[[dbg]] WX_PORT: $WX_PORT" fi dnl Avoid problem described in the WX_STANDARD_OPTIONS which happens when dnl the user gives the options: dnl ./configure --enable-shared --without-wxshared dnl or just do dnl ./configure --enable-shared dnl but there is only a static build of wxWidgets available. if test "$WX_SHARED" = "0" -a "$SHARED" = "1"; then AC_MSG_ERROR([ Cannot build shared library against a static build of wxWidgets ! This error happens because the wxWidgets build which was selected has been detected as static while you asked to build $PACKAGE_NAME as shared library and this is not possible. Use the '--disable-shared' option to build $PACKAGE_NAME as static library or '--with-wxshared' to use wxWidgets as shared library. ]) fi dnl now we can finally update the DEBUG,UNICODE,SHARED options dnl to their final values if they were set to 'auto' if test "$DEBUG" = "auto"; then DEBUG=$WX_DEBUG fi if test "$UNICODE" = "auto"; then UNICODE=$WX_UNICODE fi if test "$SHARED" = "auto"; then SHARED=$WX_SHARED fi if test "$TOOLKIT" = "auto"; then TOOLKIT=$WX_PORT fi dnl in case the user needs a BUILD=debug/release var... if test "$DEBUG" = "1"; then BUILD="debug" elif test "$DEBUG" = "0" -o "$DEBUG" = ""; then BUILD="release" fi dnl respect the DEBUG variable adding the optimize/debug flags dnl NOTE: the CXXFLAGS are merged together with the CPPFLAGS so we dnl don't need to set them, too if test "$DEBUG" = "1"; then CXXFLAGS="$CXXFLAGS -g -O0" CFLAGS="$CFLAGS -g -O0" else CXXFLAGS="$CXXFLAGS -O2" CFLAGS="$CFLAGS -O2" fi ]) dnl --------------------------------------------------------------------------- dnl WX_BOOLOPT_SUMMARY([name of the boolean variable to show summary for], dnl [what to print when var is 1], dnl [what to print when var is 0]) dnl dnl Prints $2 when variable $1 == 1 and prints $3 when variable $1 == 0. dnl This macro mainly exists just to make configure.ac scripts more readable. dnl dnl NOTE: you need to use the [" my message"] syntax for 2nd and 3rd arguments dnl if you want that m4 avoid to throw away the spaces prefixed to the dnl argument value. dnl --------------------------------------------------------------------------- AC_DEFUN([WX_BOOLOPT_SUMMARY], [ if test "x$$1" = "x1" ; then echo $2 elif test "x$$1" = "x0" ; then echo $3 else echo "$1 is $$1" fi ]) dnl --------------------------------------------------------------------------- dnl WX_STANDARD_OPTIONS_SUMMARY_MSG dnl dnl Shows a summary message to the user about the WX_* variable contents. dnl This macro is used typically at the end of the configure script. dnl --------------------------------------------------------------------------- AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG], [ echo echo " The wxWidgets build which will be used by $PACKAGE_NAME $PACKAGE_VERSION" echo " has the following settings:" WX_BOOLOPT_SUMMARY([WX_DEBUG], [" - DEBUG build"], [" - RELEASE build"]) WX_BOOLOPT_SUMMARY([WX_UNICODE], [" - UNICODE mode"], [" - ANSI mode"]) WX_BOOLOPT_SUMMARY([WX_SHARED], [" - SHARED mode"], [" - STATIC mode"]) echo " - VERSION: $WX_VERSION" echo " - PORT: $WX_PORT" ]) dnl --------------------------------------------------------------------------- dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN, WX_STANDARD_OPTIONS_SUMMARY_MSG_END dnl dnl Like WX_STANDARD_OPTIONS_SUMMARY_MSG macro but these two macros also gives info dnl about the configuration of the package which used the wxpresets. dnl dnl Typical usage: dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN dnl echo " - Package setting 1: $SETTING1" dnl echo " - Package setting 2: $SETTING1" dnl ... dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_END dnl dnl --------------------------------------------------------------------------- AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN], [ echo echo " ----------------------------------------------------------------" echo " Configuration for $PACKAGE_NAME $PACKAGE_VERSION successfully completed." echo " Summary of main configuration settings for $PACKAGE_NAME:" WX_BOOLOPT_SUMMARY([DEBUG], [" - DEBUG build"], [" - RELEASE build"]) WX_BOOLOPT_SUMMARY([UNICODE], [" - UNICODE mode"], [" - ANSI mode"]) WX_BOOLOPT_SUMMARY([SHARED], [" - SHARED mode"], [" - STATIC mode"]) ]) AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG_END], [ WX_STANDARD_OPTIONS_SUMMARY_MSG echo echo " Now, just run make." echo " ----------------------------------------------------------------" echo ]) dnl --------------------------------------------------------------------------- dnl Deprecated macro wrappers dnl --------------------------------------------------------------------------- AC_DEFUN([AM_OPTIONS_WXCONFIG], [WX_CONFIG_OPTIONS]) AC_DEFUN([AM_PATH_WXCONFIG], [ WX_CONFIG_CHECK([$1],[$2],[$3],[$4],[$5]) ]) golly-2.7-src/gui-wx/configure/m4/wximage.m40000644000175000017500000000133212536111364015643 00000000000000dnl --------------------------------------------------------------------------- dnl Custom test to check for presence of specific image handlers in wxWindows. dnl Assumes WX_CONFIG_CHECK has already passed. dnl --------------------------------------------------------------------------- AC_DEFUN([WX_CHECK_IMAGE_HANDLER], [ AC_LANG_PUSH([C++]) save_CXXFLAGS=$CXXFLAGS save_LIBS=$LIBS CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" LIBS="$LIBS $WX_LIBS" AC_MSG_CHECKING([for ]$1[ image handler]) AC_LINK_IFELSE([AC_LANG_SOURCE([ #include int main() { new wx]$1[Handler(); } ])], [AC_MSG_RESULT([yes]); AC_DEFINE([HAVE_WX_]$1[_HANDLER])], [AC_MSG_RESULT([no])] ) CXXFLAGS=$save_CXXFLAGS LIBS=$save_LIBS AC_LANG_POP() ]) golly-2.7-src/gui-wx/configure/config.guess0000755000175000017500000012743212536111506015750 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-02-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: golly-2.7-src/gui-wx/configure/aclocal.m40000644000175000017500000011016312536111505015260 00000000000000# generated automatically by aclocal 1.11.6 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, # Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.6], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.6])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # Copyright (C) 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_AR([ACT-IF-FAIL]) # ------------------------- # Try to determine the archiver interface, and trigger the ar-lib wrapper # if it is needed. If the detection of archiver interface fails, run # ACT-IF-FAIL (default is to abort configure with a proper error message). AC_DEFUN([AM_PROG_AR], [AC_BEFORE([$0], [LT_INIT])dnl AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([ar-lib])dnl AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) : ${AR=ar} AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], [am_cv_ar_interface=ar AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([am_ar_try]) if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a ]) ]) case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) m4_default([$1], [AC_MSG_ERROR([could not determine $AR interface])]) ;; esac AC_SUBST([AR])dnl ]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, # 2010, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 12 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([m4/shlib.m4]) m4_include([m4/wximage.m4]) m4_include([m4/wxwin.m4]) golly-2.7-src/gui-wx/configure/config.sub0000755000175000017500000010532712536111506015412 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-04-18' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted GNU ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze) basic_machine=microblaze-xilinx ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i386-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: golly-2.7-src/gui-wx/configure/configure.ac0000644000175000017500000000761112536111364015714 00000000000000AC_PREREQ(2.61) AC_INIT([golly], [2.7]) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([-Wall -Werror foreign no-define]) AC_CONFIG_SRCDIR([../../cmdline/bgolly.cpp]) # Custom configure arguments: AC_ARG_WITH([zlib], [AS_HELP_STRING([--with-zlib], [support reading compressed pattern files with zlib])], , [with_zlib=yes]) AC_ARG_WITH([perl-shlib], [AS_HELP_STRING([--with-perl-shlib=ARG], [name of the Perl library when loaded dynamically (e.g. libperl.so.5.12)])], , [with_perl_shlib=check]) AC_ARG_WITH([python-shlib], [AS_HELP_STRING([--with-python-shlib=ARG], [name of the Python library when loaded dynamically (e.g. libpython2.6.so)])], , [with_python_shlib=check]) AC_ARG_VAR([GOLLYDIR], [golly data directory [default=DATADIR/golly]]) AC_ARG_VAR([PERL], [Perl 5 interpreter]) AC_ARG_VAR([PYTHON], [Python 2 interpreter]) # Check for build tools: m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AC_PROG_GREP AC_PROG_EGREP AC_PROG_SED AC_PROG_RANLIB AC_PROG_CXX AC_CHECK_TOOL([OBJDUMP], [objdump]) AS_IF([test "x$OBJDUMP" = x], [AC_MSG_ERROR([missing objdump])]) AC_CHECK_TOOL([STRIP], [strip]) # Check for standard header files: AC_CHECK_HEADERS([inttypes.h limits.h stdint.h stdlib.h string.h sys/time.h]) # Check for compiler characteristics: AC_TYPE_SIZE_T # Check for large file support (enabled by default) AC_SYS_LARGEFILE # Check for library functions AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([gettimeofday memset pow strchr strdup strrchr]) # Find wxWidgets WX_CONFIG_OPTIONS WX_STANDARD_OPTIONS([debug,unicode,shared,toolkit,wxshared]) WX_DEBUG=$DEBUG WX_UNICODE=$UNICODE WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS WX_CONFIG_CHECK([2.8.0], , [AC_MSG_ERROR([missing wxWidgets])], , [$WXCONFIG_FLAGS]) WX_DETECT_STANDARD_OPTION_VALUES AM_CONDITIONAL([RESCOMP], [test "x$WX_RESCOMP" != x]) WX_CHECK_IMAGE_HANDLER([BMP]) WX_CHECK_IMAGE_HANDLER([GIF]) WX_CHECK_IMAGE_HANDLER([PNG]) WX_CHECK_IMAGE_HANDLER([TIFF]) # Find Perl AC_PATH_PROGS([PERL], [perl5 perl]) AS_IF([test "x$PERL" = x], [AC_MSG_ERROR([missing Perl])]) AC_SUBST([PERL_INCLUDE], [`$PERL -MExtUtils::Embed -e ccopts`]) AS_IF([test "x$with_perl_shlib" = xcheck], [CHECK_SHLIB_USED([shlib], [$PERL], [perl])], [shlib=$with_perl_shlib] ) AS_IF([test "x$shlib" = x], AC_MSG_ERROR([could not determine Perl shared library name])) AC_DEFINE_UNQUOTED([PERL_SHLIB], [$shlib]) # Find Python AC_PATH_PROGS(PYTHON, [python2 python]) AS_IF([test "x$PYTHON" = x], [AC_MSG_ERROR([missing Python])]) AC_SUBST([PYTHON_INCLUDE], [-I"'`$PYTHON -c "import distutils.sysconfig; print(distutils.sysconfig.get_python_inc())"`'"]) AS_IF([test "x$with_python_shlib" = xcheck], [ [shlib=`$PYTHON -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LDLIBRARY') or '')"`] AS_IF([test "x$shlib" = x], [CHECK_SHLIB_USED([shlib], [$PYTHON], [python])]) ], [ shlib=$with_python_shlib ] ) AS_IF([test "x$shlib" = x], AC_MSG_ERROR([could not determine Python shared library name])) AC_DEFINE_UNQUOTED([PYTHON_SHLIB], [$shlib]) # Find zlib (unless explicitly disabled) AS_IF([test "x$with_zlib" != xno], [ AC_CHECK_HEADER([zlib.h], , [AC_MSG_ERROR([missing zlib])]) AC_SEARCH_LIBS([gzopen], [z], , [AC_MSG_ERROR([missing zlib])]) AC_DEFINE(ZLIB) ] ) # Definitions used in the source: AC_DEFINE_UNQUOTED([VERSION], [$PACKAGE_VERSION]) GOLLYDIR=${GOLLYDIR:-'${pkgdatadir}'} # Determine which of three supported target operating systems we will compile # for, and set a suffix for binary distributions accordingly: case $target_os in cygwin* | mingw* | pw32* | cegcc*) id=win ;; darwin* | rhapsody*) id=mac ;; linux*) id=gtk ;; *) id= ;; esac case $target_cpu in *64) bits=64 ;; *) bits= ;; esac AC_SUBST([BINDISTSUFFIX], [${id:+-$id$bits}]) AC_SUBST([SRCDISTSUFFIX], [-src]) AM_CONDITIONAL([WINDOWS], [test x$id = xwin ]) AM_CONDITIONAL([MAC], [test x$id = xmac ]) AM_CONDITIONAL([LINUX], [test x$id = xgtk ]) # Generate output AC_CONFIG_FILES([Makefile]) AC_OUTPUT WX_STANDARD_OPTIONS_SUMMARY_MSG golly-2.7-src/gui-wx/configure/install-sh0000755000175000017500000003325612536111506015434 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-01-19.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for `test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: golly-2.7-src/gui-wx/configure/missing0000755000175000017500000002415212536111506015022 00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2012-01-06.13; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: golly-2.7-src/gui-wx/configure/configure0000755000175000017500000072532212536111506015341 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for golly 2.7. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='golly' PACKAGE_TARNAME='golly' PACKAGE_VERSION='2.7' PACKAGE_STRING='golly 2.7' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_unique_file="../../cmdline/bgolly.cpp" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LINUX_FALSE LINUX_TRUE MAC_FALSE MAC_TRUE WINDOWS_FALSE WINDOWS_TRUE SRCDISTSUFFIX BINDISTSUFFIX PYTHON_INCLUDE PERL_INCLUDE RESCOMP_FALSE RESCOMP_TRUE WX_PORT WX_SHARED WX_DEBUG WX_UNICODE WX_VERSION_MICRO WX_VERSION_MINOR WX_VERSION_MAJOR WX_RESCOMP WX_VERSION WX_LIBS_STATIC WX_LIBS WX_CXXFLAGS_ONLY WX_CFLAGS_ONLY WX_CXXFLAGS WX_CFLAGS WX_CPPFLAGS WX_CONFIG_PATH LIBOBJS CPP OBJDUMP am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE ac_ct_CXX CXXFLAGS CXX RANLIB SED EGREP GREP am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC ac_ct_AR AR PYTHON PERL GOLLYDIR am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_zlib with_perl_shlib with_python_shlib enable_dependency_tracking enable_largefile with_wxdir with_wx_config with_wx_prefix with_wx_exec_prefix enable_debug enable_unicode enable_shared with_toolkit with_wxshared ' ac_precious_vars='build_alias host_alias target_alias GOLLYDIR PERL PYTHON CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures golly 2.7 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/golly] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of golly 2.7:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --disable-largefile omit support for large files --enable-debug Build in debug mode (default is auto) --enable-unicode Build in Unicode mode (default is auto) --enable-shared Build as shared library (default is auto) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-zlib support reading compressed pattern files with zlib --with-perl-shlib=ARG name of the Perl library when loaded dynamically (e.g. libperl.so.5.12) --with-python-shlib=ARG name of the Python library when loaded dynamically (e.g. libpython2.6.so) --with-wxdir=PATH Use uninstalled version of wxWidgets in PATH --with-wx-config=CONFIG wx-config script to use (optional) --with-wx-prefix=PREFIX Prefix where wxWidgets is installed (optional) --with-wx-exec-prefix=PREFIX Exec prefix where wxWidgets is installed (optional) --with-toolkit Build against a specific wxWidgets toolkit (default is auto) --with-wxshared Force building against a shared build of wxWidgets, even if --disable-shared is given (default is auto) Some influential environment variables: GOLLYDIR golly data directory [default=DATADIR/golly] PERL Perl 5 interpreter PYTHON Python 2 interpreter CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF golly configure 2.7 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by golly $as_me 2.7, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- am__api_version='1.11' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='golly' VERSION='2.7' # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Custom configure arguments: # Check whether --with-zlib was given. if test "${with_zlib+set}" = set; then : withval=$with_zlib; else with_zlib=yes fi # Check whether --with-perl-shlib was given. if test "${with_perl_shlib+set}" = set; then : withval=$with_perl_shlib; else with_perl_shlib=check fi # Check whether --with-python-shlib was given. if test "${with_python_shlib+set}" = set; then : withval=$with_python_shlib; else with_python_shlib=check fi # Check for build tools: DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi if test -n "$ac_tool_prefix"; then for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar lib "link -lib" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} { $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5 $as_echo_n "checking the archiver ($AR) interface... " >&6; } if ${am_cv_ar_interface+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_ar_interface=ar cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int some_variable = 0; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=ar else am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5 (eval $am_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then am_cv_ar_interface=lib else am_cv_ar_interface=unknown fi fi rm -f conftest.lib libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5 $as_echo "$am_cv_ar_interface" >&6; } case $am_cv_ar_interface in ar) ;; lib) # Microsoft lib, so override with the ar-lib wrapper script. # FIXME: It is wrong to rewrite AR. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__AR in this case, # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something # similar. AR="$am_aux_dir/ar-lib $AR" ;; unknown) as_fn_error $? "could not determine $AR interface" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CXX_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CXX_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CXX_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CXX_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 $as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then am__fastdepCXX_TRUE= am__fastdepCXX_FALSE='#' else am__fastdepCXX_TRUE='#' am__fastdepCXX_FALSE= fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi if test "x$OBJDUMP" = x; then : as_fn_error $? "missing objdump" "$LINENO" 5 fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi # Check for standard header files: ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in inttypes.h limits.h stdint.h stdlib.h string.h sys/time.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Check for compiler characteristics: ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi # Check for large file support (enabled by default) # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if ${ac_cv_sys_largefile_CC+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if ${ac_cv_sys_large_files+:} false; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi # Check for library functions for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if ${ac_cv_func_malloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 $as_echo_n "checking for GNU libc compatible realloc... " >&6; } if ${ac_cv_func_realloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_realloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *realloc (); #endif int main () { return ! realloc (0, 0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_realloc_0_nonnull=yes else ac_cv_func_realloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 $as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } if test $ac_cv_func_realloc_0_nonnull = yes; then : $as_echo "#define HAVE_REALLOC 1" >>confdefs.h else $as_echo "#define HAVE_REALLOC 0" >>confdefs.h case " $LIBOBJS " in *" realloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS realloc.$ac_objext" ;; esac $as_echo "#define realloc rpl_realloc" >>confdefs.h fi for ac_func in gettimeofday memset pow strchr strdup strrchr do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # Find wxWidgets # Check whether --with-wxdir was given. if test "${with_wxdir+set}" = set; then : withval=$with_wxdir; wx_config_name="$withval/wx-config" wx_config_args="--inplace" fi # Check whether --with-wx-config was given. if test "${with_wx_config+set}" = set; then : withval=$with_wx_config; wx_config_name="$withval" fi # Check whether --with-wx-prefix was given. if test "${with_wx_prefix+set}" = set; then : withval=$with_wx_prefix; wx_config_prefix="$withval" else wx_config_prefix="" fi # Check whether --with-wx-exec-prefix was given. if test "${with_wx_exec_prefix+set}" = set; then : withval=$with_wx_exec_prefix; wx_config_exec_prefix="$withval" else wx_config_exec_prefix="" fi # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; else enableval="auto" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the --enable-debug option" >&5 $as_echo_n "checking for the --enable-debug option... " >&6; } if test "$enableval" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } DEBUG=1 elif test "$enableval" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } DEBUG=0 elif test "$enableval" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: will be automatically detected" >&5 $as_echo "will be automatically detected" >&6; } DEBUG="auto" else as_fn_error $? " Unrecognized option value (allowed values: yes, no, auto) " "$LINENO" 5 fi # Check whether --enable-unicode was given. if test "${enable_unicode+set}" = set; then : enableval=$enable_unicode; else enableval="auto" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the --enable-unicode option" >&5 $as_echo_n "checking for the --enable-unicode option... " >&6; } if test "$enableval" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } UNICODE=1 elif test "$enableval" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } UNICODE=0 elif test "$enableval" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: will be automatically detected" >&5 $as_echo "will be automatically detected" >&6; } UNICODE="auto" else as_fn_error $? " Unrecognized option value (allowed values: yes, no, auto) " "$LINENO" 5 fi # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; else enableval="auto" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the --enable-shared option" >&5 $as_echo_n "checking for the --enable-shared option... " >&6; } if test "$enableval" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SHARED=1 elif test "$enableval" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SHARED=0 elif test "$enableval" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: will be automatically detected" >&5 $as_echo "will be automatically detected" >&6; } SHARED="auto" else as_fn_error $? " Unrecognized option value (allowed values: yes, no, auto) " "$LINENO" 5 fi # Check whether --with-toolkit was given. if test "${with_toolkit+set}" = set; then : withval=$with_toolkit; else withval="auto" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the --with-toolkit option" >&5 $as_echo_n "checking for the --with-toolkit option... " >&6; } if test "$withval" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: will be automatically detected" >&5 $as_echo "will be automatically detected" >&6; } TOOLKIT="auto" else TOOLKIT="$withval" if test "$TOOLKIT" != "gtk1" -a "$TOOLKIT" != "gtk2" -a \ "$TOOLKIT" != "msw" -a "$TOOLKIT" != "motif" -a \ "$TOOLKIT" != "x11" -a "$TOOLKIT" != "mac" -a \ "$TOOLKIT" != "mgl" -a "$TOOLKIT" != "dfb" ; then as_fn_error $? " Unrecognized option value (allowed values: auto, gtk1, gtk2, msw, motif, x11, mac, mgl, dfb) " "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $TOOLKIT" >&5 $as_echo "$TOOLKIT" >&6; } fi # Check whether --with-wxshared was given. if test "${with_wxshared+set}" = set; then : withval=$with_wxshared; else withval="auto" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the --with-wxshared option" >&5 $as_echo_n "checking for the --with-wxshared option... " >&6; } if test "$withval" = "yes" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } WX_SHARED=1 elif test "1" = "1" -a "$withval" = "no" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } WX_SHARED=0 elif test "$withval" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: will be automatically detected" >&5 $as_echo "will be automatically detected" >&6; } WX_SHARED="auto" else as_fn_error $? " Unrecognized option value (allowed values: yes, auto) " "$LINENO" 5 fi if test "$WX_DEBUG_CONFIGURE" = "1"; then echo "[dbg] DEBUG: $DEBUG, WX_DEBUG: $WX_DEBUG" echo "[dbg] UNICODE: $UNICODE, WX_UNICODE: $WX_UNICODE" echo "[dbg] SHARED: $SHARED, WX_SHARED: $WX_SHARED" echo "[dbg] TOOLKIT: $TOOLKIT, WX_TOOLKIT: $WX_TOOLKIT" echo "[dbg] VERSION: $VERSION, WX_RELEASE: $WX_RELEASE" fi WX_DEBUG=$DEBUG WX_UNICODE=$UNICODE if test "$WX_SHARED" = "1" ; then WXCONFIG_FLAGS="--static=no " elif test "$WX_SHARED" = "0" ; then WXCONFIG_FLAGS="--static=yes " fi if test "$WX_DEBUG" = "1" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--debug=yes " elif test "$WX_DEBUG" = "0" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--debug=no " fi if test "$WX_UNICODE" = "1" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=yes " elif test "$WX_UNICODE" = "0" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=no " fi if test "$TOOLKIT" != "auto" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--toolkit=$TOOLKIT " fi if test "$WX_RELEASE" != "auto" ; then WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--version=$WX_RELEASE " fi WXCONFIG_FLAGS=${WXCONFIG_FLAGS% } if test "$WX_DEBUG_CONFIGURE" = "1"; then echo "[dbg] WXCONFIG_FLAGS: $WXCONFIG_FLAGS" fi if test x${WX_CONFIG_NAME+set} != xset ; then WX_CONFIG_NAME=wx-config fi if test "x$wx_config_name" != x ; then WX_CONFIG_NAME="$wx_config_name" fi if test x$wx_config_exec_prefix != x ; then wx_config_args="$wx_config_args --exec-prefix=$wx_config_exec_prefix" WX_LOOKUP_PATH="$wx_config_exec_prefix/bin" fi if test x$wx_config_prefix != x ; then wx_config_args="$wx_config_args --prefix=$wx_config_prefix" WX_LOOKUP_PATH="$WX_LOOKUP_PATH:$wx_config_prefix/bin" fi if test "$cross_compiling" = "yes"; then wx_config_args="$wx_config_args --host=$host_alias" fi if test -x "$WX_CONFIG_NAME" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wx-config" >&5 $as_echo_n "checking for wx-config... " >&6; } WX_CONFIG_PATH="$WX_CONFIG_NAME" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 $as_echo "$WX_CONFIG_PATH" >&6; } else # Extract the first word of "$WX_CONFIG_NAME", so it can be a program name with args. set dummy $WX_CONFIG_NAME; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_WX_CONFIG_PATH+:} false; then : $as_echo_n "(cached) " >&6 else case $WX_CONFIG_PATH in [\\/]* | ?:[\\/]*) ac_cv_path_WX_CONFIG_PATH="$WX_CONFIG_PATH" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_dummy=""$WX_LOOKUP_PATH:$PATH"" for as_dir in $as_dummy do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_WX_CONFIG_PATH="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_path_WX_CONFIG_PATH" && ac_cv_path_WX_CONFIG_PATH="no" ;; esac fi WX_CONFIG_PATH=$ac_cv_path_WX_CONFIG_PATH if test -n "$WX_CONFIG_PATH"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 $as_echo "$WX_CONFIG_PATH" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test "$WX_CONFIG_PATH" != "no" ; then WX_VERSION="" min_wx_version=2.8.0 if test -z "$WXCONFIG_FLAGS" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5 $as_echo_n "checking for wxWidgets version >= $min_wx_version... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version ($WXCONFIG_FLAGS)" >&5 $as_echo_n "checking for wxWidgets version >= $min_wx_version ($WXCONFIG_FLAGS)... " >&6; } fi WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args $WXCONFIG_FLAGS" WX_VERSION=`$WX_CONFIG_WITH_ARGS --version 2>/dev/null` wx_config_major_version=`echo $WX_VERSION | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` wx_config_minor_version=`echo $WX_VERSION | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` wx_config_micro_version=`echo $WX_VERSION | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` wx_requested_major_version=`echo $min_wx_version | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` wx_requested_minor_version=`echo $min_wx_version | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` wx_requested_micro_version=`echo $min_wx_version | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` wx_ver_ok="" if test "x$WX_VERSION" != x ; then if test $wx_config_major_version -gt $wx_requested_major_version; then wx_ver_ok=yes else if test $wx_config_major_version -eq $wx_requested_major_version; then if test $wx_config_minor_version -gt $wx_requested_minor_version; then wx_ver_ok=yes else if test $wx_config_minor_version -eq $wx_requested_minor_version; then if test $wx_config_micro_version -ge $wx_requested_micro_version; then wx_ver_ok=yes fi fi fi fi fi fi if test -n "$wx_ver_ok"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 $as_echo "yes (version $WX_VERSION)" >&6; } WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs ` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 $as_echo_n "checking for wxWidgets static library... " >&6; } WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs 2>/dev/null` if test "x$WX_LIBS_STATIC" = "x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi wx_has_cppflags="" if test $wx_config_major_version -gt 2; then wx_has_cppflags=yes else if test $wx_config_major_version -eq 2; then if test $wx_config_minor_version -gt 2; then wx_has_cppflags=yes else if test $wx_config_minor_version -eq 2; then if test $wx_config_micro_version -ge 6; then wx_has_cppflags=yes fi fi fi fi fi wx_has_rescomp="" if test $wx_config_major_version -gt 2; then wx_has_rescomp=yes else if test $wx_config_major_version -eq 2; then if test $wx_config_minor_version -ge 7; then wx_has_rescomp=yes fi fi fi if test "x$wx_has_rescomp" = x ; then WX_RESCOMP= else WX_RESCOMP=`$WX_CONFIG_WITH_ARGS --rescomp` fi if test "x$wx_has_cppflags" = x ; then WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags ` WX_CPPFLAGS=$WX_CFLAGS WX_CXXFLAGS=$WX_CFLAGS WX_CFLAGS_ONLY=$WX_CFLAGS WX_CXXFLAGS_ONLY=$WX_CFLAGS else WX_CPPFLAGS=`$WX_CONFIG_WITH_ARGS --cppflags ` WX_CXXFLAGS=`$WX_CONFIG_WITH_ARGS --cxxflags ` WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags ` WX_CFLAGS_ONLY=`echo $WX_CFLAGS | sed "s@^$WX_CPPFLAGS *@@"` WX_CXXFLAGS_ONLY=`echo $WX_CXXFLAGS | sed "s@^$WX_CFLAGS *@@"` fi : else if test "x$WX_VERSION" = x; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no (version $WX_VERSION is not new enough)" >&5 $as_echo "no (version $WX_VERSION is not new enough)" >&6; } fi WX_CFLAGS="" WX_CPPFLAGS="" WX_CXXFLAGS="" WX_LIBS="" WX_LIBS_STATIC="" WX_RESCOMP="" if test ! -z "$WXCONFIG_FLAGS"; then wx_error_message=" The configuration you asked for $PACKAGE_NAME requires a wxWidgets build with the following settings: $WXCONFIG_FLAGS but such build is not available. To see the wxWidgets builds available on this system, please use 'wx-config --list' command. To use the default build, returned by 'wx-config --selected-config', use the options with their 'auto' default values." fi wx_error_message=" The requested wxWidgets build couldn't be found. $wx_error_message If you still get this error, then check that 'wx-config' is in path, the directory where wxWidgets libraries are installed (returned by 'wx-config --libs' command) is in LD_LIBRARY_PATH or equivalent variable and wxWidgets version is 2.8.0 or above." as_fn_error $? "missing wxWidgets" "$LINENO" 5 fi else WX_CFLAGS="" WX_CPPFLAGS="" WX_CXXFLAGS="" WX_LIBS="" WX_LIBS_STATIC="" WX_RESCOMP="" as_fn_error $? "missing wxWidgets" "$LINENO" 5 fi WX_VERSION_MAJOR="$wx_config_major_version" WX_VERSION_MINOR="$wx_config_minor_version" WX_VERSION_MICRO="$wx_config_micro_version" WX_RELEASE="$WX_VERSION_MAJOR""$WX_VERSION_MINOR" if test $WX_RELEASE -lt 26 ; then as_fn_error $? " Cannot detect the wxWidgets configuration for the selected wxWidgets build since its version is $WX_VERSION < 2.6.0; please install a newer version of wxWidgets. " "$LINENO" 5 fi WX_SELECTEDCONFIG=$($WX_CONFIG_WITH_ARGS --selected_config) if test "$WX_DEBUG_CONFIGURE" = "1"; then echo "[dbg] Using wx-config --selected-config" echo "[dbg] WX_SELECTEDCONFIG: $WX_SELECTEDCONFIG" fi if test $WX_SHARED = "1"; then STATIC=0 elif test $WX_SHARED = "0"; then STATIC=1 elif test $WX_SHARED = "auto"; then STATIC="auto" fi if test "$UNICODE" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if wxWidgets was built with UNICODE enabled" >&5 $as_echo_n "checking if wxWidgets was built with UNICODE enabled... " >&6; } WX_UNICODE=$(expr "$WX_SELECTEDCONFIG" : ".*unicode.*") if test "$WX_UNICODE" != "0"; then WX_UNICODE=1 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : else WX_UNICODE=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi else WX_UNICODE=$UNICODE fi if test "$DEBUG" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if wxWidgets was built in DEBUG mode" >&5 $as_echo_n "checking if wxWidgets was built in DEBUG mode... " >&6; } WX_DEBUG=$(expr "$WX_SELECTEDCONFIG" : ".*debug.*") if test "$WX_DEBUG" != "0"; then WX_DEBUG=1 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : else WX_DEBUG=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi else WX_DEBUG=$DEBUG fi if test "$STATIC" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if wxWidgets was built in STATIC mode" >&5 $as_echo_n "checking if wxWidgets was built in STATIC mode... " >&6; } WX_STATIC=$(expr "$WX_SELECTEDCONFIG" : ".*static.*") if test "$WX_STATIC" != "0"; then WX_STATIC=1 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : else WX_STATIC=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } : fi else WX_STATIC=$STATIC fi if test "$WX_STATIC" != "0"; then WX_SHARED=0 else WX_SHARED=1 fi if test "$TOOLKIT" = "auto" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking which wxWidgets toolkit was selected" >&5 $as_echo_n "checking which wxWidgets toolkit was selected... " >&6; } WX_GTKPORT1=$(expr "$WX_SELECTEDCONFIG" : ".*gtk1.*") WX_GTKPORT2=$(expr "$WX_SELECTEDCONFIG" : ".*gtk2.*") WX_MSWPORT=$(expr "$WX_SELECTEDCONFIG" : ".*msw.*") WX_MOTIFPORT=$(expr "$WX_SELECTEDCONFIG" : ".*motif.*") WX_OSXCOCOAPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_cocoa.*") WX_OSXCARBONPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_carbon.*") WX_X11PORT=$(expr "$WX_SELECTEDCONFIG" : ".*x11.*") WX_MGLPORT=$(expr "$WX_SELECTEDCONFIG" : ".*mgl.*") WX_DFBPORT=$(expr "$WX_SELECTEDCONFIG" : ".*dfb.*") WX_PORT="unknown" if test "$WX_GTKPORT1" != "0"; then WX_PORT="gtk1"; fi if test "$WX_GTKPORT2" != "0"; then WX_PORT="gtk2"; fi if test "$WX_MSWPORT" != "0"; then WX_PORT="msw"; fi if test "$WX_MOTIFPORT" != "0"; then WX_PORT="motif"; fi if test "$WX_OSXCOCOAPORT" != "0"; then WX_PORT="osx_cocoa"; fi if test "$WX_OSXCARBONPORT" != "0"; then WX_PORT="osx_carbon"; fi if test "$WX_X11PORT" != "0"; then WX_PORT="x11"; fi if test "$WX_MGLPORT" != "0"; then WX_PORT="mgl"; fi if test "$WX_DFBPORT" != "0"; then WX_PORT="dfb"; fi WX_MACPORT=$(expr "$WX_SELECTEDCONFIG" : ".*mac.*") if test "$WX_MACPORT" != "0"; then WX_PORT="mac"; fi if test "$WX_PORT" = "unknown" ; then as_fn_error $? " Cannot detect the currently installed wxWidgets port ! Please check your 'wx-config --cxxflags'... " "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $WX_PORT" >&5 $as_echo "$WX_PORT" >&6; } else if test -z "$TOOLKIT" ; then WX_PORT=$TOOLKIT else WX_PORT=$PORT fi fi if test "$WX_DEBUG_CONFIGURE" = "1"; then echo "[dbg] Values of all WX_* options after final detection:" echo "[dbg] WX_DEBUG: $WX_DEBUG" echo "[dbg] WX_UNICODE: $WX_UNICODE" echo "[dbg] WX_SHARED: $WX_SHARED" echo "[dbg] WX_RELEASE: $WX_RELEASE" echo "[dbg] WX_PORT: $WX_PORT" fi if test "$WX_SHARED" = "0" -a "$SHARED" = "1"; then as_fn_error $? " Cannot build shared library against a static build of wxWidgets ! This error happens because the wxWidgets build which was selected has been detected as static while you asked to build $PACKAGE_NAME as shared library and this is not possible. Use the '--disable-shared' option to build $PACKAGE_NAME as static library or '--with-wxshared' to use wxWidgets as shared library. " "$LINENO" 5 fi if test "$DEBUG" = "auto"; then DEBUG=$WX_DEBUG fi if test "$UNICODE" = "auto"; then UNICODE=$WX_UNICODE fi if test "$SHARED" = "auto"; then SHARED=$WX_SHARED fi if test "$TOOLKIT" = "auto"; then TOOLKIT=$WX_PORT fi if test "$DEBUG" = "1"; then BUILD="debug" elif test "$DEBUG" = "0" -o "$DEBUG" = ""; then BUILD="release" fi if test "$DEBUG" = "1"; then CXXFLAGS="$CXXFLAGS -g -O0" CFLAGS="$CFLAGS -g -O0" else CXXFLAGS="$CXXFLAGS -O2" CFLAGS="$CFLAGS -O2" fi if test "x$WX_RESCOMP" != x; then RESCOMP_TRUE= RESCOMP_FALSE='#' else RESCOMP_TRUE='#' RESCOMP_FALSE= fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu save_CXXFLAGS=$CXXFLAGS save_LIBS=$LIBS CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" LIBS="$LIBS $WX_LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BMP image handler" >&5 $as_echo_n "checking for BMP image handler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main() { new wxBMPHandler(); } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; $as_echo "#define HAVE_WX_BMP_HANDLER 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS=$save_CXXFLAGS LIBS=$save_LIBS ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu save_CXXFLAGS=$CXXFLAGS save_LIBS=$LIBS CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" LIBS="$LIBS $WX_LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GIF image handler" >&5 $as_echo_n "checking for GIF image handler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main() { new wxGIFHandler(); } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; $as_echo "#define HAVE_WX_GIF_HANDLER 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS=$save_CXXFLAGS LIBS=$save_LIBS ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu save_CXXFLAGS=$CXXFLAGS save_LIBS=$LIBS CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" LIBS="$LIBS $WX_LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PNG image handler" >&5 $as_echo_n "checking for PNG image handler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main() { new wxPNGHandler(); } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; $as_echo "#define HAVE_WX_PNG_HANDLER 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS=$save_CXXFLAGS LIBS=$save_LIBS ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu save_CXXFLAGS=$CXXFLAGS save_LIBS=$LIBS CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS" LIBS="$LIBS $WX_LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for TIFF image handler" >&5 $as_echo_n "checking for TIFF image handler... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main() { new wxTIFFHandler(); } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; }; $as_echo "#define HAVE_WX_TIFF_HANDLER 1" >>confdefs.h else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS=$save_CXXFLAGS LIBS=$save_LIBS ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find Perl for ac_prog in perl5 perl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PERL+:} false; then : $as_echo_n "(cached) " >&6 else case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 $as_echo "$PERL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$PERL" && break done if test "x$PERL" = x; then : as_fn_error $? "missing Perl" "$LINENO" 5 fi PERL_INCLUDE=`$PERL -MExtUtils::Embed -e ccopts` if test "x$with_perl_shlib" = xcheck; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for perl shared library used by $PERL" >&5 $as_echo_n "checking for perl shared library used by $PERL... " >&6; } shlib=`$OBJDUMP -p "$PERL" \ | $EGREP -i 'NEEDED +libperl[0-9.]*[.]so|DLL Name: +perl[0-9.]*[.]dll' \ | $SED 's/^.* //'` if test "x$shlib" != x; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: $shlib" >&5 $as_echo "$shlib" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } shlib= fi else shlib=$with_perl_shlib fi if test "x$shlib" = x; then : as_fn_error $? "could not determine Perl shared library name" "$LINENO" 5 fi cat >>confdefs.h <<_ACEOF #define PERL_SHLIB $shlib _ACEOF # Find Python for ac_prog in python2 python do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PYTHON+:} false; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$PYTHON" && break done if test "x$PYTHON" = x; then : as_fn_error $? "missing Python" "$LINENO" 5 fi PYTHON_INCLUDE=-I"'`$PYTHON -c "import distutils.sysconfig; print(distutils.sysconfig.get_python_inc())"`'" if test "x$with_python_shlib" = xcheck; then : shlib=`$PYTHON -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LDLIBRARY') or '')"` if test "x$shlib" = x; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for python shared library used by $PYTHON" >&5 $as_echo_n "checking for python shared library used by $PYTHON... " >&6; } shlib=`$OBJDUMP -p "$PYTHON" \ | $EGREP -i 'NEEDED +libpython[0-9.]*[.]so|DLL Name: +python[0-9.]*[.]dll' \ | $SED 's/^.* //'` if test "x$shlib" != x; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: $shlib" >&5 $as_echo "$shlib" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 $as_echo "not found" >&6; } shlib= fi fi else shlib=$with_python_shlib fi if test "x$shlib" = x; then : as_fn_error $? "could not determine Python shared library name" "$LINENO" 5 fi cat >>confdefs.h <<_ACEOF #define PYTHON_SHLIB $shlib _ACEOF # Find zlib (unless explicitly disabled) if test "x$with_zlib" != xno; then : ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes; then : else as_fn_error $? "missing zlib" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gzopen" >&5 $as_echo_n "checking for library containing gzopen... " >&6; } if ${ac_cv_search_gzopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gzopen (); int main () { return gzopen (); ; return 0; } _ACEOF for ac_lib in '' z; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_gzopen=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if ${ac_cv_search_gzopen+:} false; then : break fi done if ${ac_cv_search_gzopen+:} false; then : else ac_cv_search_gzopen=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gzopen" >&5 $as_echo "$ac_cv_search_gzopen" >&6; } ac_res=$ac_cv_search_gzopen if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" else as_fn_error $? "missing zlib" "$LINENO" 5 fi $as_echo "#define ZLIB 1" >>confdefs.h fi # Definitions used in the source: cat >>confdefs.h <<_ACEOF #define VERSION $PACKAGE_VERSION _ACEOF GOLLYDIR=${GOLLYDIR:-'${pkgdatadir}'} # Determine which of three supported target operating systems we will compile # for, and set a suffix for binary distributions accordingly: case $target_os in cygwin* | mingw* | pw32* | cegcc*) id=win ;; darwin* | rhapsody*) id=mac ;; linux*) id=gtk ;; *) id= ;; esac case $target_cpu in *64) bits=64 ;; *) bits= ;; esac BINDISTSUFFIX=${id:+-$id$bits} SRCDISTSUFFIX=-src if test x$id = xwin ; then WINDOWS_TRUE= WINDOWS_FALSE='#' else WINDOWS_TRUE='#' WINDOWS_FALSE= fi if test x$id = xmac ; then MAC_TRUE= MAC_FALSE='#' else MAC_TRUE='#' MAC_FALSE= fi if test x$id = xgtk ; then LINUX_TRUE= LINUX_FALSE='#' else LINUX_TRUE='#' LINUX_FALSE= fi # Generate output ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${RESCOMP_TRUE}" && test -z "${RESCOMP_FALSE}"; then as_fn_error $? "conditional \"RESCOMP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WINDOWS_TRUE}" && test -z "${WINDOWS_FALSE}"; then as_fn_error $? "conditional \"WINDOWS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${MAC_TRUE}" && test -z "${MAC_FALSE}"; then as_fn_error $? "conditional \"MAC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${LINUX_TRUE}" && test -z "${LINUX_FALSE}"; then as_fn_error $? "conditional \"LINUX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by golly $as_me 2.7, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ golly config.status 2.7 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi echo echo " The wxWidgets build which will be used by $PACKAGE_NAME $PACKAGE_VERSION" echo " has the following settings:" if test "x$WX_DEBUG" = "x1" ; then echo " - DEBUG build" elif test "x$WX_DEBUG" = "x0" ; then echo " - RELEASE build" else echo "WX_DEBUG is $WX_DEBUG" fi if test "x$WX_UNICODE" = "x1" ; then echo " - UNICODE mode" elif test "x$WX_UNICODE" = "x0" ; then echo " - ANSI mode" else echo "WX_UNICODE is $WX_UNICODE" fi if test "x$WX_SHARED" = "x1" ; then echo " - SHARED mode" elif test "x$WX_SHARED" = "x0" ; then echo " - STATIC mode" else echo "WX_SHARED is $WX_SHARED" fi echo " - VERSION: $WX_VERSION" echo " - PORT: $WX_PORT" golly-2.7-src/gui-wx/configure/autogen.sh0000755000175000017500000000114112536111364015417 00000000000000#!/bin/bash -e rm -f sources.am echo libgolly_a_SOURCES = ../../gollybase/*.{h,cpp} >>sources.am echo golly_SOURCES = ../../gui-wx/*.{h,cpp} >>sources.am echo 'gollydatadir = $(pkgdatadir)/Patterns/Life/' >>sources.am echo nobase_dist_gollydata_DATA = `find ../../{Help,Patterns,Rules,Scripts} -type f | sort` >>sources.am echo EXTRA_DIST = \ ../../gui-wx/{makefile-{gtk,mac,win},CMakeLists.txt,Info.plist.in,*.mk,*.rc,configure/autogen.sh,icons,bitmaps} \ ../../gui-common $(find ../../gui-{android,ios,web} -type f | sort) \ ../../docs >>sources.am aclocal -I m4 automake --add-missing --copy autoconf golly-2.7-src/gui-wx/configure/Makefile.in0000644000175000017500000043333412536111506015476 00000000000000# Makefile.in generated by automake 1.11.6 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__make_dryrun = \ { \ am__dry=no; \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ *) \ for am__flg in $$MAKEFLAGS; do \ case $$am__flg in \ *=*|--*) ;; \ *n*) am__dry=yes; break;; \ esac; \ done;; \ esac; \ test $$am__dry = yes; \ } pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = golly$(EXEEXT) bgolly$(EXEEXT) noinst_PROGRAMS = RuleTableToTree$(EXEEXT) DIST_COMMON = $(am__configure_deps) $(nobase_dist_gollydata_DATA) \ $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/sources.am $(top_srcdir)/configure ar-lib \ config.guess config.sub depcomp install-sh missing @WINDOWS_TRUE@am__append_1 = gollyres.o subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/shlib.m4 \ $(top_srcdir)/m4/wximage.m4 $(top_srcdir)/m4/wxwin.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru libgolly_a_AR = $(AR) $(ARFLAGS) libgolly_a_LIBADD = am_libgolly_a_OBJECTS = bigint.$(OBJEXT) generationsalgo.$(OBJEXT) \ ghashbase.$(OBJEXT) ghashdraw.$(OBJEXT) hlifealgo.$(OBJEXT) \ hlifedraw.$(OBJEXT) jvnalgo.$(OBJEXT) lifealgo.$(OBJEXT) \ lifepoll.$(OBJEXT) liferender.$(OBJEXT) liferules.$(OBJEXT) \ qlifealgo.$(OBJEXT) qlifedraw.$(OBJEXT) readpattern.$(OBJEXT) \ ruleloaderalgo.$(OBJEXT) ruletable_algo.$(OBJEXT) \ ruletreealgo.$(OBJEXT) util.$(OBJEXT) viewport.$(OBJEXT) \ writepattern.$(OBJEXT) libgolly_a_OBJECTS = $(am_libgolly_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)" \ "$(DESTDIR)$(gollydatadir)" PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_RuleTableToTree_OBJECTS = RuleTableToTree.$(OBJEXT) RuleTableToTree_OBJECTS = $(am_RuleTableToTree_OBJECTS) RuleTableToTree_DEPENDENCIES = libgolly.a am_bgolly_OBJECTS = bgolly.$(OBJEXT) bgolly_OBJECTS = $(am_bgolly_OBJECTS) bgolly_DEPENDENCIES = libgolly.a am_golly_OBJECTS = golly-wxalgos.$(OBJEXT) golly-wxcontrol.$(OBJEXT) \ golly-wxedit.$(OBJEXT) golly-wxfile.$(OBJEXT) \ golly-wxgolly.$(OBJEXT) golly-wxhelp.$(OBJEXT) \ golly-wxinfo.$(OBJEXT) golly-wxlayer.$(OBJEXT) \ golly-wxmain.$(OBJEXT) golly-wxperl.$(OBJEXT) \ golly-wxprefs.$(OBJEXT) golly-wxpython.$(OBJEXT) \ golly-wxrender.$(OBJEXT) golly-wxrule.$(OBJEXT) \ golly-wxscript.$(OBJEXT) golly-wxselect.$(OBJEXT) \ golly-wxstatus.$(OBJEXT) golly-wxtimeline.$(OBJEXT) \ golly-wxundo.$(OBJEXT) golly-wxutils.$(OBJEXT) \ golly-wxview.$(OBJEXT) golly_OBJECTS = $(am_golly_OBJECTS) am__DEPENDENCIES_1 = golly_DEPENDENCIES = $(am__DEPENDENCIES_1) libgolly.a $(am__append_1) golly_LINK = $(CXXLD) $(golly_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(libgolly_a_SOURCES) $(RuleTableToTree_SOURCES) \ $(bgolly_SOURCES) $(golly_SOURCES) DIST_SOURCES = $(libgolly_a_SOURCES) $(RuleTableToTree_SOURCES) \ $(bgolly_SOURCES) $(golly_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(doc_DATA) $(nobase_dist_gollydata_DATA) ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDISTSUFFIX = @BINDISTSUFFIX@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CXX = @CXX@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GOLLYDIR = @GOLLYDIR@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PERL_INCLUDE = @PERL_INCLUDE@ PYTHON = @PYTHON@ PYTHON_INCLUDE = @PYTHON_INCLUDE@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SRCDISTSUFFIX = @SRCDISTSUFFIX@ STRIP = @STRIP@ VERSION = @VERSION@ WX_CFLAGS = @WX_CFLAGS@ WX_CFLAGS_ONLY = @WX_CFLAGS_ONLY@ WX_CONFIG_PATH = @WX_CONFIG_PATH@ WX_CPPFLAGS = @WX_CPPFLAGS@ WX_CXXFLAGS = @WX_CXXFLAGS@ WX_CXXFLAGS_ONLY = @WX_CXXFLAGS_ONLY@ WX_DEBUG = @WX_DEBUG@ WX_LIBS = @WX_LIBS@ WX_LIBS_STATIC = @WX_LIBS_STATIC@ WX_PORT = @WX_PORT@ WX_RESCOMP = @WX_RESCOMP@ WX_SHARED = @WX_SHARED@ WX_UNICODE = @WX_UNICODE@ WX_VERSION = @WX_VERSION@ WX_VERSION_MAJOR = @WX_VERSION_MAJOR@ WX_VERSION_MICRO = @WX_VERSION_MICRO@ WX_VERSION_MINOR = @WX_VERSION_MINOR@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -I$(top_srcdir)/../../gollybase/ AM_CXXFLAGS = -DGOLLYDIR="$(GOLLYDIR)" -Wall -fno-strict-aliasing AM_LDFLAGS = -Wl,--as-needed noinst_LIBRARIES = libgolly.a doc_DATA = ../../docs/License.html ../../docs/ReadMe.html libgolly_a_SOURCES = ../../gollybase/bigint.h \ ../../gollybase/generationsalgo.h ../../gollybase/ghashbase.h \ ../../gollybase/hlifealgo.h ../../gollybase/jvnalgo.h \ ../../gollybase/lifealgo.h ../../gollybase/lifepoll.h \ ../../gollybase/liferender.h ../../gollybase/liferules.h \ ../../gollybase/platform.h ../../gollybase/qlifealgo.h \ ../../gollybase/readpattern.h ../../gollybase/ruleloaderalgo.h \ ../../gollybase/ruletable_algo.h \ ../../gollybase/ruletreealgo.h ../../gollybase/util.h \ ../../gollybase/viewport.h ../../gollybase/writepattern.h \ ../../gollybase/bigint.cpp ../../gollybase/generationsalgo.cpp \ ../../gollybase/ghashbase.cpp ../../gollybase/ghashdraw.cpp \ ../../gollybase/hlifealgo.cpp ../../gollybase/hlifedraw.cpp \ ../../gollybase/jvnalgo.cpp ../../gollybase/lifealgo.cpp \ ../../gollybase/lifepoll.cpp ../../gollybase/liferender.cpp \ ../../gollybase/liferules.cpp ../../gollybase/qlifealgo.cpp \ ../../gollybase/qlifedraw.cpp ../../gollybase/readpattern.cpp \ ../../gollybase/ruleloaderalgo.cpp \ ../../gollybase/ruletable_algo.cpp \ ../../gollybase/ruletreealgo.cpp ../../gollybase/util.cpp \ ../../gollybase/viewport.cpp ../../gollybase/writepattern.cpp golly_SOURCES = ../../gui-wx/wxalgos.h ../../gui-wx/wxedit.h ../../gui-wx/wxgolly.h ../../gui-wx/wxhelp.h ../../gui-wx/wxinfo.h ../../gui-wx/wxlayer.h ../../gui-wx/wxmain.h ../../gui-wx/wxperl.h ../../gui-wx/wxprefs.h ../../gui-wx/wxpython.h ../../gui-wx/wxrender.h ../../gui-wx/wxrule.h ../../gui-wx/wxscript.h ../../gui-wx/wxselect.h ../../gui-wx/wxstatus.h ../../gui-wx/wxtimeline.h ../../gui-wx/wxundo.h ../../gui-wx/wxutils.h ../../gui-wx/wxview.h ../../gui-wx/wxalgos.cpp ../../gui-wx/wxcontrol.cpp ../../gui-wx/wxedit.cpp ../../gui-wx/wxfile.cpp ../../gui-wx/wxgolly.cpp ../../gui-wx/wxhelp.cpp ../../gui-wx/wxinfo.cpp ../../gui-wx/wxlayer.cpp ../../gui-wx/wxmain.cpp ../../gui-wx/wxperl.cpp ../../gui-wx/wxprefs.cpp ../../gui-wx/wxpython.cpp ../../gui-wx/wxrender.cpp ../../gui-wx/wxrule.cpp ../../gui-wx/wxscript.cpp ../../gui-wx/wxselect.cpp ../../gui-wx/wxstatus.cpp ../../gui-wx/wxtimeline.cpp ../../gui-wx/wxundo.cpp ../../gui-wx/wxutils.cpp ../../gui-wx/wxview.cpp gollydatadir = $(pkgdatadir)/Patterns/Life/ nobase_dist_gollydata_DATA = ../../Help/about.gif \ ../../Help/about.html ../../Help/Algorithms/Generations.html \ ../../Help/Algorithms/HashLife.html \ ../../Help/Algorithms/JvN.html \ ../../Help/Algorithms/QuickLife.html \ ../../Help/Algorithms/RuleLoader.html ../../Help/algos.html \ ../../Help/archives.html ../../Help/bounded.html \ ../../Help/changes.html ../../Help/control.html \ ../../Help/credits.html ../../Help/edit.html \ ../../Help/file.html ../../Help/formats.html \ ../../Help/help.html ../../Help/index.html \ ../../Help/intro.html ../../Help/layer.html \ ../../Help/Lexicon/lex_1.htm ../../Help/Lexicon/lex_a.htm \ ../../Help/Lexicon/lex_b.htm ../../Help/Lexicon/lex_bib.htm \ ../../Help/Lexicon/lex_c.htm ../../Help/Lexicon/lex_d.htm \ ../../Help/Lexicon/lex_e.htm ../../Help/Lexicon/lex_f.htm \ ../../Help/Lexicon/lex_g.htm ../../Help/Lexicon/lex_h.htm \ ../../Help/Lexicon/lex.htm ../../Help/Lexicon/lex_i.htm \ ../../Help/Lexicon/lex_j.htm ../../Help/Lexicon/lex_k.htm \ ../../Help/Lexicon/lex_l.htm ../../Help/Lexicon/lex_m.htm \ ../../Help/Lexicon/lex_n.htm ../../Help/Lexicon/lex_o.htm \ ../../Help/Lexicon/lex_p.htm ../../Help/Lexicon/lex_q.htm \ ../../Help/Lexicon/lex_r.htm ../../Help/Lexicon/lex_s.htm \ ../../Help/Lexicon/lex_t.htm ../../Help/Lexicon/lex_u.htm \ ../../Help/Lexicon/lex_v.htm ../../Help/Lexicon/lex_w.htm \ ../../Help/Lexicon/lex_x.htm ../../Help/Lexicon/lex_y.htm \ ../../Help/Lexicon/lex_z.htm ../../Help/Lexicon/modify.pl \ ../../Help/mouse.html ../../Help/perl.html \ ../../Help/problems.html ../../Help/python.html \ ../../Help/refs.html ../../Help/tips.html ../../Help/view.html \ ../../Patterns/Banks/Banks-I-demo.rle \ ../../Patterns/Banks/Banks-II-demo.rle \ ../../Patterns/Banks/Banks-III-demo.rle \ ../../Patterns/Banks/Banks-IV-constructor.rle.gz \ ../../Patterns/Banks/Banks-IV-demo.rle \ ../../Patterns/Codd/clocking-on-demo.rle \ ../../Patterns/Codd/coders-demo.rle \ ../../Patterns/Codd/construction-arm-demo.rle \ ../../Patterns/Codd/crossover-unidir-demo.rle \ ../../Patterns/Codd/decoder-4bit-demo.rle.gz \ ../../Patterns/Codd/echo-discriminator.rle \ ../../Patterns/Codd/echo-switch-demo.rle \ ../../Patterns/Codd/extend-coder-demo.rle \ ../../Patterns/Codd/gates-demo.rle \ ../../Patterns/Codd/golly-constructor.rle.gz \ ../../Patterns/Codd/Goucher-replicator.mc.gz \ ../../Patterns/Codd/repeater-emitter-demo.rle \ ../../Patterns/Codd/sensing-demo.rle \ ../../Patterns/Codd/sheathing-demo.rle \ ../../Patterns/Codd/sheathing-problems.rle \ ../../Patterns/Codd/signals-demo.rle \ ../../Patterns/Codd/tape-reader-demo.rle \ ../../Patterns/Devore/crossover.rle \ ../../Patterns/Devore/Devore-body.rle \ ../../Patterns/Devore/Devore-rep.rle \ ../../Patterns/Devore/discriminator.rle \ ../../Patterns/Generations/Banner.mcl \ ../../Patterns/Generations/Bloomerang.mcl \ ../../Patterns/Generations/Burst.mcl \ ../../Patterns/Generations/Caterpillars.mcl \ ../../Patterns/Generations/Delta.rle \ ../../Patterns/Generations/Ebb-and-Flow.mcl \ ../../Patterns/Generations/Fireworks.mcl \ ../../Patterns/Generations/Lava.mcl \ ../../Patterns/Generations/Lines.mcl \ ../../Patterns/Generations/MeteorGuns.mcl \ ../../Patterns/Generations/Nova.mcl \ ../../Patterns/Generations/Perfect-spiral.mcl \ ../../Patterns/Generations/Sawfish.rle \ ../../Patterns/Generations/SediMental.mcl \ ../../Patterns/Generations/Steeplechase.mcl \ ../../Patterns/Generations/Transers.mcl \ ../../Patterns/Generations/What-a-mess.mcl \ ../../Patterns/HashLife/broken-lines.mc \ ../../Patterns/HashLife/catacryst.mc \ ../../Patterns/HashLife/gotts-dots.mc \ ../../Patterns/HashLife/hashlife-oddity1.mc \ ../../Patterns/HashLife/hashlife-oddity2.mc \ ../../Patterns/HashLife/hexadecimal.mc.gz \ ../../Patterns/HashLife/jagged2.mc \ ../../Patterns/HashLife/jagged.mc \ ../../Patterns/HashLife/loafer-gun-p8388608-linear.mc.gz \ ../../Patterns/HashLife/logarithmic-width.mc \ ../../Patterns/HashLife/metacatacryst.mc \ ../../Patterns/HashLife/metapixel-galaxy.mc.gz \ ../../Patterns/HashLife/metapixel-p216-gun.mc.gz \ ../../Patterns/HashLife/metapixel-parity64.mc.gz \ ../../Patterns/HashLife/mosquito5.mc \ ../../Patterns/HashLife/nick-gotts-1.mc \ ../../Patterns/HashLife/nick-gotts-2.mc \ ../../Patterns/HashLife/puzzle.mc \ ../../Patterns/HashLife/Replicator-p237228340.mc.gz \ ../../Patterns/HashLife/ruler.mc \ ../../Patterns/HashLife/totalperiodic.mc \ ../../Patterns/HashLife/unlimited-novelty.mc \ ../../Patterns/HashLife/wedge-grow.mc \ ../../Patterns/HashLife/wolfram22.mc \ ../../Patterns/JvN/Boustrophedon-replicator.rle \ ../../Patterns/JvN/cell-coders-demo.rle \ ../../Patterns/JvN/codon4-auto-retract.rle \ ../../Patterns/JvN/codon5-auto-retract.rle \ ../../Patterns/JvN/construction-arm-demo.rle \ ../../Patterns/JvN/counter-demo.rle \ ../../Patterns/JvN/golly-constructor.rle \ ../../Patterns/JvN/Hutton-replicator.rle \ ../../Patterns/JvN/JvN-loop-replicator.rle.gz \ ../../Patterns/JvN/N-compressed-replicator.rle \ ../../Patterns/JvN/NP-mutation.rle.gz \ ../../Patterns/JvN/NP-replicator.rle.gz \ ../../Patterns/JvN/partial-constructor.mc.gz \ ../../Patterns/JvN/read-arm-demo.rle \ ../../Patterns/JvN/sphinx.mc.gz \ ../../Patterns/JvN/sphinx-midpoint.mc.gz \ ../../Patterns/JvN/sphinx-spark.mc.gz \ ../../Patterns/Life/Bounded-Grids/agar-p3.rle \ ../../Patterns/Life/Bounded-Grids/cross-surface.rle \ ../../Patterns/Life/Bounded-Grids/herringbone-agar-p14.rle \ ../../Patterns/Life/Bounded-Grids/Klein-bottle.rle \ ../../Patterns/Life/Bounded-Grids/lightspeed-bubble.rle \ ../../Patterns/Life/Bounded-Grids/pulsars-in-tube.rle \ ../../Patterns/Life/Bounded-Grids/sphere.rle \ ../../Patterns/Life/Bounded-Grids/torus.rle \ ../../Patterns/Life/Bounded-Grids/torus-with-shift.rle \ ../../Patterns/Life/Breeders/breeder.lif \ ../../Patterns/Life/Breeders/c4-diag-switch-engines.rle \ ../../Patterns/Life/Breeders/LWSS-breeder.rle \ ../../Patterns/Life/Breeders/p100-H-channel-breeder.rle \ ../../Patterns/Life/Breeders/p90-rake-factory.rle \ ../../Patterns/Life/Breeders/pi-blink-breeder1.rle \ ../../Patterns/Life/Breeders/pi-blink-breeder2.rle \ ../../Patterns/Life/Breeders/rake-breeder.rle \ ../../Patterns/Life/Breeders/slide-breeder.rle \ ../../Patterns/Life/Breeders/spacefiller.rle \ ../../Patterns/Life/Breeders/switch-engine-breeder-MR.rle \ ../../Patterns/Life/Breeders/switch-engine-breeder.rle \ ../../Patterns/Life/Guns/2c5-spaceship-gun-p416.rle \ ../../Patterns/Life/Guns/2c5-spaceship-gun-p690.rle \ ../../Patterns/Life/Guns/7-in-a-row-Cordership-V-gun.rle \ ../../Patterns/Life/Guns/Cordership-gun-p784.rle \ ../../Patterns/Life/Guns/golly-ticker.rle \ ../../Patterns/Life/Guns/gun-p165mwss.rle \ ../../Patterns/Life/Guns/loafer-gun-p210.rle \ ../../Patterns/Life/Guns/p59-gun-with-Snark-reflectors.rle \ ../../Patterns/Life/Guns/p690-PT-Cordership-gun.rle \ ../../Patterns/Life/Guns/pseudo-p34-gun.rle \ ../../Patterns/Life/Guns/vacuum-cleaner.rle \ ../../Patterns/Life-Like/alt-wicks.py \ ../../Patterns/Life-Like/coral.rle \ ../../Patterns/Life-Like/Day-and-Night-gun-and-antigun.rle \ ../../Patterns/Life-Like/ice-nine.rle \ ../../Patterns/Life-Like/Morley/breeder2.rle \ ../../Patterns/Life-Like/Morley/enterprise-gun.rle \ ../../Patterns/Life-Like/Morley/growing-ship.rle \ ../../Patterns/Life-Like/p168-knightship.rle \ ../../Patterns/Life-Like/persian-rugs.lif \ ../../Patterns/Life-Like/replicator.rle \ ../../Patterns/Life-Like/spiral-growth.rle \ ../../Patterns/Life-Like/white-whale.rle \ ../../Patterns/Life/Methuselahs/acorn.lif \ ../../Patterns/Life/Methuselahs/ark1.rle \ ../../Patterns/Life/Methuselahs/ark2.rle \ ../../Patterns/Life/Methuselahs/blom.rle \ ../../Patterns/Life/Methuselahs/iwona.rle \ ../../Patterns/Life/Methuselahs/justyna.rle \ ../../Patterns/Life/Methuselahs/lidka-predecessor.rle \ ../../Patterns/Life/Methuselahs/natural-LWSS.rle \ ../../Patterns/Life/Methuselahs/rabbits.lif \ ../../Patterns/Life/Methuselahs/rabbits-relation-17423.rle \ ../../Patterns/Life/Methuselahs/rabbits-relation-17465.rle \ ../../Patterns/Life/Methuselahs/temp-pulsars-big-s.rle \ ../../Patterns/Life/Miscellaneous/blockstacker.rle \ ../../Patterns/Life/Miscellaneous/Calcyman-primer.zip \ ../../Patterns/Life/Miscellaneous/Cambrian-Explosion.rle \ ../../Patterns/Life/Miscellaneous/diagfuse1.rle \ ../../Patterns/Life/Miscellaneous/die658.rle \ ../../Patterns/Life/Miscellaneous/elbow-ladders.rle \ ../../Patterns/Life/Miscellaneous/fermat-primes.rle \ ../../Patterns/Life/Miscellaneous/four-primers.rle.gz \ ../../Patterns/Life/Miscellaneous/infinity-hotel0.rle \ ../../Patterns/Life/Miscellaneous/infinity-hotel1.rle \ ../../Patterns/Life/Miscellaneous/infinity-hotel2.rle \ ../../Patterns/Life/Miscellaneous/infinity-hotel3.rle \ ../../Patterns/Life/Miscellaneous/lightspeed.rle \ ../../Patterns/Life/Miscellaneous/loggrow-corder.rle \ ../../Patterns/Life/Miscellaneous/sawtooth6b.rle \ ../../Patterns/Life/Miscellaneous/tubstretch-c124b.rle \ ../../Patterns/Life/Miscellaneous/twinprimes.rle \ ../../Patterns/Life/Miscellaneous/wicks-DRH-2002.rle \ ../../Patterns/Life/Oscillators/billiard-table.rle \ ../../Patterns/Life/Oscillators/DRH-oscillators.rle \ ../../Patterns/Life/Oscillators/extensible-low-period.rle \ ../../Patterns/Life/Oscillators/glider-stream-crystal.rle \ ../../Patterns/Life/Oscillators/low-period.rle \ ../../Patterns/Life/Oscillators/p103079214841.rle \ ../../Patterns/Life/Oscillators/p138.rle \ ../../Patterns/Life/Oscillators/p59-glider-loop.py \ ../../Patterns/Life/Oscillators/queen-bee-turn.rle \ ../../Patterns/Life/Oscillators/traffic-light-hasslers.rle \ ../../Patterns/Life/Oscillators/unique-high-period.rle \ ../../Patterns/Life/Puffers/c4-diagonal-puffer.rle \ ../../Patterns/Life/Puffers/line-puffer-superstable.rle \ ../../Patterns/Life/Puffers/line-puffer-unstable.rle \ ../../Patterns/Life/Puffers/p100-H-track-puffer.rle \ ../../Patterns/Life/Puffers/pi-fuse-puffer.rle \ ../../Patterns/Life/Puffers/puffer-2c5.rle \ ../../Patterns/Life/Puffers/puffer-train.rle \ ../../Patterns/Life/Puffers/zigzag-wickstretcher.rle \ ../../Patterns/Life/Rakes/2c5-engineless-rake-p185.rle \ ../../Patterns/Life/Rakes/2c5-spaceship-rake-p240.rle \ ../../Patterns/Life/Rakes/basic-rakes.rle \ ../../Patterns/Life/Rakes/c2-Cordership-rake.rle \ ../../Patterns/Life/Rakes/c3-forward-rake-p333.rle \ ../../Patterns/Life/Rakes/c4-sideways-rake.rle \ ../../Patterns/Life/Rakes/c5-adjustable-rake.rle \ ../../Patterns/Life/Rakes/forward-LWSS-rake-p90.rle \ ../../Patterns/Life/Rakes/p270-frothing-puffer-rake.rle \ ../../Patterns/Life/Rakes/spider-rake.rle \ ../../Patterns/Life/Signal-Circuitry/advancer.rle \ ../../Patterns/Life/Signal-Circuitry/constructor-memory-loop.rle \ ../../Patterns/Life/Signal-Circuitry/constructor-memory-tape.rle \ ../../Patterns/Life/Signal-Circuitry/heisenblinker-30.rle \ ../../Patterns/Life/Signal-Circuitry/heisenburp-30.rle \ ../../Patterns/Life/Signal-Circuitry/heisenburp-46-natural.rle \ ../../Patterns/Life/Signal-Circuitry/heisenburp-46.rle \ ../../Patterns/Life/Signal-Circuitry/Herschel-conduit-stamp-collection.rle \ ../../Patterns/Life/Signal-Circuitry/lightspeed-telegraph.rle \ ../../Patterns/Life/Signal-Circuitry/p30-racetrack.rle \ ../../Patterns/Life/Signal-Circuitry/p46racetrack.rle \ ../../Patterns/Life/Signal-Circuitry/reflectors2.rle \ ../../Patterns/Life/Signal-Circuitry/reflectors.rle \ ../../Patterns/Life/Signal-Circuitry/signal-turn.rle \ ../../Patterns/Life/Signal-Circuitry/stargate.rle \ ../../Patterns/Life/Signal-Circuitry/traffic-lights-extruder.rle \ ../../Patterns/Life/Signal-Circuitry/Turing-Machine-3-state.rle \ ../../Patterns/Life/Signal-Circuitry/Unit-Life-Cell-512x512.rle \ ../../Patterns/Life/Signal-Circuitry/Unit-Life-Deep-Cell.rle \ ../../Patterns/Life/Spaceships/2c5-orthogonal.rle \ ../../Patterns/Life/Spaceships/adjustable-Corder-lineship.rle \ ../../Patterns/Life/Spaceships/c3-orthogonal.rle \ ../../Patterns/Life/Spaceships/c4-diagonal.rle \ ../../Patterns/Life/Spaceships/c4-orthogonal.rle \ ../../Patterns/Life/Spaceships/Corder-lineship.rle \ ../../Patterns/Life/Spaceships/Cordership-boat-burner.rle \ ../../Patterns/Life/Spaceships/Cordership-LWSS-freeze-tag.rle \ ../../Patterns/Life/Spaceships/corderships.rle \ ../../Patterns/Life/Spaceships/diagonal.rle \ ../../Patterns/Life/Spaceships/orthogonal.rle \ ../../Patterns/Life/Spaceships/short-thin-race.rle \ ../../Patterns/Life/Spaceships/smallest-low-period.rle \ ../../Patterns/Life/Spaceships/spaceship-types.rle \ ../../Patterns/Life/Still-Lifes/1998-eater-stamp-collection.rle \ ../../Patterns/Life/Still-Lifes/eaters-misc.rle \ ../../Patterns/Life/Still-Lifes/eaters.rle \ ../../Patterns/Life/Still-Lifes/random.rle \ ../../Patterns/Life/Still-Lifes/ss-eaters.rle \ ../../Patterns/Life/Still-Lifes/stripey.rle \ ../../Patterns/Life/Syntheses/109-still-lifes.rle \ ../../Patterns/Life/Syntheses/29-still-lifes.rle \ ../../Patterns/Life/Syntheses/blockish-and-blockic-seeds.rle \ ../../Patterns/Life/Syntheses/life-integer-constructions.rle \ ../../Patterns/Life/Syntheses/make-harbor.rle \ ../../Patterns/Life/Syntheses/make-lightbulb.rle \ ../../Patterns/Life/Syntheses/make-osc-p3.rle \ ../../Patterns/Life/Syntheses/make-osc-p4.rle \ ../../Patterns/Life/Syntheses/make-osc-p5-plus.rle \ ../../Patterns/Life/Syntheses/make-p11.rle \ ../../Patterns/Life/Syntheses/make-p18.rle \ ../../Patterns/Life/Syntheses/make-p33.rle \ ../../Patterns/Life/Syntheses/oscillator-syntheses.rle \ ../../Patterns/Life/Syntheses/slow-salvo-eater-recipes.rle \ ../../Patterns/Life/Syntheses/two-glider-collisions.rle \ ../../Patterns/Loops/Byl-Loop.rle \ ../../Patterns/Loops/Chou-Reggia-Loop-1.rle \ ../../Patterns/Loops/Chou-Reggia-Loop-2.rle \ ../../Patterns/Loops/Evoloop-finite.rle \ ../../Patterns/Loops/Evoloop.rle \ ../../Patterns/Loops/Langtons-Loops.rle \ ../../Patterns/Loops/Perrier-Loop.rle \ ../../Patterns/Loops/Perrier-Parenthesis-Checker.rle \ ../../Patterns/Loops/SDSR-Loop.rle \ ../../Patterns/Loops/Tempesti-Loop.rle \ ../../Patterns/Margolus/BBM.rle \ ../../Patterns/Margolus/CrittersCircle.rle \ ../../Patterns/Margolus/CrittersOscillators.rle \ ../../Patterns/Margolus/DLA.rle \ ../../Patterns/Margolus/HPP_large.rle \ ../../Patterns/Margolus/HPP.rle \ ../../Patterns/Margolus/Sand.rle \ ../../Patterns/Margolus/Sand-Test.rle \ ../../Patterns/Margolus/TMGas_largeWithHole.rle \ ../../Patterns/Margolus/TMGas.rle \ ../../Patterns/Margolus/TripATron_BlockAligned.rle \ ../../Patterns/Margolus/TripATron.rle \ ../../Patterns/Other-Rules/Ed-rep.rle \ ../../Patterns/Other-Rules/golly-ants.rle \ ../../Patterns/Other-Rules/HPP-demo.rle \ ../../Patterns/Other-Rules/HPP-demo-small.rle \ ../../Patterns/Other-Rules/Langtons-Ant.rle \ ../../Patterns/Other-Rules/life-on-the-edge.rle \ ../../Patterns/Other-Rules/life-on-the-slope.rle \ ../../Patterns/Patersons-Worms/worm-1040512.rle \ ../../Patterns/Patersons-Worms/worm-1042015.rle \ ../../Patterns/Patersons-Worms/worm-1042020.rle \ ../../Patterns/Patersons-Worms/worm-1252121.rle \ ../../Patterns/Patersons-Worms/worm-1525115.rle \ ../../Patterns/Turmites/AlienCounter.rle \ ../../Patterns/Turmites/ComputerArt.rle \ ../../Patterns/Turmites/Extinction.rle \ ../../Patterns/Turmites/FibonacciSpiral.rle \ ../../Patterns/Turmites/Highway2074575.rle \ ../../Patterns/Turmites/LangtonsAnt_LLRR.rle \ ../../Patterns/Turmites/Perfectionist.rle \ ../../Patterns/Turmites/TriangularAnt_period92.rle \ ../../Patterns/Turmites/TriangularLangtonsAnt.rle \ ../../Patterns/Turmites/WormTrails.rle \ ../../Patterns/WireWorld/circuit.mcl \ ../../Patterns/WireWorld/clocks.mcl \ ../../Patterns/WireWorld/flip-flop.mcl \ ../../Patterns/WireWorld/gate-AND.mcl \ ../../Patterns/WireWorld/gate-NOT.mcl \ ../../Patterns/WireWorld/gate-OR.mcl \ ../../Patterns/WireWorld/gate-XOR.mcl \ ../../Patterns/WireWorld/Langtons-ant.zip \ ../../Patterns/WireWorld/memory-cell.mcl \ ../../Patterns/WireWorld/NickGardner.mcl \ ../../Patterns/WireWorld/NylesHeise.mcl \ ../../Patterns/WireWorld/primes.mc \ ../../Patterns/WireWorld/unary-multiplier.mcl \ ../../Rules/AbsoluteTurmite_0N21S10E00S01W11N2.rule \ ../../Rules/AbsoluteTurmite_0S11W11E21S21W00N0.rule \ ../../Rules/AbsoluteTurmite_1N10S11S30N21W01N11S20E1.rule \ ../../Rules/Banks-III.rule ../../Rules/Banks-II.rule \ ../../Rules/Banks-I.rule ../../Rules/Banks-IV.rule \ ../../Rules/BBM-Margolus-emulated.rule \ ../../Rules/BriansBrain.rule ../../Rules/Byl-Loop.rule \ ../../Rules/Caterpillars.rule ../../Rules/Chou-Reggia-1.rule \ ../../Rules/Chou-Reggia-2.rule ../../Rules/Codd2.rule \ ../../Rules/Codd.rule \ ../../Rules/CrittersMargolus_emulated.rule \ ../../Rules/Devore.rule ../../Rules/DLA-Margolus-emulated.rule \ ../../Rules/Ed-rep.rule ../../Rules/Evoloop-finite.rule \ ../../Rules/Evoloop.rule ../../Rules/HPPMargolus_emulated.rule \ ../../Rules/HPP.rule ../../Rules/LangtonsAnt_LLRR.rule \ ../../Rules/Langtons-Ant.rule ../../Rules/Langtons-Loops.rule \ ../../Rules/LifeHistory.rule ../../Rules/LifeOnTheEdge.rule \ ../../Rules/LifeOnTheSlope.rule ../../Rules/Life.rule \ ../../Rules/Perrier.rule \ ../../Rules/Sand-Margolus-emulated.rule \ ../../Rules/Sand-square4cyclic_emulated.rule \ ../../Rules/SDSR-Loop.rule ../../Rules/StarWars.rule \ ../../Rules/TableGenerators/make-ruletable.cpp \ ../../Rules/Tempesti.rule \ ../../Rules/TMGasMargolus_emulated.rule \ ../../Rules/TreeGenerators/LifeOnTheEdge.cpp \ ../../Rules/TreeGenerators/LifeOnTheSlope.cpp \ ../../Rules/TreeGenerators/RuleTreeGen.cpp \ ../../Rules/TreeGenerators/RuleTreeGen.java \ ../../Rules/TreeGenerators/RuleTreeGen.pl \ ../../Rules/TreeGenerators/RuleTreeGen.py \ ../../Rules/TripATronMargolus_emulated.rule \ ../../Rules/TriTurmite_120010.rule \ ../../Rules/Turmite_1202822111121111812a0281282.rule \ ../../Rules/Turmite_121181121020.rule \ ../../Rules/Turmite_180121020081.rule \ ../../Rules/Turmite_181181121010.rule \ ../../Rules/WireWorld.rule ../../Rules/Worm-1040512.rule \ ../../Rules/Worm-1042015.rule ../../Rules/Worm-1042020.rule \ ../../Rules/Worm-1252121.rule ../../Rules/Worm-1525115.rule \ ../../Rules/Worm-complement.rule ../../Rules/Worm-shared.rule \ ../../Scripts/Perl/density.pl ../../Scripts/Perl/envelope.pl \ ../../Scripts/Perl/giffer.pl ../../Scripts/Perl/goto.pl \ ../../Scripts/Perl/invert.pl ../../Scripts/Perl/make-torus.pl \ ../../Scripts/Perl/oscar.pl \ ../../Scripts/Perl/p1100-MWSS-gun.pl \ ../../Scripts/Perl/pop-plot.pl ../../Scripts/Perl/shift.pl \ ../../Scripts/Perl/tile.pl \ ../../Scripts/Perl/tile-with-clip.pl \ ../../Scripts/Python/bricklayer.py \ ../../Scripts/Python/density.py \ ../../Scripts/Python/draw-lines.py \ ../../Scripts/Python/envelope.py \ ../../Scripts/Python/flood-fill.py \ ../../Scripts/Python/glife/base.py \ ../../Scripts/Python/glife/BuiltinIcons.py \ ../../Scripts/Python/glife/EmulateHexagonal.py \ ../../Scripts/Python/glife/EmulateMargolus.py \ ../../Scripts/Python/glife/EmulateOneDimensional.py \ ../../Scripts/Python/glife/EmulateTriangular.py \ ../../Scripts/Python/glife/gun24.py \ ../../Scripts/Python/glife/gun256.py \ ../../Scripts/Python/glife/gun30.py \ ../../Scripts/Python/glife/gun46.py \ ../../Scripts/Python/glife/herschel.py \ ../../Scripts/Python/glife/__init__.py \ ../../Scripts/Python/glife/ReadRuleTable.py \ ../../Scripts/Python/glife/RuleTree.py \ ../../Scripts/Python/glife/text.py \ ../../Scripts/Python/glife/WriteBMP.py \ ../../Scripts/Python/glife/WriteRuleTable.py \ ../../Scripts/Python/goto_expression.py \ ../../Scripts/Python/goto.py ../../Scripts/Python/gun-demo.py \ ../../Scripts/Python/heisenburp.py \ ../../Scripts/Python/invert.py \ ../../Scripts/Python/life-integer-gun30.py \ ../../Scripts/Python/make-Banks-IV-constructor.py \ ../../Scripts/Python/make-Codd-constructor.py \ ../../Scripts/Python/make-Devore-tape.py \ ../../Scripts/Python/make-torus.py \ ../../Scripts/Python/Margolus/convert-MCell-string.py \ ../../Scripts/Python/Margolus/export.py \ ../../Scripts/Python/Margolus/import.py \ ../../Scripts/Python/metafier.py \ ../../Scripts/Python/move-object.py \ ../../Scripts/Python/move-selection.py \ ../../Scripts/Python/oscar.py \ ../../Scripts/Python/p1100-MWSS-gun.py \ ../../Scripts/Python/pd-glider.py \ ../../Scripts/Python/pop-plot.py \ ../../Scripts/Python/Rule-Generators/AbsoluteHexTurmite-gen.py \ ../../Scripts/Python/Rule-Generators/AbsoluteTurmite-gen.py \ ../../Scripts/Python/Rule-Generators/FredkinModN-gen.py \ ../../Scripts/Python/Rule-Generators/HexTurmite-gen.py \ ../../Scripts/Python/Rule-Generators/icon-exporter.py \ ../../Scripts/Python/Rule-Generators/icon-importer.py \ ../../Scripts/Python/Rule-Generators/Langtons-Ant-gen.py \ ../../Scripts/Python/Rule-Generators/make-ruletree.py \ ../../Scripts/Python/Rule-Generators/RuleTableToTree.py \ ../../Scripts/Python/Rule-Generators/TriTurmite-gen.py \ ../../Scripts/Python/Rule-Generators/Turmite-gen.py \ ../../Scripts/Python/shift.py \ ../../Scripts/Python/slide-show.py \ ../../Scripts/Python/tile.py \ ../../Scripts/Python/tile-with-clip.py EXTRA_DIST = ../../gui-wx/makefile-gtk ../../gui-wx/makefile-mac \ ../../gui-wx/makefile-win ../../gui-wx/CMakeLists.txt \ ../../gui-wx/Info.plist.in ../../gui-wx/local-win-template.mk \ ../../gui-wx/golly.rc ../../gui-wx/configure/autogen.sh \ ../../gui-wx/icons ../../gui-wx/bitmaps ../../gui-common \ ../../gui-android/Golly/AndroidManifest.xml \ ../../gui-android/Golly/assets/readme.txt \ ../../gui-android/Golly/assets/triangle-down.png \ ../../gui-android/Golly/assets/triangle-right.png \ ../../gui-android/Golly/build.xml \ ../../gui-android/Golly/ic_launcher-web.png \ ../../gui-android/Golly/jni/Android.mk \ ../../gui-android/Golly/jni/Application.mk \ ../../gui-android/Golly/jni/jnicalls.cpp \ ../../gui-android/Golly/jni/jnicalls.h \ ../../gui-android/Golly/proguard-project.txt \ ../../gui-android/Golly/project.properties \ ../../gui-android/Golly/res/drawable-hdpi/ic_launcher.png \ ../../gui-android/Golly/res/drawable-ldpi/readme.txt \ ../../gui-android/Golly/res/drawable-mdpi/ic_launcher.png \ ../../gui-android/Golly/res/drawable-xhdpi/ic_launcher.png \ ../../gui-android/Golly/res/drawable-xxhdpi/ic_launcher.png \ ../../gui-android/Golly/res/layout/edit_layout.xml \ ../../gui-android/Golly/res/layout/help_layout.xml \ ../../gui-android/Golly/res/layout/info_layout.xml \ ../../gui-android/Golly/res/layout/main_layout_wide.xml \ ../../gui-android/Golly/res/layout/main_layout.xml \ ../../gui-android/Golly/res/layout/open_layout.xml \ ../../gui-android/Golly/res/layout/rule_layout.xml \ ../../gui-android/Golly/res/layout/settings_layout.xml \ ../../gui-android/Golly/res/layout/state_layout.xml \ ../../gui-android/Golly/res/menu/control_menu.xml \ ../../gui-android/Golly/res/menu/edit_menu.xml \ ../../gui-android/Golly/res/menu/main.xml \ ../../gui-android/Golly/res/menu/mode_menu.xml \ ../../gui-android/Golly/res/menu/paste_menu.xml \ ../../gui-android/Golly/res/menu/pastemode_menu.xml \ ../../gui-android/Golly/res/menu/selection_menu.xml \ ../../gui-android/Golly/res/menu/view_menu.xml \ ../../gui-android/Golly/res/values/dimens.xml \ ../../gui-android/Golly/res/values/strings.xml \ ../../gui-android/Golly/res/values/styles.xml \ ../../gui-android/Golly/res/values-sw600dp/dimens.xml \ ../../gui-android/Golly/res/values-sw720dp-land/dimens.xml \ ../../gui-android/Golly/res/values-v11/styles.xml \ ../../gui-android/Golly/res/values-v14/styles.xml \ ../../gui-android/Golly/src/net/sf/golly/BaseActivity.java \ ../../gui-android/Golly/src/net/sf/golly/BaseApp.java \ ../../gui-android/Golly/src/net/sf/golly/EditActivity.java \ ../../gui-android/Golly/src/net/sf/golly/HelpActivity.java \ ../../gui-android/Golly/src/net/sf/golly/InfoActivity.java \ ../../gui-android/Golly/src/net/sf/golly/MainActivity.java \ ../../gui-android/Golly/src/net/sf/golly/OpenActivity.java \ ../../gui-android/Golly/src/net/sf/golly/PatternGLSurfaceView.java \ ../../gui-android/Golly/src/net/sf/golly/RuleActivity.java \ ../../gui-android/Golly/src/net/sf/golly/SettingsActivity.java \ ../../gui-android/Golly/src/net/sf/golly/StateActivity.java \ ../../gui-android/Golly/src/net/sf/golly/StateGLSurfaceView.java \ ../../gui-ios/Golly/beep.aiff \ ../../gui-ios/Golly/Default-Landscape~ipad.png \ ../../gui-ios/Golly/Default-Portrait~ipad.png \ ../../gui-ios/Golly/en.lproj/InfoPlist.strings \ ../../gui-ios/Golly/GollyAppDelegate.h \ ../../gui-ios/Golly/GollyAppDelegate.m \ ../../gui-ios/Golly/Golly-Info.plist \ ../../gui-ios/Golly/Golly-Prefix.pch \ ../../gui-ios/Golly/help@2x.png ../../gui-ios/Golly/help.png \ ../../gui-ios/Golly/HelpViewController.h \ ../../gui-ios/Golly/HelpViewController.m \ ../../gui-ios/Golly/HelpViewController.xib \ ../../gui-ios/Golly/Icon@2x.png ../../gui-ios/Golly/Icon.png \ ../../gui-ios/Golly/InfoViewController.h \ ../../gui-ios/Golly/InfoViewController.m \ ../../gui-ios/Golly/InfoViewController.xib \ ../../gui-ios/Golly/iTunesArtwork \ ../../gui-ios/Golly/iTunesArtwork@2x \ ../../gui-ios/Golly/main.m ../../gui-ios/Golly/open@2x.png \ ../../gui-ios/Golly/open.png \ ../../gui-ios/Golly/OpenViewController.h \ ../../gui-ios/Golly/OpenViewController.m \ ../../gui-ios/Golly/OpenViewController.xib \ ../../gui-ios/Golly/pattern@2x.png \ ../../gui-ios/Golly/pattern.png \ ../../gui-ios/Golly/PatternViewController.h \ ../../gui-ios/Golly/PatternViewController.m \ ../../gui-ios/Golly/PatternViewController.xib \ ../../gui-ios/Golly/PatternView.h \ ../../gui-ios/Golly/PatternView.m \ ../../gui-ios/Golly/RuleViewController.h \ ../../gui-ios/Golly/RuleViewController.m \ ../../gui-ios/Golly/RuleViewController.xib \ ../../gui-ios/Golly/SaveViewController.h \ ../../gui-ios/Golly/SaveViewController.m \ ../../gui-ios/Golly/SaveViewController.xib \ ../../gui-ios/Golly/settings@2x.png \ ../../gui-ios/Golly/settings.png \ ../../gui-ios/Golly/SettingsViewController.h \ ../../gui-ios/Golly/SettingsViewController.m \ ../../gui-ios/Golly/SettingsViewController.xib \ ../../gui-ios/Golly/StatePickerController.h \ ../../gui-ios/Golly/StatePickerController.m \ ../../gui-ios/Golly/StatePickerController.xib \ ../../gui-ios/Golly/StatePickerView.h \ ../../gui-ios/Golly/StatePickerView.m \ ../../gui-ios/Golly/StateView.h \ ../../gui-ios/Golly/StateView.m \ ../../gui-ios/Golly/StatusView.h \ ../../gui-ios/Golly/StatusView.m \ ../../gui-ios/Golly/triangle-down.png \ ../../gui-ios/Golly/triangle-right.png \ ../../gui-ios/Golly.xcodeproj/project.pbxproj \ ../../gui-ios/Golly.xcodeproj/project.xcworkspace/contents.xcworkspacedata \ ../../gui-web/beep.wav ../../gui-web/Help/about.html \ ../../gui-web/Help/changes.html ../../gui-web/Help/help.html \ ../../gui-web/Help/index.html ../../gui-web/Help/keyboard.html \ ../../gui-web/Help/problems.html \ ../../gui-web/images/about.gif \ ../../gui-web/images/cursor_draw.png \ ../../gui-web/images/cursor_move.png \ ../../gui-web/images/cursor_pick.png \ ../../gui-web/images/cursor_zoomin.png \ ../../gui-web/images/cursor_zoomout.png \ ../../gui-web/images/faster.png \ ../../gui-web/images/favicon.ico ../../gui-web/images/fit.png \ ../../gui-web/images/full.png ../../gui-web/images/help.png \ ../../gui-web/images/info.png \ ../../gui-web/images/item_blank.png \ ../../gui-web/images/item_tick.png \ ../../gui-web/images/menu_down.png \ ../../gui-web/images/menu_right.png \ ../../gui-web/images/new.png ../../gui-web/images/next.png \ ../../gui-web/images/redo.png ../../gui-web/images/reset.png \ ../../gui-web/images/scale1to1.png \ ../../gui-web/images/slower.png ../../gui-web/images/start.png \ ../../gui-web/images/step1.png ../../gui-web/images/step.png \ ../../gui-web/images/stop.png \ ../../gui-web/images/triangle_down.png \ ../../gui-web/images/triangle_right.png \ ../../gui-web/images/undo.png ../../gui-web/images/zoomin.png \ ../../gui-web/images/zoomout.png ../../gui-web/jslib.js \ ../../gui-web/main.cpp ../../gui-web/Makefile \ ../../gui-web/patterns.py ../../gui-web/shell.html \ ../../gui-web/webcalls.cpp ../../gui-web/webcalls.h \ ../../gui-web/zlib/adler32.c ../../gui-web/zlib/compress.c \ ../../gui-web/zlib/crc32.c ../../gui-web/zlib/crc32.h \ ../../gui-web/zlib/deflate.c ../../gui-web/zlib/deflate.h \ ../../gui-web/zlib/gzclose.c ../../gui-web/zlib/gzguts.h \ ../../gui-web/zlib/gzlib.c ../../gui-web/zlib/gzread.c \ ../../gui-web/zlib/gzwrite.c ../../gui-web/zlib/infback.c \ ../../gui-web/zlib/inffast.c ../../gui-web/zlib/inffast.h \ ../../gui-web/zlib/inffixed.h ../../gui-web/zlib/inflate.c \ ../../gui-web/zlib/inflate.h ../../gui-web/zlib/inftrees.c \ ../../gui-web/zlib/inftrees.h ../../gui-web/zlib/README \ ../../gui-web/zlib/trees.c ../../gui-web/zlib/trees.h \ ../../gui-web/zlib/uncompr.c ../../gui-web/zlib/zconf.h \ ../../gui-web/zlib/zlib.h ../../gui-web/zlib/zutil.c \ ../../gui-web/zlib/zutil.h ../../docs golly_CPPFLAGS = $(AM_CPPFLAGS) $(WX_CPPFLAGS) $(PERL_INCLUDE) $(PYTHON_INCLUDE) golly_CXXFLAGS = $(AM_CXXFLAGS) $(WX_CXXFLAGS_ONLY) golly_LDADD = $(WX_LIBS) libgolly.a $(am__append_1) bgolly_SOURCES = ../../cmdline/bgolly.cpp bgolly_LDADD = libgolly.a RuleTableToTree_SOURCES = ../../cmdline/RuleTableToTree.cpp RuleTableToTree_LDADD = libgolly.a srcdistdir = $(PACKAGE)-$(VERSION)$(SRCDISTSUFFIX) bindistdir = $(PACKAGE)-$(VERSION)$(BINDISTSUFFIX) all: all-am .SUFFIXES: .SUFFIXES: .cpp .o .obj am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/sources.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(srcdir)/sources.am: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) libgolly.a: $(libgolly_a_OBJECTS) $(libgolly_a_DEPENDENCIES) $(EXTRA_libgolly_a_DEPENDENCIES) -rm -f libgolly.a $(libgolly_a_AR) libgolly.a $(libgolly_a_OBJECTS) $(libgolly_a_LIBADD) $(RANLIB) libgolly.a install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) clean-noinstPROGRAMS: -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) RuleTableToTree$(EXEEXT): $(RuleTableToTree_OBJECTS) $(RuleTableToTree_DEPENDENCIES) $(EXTRA_RuleTableToTree_DEPENDENCIES) @rm -f RuleTableToTree$(EXEEXT) $(CXXLINK) $(RuleTableToTree_OBJECTS) $(RuleTableToTree_LDADD) $(LIBS) bgolly$(EXEEXT): $(bgolly_OBJECTS) $(bgolly_DEPENDENCIES) $(EXTRA_bgolly_DEPENDENCIES) @rm -f bgolly$(EXEEXT) $(CXXLINK) $(bgolly_OBJECTS) $(bgolly_LDADD) $(LIBS) golly$(EXEEXT): $(golly_OBJECTS) $(golly_DEPENDENCIES) $(EXTRA_golly_DEPENDENCIES) @rm -f golly$(EXEEXT) $(golly_LINK) $(golly_OBJECTS) $(golly_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RuleTableToTree.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bgolly.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bigint.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generationsalgo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ghashbase.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ghashdraw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxalgos.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxcontrol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxedit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxgolly.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxhelp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxlayer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxmain.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxperl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxprefs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxpython.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxrender.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxrule.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxscript.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxselect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxstatus.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxtimeline.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxundo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxutils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/golly-wxview.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hlifealgo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hlifedraw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jvnalgo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lifealgo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lifepoll.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liferender.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liferules.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qlifealgo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qlifedraw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readpattern.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ruleloaderalgo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ruletable_algo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ruletreealgo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/viewport.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/writepattern.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< .cpp.obj: @am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` bigint.o: ../../gollybase/bigint.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bigint.o -MD -MP -MF $(DEPDIR)/bigint.Tpo -c -o bigint.o `test -f '../../gollybase/bigint.cpp' || echo '$(srcdir)/'`../../gollybase/bigint.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/bigint.Tpo $(DEPDIR)/bigint.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/bigint.cpp' object='bigint.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bigint.o `test -f '../../gollybase/bigint.cpp' || echo '$(srcdir)/'`../../gollybase/bigint.cpp bigint.obj: ../../gollybase/bigint.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bigint.obj -MD -MP -MF $(DEPDIR)/bigint.Tpo -c -o bigint.obj `if test -f '../../gollybase/bigint.cpp'; then $(CYGPATH_W) '../../gollybase/bigint.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/bigint.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/bigint.Tpo $(DEPDIR)/bigint.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/bigint.cpp' object='bigint.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bigint.obj `if test -f '../../gollybase/bigint.cpp'; then $(CYGPATH_W) '../../gollybase/bigint.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/bigint.cpp'; fi` generationsalgo.o: ../../gollybase/generationsalgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT generationsalgo.o -MD -MP -MF $(DEPDIR)/generationsalgo.Tpo -c -o generationsalgo.o `test -f '../../gollybase/generationsalgo.cpp' || echo '$(srcdir)/'`../../gollybase/generationsalgo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/generationsalgo.Tpo $(DEPDIR)/generationsalgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/generationsalgo.cpp' object='generationsalgo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o generationsalgo.o `test -f '../../gollybase/generationsalgo.cpp' || echo '$(srcdir)/'`../../gollybase/generationsalgo.cpp generationsalgo.obj: ../../gollybase/generationsalgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT generationsalgo.obj -MD -MP -MF $(DEPDIR)/generationsalgo.Tpo -c -o generationsalgo.obj `if test -f '../../gollybase/generationsalgo.cpp'; then $(CYGPATH_W) '../../gollybase/generationsalgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/generationsalgo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/generationsalgo.Tpo $(DEPDIR)/generationsalgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/generationsalgo.cpp' object='generationsalgo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o generationsalgo.obj `if test -f '../../gollybase/generationsalgo.cpp'; then $(CYGPATH_W) '../../gollybase/generationsalgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/generationsalgo.cpp'; fi` ghashbase.o: ../../gollybase/ghashbase.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ghashbase.o -MD -MP -MF $(DEPDIR)/ghashbase.Tpo -c -o ghashbase.o `test -f '../../gollybase/ghashbase.cpp' || echo '$(srcdir)/'`../../gollybase/ghashbase.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ghashbase.Tpo $(DEPDIR)/ghashbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ghashbase.cpp' object='ghashbase.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ghashbase.o `test -f '../../gollybase/ghashbase.cpp' || echo '$(srcdir)/'`../../gollybase/ghashbase.cpp ghashbase.obj: ../../gollybase/ghashbase.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ghashbase.obj -MD -MP -MF $(DEPDIR)/ghashbase.Tpo -c -o ghashbase.obj `if test -f '../../gollybase/ghashbase.cpp'; then $(CYGPATH_W) '../../gollybase/ghashbase.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ghashbase.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ghashbase.Tpo $(DEPDIR)/ghashbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ghashbase.cpp' object='ghashbase.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ghashbase.obj `if test -f '../../gollybase/ghashbase.cpp'; then $(CYGPATH_W) '../../gollybase/ghashbase.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ghashbase.cpp'; fi` ghashdraw.o: ../../gollybase/ghashdraw.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ghashdraw.o -MD -MP -MF $(DEPDIR)/ghashdraw.Tpo -c -o ghashdraw.o `test -f '../../gollybase/ghashdraw.cpp' || echo '$(srcdir)/'`../../gollybase/ghashdraw.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ghashdraw.Tpo $(DEPDIR)/ghashdraw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ghashdraw.cpp' object='ghashdraw.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ghashdraw.o `test -f '../../gollybase/ghashdraw.cpp' || echo '$(srcdir)/'`../../gollybase/ghashdraw.cpp ghashdraw.obj: ../../gollybase/ghashdraw.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ghashdraw.obj -MD -MP -MF $(DEPDIR)/ghashdraw.Tpo -c -o ghashdraw.obj `if test -f '../../gollybase/ghashdraw.cpp'; then $(CYGPATH_W) '../../gollybase/ghashdraw.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ghashdraw.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ghashdraw.Tpo $(DEPDIR)/ghashdraw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ghashdraw.cpp' object='ghashdraw.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ghashdraw.obj `if test -f '../../gollybase/ghashdraw.cpp'; then $(CYGPATH_W) '../../gollybase/ghashdraw.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ghashdraw.cpp'; fi` hlifealgo.o: ../../gollybase/hlifealgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT hlifealgo.o -MD -MP -MF $(DEPDIR)/hlifealgo.Tpo -c -o hlifealgo.o `test -f '../../gollybase/hlifealgo.cpp' || echo '$(srcdir)/'`../../gollybase/hlifealgo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/hlifealgo.Tpo $(DEPDIR)/hlifealgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/hlifealgo.cpp' object='hlifealgo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o hlifealgo.o `test -f '../../gollybase/hlifealgo.cpp' || echo '$(srcdir)/'`../../gollybase/hlifealgo.cpp hlifealgo.obj: ../../gollybase/hlifealgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT hlifealgo.obj -MD -MP -MF $(DEPDIR)/hlifealgo.Tpo -c -o hlifealgo.obj `if test -f '../../gollybase/hlifealgo.cpp'; then $(CYGPATH_W) '../../gollybase/hlifealgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/hlifealgo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/hlifealgo.Tpo $(DEPDIR)/hlifealgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/hlifealgo.cpp' object='hlifealgo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o hlifealgo.obj `if test -f '../../gollybase/hlifealgo.cpp'; then $(CYGPATH_W) '../../gollybase/hlifealgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/hlifealgo.cpp'; fi` hlifedraw.o: ../../gollybase/hlifedraw.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT hlifedraw.o -MD -MP -MF $(DEPDIR)/hlifedraw.Tpo -c -o hlifedraw.o `test -f '../../gollybase/hlifedraw.cpp' || echo '$(srcdir)/'`../../gollybase/hlifedraw.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/hlifedraw.Tpo $(DEPDIR)/hlifedraw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/hlifedraw.cpp' object='hlifedraw.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o hlifedraw.o `test -f '../../gollybase/hlifedraw.cpp' || echo '$(srcdir)/'`../../gollybase/hlifedraw.cpp hlifedraw.obj: ../../gollybase/hlifedraw.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT hlifedraw.obj -MD -MP -MF $(DEPDIR)/hlifedraw.Tpo -c -o hlifedraw.obj `if test -f '../../gollybase/hlifedraw.cpp'; then $(CYGPATH_W) '../../gollybase/hlifedraw.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/hlifedraw.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/hlifedraw.Tpo $(DEPDIR)/hlifedraw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/hlifedraw.cpp' object='hlifedraw.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o hlifedraw.obj `if test -f '../../gollybase/hlifedraw.cpp'; then $(CYGPATH_W) '../../gollybase/hlifedraw.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/hlifedraw.cpp'; fi` jvnalgo.o: ../../gollybase/jvnalgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT jvnalgo.o -MD -MP -MF $(DEPDIR)/jvnalgo.Tpo -c -o jvnalgo.o `test -f '../../gollybase/jvnalgo.cpp' || echo '$(srcdir)/'`../../gollybase/jvnalgo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/jvnalgo.Tpo $(DEPDIR)/jvnalgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/jvnalgo.cpp' object='jvnalgo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o jvnalgo.o `test -f '../../gollybase/jvnalgo.cpp' || echo '$(srcdir)/'`../../gollybase/jvnalgo.cpp jvnalgo.obj: ../../gollybase/jvnalgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT jvnalgo.obj -MD -MP -MF $(DEPDIR)/jvnalgo.Tpo -c -o jvnalgo.obj `if test -f '../../gollybase/jvnalgo.cpp'; then $(CYGPATH_W) '../../gollybase/jvnalgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/jvnalgo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/jvnalgo.Tpo $(DEPDIR)/jvnalgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/jvnalgo.cpp' object='jvnalgo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o jvnalgo.obj `if test -f '../../gollybase/jvnalgo.cpp'; then $(CYGPATH_W) '../../gollybase/jvnalgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/jvnalgo.cpp'; fi` lifealgo.o: ../../gollybase/lifealgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lifealgo.o -MD -MP -MF $(DEPDIR)/lifealgo.Tpo -c -o lifealgo.o `test -f '../../gollybase/lifealgo.cpp' || echo '$(srcdir)/'`../../gollybase/lifealgo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/lifealgo.Tpo $(DEPDIR)/lifealgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/lifealgo.cpp' object='lifealgo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lifealgo.o `test -f '../../gollybase/lifealgo.cpp' || echo '$(srcdir)/'`../../gollybase/lifealgo.cpp lifealgo.obj: ../../gollybase/lifealgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lifealgo.obj -MD -MP -MF $(DEPDIR)/lifealgo.Tpo -c -o lifealgo.obj `if test -f '../../gollybase/lifealgo.cpp'; then $(CYGPATH_W) '../../gollybase/lifealgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/lifealgo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/lifealgo.Tpo $(DEPDIR)/lifealgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/lifealgo.cpp' object='lifealgo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lifealgo.obj `if test -f '../../gollybase/lifealgo.cpp'; then $(CYGPATH_W) '../../gollybase/lifealgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/lifealgo.cpp'; fi` lifepoll.o: ../../gollybase/lifepoll.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lifepoll.o -MD -MP -MF $(DEPDIR)/lifepoll.Tpo -c -o lifepoll.o `test -f '../../gollybase/lifepoll.cpp' || echo '$(srcdir)/'`../../gollybase/lifepoll.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/lifepoll.Tpo $(DEPDIR)/lifepoll.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/lifepoll.cpp' object='lifepoll.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lifepoll.o `test -f '../../gollybase/lifepoll.cpp' || echo '$(srcdir)/'`../../gollybase/lifepoll.cpp lifepoll.obj: ../../gollybase/lifepoll.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT lifepoll.obj -MD -MP -MF $(DEPDIR)/lifepoll.Tpo -c -o lifepoll.obj `if test -f '../../gollybase/lifepoll.cpp'; then $(CYGPATH_W) '../../gollybase/lifepoll.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/lifepoll.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/lifepoll.Tpo $(DEPDIR)/lifepoll.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/lifepoll.cpp' object='lifepoll.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o lifepoll.obj `if test -f '../../gollybase/lifepoll.cpp'; then $(CYGPATH_W) '../../gollybase/lifepoll.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/lifepoll.cpp'; fi` liferender.o: ../../gollybase/liferender.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liferender.o -MD -MP -MF $(DEPDIR)/liferender.Tpo -c -o liferender.o `test -f '../../gollybase/liferender.cpp' || echo '$(srcdir)/'`../../gollybase/liferender.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/liferender.Tpo $(DEPDIR)/liferender.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/liferender.cpp' object='liferender.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liferender.o `test -f '../../gollybase/liferender.cpp' || echo '$(srcdir)/'`../../gollybase/liferender.cpp liferender.obj: ../../gollybase/liferender.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liferender.obj -MD -MP -MF $(DEPDIR)/liferender.Tpo -c -o liferender.obj `if test -f '../../gollybase/liferender.cpp'; then $(CYGPATH_W) '../../gollybase/liferender.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/liferender.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/liferender.Tpo $(DEPDIR)/liferender.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/liferender.cpp' object='liferender.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liferender.obj `if test -f '../../gollybase/liferender.cpp'; then $(CYGPATH_W) '../../gollybase/liferender.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/liferender.cpp'; fi` liferules.o: ../../gollybase/liferules.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liferules.o -MD -MP -MF $(DEPDIR)/liferules.Tpo -c -o liferules.o `test -f '../../gollybase/liferules.cpp' || echo '$(srcdir)/'`../../gollybase/liferules.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/liferules.Tpo $(DEPDIR)/liferules.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/liferules.cpp' object='liferules.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liferules.o `test -f '../../gollybase/liferules.cpp' || echo '$(srcdir)/'`../../gollybase/liferules.cpp liferules.obj: ../../gollybase/liferules.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT liferules.obj -MD -MP -MF $(DEPDIR)/liferules.Tpo -c -o liferules.obj `if test -f '../../gollybase/liferules.cpp'; then $(CYGPATH_W) '../../gollybase/liferules.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/liferules.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/liferules.Tpo $(DEPDIR)/liferules.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/liferules.cpp' object='liferules.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o liferules.obj `if test -f '../../gollybase/liferules.cpp'; then $(CYGPATH_W) '../../gollybase/liferules.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/liferules.cpp'; fi` qlifealgo.o: ../../gollybase/qlifealgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT qlifealgo.o -MD -MP -MF $(DEPDIR)/qlifealgo.Tpo -c -o qlifealgo.o `test -f '../../gollybase/qlifealgo.cpp' || echo '$(srcdir)/'`../../gollybase/qlifealgo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/qlifealgo.Tpo $(DEPDIR)/qlifealgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/qlifealgo.cpp' object='qlifealgo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o qlifealgo.o `test -f '../../gollybase/qlifealgo.cpp' || echo '$(srcdir)/'`../../gollybase/qlifealgo.cpp qlifealgo.obj: ../../gollybase/qlifealgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT qlifealgo.obj -MD -MP -MF $(DEPDIR)/qlifealgo.Tpo -c -o qlifealgo.obj `if test -f '../../gollybase/qlifealgo.cpp'; then $(CYGPATH_W) '../../gollybase/qlifealgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/qlifealgo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/qlifealgo.Tpo $(DEPDIR)/qlifealgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/qlifealgo.cpp' object='qlifealgo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o qlifealgo.obj `if test -f '../../gollybase/qlifealgo.cpp'; then $(CYGPATH_W) '../../gollybase/qlifealgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/qlifealgo.cpp'; fi` qlifedraw.o: ../../gollybase/qlifedraw.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT qlifedraw.o -MD -MP -MF $(DEPDIR)/qlifedraw.Tpo -c -o qlifedraw.o `test -f '../../gollybase/qlifedraw.cpp' || echo '$(srcdir)/'`../../gollybase/qlifedraw.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/qlifedraw.Tpo $(DEPDIR)/qlifedraw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/qlifedraw.cpp' object='qlifedraw.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o qlifedraw.o `test -f '../../gollybase/qlifedraw.cpp' || echo '$(srcdir)/'`../../gollybase/qlifedraw.cpp qlifedraw.obj: ../../gollybase/qlifedraw.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT qlifedraw.obj -MD -MP -MF $(DEPDIR)/qlifedraw.Tpo -c -o qlifedraw.obj `if test -f '../../gollybase/qlifedraw.cpp'; then $(CYGPATH_W) '../../gollybase/qlifedraw.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/qlifedraw.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/qlifedraw.Tpo $(DEPDIR)/qlifedraw.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/qlifedraw.cpp' object='qlifedraw.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o qlifedraw.obj `if test -f '../../gollybase/qlifedraw.cpp'; then $(CYGPATH_W) '../../gollybase/qlifedraw.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/qlifedraw.cpp'; fi` readpattern.o: ../../gollybase/readpattern.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT readpattern.o -MD -MP -MF $(DEPDIR)/readpattern.Tpo -c -o readpattern.o `test -f '../../gollybase/readpattern.cpp' || echo '$(srcdir)/'`../../gollybase/readpattern.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/readpattern.Tpo $(DEPDIR)/readpattern.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/readpattern.cpp' object='readpattern.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o readpattern.o `test -f '../../gollybase/readpattern.cpp' || echo '$(srcdir)/'`../../gollybase/readpattern.cpp readpattern.obj: ../../gollybase/readpattern.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT readpattern.obj -MD -MP -MF $(DEPDIR)/readpattern.Tpo -c -o readpattern.obj `if test -f '../../gollybase/readpattern.cpp'; then $(CYGPATH_W) '../../gollybase/readpattern.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/readpattern.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/readpattern.Tpo $(DEPDIR)/readpattern.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/readpattern.cpp' object='readpattern.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o readpattern.obj `if test -f '../../gollybase/readpattern.cpp'; then $(CYGPATH_W) '../../gollybase/readpattern.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/readpattern.cpp'; fi` ruleloaderalgo.o: ../../gollybase/ruleloaderalgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ruleloaderalgo.o -MD -MP -MF $(DEPDIR)/ruleloaderalgo.Tpo -c -o ruleloaderalgo.o `test -f '../../gollybase/ruleloaderalgo.cpp' || echo '$(srcdir)/'`../../gollybase/ruleloaderalgo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ruleloaderalgo.Tpo $(DEPDIR)/ruleloaderalgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ruleloaderalgo.cpp' object='ruleloaderalgo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ruleloaderalgo.o `test -f '../../gollybase/ruleloaderalgo.cpp' || echo '$(srcdir)/'`../../gollybase/ruleloaderalgo.cpp ruleloaderalgo.obj: ../../gollybase/ruleloaderalgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ruleloaderalgo.obj -MD -MP -MF $(DEPDIR)/ruleloaderalgo.Tpo -c -o ruleloaderalgo.obj `if test -f '../../gollybase/ruleloaderalgo.cpp'; then $(CYGPATH_W) '../../gollybase/ruleloaderalgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ruleloaderalgo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ruleloaderalgo.Tpo $(DEPDIR)/ruleloaderalgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ruleloaderalgo.cpp' object='ruleloaderalgo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ruleloaderalgo.obj `if test -f '../../gollybase/ruleloaderalgo.cpp'; then $(CYGPATH_W) '../../gollybase/ruleloaderalgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ruleloaderalgo.cpp'; fi` ruletable_algo.o: ../../gollybase/ruletable_algo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ruletable_algo.o -MD -MP -MF $(DEPDIR)/ruletable_algo.Tpo -c -o ruletable_algo.o `test -f '../../gollybase/ruletable_algo.cpp' || echo '$(srcdir)/'`../../gollybase/ruletable_algo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ruletable_algo.Tpo $(DEPDIR)/ruletable_algo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ruletable_algo.cpp' object='ruletable_algo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ruletable_algo.o `test -f '../../gollybase/ruletable_algo.cpp' || echo '$(srcdir)/'`../../gollybase/ruletable_algo.cpp ruletable_algo.obj: ../../gollybase/ruletable_algo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ruletable_algo.obj -MD -MP -MF $(DEPDIR)/ruletable_algo.Tpo -c -o ruletable_algo.obj `if test -f '../../gollybase/ruletable_algo.cpp'; then $(CYGPATH_W) '../../gollybase/ruletable_algo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ruletable_algo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ruletable_algo.Tpo $(DEPDIR)/ruletable_algo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ruletable_algo.cpp' object='ruletable_algo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ruletable_algo.obj `if test -f '../../gollybase/ruletable_algo.cpp'; then $(CYGPATH_W) '../../gollybase/ruletable_algo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ruletable_algo.cpp'; fi` ruletreealgo.o: ../../gollybase/ruletreealgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ruletreealgo.o -MD -MP -MF $(DEPDIR)/ruletreealgo.Tpo -c -o ruletreealgo.o `test -f '../../gollybase/ruletreealgo.cpp' || echo '$(srcdir)/'`../../gollybase/ruletreealgo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ruletreealgo.Tpo $(DEPDIR)/ruletreealgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ruletreealgo.cpp' object='ruletreealgo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ruletreealgo.o `test -f '../../gollybase/ruletreealgo.cpp' || echo '$(srcdir)/'`../../gollybase/ruletreealgo.cpp ruletreealgo.obj: ../../gollybase/ruletreealgo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ruletreealgo.obj -MD -MP -MF $(DEPDIR)/ruletreealgo.Tpo -c -o ruletreealgo.obj `if test -f '../../gollybase/ruletreealgo.cpp'; then $(CYGPATH_W) '../../gollybase/ruletreealgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ruletreealgo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/ruletreealgo.Tpo $(DEPDIR)/ruletreealgo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/ruletreealgo.cpp' object='ruletreealgo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ruletreealgo.obj `if test -f '../../gollybase/ruletreealgo.cpp'; then $(CYGPATH_W) '../../gollybase/ruletreealgo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/ruletreealgo.cpp'; fi` util.o: ../../gollybase/util.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT util.o -MD -MP -MF $(DEPDIR)/util.Tpo -c -o util.o `test -f '../../gollybase/util.cpp' || echo '$(srcdir)/'`../../gollybase/util.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/util.Tpo $(DEPDIR)/util.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/util.cpp' object='util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o util.o `test -f '../../gollybase/util.cpp' || echo '$(srcdir)/'`../../gollybase/util.cpp util.obj: ../../gollybase/util.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT util.obj -MD -MP -MF $(DEPDIR)/util.Tpo -c -o util.obj `if test -f '../../gollybase/util.cpp'; then $(CYGPATH_W) '../../gollybase/util.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/util.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/util.Tpo $(DEPDIR)/util.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/util.cpp' object='util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o util.obj `if test -f '../../gollybase/util.cpp'; then $(CYGPATH_W) '../../gollybase/util.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/util.cpp'; fi` viewport.o: ../../gollybase/viewport.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT viewport.o -MD -MP -MF $(DEPDIR)/viewport.Tpo -c -o viewport.o `test -f '../../gollybase/viewport.cpp' || echo '$(srcdir)/'`../../gollybase/viewport.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/viewport.Tpo $(DEPDIR)/viewport.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/viewport.cpp' object='viewport.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o viewport.o `test -f '../../gollybase/viewport.cpp' || echo '$(srcdir)/'`../../gollybase/viewport.cpp viewport.obj: ../../gollybase/viewport.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT viewport.obj -MD -MP -MF $(DEPDIR)/viewport.Tpo -c -o viewport.obj `if test -f '../../gollybase/viewport.cpp'; then $(CYGPATH_W) '../../gollybase/viewport.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/viewport.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/viewport.Tpo $(DEPDIR)/viewport.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/viewport.cpp' object='viewport.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o viewport.obj `if test -f '../../gollybase/viewport.cpp'; then $(CYGPATH_W) '../../gollybase/viewport.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/viewport.cpp'; fi` writepattern.o: ../../gollybase/writepattern.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT writepattern.o -MD -MP -MF $(DEPDIR)/writepattern.Tpo -c -o writepattern.o `test -f '../../gollybase/writepattern.cpp' || echo '$(srcdir)/'`../../gollybase/writepattern.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/writepattern.Tpo $(DEPDIR)/writepattern.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/writepattern.cpp' object='writepattern.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o writepattern.o `test -f '../../gollybase/writepattern.cpp' || echo '$(srcdir)/'`../../gollybase/writepattern.cpp writepattern.obj: ../../gollybase/writepattern.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT writepattern.obj -MD -MP -MF $(DEPDIR)/writepattern.Tpo -c -o writepattern.obj `if test -f '../../gollybase/writepattern.cpp'; then $(CYGPATH_W) '../../gollybase/writepattern.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/writepattern.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/writepattern.Tpo $(DEPDIR)/writepattern.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gollybase/writepattern.cpp' object='writepattern.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o writepattern.obj `if test -f '../../gollybase/writepattern.cpp'; then $(CYGPATH_W) '../../gollybase/writepattern.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gollybase/writepattern.cpp'; fi` RuleTableToTree.o: ../../cmdline/RuleTableToTree.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RuleTableToTree.o -MD -MP -MF $(DEPDIR)/RuleTableToTree.Tpo -c -o RuleTableToTree.o `test -f '../../cmdline/RuleTableToTree.cpp' || echo '$(srcdir)/'`../../cmdline/RuleTableToTree.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/RuleTableToTree.Tpo $(DEPDIR)/RuleTableToTree.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../cmdline/RuleTableToTree.cpp' object='RuleTableToTree.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RuleTableToTree.o `test -f '../../cmdline/RuleTableToTree.cpp' || echo '$(srcdir)/'`../../cmdline/RuleTableToTree.cpp RuleTableToTree.obj: ../../cmdline/RuleTableToTree.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT RuleTableToTree.obj -MD -MP -MF $(DEPDIR)/RuleTableToTree.Tpo -c -o RuleTableToTree.obj `if test -f '../../cmdline/RuleTableToTree.cpp'; then $(CYGPATH_W) '../../cmdline/RuleTableToTree.cpp'; else $(CYGPATH_W) '$(srcdir)/../../cmdline/RuleTableToTree.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/RuleTableToTree.Tpo $(DEPDIR)/RuleTableToTree.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../cmdline/RuleTableToTree.cpp' object='RuleTableToTree.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o RuleTableToTree.obj `if test -f '../../cmdline/RuleTableToTree.cpp'; then $(CYGPATH_W) '../../cmdline/RuleTableToTree.cpp'; else $(CYGPATH_W) '$(srcdir)/../../cmdline/RuleTableToTree.cpp'; fi` bgolly.o: ../../cmdline/bgolly.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bgolly.o -MD -MP -MF $(DEPDIR)/bgolly.Tpo -c -o bgolly.o `test -f '../../cmdline/bgolly.cpp' || echo '$(srcdir)/'`../../cmdline/bgolly.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/bgolly.Tpo $(DEPDIR)/bgolly.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../cmdline/bgolly.cpp' object='bgolly.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bgolly.o `test -f '../../cmdline/bgolly.cpp' || echo '$(srcdir)/'`../../cmdline/bgolly.cpp bgolly.obj: ../../cmdline/bgolly.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bgolly.obj -MD -MP -MF $(DEPDIR)/bgolly.Tpo -c -o bgolly.obj `if test -f '../../cmdline/bgolly.cpp'; then $(CYGPATH_W) '../../cmdline/bgolly.cpp'; else $(CYGPATH_W) '$(srcdir)/../../cmdline/bgolly.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/bgolly.Tpo $(DEPDIR)/bgolly.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../cmdline/bgolly.cpp' object='bgolly.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bgolly.obj `if test -f '../../cmdline/bgolly.cpp'; then $(CYGPATH_W) '../../cmdline/bgolly.cpp'; else $(CYGPATH_W) '$(srcdir)/../../cmdline/bgolly.cpp'; fi` golly-wxalgos.o: ../../gui-wx/wxalgos.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxalgos.o -MD -MP -MF $(DEPDIR)/golly-wxalgos.Tpo -c -o golly-wxalgos.o `test -f '../../gui-wx/wxalgos.cpp' || echo '$(srcdir)/'`../../gui-wx/wxalgos.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxalgos.Tpo $(DEPDIR)/golly-wxalgos.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxalgos.cpp' object='golly-wxalgos.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxalgos.o `test -f '../../gui-wx/wxalgos.cpp' || echo '$(srcdir)/'`../../gui-wx/wxalgos.cpp golly-wxalgos.obj: ../../gui-wx/wxalgos.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxalgos.obj -MD -MP -MF $(DEPDIR)/golly-wxalgos.Tpo -c -o golly-wxalgos.obj `if test -f '../../gui-wx/wxalgos.cpp'; then $(CYGPATH_W) '../../gui-wx/wxalgos.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxalgos.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxalgos.Tpo $(DEPDIR)/golly-wxalgos.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxalgos.cpp' object='golly-wxalgos.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxalgos.obj `if test -f '../../gui-wx/wxalgos.cpp'; then $(CYGPATH_W) '../../gui-wx/wxalgos.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxalgos.cpp'; fi` golly-wxcontrol.o: ../../gui-wx/wxcontrol.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxcontrol.o -MD -MP -MF $(DEPDIR)/golly-wxcontrol.Tpo -c -o golly-wxcontrol.o `test -f '../../gui-wx/wxcontrol.cpp' || echo '$(srcdir)/'`../../gui-wx/wxcontrol.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxcontrol.Tpo $(DEPDIR)/golly-wxcontrol.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxcontrol.cpp' object='golly-wxcontrol.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxcontrol.o `test -f '../../gui-wx/wxcontrol.cpp' || echo '$(srcdir)/'`../../gui-wx/wxcontrol.cpp golly-wxcontrol.obj: ../../gui-wx/wxcontrol.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxcontrol.obj -MD -MP -MF $(DEPDIR)/golly-wxcontrol.Tpo -c -o golly-wxcontrol.obj `if test -f '../../gui-wx/wxcontrol.cpp'; then $(CYGPATH_W) '../../gui-wx/wxcontrol.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxcontrol.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxcontrol.Tpo $(DEPDIR)/golly-wxcontrol.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxcontrol.cpp' object='golly-wxcontrol.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxcontrol.obj `if test -f '../../gui-wx/wxcontrol.cpp'; then $(CYGPATH_W) '../../gui-wx/wxcontrol.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxcontrol.cpp'; fi` golly-wxedit.o: ../../gui-wx/wxedit.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxedit.o -MD -MP -MF $(DEPDIR)/golly-wxedit.Tpo -c -o golly-wxedit.o `test -f '../../gui-wx/wxedit.cpp' || echo '$(srcdir)/'`../../gui-wx/wxedit.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxedit.Tpo $(DEPDIR)/golly-wxedit.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxedit.cpp' object='golly-wxedit.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxedit.o `test -f '../../gui-wx/wxedit.cpp' || echo '$(srcdir)/'`../../gui-wx/wxedit.cpp golly-wxedit.obj: ../../gui-wx/wxedit.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxedit.obj -MD -MP -MF $(DEPDIR)/golly-wxedit.Tpo -c -o golly-wxedit.obj `if test -f '../../gui-wx/wxedit.cpp'; then $(CYGPATH_W) '../../gui-wx/wxedit.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxedit.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxedit.Tpo $(DEPDIR)/golly-wxedit.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxedit.cpp' object='golly-wxedit.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxedit.obj `if test -f '../../gui-wx/wxedit.cpp'; then $(CYGPATH_W) '../../gui-wx/wxedit.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxedit.cpp'; fi` golly-wxfile.o: ../../gui-wx/wxfile.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxfile.o -MD -MP -MF $(DEPDIR)/golly-wxfile.Tpo -c -o golly-wxfile.o `test -f '../../gui-wx/wxfile.cpp' || echo '$(srcdir)/'`../../gui-wx/wxfile.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxfile.Tpo $(DEPDIR)/golly-wxfile.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxfile.cpp' object='golly-wxfile.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxfile.o `test -f '../../gui-wx/wxfile.cpp' || echo '$(srcdir)/'`../../gui-wx/wxfile.cpp golly-wxfile.obj: ../../gui-wx/wxfile.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxfile.obj -MD -MP -MF $(DEPDIR)/golly-wxfile.Tpo -c -o golly-wxfile.obj `if test -f '../../gui-wx/wxfile.cpp'; then $(CYGPATH_W) '../../gui-wx/wxfile.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxfile.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxfile.Tpo $(DEPDIR)/golly-wxfile.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxfile.cpp' object='golly-wxfile.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxfile.obj `if test -f '../../gui-wx/wxfile.cpp'; then $(CYGPATH_W) '../../gui-wx/wxfile.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxfile.cpp'; fi` golly-wxgolly.o: ../../gui-wx/wxgolly.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxgolly.o -MD -MP -MF $(DEPDIR)/golly-wxgolly.Tpo -c -o golly-wxgolly.o `test -f '../../gui-wx/wxgolly.cpp' || echo '$(srcdir)/'`../../gui-wx/wxgolly.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxgolly.Tpo $(DEPDIR)/golly-wxgolly.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxgolly.cpp' object='golly-wxgolly.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxgolly.o `test -f '../../gui-wx/wxgolly.cpp' || echo '$(srcdir)/'`../../gui-wx/wxgolly.cpp golly-wxgolly.obj: ../../gui-wx/wxgolly.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxgolly.obj -MD -MP -MF $(DEPDIR)/golly-wxgolly.Tpo -c -o golly-wxgolly.obj `if test -f '../../gui-wx/wxgolly.cpp'; then $(CYGPATH_W) '../../gui-wx/wxgolly.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxgolly.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxgolly.Tpo $(DEPDIR)/golly-wxgolly.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxgolly.cpp' object='golly-wxgolly.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxgolly.obj `if test -f '../../gui-wx/wxgolly.cpp'; then $(CYGPATH_W) '../../gui-wx/wxgolly.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxgolly.cpp'; fi` golly-wxhelp.o: ../../gui-wx/wxhelp.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxhelp.o -MD -MP -MF $(DEPDIR)/golly-wxhelp.Tpo -c -o golly-wxhelp.o `test -f '../../gui-wx/wxhelp.cpp' || echo '$(srcdir)/'`../../gui-wx/wxhelp.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxhelp.Tpo $(DEPDIR)/golly-wxhelp.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxhelp.cpp' object='golly-wxhelp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxhelp.o `test -f '../../gui-wx/wxhelp.cpp' || echo '$(srcdir)/'`../../gui-wx/wxhelp.cpp golly-wxhelp.obj: ../../gui-wx/wxhelp.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxhelp.obj -MD -MP -MF $(DEPDIR)/golly-wxhelp.Tpo -c -o golly-wxhelp.obj `if test -f '../../gui-wx/wxhelp.cpp'; then $(CYGPATH_W) '../../gui-wx/wxhelp.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxhelp.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxhelp.Tpo $(DEPDIR)/golly-wxhelp.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxhelp.cpp' object='golly-wxhelp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxhelp.obj `if test -f '../../gui-wx/wxhelp.cpp'; then $(CYGPATH_W) '../../gui-wx/wxhelp.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxhelp.cpp'; fi` golly-wxinfo.o: ../../gui-wx/wxinfo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxinfo.o -MD -MP -MF $(DEPDIR)/golly-wxinfo.Tpo -c -o golly-wxinfo.o `test -f '../../gui-wx/wxinfo.cpp' || echo '$(srcdir)/'`../../gui-wx/wxinfo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxinfo.Tpo $(DEPDIR)/golly-wxinfo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxinfo.cpp' object='golly-wxinfo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxinfo.o `test -f '../../gui-wx/wxinfo.cpp' || echo '$(srcdir)/'`../../gui-wx/wxinfo.cpp golly-wxinfo.obj: ../../gui-wx/wxinfo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxinfo.obj -MD -MP -MF $(DEPDIR)/golly-wxinfo.Tpo -c -o golly-wxinfo.obj `if test -f '../../gui-wx/wxinfo.cpp'; then $(CYGPATH_W) '../../gui-wx/wxinfo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxinfo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxinfo.Tpo $(DEPDIR)/golly-wxinfo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxinfo.cpp' object='golly-wxinfo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxinfo.obj `if test -f '../../gui-wx/wxinfo.cpp'; then $(CYGPATH_W) '../../gui-wx/wxinfo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxinfo.cpp'; fi` golly-wxlayer.o: ../../gui-wx/wxlayer.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxlayer.o -MD -MP -MF $(DEPDIR)/golly-wxlayer.Tpo -c -o golly-wxlayer.o `test -f '../../gui-wx/wxlayer.cpp' || echo '$(srcdir)/'`../../gui-wx/wxlayer.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxlayer.Tpo $(DEPDIR)/golly-wxlayer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxlayer.cpp' object='golly-wxlayer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxlayer.o `test -f '../../gui-wx/wxlayer.cpp' || echo '$(srcdir)/'`../../gui-wx/wxlayer.cpp golly-wxlayer.obj: ../../gui-wx/wxlayer.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxlayer.obj -MD -MP -MF $(DEPDIR)/golly-wxlayer.Tpo -c -o golly-wxlayer.obj `if test -f '../../gui-wx/wxlayer.cpp'; then $(CYGPATH_W) '../../gui-wx/wxlayer.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxlayer.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxlayer.Tpo $(DEPDIR)/golly-wxlayer.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxlayer.cpp' object='golly-wxlayer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxlayer.obj `if test -f '../../gui-wx/wxlayer.cpp'; then $(CYGPATH_W) '../../gui-wx/wxlayer.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxlayer.cpp'; fi` golly-wxmain.o: ../../gui-wx/wxmain.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxmain.o -MD -MP -MF $(DEPDIR)/golly-wxmain.Tpo -c -o golly-wxmain.o `test -f '../../gui-wx/wxmain.cpp' || echo '$(srcdir)/'`../../gui-wx/wxmain.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxmain.Tpo $(DEPDIR)/golly-wxmain.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxmain.cpp' object='golly-wxmain.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxmain.o `test -f '../../gui-wx/wxmain.cpp' || echo '$(srcdir)/'`../../gui-wx/wxmain.cpp golly-wxmain.obj: ../../gui-wx/wxmain.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxmain.obj -MD -MP -MF $(DEPDIR)/golly-wxmain.Tpo -c -o golly-wxmain.obj `if test -f '../../gui-wx/wxmain.cpp'; then $(CYGPATH_W) '../../gui-wx/wxmain.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxmain.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxmain.Tpo $(DEPDIR)/golly-wxmain.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxmain.cpp' object='golly-wxmain.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxmain.obj `if test -f '../../gui-wx/wxmain.cpp'; then $(CYGPATH_W) '../../gui-wx/wxmain.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxmain.cpp'; fi` golly-wxperl.o: ../../gui-wx/wxperl.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxperl.o -MD -MP -MF $(DEPDIR)/golly-wxperl.Tpo -c -o golly-wxperl.o `test -f '../../gui-wx/wxperl.cpp' || echo '$(srcdir)/'`../../gui-wx/wxperl.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxperl.Tpo $(DEPDIR)/golly-wxperl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxperl.cpp' object='golly-wxperl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxperl.o `test -f '../../gui-wx/wxperl.cpp' || echo '$(srcdir)/'`../../gui-wx/wxperl.cpp golly-wxperl.obj: ../../gui-wx/wxperl.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxperl.obj -MD -MP -MF $(DEPDIR)/golly-wxperl.Tpo -c -o golly-wxperl.obj `if test -f '../../gui-wx/wxperl.cpp'; then $(CYGPATH_W) '../../gui-wx/wxperl.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxperl.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxperl.Tpo $(DEPDIR)/golly-wxperl.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxperl.cpp' object='golly-wxperl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxperl.obj `if test -f '../../gui-wx/wxperl.cpp'; then $(CYGPATH_W) '../../gui-wx/wxperl.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxperl.cpp'; fi` golly-wxprefs.o: ../../gui-wx/wxprefs.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxprefs.o -MD -MP -MF $(DEPDIR)/golly-wxprefs.Tpo -c -o golly-wxprefs.o `test -f '../../gui-wx/wxprefs.cpp' || echo '$(srcdir)/'`../../gui-wx/wxprefs.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxprefs.Tpo $(DEPDIR)/golly-wxprefs.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxprefs.cpp' object='golly-wxprefs.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxprefs.o `test -f '../../gui-wx/wxprefs.cpp' || echo '$(srcdir)/'`../../gui-wx/wxprefs.cpp golly-wxprefs.obj: ../../gui-wx/wxprefs.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxprefs.obj -MD -MP -MF $(DEPDIR)/golly-wxprefs.Tpo -c -o golly-wxprefs.obj `if test -f '../../gui-wx/wxprefs.cpp'; then $(CYGPATH_W) '../../gui-wx/wxprefs.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxprefs.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxprefs.Tpo $(DEPDIR)/golly-wxprefs.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxprefs.cpp' object='golly-wxprefs.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxprefs.obj `if test -f '../../gui-wx/wxprefs.cpp'; then $(CYGPATH_W) '../../gui-wx/wxprefs.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxprefs.cpp'; fi` golly-wxpython.o: ../../gui-wx/wxpython.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxpython.o -MD -MP -MF $(DEPDIR)/golly-wxpython.Tpo -c -o golly-wxpython.o `test -f '../../gui-wx/wxpython.cpp' || echo '$(srcdir)/'`../../gui-wx/wxpython.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxpython.Tpo $(DEPDIR)/golly-wxpython.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxpython.cpp' object='golly-wxpython.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxpython.o `test -f '../../gui-wx/wxpython.cpp' || echo '$(srcdir)/'`../../gui-wx/wxpython.cpp golly-wxpython.obj: ../../gui-wx/wxpython.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxpython.obj -MD -MP -MF $(DEPDIR)/golly-wxpython.Tpo -c -o golly-wxpython.obj `if test -f '../../gui-wx/wxpython.cpp'; then $(CYGPATH_W) '../../gui-wx/wxpython.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxpython.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxpython.Tpo $(DEPDIR)/golly-wxpython.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxpython.cpp' object='golly-wxpython.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxpython.obj `if test -f '../../gui-wx/wxpython.cpp'; then $(CYGPATH_W) '../../gui-wx/wxpython.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxpython.cpp'; fi` golly-wxrender.o: ../../gui-wx/wxrender.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxrender.o -MD -MP -MF $(DEPDIR)/golly-wxrender.Tpo -c -o golly-wxrender.o `test -f '../../gui-wx/wxrender.cpp' || echo '$(srcdir)/'`../../gui-wx/wxrender.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxrender.Tpo $(DEPDIR)/golly-wxrender.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxrender.cpp' object='golly-wxrender.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxrender.o `test -f '../../gui-wx/wxrender.cpp' || echo '$(srcdir)/'`../../gui-wx/wxrender.cpp golly-wxrender.obj: ../../gui-wx/wxrender.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxrender.obj -MD -MP -MF $(DEPDIR)/golly-wxrender.Tpo -c -o golly-wxrender.obj `if test -f '../../gui-wx/wxrender.cpp'; then $(CYGPATH_W) '../../gui-wx/wxrender.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxrender.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxrender.Tpo $(DEPDIR)/golly-wxrender.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxrender.cpp' object='golly-wxrender.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxrender.obj `if test -f '../../gui-wx/wxrender.cpp'; then $(CYGPATH_W) '../../gui-wx/wxrender.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxrender.cpp'; fi` golly-wxrule.o: ../../gui-wx/wxrule.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxrule.o -MD -MP -MF $(DEPDIR)/golly-wxrule.Tpo -c -o golly-wxrule.o `test -f '../../gui-wx/wxrule.cpp' || echo '$(srcdir)/'`../../gui-wx/wxrule.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxrule.Tpo $(DEPDIR)/golly-wxrule.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxrule.cpp' object='golly-wxrule.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxrule.o `test -f '../../gui-wx/wxrule.cpp' || echo '$(srcdir)/'`../../gui-wx/wxrule.cpp golly-wxrule.obj: ../../gui-wx/wxrule.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxrule.obj -MD -MP -MF $(DEPDIR)/golly-wxrule.Tpo -c -o golly-wxrule.obj `if test -f '../../gui-wx/wxrule.cpp'; then $(CYGPATH_W) '../../gui-wx/wxrule.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxrule.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxrule.Tpo $(DEPDIR)/golly-wxrule.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxrule.cpp' object='golly-wxrule.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxrule.obj `if test -f '../../gui-wx/wxrule.cpp'; then $(CYGPATH_W) '../../gui-wx/wxrule.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxrule.cpp'; fi` golly-wxscript.o: ../../gui-wx/wxscript.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxscript.o -MD -MP -MF $(DEPDIR)/golly-wxscript.Tpo -c -o golly-wxscript.o `test -f '../../gui-wx/wxscript.cpp' || echo '$(srcdir)/'`../../gui-wx/wxscript.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxscript.Tpo $(DEPDIR)/golly-wxscript.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxscript.cpp' object='golly-wxscript.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxscript.o `test -f '../../gui-wx/wxscript.cpp' || echo '$(srcdir)/'`../../gui-wx/wxscript.cpp golly-wxscript.obj: ../../gui-wx/wxscript.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxscript.obj -MD -MP -MF $(DEPDIR)/golly-wxscript.Tpo -c -o golly-wxscript.obj `if test -f '../../gui-wx/wxscript.cpp'; then $(CYGPATH_W) '../../gui-wx/wxscript.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxscript.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxscript.Tpo $(DEPDIR)/golly-wxscript.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxscript.cpp' object='golly-wxscript.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxscript.obj `if test -f '../../gui-wx/wxscript.cpp'; then $(CYGPATH_W) '../../gui-wx/wxscript.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxscript.cpp'; fi` golly-wxselect.o: ../../gui-wx/wxselect.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxselect.o -MD -MP -MF $(DEPDIR)/golly-wxselect.Tpo -c -o golly-wxselect.o `test -f '../../gui-wx/wxselect.cpp' || echo '$(srcdir)/'`../../gui-wx/wxselect.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxselect.Tpo $(DEPDIR)/golly-wxselect.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxselect.cpp' object='golly-wxselect.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxselect.o `test -f '../../gui-wx/wxselect.cpp' || echo '$(srcdir)/'`../../gui-wx/wxselect.cpp golly-wxselect.obj: ../../gui-wx/wxselect.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxselect.obj -MD -MP -MF $(DEPDIR)/golly-wxselect.Tpo -c -o golly-wxselect.obj `if test -f '../../gui-wx/wxselect.cpp'; then $(CYGPATH_W) '../../gui-wx/wxselect.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxselect.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxselect.Tpo $(DEPDIR)/golly-wxselect.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxselect.cpp' object='golly-wxselect.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxselect.obj `if test -f '../../gui-wx/wxselect.cpp'; then $(CYGPATH_W) '../../gui-wx/wxselect.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxselect.cpp'; fi` golly-wxstatus.o: ../../gui-wx/wxstatus.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxstatus.o -MD -MP -MF $(DEPDIR)/golly-wxstatus.Tpo -c -o golly-wxstatus.o `test -f '../../gui-wx/wxstatus.cpp' || echo '$(srcdir)/'`../../gui-wx/wxstatus.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxstatus.Tpo $(DEPDIR)/golly-wxstatus.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxstatus.cpp' object='golly-wxstatus.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxstatus.o `test -f '../../gui-wx/wxstatus.cpp' || echo '$(srcdir)/'`../../gui-wx/wxstatus.cpp golly-wxstatus.obj: ../../gui-wx/wxstatus.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxstatus.obj -MD -MP -MF $(DEPDIR)/golly-wxstatus.Tpo -c -o golly-wxstatus.obj `if test -f '../../gui-wx/wxstatus.cpp'; then $(CYGPATH_W) '../../gui-wx/wxstatus.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxstatus.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxstatus.Tpo $(DEPDIR)/golly-wxstatus.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxstatus.cpp' object='golly-wxstatus.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxstatus.obj `if test -f '../../gui-wx/wxstatus.cpp'; then $(CYGPATH_W) '../../gui-wx/wxstatus.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxstatus.cpp'; fi` golly-wxtimeline.o: ../../gui-wx/wxtimeline.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxtimeline.o -MD -MP -MF $(DEPDIR)/golly-wxtimeline.Tpo -c -o golly-wxtimeline.o `test -f '../../gui-wx/wxtimeline.cpp' || echo '$(srcdir)/'`../../gui-wx/wxtimeline.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxtimeline.Tpo $(DEPDIR)/golly-wxtimeline.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxtimeline.cpp' object='golly-wxtimeline.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxtimeline.o `test -f '../../gui-wx/wxtimeline.cpp' || echo '$(srcdir)/'`../../gui-wx/wxtimeline.cpp golly-wxtimeline.obj: ../../gui-wx/wxtimeline.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxtimeline.obj -MD -MP -MF $(DEPDIR)/golly-wxtimeline.Tpo -c -o golly-wxtimeline.obj `if test -f '../../gui-wx/wxtimeline.cpp'; then $(CYGPATH_W) '../../gui-wx/wxtimeline.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxtimeline.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxtimeline.Tpo $(DEPDIR)/golly-wxtimeline.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxtimeline.cpp' object='golly-wxtimeline.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxtimeline.obj `if test -f '../../gui-wx/wxtimeline.cpp'; then $(CYGPATH_W) '../../gui-wx/wxtimeline.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxtimeline.cpp'; fi` golly-wxundo.o: ../../gui-wx/wxundo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxundo.o -MD -MP -MF $(DEPDIR)/golly-wxundo.Tpo -c -o golly-wxundo.o `test -f '../../gui-wx/wxundo.cpp' || echo '$(srcdir)/'`../../gui-wx/wxundo.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxundo.Tpo $(DEPDIR)/golly-wxundo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxundo.cpp' object='golly-wxundo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxundo.o `test -f '../../gui-wx/wxundo.cpp' || echo '$(srcdir)/'`../../gui-wx/wxundo.cpp golly-wxundo.obj: ../../gui-wx/wxundo.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxundo.obj -MD -MP -MF $(DEPDIR)/golly-wxundo.Tpo -c -o golly-wxundo.obj `if test -f '../../gui-wx/wxundo.cpp'; then $(CYGPATH_W) '../../gui-wx/wxundo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxundo.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxundo.Tpo $(DEPDIR)/golly-wxundo.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxundo.cpp' object='golly-wxundo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxundo.obj `if test -f '../../gui-wx/wxundo.cpp'; then $(CYGPATH_W) '../../gui-wx/wxundo.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxundo.cpp'; fi` golly-wxutils.o: ../../gui-wx/wxutils.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxutils.o -MD -MP -MF $(DEPDIR)/golly-wxutils.Tpo -c -o golly-wxutils.o `test -f '../../gui-wx/wxutils.cpp' || echo '$(srcdir)/'`../../gui-wx/wxutils.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxutils.Tpo $(DEPDIR)/golly-wxutils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxutils.cpp' object='golly-wxutils.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxutils.o `test -f '../../gui-wx/wxutils.cpp' || echo '$(srcdir)/'`../../gui-wx/wxutils.cpp golly-wxutils.obj: ../../gui-wx/wxutils.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxutils.obj -MD -MP -MF $(DEPDIR)/golly-wxutils.Tpo -c -o golly-wxutils.obj `if test -f '../../gui-wx/wxutils.cpp'; then $(CYGPATH_W) '../../gui-wx/wxutils.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxutils.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxutils.Tpo $(DEPDIR)/golly-wxutils.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxutils.cpp' object='golly-wxutils.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxutils.obj `if test -f '../../gui-wx/wxutils.cpp'; then $(CYGPATH_W) '../../gui-wx/wxutils.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxutils.cpp'; fi` golly-wxview.o: ../../gui-wx/wxview.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxview.o -MD -MP -MF $(DEPDIR)/golly-wxview.Tpo -c -o golly-wxview.o `test -f '../../gui-wx/wxview.cpp' || echo '$(srcdir)/'`../../gui-wx/wxview.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxview.Tpo $(DEPDIR)/golly-wxview.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxview.cpp' object='golly-wxview.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxview.o `test -f '../../gui-wx/wxview.cpp' || echo '$(srcdir)/'`../../gui-wx/wxview.cpp golly-wxview.obj: ../../gui-wx/wxview.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxview.obj -MD -MP -MF $(DEPDIR)/golly-wxview.Tpo -c -o golly-wxview.obj `if test -f '../../gui-wx/wxview.cpp'; then $(CYGPATH_W) '../../gui-wx/wxview.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxview.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxview.Tpo $(DEPDIR)/golly-wxview.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxview.cpp' object='golly-wxview.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -c -o golly-wxview.obj `if test -f '../../gui-wx/wxview.cpp'; then $(CYGPATH_W) '../../gui-wx/wxview.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxview.cpp'; fi` install-docDATA: $(doc_DATA) @$(NORMAL_INSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-docDATA: @$(NORMAL_UNINSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) install-nobase_dist_gollydataDATA: $(nobase_dist_gollydata_DATA) @$(NORMAL_INSTALL) @list='$(nobase_dist_gollydata_DATA)'; test -n "$(gollydatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(gollydatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(gollydatadir)" || exit 1; \ fi; \ $(am__nobase_list) | while read dir files; do \ xfiles=; for file in $$files; do \ if test -f "$$file"; then xfiles="$$xfiles $$file"; \ else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \ test -z "$$xfiles" || { \ test "x$$dir" = x. || { \ echo " $(MKDIR_P) '$(DESTDIR)$(gollydatadir)/$$dir'"; \ $(MKDIR_P) "$(DESTDIR)$(gollydatadir)/$$dir"; }; \ echo " $(INSTALL_DATA) $$xfiles '$(DESTDIR)$(gollydatadir)/$$dir'"; \ $(INSTALL_DATA) $$xfiles "$(DESTDIR)$(gollydatadir)/$$dir" || exit $$?; }; \ done uninstall-nobase_dist_gollydataDATA: @$(NORMAL_UNINSTALL) @list='$(nobase_dist_gollydata_DATA)'; test -n "$(gollydatadir)" || list=; \ $(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \ dir='$(DESTDIR)$(gollydatadir)'; $(am__uninstall_files_from_dir) ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod u+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)" "$(DESTDIR)$(gollydatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-noinstLIBRARIES \ clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-docDATA install-nobase_dist_gollydataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-docDATA \ uninstall-nobase_dist_gollydataDATA .MAKE: install-am install-strip .PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ clean-binPROGRAMS clean-generic clean-noinstLIBRARIES \ clean-noinstPROGRAMS ctags dist dist-all dist-bzip2 dist-gzip \ dist-lzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-compile distclean-generic \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am \ install-docDATA install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-nobase_dist_gollydataDATA \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-docDATA uninstall-nobase_dist_gollydataDATA @WINDOWS_TRUE@gollyres.o: ../golly.rc; $(WX_RESCOMP) $< $@ srcdist: mkdir -p $(srcdistdir)/gui-wx/configure make distdir=$(srcdistdir)/gui-wx/configure distdir tardir=$(srcdistdir) && $(am__tar) \ | GZIP=$(GZIP_ENV) gzip -c >$(srcdistdir).tar.gz rm -r $(srcdistdir) bindist: make bindir=/ pkgdatadir=/ docdir=/ GOLLYDIR= \ DESTDIR=$(builddir)/$(bindistdir) clean all install-strip tardir=$(bindistdir) && $(am__tar) \ | GZIP=$(GZIP_ENV) gzip -c >$(bindistdir).tar.gz rm -r $(bindistdir) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: golly-2.7-src/gui-wx/configure/ar-lib0000755000175000017500000001330312536111506014513 00000000000000#! /bin/sh # Wrapper for Microsoft lib.exe me=ar-lib scriptversion=2012-03-01.08; # UTC # Copyright (C) 2010, 2012 Free Software Foundation, Inc. # Written by Peter Rosin . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . # func_error message func_error () { echo "$me: $1" 1>&2 exit 1 } file_conv= # func_file_conv build_file # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv in mingw) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin) file=`cygpath -m "$file" || echo "$file"` ;; wine) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_at_file at_file operation archive # Iterate over all members in AT_FILE performing OPERATION on ARCHIVE # for each of them. # When interpreting the content of the @FILE, do NOT use func_file_conv, # since the user would need to supply preconverted file names to # binutils ar, at least for MinGW. func_at_file () { operation=$2 archive=$3 at_file_contents=`cat "$1"` eval set x "$at_file_contents" shift for member do $AR -NOLOGO $operation:"$member" "$archive" || exit $? done } case $1 in '') func_error "no command. Try '$0 --help' for more information." ;; -h | --h*) cat <$(srcdistdir).tar.gz rm -r $(srcdistdir) bindist: make bindir=/ pkgdatadir=/ docdir=/ GOLLYDIR= \ DESTDIR=$(builddir)/$(bindistdir) clean all install-strip tardir=$(bindistdir) && $(am__tar) \ | GZIP=$(GZIP_ENV) gzip -c >$(bindistdir).tar.gz rm -r $(bindistdir) golly-2.7-src/gui-wx/configure/sources.am0000644000175000017500000007202212536111503015421 00000000000000libgolly_a_SOURCES = ../../gollybase/bigint.h ../../gollybase/generationsalgo.h ../../gollybase/ghashbase.h ../../gollybase/hlifealgo.h ../../gollybase/jvnalgo.h ../../gollybase/lifealgo.h ../../gollybase/lifepoll.h ../../gollybase/liferender.h ../../gollybase/liferules.h ../../gollybase/platform.h ../../gollybase/qlifealgo.h ../../gollybase/readpattern.h ../../gollybase/ruleloaderalgo.h ../../gollybase/ruletable_algo.h ../../gollybase/ruletreealgo.h ../../gollybase/util.h ../../gollybase/viewport.h ../../gollybase/writepattern.h ../../gollybase/bigint.cpp ../../gollybase/generationsalgo.cpp ../../gollybase/ghashbase.cpp ../../gollybase/ghashdraw.cpp ../../gollybase/hlifealgo.cpp ../../gollybase/hlifedraw.cpp ../../gollybase/jvnalgo.cpp ../../gollybase/lifealgo.cpp ../../gollybase/lifepoll.cpp ../../gollybase/liferender.cpp ../../gollybase/liferules.cpp ../../gollybase/qlifealgo.cpp ../../gollybase/qlifedraw.cpp ../../gollybase/readpattern.cpp ../../gollybase/ruleloaderalgo.cpp ../../gollybase/ruletable_algo.cpp ../../gollybase/ruletreealgo.cpp ../../gollybase/util.cpp ../../gollybase/viewport.cpp ../../gollybase/writepattern.cpp golly_SOURCES = ../../gui-wx/wxalgos.h ../../gui-wx/wxedit.h ../../gui-wx/wxgolly.h ../../gui-wx/wxhelp.h ../../gui-wx/wxinfo.h ../../gui-wx/wxlayer.h ../../gui-wx/wxmain.h ../../gui-wx/wxperl.h ../../gui-wx/wxprefs.h ../../gui-wx/wxpython.h ../../gui-wx/wxrender.h ../../gui-wx/wxrule.h ../../gui-wx/wxscript.h ../../gui-wx/wxselect.h ../../gui-wx/wxstatus.h ../../gui-wx/wxtimeline.h ../../gui-wx/wxundo.h ../../gui-wx/wxutils.h ../../gui-wx/wxview.h ../../gui-wx/wxalgos.cpp ../../gui-wx/wxcontrol.cpp ../../gui-wx/wxedit.cpp ../../gui-wx/wxfile.cpp ../../gui-wx/wxgolly.cpp ../../gui-wx/wxhelp.cpp ../../gui-wx/wxinfo.cpp ../../gui-wx/wxlayer.cpp ../../gui-wx/wxmain.cpp ../../gui-wx/wxperl.cpp ../../gui-wx/wxprefs.cpp ../../gui-wx/wxpython.cpp ../../gui-wx/wxrender.cpp ../../gui-wx/wxrule.cpp ../../gui-wx/wxscript.cpp ../../gui-wx/wxselect.cpp ../../gui-wx/wxstatus.cpp ../../gui-wx/wxtimeline.cpp ../../gui-wx/wxundo.cpp ../../gui-wx/wxutils.cpp ../../gui-wx/wxview.cpp gollydatadir = $(pkgdatadir)/Patterns/Life/ nobase_dist_gollydata_DATA = ../../Help/about.gif ../../Help/about.html ../../Help/Algorithms/Generations.html ../../Help/Algorithms/HashLife.html ../../Help/Algorithms/JvN.html ../../Help/Algorithms/QuickLife.html ../../Help/Algorithms/RuleLoader.html ../../Help/algos.html ../../Help/archives.html ../../Help/bounded.html ../../Help/changes.html ../../Help/control.html ../../Help/credits.html ../../Help/edit.html ../../Help/file.html ../../Help/formats.html ../../Help/help.html ../../Help/index.html ../../Help/intro.html ../../Help/layer.html ../../Help/Lexicon/lex_1.htm ../../Help/Lexicon/lex_a.htm ../../Help/Lexicon/lex_b.htm ../../Help/Lexicon/lex_bib.htm ../../Help/Lexicon/lex_c.htm ../../Help/Lexicon/lex_d.htm ../../Help/Lexicon/lex_e.htm ../../Help/Lexicon/lex_f.htm ../../Help/Lexicon/lex_g.htm ../../Help/Lexicon/lex_h.htm ../../Help/Lexicon/lex.htm ../../Help/Lexicon/lex_i.htm ../../Help/Lexicon/lex_j.htm ../../Help/Lexicon/lex_k.htm ../../Help/Lexicon/lex_l.htm ../../Help/Lexicon/lex_m.htm ../../Help/Lexicon/lex_n.htm ../../Help/Lexicon/lex_o.htm ../../Help/Lexicon/lex_p.htm ../../Help/Lexicon/lex_q.htm ../../Help/Lexicon/lex_r.htm ../../Help/Lexicon/lex_s.htm ../../Help/Lexicon/lex_t.htm ../../Help/Lexicon/lex_u.htm ../../Help/Lexicon/lex_v.htm ../../Help/Lexicon/lex_w.htm ../../Help/Lexicon/lex_x.htm ../../Help/Lexicon/lex_y.htm ../../Help/Lexicon/lex_z.htm ../../Help/Lexicon/modify.pl ../../Help/mouse.html ../../Help/perl.html ../../Help/problems.html ../../Help/python.html ../../Help/refs.html ../../Help/tips.html ../../Help/view.html ../../Patterns/Banks/Banks-I-demo.rle ../../Patterns/Banks/Banks-II-demo.rle ../../Patterns/Banks/Banks-III-demo.rle ../../Patterns/Banks/Banks-IV-constructor.rle.gz ../../Patterns/Banks/Banks-IV-demo.rle ../../Patterns/Codd/clocking-on-demo.rle ../../Patterns/Codd/coders-demo.rle ../../Patterns/Codd/construction-arm-demo.rle ../../Patterns/Codd/crossover-unidir-demo.rle ../../Patterns/Codd/decoder-4bit-demo.rle.gz ../../Patterns/Codd/echo-discriminator.rle ../../Patterns/Codd/echo-switch-demo.rle ../../Patterns/Codd/extend-coder-demo.rle ../../Patterns/Codd/gates-demo.rle ../../Patterns/Codd/golly-constructor.rle.gz ../../Patterns/Codd/Goucher-replicator.mc.gz ../../Patterns/Codd/repeater-emitter-demo.rle ../../Patterns/Codd/sensing-demo.rle ../../Patterns/Codd/sheathing-demo.rle ../../Patterns/Codd/sheathing-problems.rle ../../Patterns/Codd/signals-demo.rle ../../Patterns/Codd/tape-reader-demo.rle ../../Patterns/Devore/crossover.rle ../../Patterns/Devore/Devore-body.rle ../../Patterns/Devore/Devore-rep.rle ../../Patterns/Devore/discriminator.rle ../../Patterns/Generations/Banner.mcl ../../Patterns/Generations/Bloomerang.mcl ../../Patterns/Generations/Burst.mcl ../../Patterns/Generations/Caterpillars.mcl ../../Patterns/Generations/Delta.rle ../../Patterns/Generations/Ebb-and-Flow.mcl ../../Patterns/Generations/Fireworks.mcl ../../Patterns/Generations/Lava.mcl ../../Patterns/Generations/Lines.mcl ../../Patterns/Generations/MeteorGuns.mcl ../../Patterns/Generations/Nova.mcl ../../Patterns/Generations/Perfect-spiral.mcl ../../Patterns/Generations/Sawfish.rle ../../Patterns/Generations/SediMental.mcl ../../Patterns/Generations/Steeplechase.mcl ../../Patterns/Generations/Transers.mcl ../../Patterns/Generations/What-a-mess.mcl ../../Patterns/HashLife/broken-lines.mc ../../Patterns/HashLife/catacryst.mc ../../Patterns/HashLife/gotts-dots.mc ../../Patterns/HashLife/hashlife-oddity1.mc ../../Patterns/HashLife/hashlife-oddity2.mc ../../Patterns/HashLife/hexadecimal.mc.gz ../../Patterns/HashLife/jagged2.mc ../../Patterns/HashLife/jagged.mc ../../Patterns/HashLife/loafer-gun-p8388608-linear.mc.gz ../../Patterns/HashLife/logarithmic-width.mc ../../Patterns/HashLife/metacatacryst.mc ../../Patterns/HashLife/metapixel-galaxy.mc.gz ../../Patterns/HashLife/metapixel-p216-gun.mc.gz ../../Patterns/HashLife/metapixel-parity64.mc.gz ../../Patterns/HashLife/mosquito5.mc ../../Patterns/HashLife/nick-gotts-1.mc ../../Patterns/HashLife/nick-gotts-2.mc ../../Patterns/HashLife/puzzle.mc ../../Patterns/HashLife/Replicator-p237228340.mc.gz ../../Patterns/HashLife/ruler.mc ../../Patterns/HashLife/totalperiodic.mc ../../Patterns/HashLife/unlimited-novelty.mc ../../Patterns/HashLife/wedge-grow.mc ../../Patterns/HashLife/wolfram22.mc ../../Patterns/JvN/Boustrophedon-replicator.rle ../../Patterns/JvN/cell-coders-demo.rle ../../Patterns/JvN/codon4-auto-retract.rle ../../Patterns/JvN/codon5-auto-retract.rle ../../Patterns/JvN/construction-arm-demo.rle ../../Patterns/JvN/counter-demo.rle ../../Patterns/JvN/golly-constructor.rle ../../Patterns/JvN/Hutton-replicator.rle ../../Patterns/JvN/JvN-loop-replicator.rle.gz ../../Patterns/JvN/N-compressed-replicator.rle ../../Patterns/JvN/NP-mutation.rle.gz ../../Patterns/JvN/NP-replicator.rle.gz ../../Patterns/JvN/partial-constructor.mc.gz ../../Patterns/JvN/read-arm-demo.rle ../../Patterns/JvN/sphinx.mc.gz ../../Patterns/JvN/sphinx-midpoint.mc.gz ../../Patterns/JvN/sphinx-spark.mc.gz ../../Patterns/Life/Bounded-Grids/agar-p3.rle ../../Patterns/Life/Bounded-Grids/cross-surface.rle ../../Patterns/Life/Bounded-Grids/herringbone-agar-p14.rle ../../Patterns/Life/Bounded-Grids/Klein-bottle.rle ../../Patterns/Life/Bounded-Grids/lightspeed-bubble.rle ../../Patterns/Life/Bounded-Grids/pulsars-in-tube.rle ../../Patterns/Life/Bounded-Grids/sphere.rle ../../Patterns/Life/Bounded-Grids/torus.rle ../../Patterns/Life/Bounded-Grids/torus-with-shift.rle ../../Patterns/Life/Breeders/breeder.lif ../../Patterns/Life/Breeders/c4-diag-switch-engines.rle ../../Patterns/Life/Breeders/LWSS-breeder.rle ../../Patterns/Life/Breeders/p100-H-channel-breeder.rle ../../Patterns/Life/Breeders/p90-rake-factory.rle ../../Patterns/Life/Breeders/pi-blink-breeder1.rle ../../Patterns/Life/Breeders/pi-blink-breeder2.rle ../../Patterns/Life/Breeders/rake-breeder.rle ../../Patterns/Life/Breeders/slide-breeder.rle ../../Patterns/Life/Breeders/spacefiller.rle ../../Patterns/Life/Breeders/switch-engine-breeder-MR.rle ../../Patterns/Life/Breeders/switch-engine-breeder.rle ../../Patterns/Life/Guns/2c5-spaceship-gun-p416.rle ../../Patterns/Life/Guns/2c5-spaceship-gun-p690.rle ../../Patterns/Life/Guns/7-in-a-row-Cordership-V-gun.rle ../../Patterns/Life/Guns/Cordership-gun-p784.rle ../../Patterns/Life/Guns/golly-ticker.rle ../../Patterns/Life/Guns/gun-p165mwss.rle ../../Patterns/Life/Guns/loafer-gun-p210.rle ../../Patterns/Life/Guns/p59-gun-with-Snark-reflectors.rle ../../Patterns/Life/Guns/p690-PT-Cordership-gun.rle ../../Patterns/Life/Guns/pseudo-p34-gun.rle ../../Patterns/Life/Guns/vacuum-cleaner.rle ../../Patterns/Life-Like/alt-wicks.py ../../Patterns/Life-Like/coral.rle ../../Patterns/Life-Like/Day-and-Night-gun-and-antigun.rle ../../Patterns/Life-Like/ice-nine.rle ../../Patterns/Life-Like/Morley/breeder2.rle ../../Patterns/Life-Like/Morley/enterprise-gun.rle ../../Patterns/Life-Like/Morley/growing-ship.rle ../../Patterns/Life-Like/p168-knightship.rle ../../Patterns/Life-Like/persian-rugs.lif ../../Patterns/Life-Like/replicator.rle ../../Patterns/Life-Like/spiral-growth.rle ../../Patterns/Life-Like/white-whale.rle ../../Patterns/Life/Methuselahs/acorn.lif ../../Patterns/Life/Methuselahs/ark1.rle ../../Patterns/Life/Methuselahs/ark2.rle ../../Patterns/Life/Methuselahs/blom.rle ../../Patterns/Life/Methuselahs/iwona.rle ../../Patterns/Life/Methuselahs/justyna.rle ../../Patterns/Life/Methuselahs/lidka-predecessor.rle ../../Patterns/Life/Methuselahs/natural-LWSS.rle ../../Patterns/Life/Methuselahs/rabbits.lif ../../Patterns/Life/Methuselahs/rabbits-relation-17423.rle ../../Patterns/Life/Methuselahs/rabbits-relation-17465.rle ../../Patterns/Life/Methuselahs/temp-pulsars-big-s.rle ../../Patterns/Life/Miscellaneous/blockstacker.rle ../../Patterns/Life/Miscellaneous/Calcyman-primer.zip ../../Patterns/Life/Miscellaneous/Cambrian-Explosion.rle ../../Patterns/Life/Miscellaneous/diagfuse1.rle ../../Patterns/Life/Miscellaneous/die658.rle ../../Patterns/Life/Miscellaneous/elbow-ladders.rle ../../Patterns/Life/Miscellaneous/fermat-primes.rle ../../Patterns/Life/Miscellaneous/four-primers.rle.gz ../../Patterns/Life/Miscellaneous/infinity-hotel0.rle ../../Patterns/Life/Miscellaneous/infinity-hotel1.rle ../../Patterns/Life/Miscellaneous/infinity-hotel2.rle ../../Patterns/Life/Miscellaneous/infinity-hotel3.rle ../../Patterns/Life/Miscellaneous/lightspeed.rle ../../Patterns/Life/Miscellaneous/loggrow-corder.rle ../../Patterns/Life/Miscellaneous/sawtooth6b.rle ../../Patterns/Life/Miscellaneous/tubstretch-c124b.rle ../../Patterns/Life/Miscellaneous/twinprimes.rle ../../Patterns/Life/Miscellaneous/wicks-DRH-2002.rle ../../Patterns/Life/Oscillators/billiard-table.rle ../../Patterns/Life/Oscillators/DRH-oscillators.rle ../../Patterns/Life/Oscillators/extensible-low-period.rle ../../Patterns/Life/Oscillators/glider-stream-crystal.rle ../../Patterns/Life/Oscillators/low-period.rle ../../Patterns/Life/Oscillators/p103079214841.rle ../../Patterns/Life/Oscillators/p138.rle ../../Patterns/Life/Oscillators/p59-glider-loop.py ../../Patterns/Life/Oscillators/queen-bee-turn.rle ../../Patterns/Life/Oscillators/traffic-light-hasslers.rle ../../Patterns/Life/Oscillators/unique-high-period.rle ../../Patterns/Life/Puffers/c4-diagonal-puffer.rle ../../Patterns/Life/Puffers/line-puffer-superstable.rle ../../Patterns/Life/Puffers/line-puffer-unstable.rle ../../Patterns/Life/Puffers/p100-H-track-puffer.rle ../../Patterns/Life/Puffers/pi-fuse-puffer.rle ../../Patterns/Life/Puffers/puffer-2c5.rle ../../Patterns/Life/Puffers/puffer-train.rle ../../Patterns/Life/Puffers/zigzag-wickstretcher.rle ../../Patterns/Life/Rakes/2c5-engineless-rake-p185.rle ../../Patterns/Life/Rakes/2c5-spaceship-rake-p240.rle ../../Patterns/Life/Rakes/basic-rakes.rle ../../Patterns/Life/Rakes/c2-Cordership-rake.rle ../../Patterns/Life/Rakes/c3-forward-rake-p333.rle ../../Patterns/Life/Rakes/c4-sideways-rake.rle ../../Patterns/Life/Rakes/c5-adjustable-rake.rle ../../Patterns/Life/Rakes/forward-LWSS-rake-p90.rle ../../Patterns/Life/Rakes/p270-frothing-puffer-rake.rle ../../Patterns/Life/Rakes/spider-rake.rle ../../Patterns/Life/Signal-Circuitry/advancer.rle ../../Patterns/Life/Signal-Circuitry/constructor-memory-loop.rle ../../Patterns/Life/Signal-Circuitry/constructor-memory-tape.rle ../../Patterns/Life/Signal-Circuitry/heisenblinker-30.rle ../../Patterns/Life/Signal-Circuitry/heisenburp-30.rle ../../Patterns/Life/Signal-Circuitry/heisenburp-46-natural.rle ../../Patterns/Life/Signal-Circuitry/heisenburp-46.rle ../../Patterns/Life/Signal-Circuitry/Herschel-conduit-stamp-collection.rle ../../Patterns/Life/Signal-Circuitry/lightspeed-telegraph.rle ../../Patterns/Life/Signal-Circuitry/p30-racetrack.rle ../../Patterns/Life/Signal-Circuitry/p46racetrack.rle ../../Patterns/Life/Signal-Circuitry/reflectors2.rle ../../Patterns/Life/Signal-Circuitry/reflectors.rle ../../Patterns/Life/Signal-Circuitry/signal-turn.rle ../../Patterns/Life/Signal-Circuitry/stargate.rle ../../Patterns/Life/Signal-Circuitry/traffic-lights-extruder.rle ../../Patterns/Life/Signal-Circuitry/Turing-Machine-3-state.rle ../../Patterns/Life/Signal-Circuitry/Unit-Life-Cell-512x512.rle ../../Patterns/Life/Signal-Circuitry/Unit-Life-Deep-Cell.rle ../../Patterns/Life/Spaceships/2c5-orthogonal.rle ../../Patterns/Life/Spaceships/adjustable-Corder-lineship.rle ../../Patterns/Life/Spaceships/c3-orthogonal.rle ../../Patterns/Life/Spaceships/c4-diagonal.rle ../../Patterns/Life/Spaceships/c4-orthogonal.rle ../../Patterns/Life/Spaceships/Corder-lineship.rle ../../Patterns/Life/Spaceships/Cordership-boat-burner.rle ../../Patterns/Life/Spaceships/Cordership-LWSS-freeze-tag.rle ../../Patterns/Life/Spaceships/corderships.rle ../../Patterns/Life/Spaceships/diagonal.rle ../../Patterns/Life/Spaceships/orthogonal.rle ../../Patterns/Life/Spaceships/short-thin-race.rle ../../Patterns/Life/Spaceships/smallest-low-period.rle ../../Patterns/Life/Spaceships/spaceship-types.rle ../../Patterns/Life/Still-Lifes/1998-eater-stamp-collection.rle ../../Patterns/Life/Still-Lifes/eaters-misc.rle ../../Patterns/Life/Still-Lifes/eaters.rle ../../Patterns/Life/Still-Lifes/random.rle ../../Patterns/Life/Still-Lifes/ss-eaters.rle ../../Patterns/Life/Still-Lifes/stripey.rle ../../Patterns/Life/Syntheses/109-still-lifes.rle ../../Patterns/Life/Syntheses/29-still-lifes.rle ../../Patterns/Life/Syntheses/blockish-and-blockic-seeds.rle ../../Patterns/Life/Syntheses/life-integer-constructions.rle ../../Patterns/Life/Syntheses/make-harbor.rle ../../Patterns/Life/Syntheses/make-lightbulb.rle ../../Patterns/Life/Syntheses/make-osc-p3.rle ../../Patterns/Life/Syntheses/make-osc-p4.rle ../../Patterns/Life/Syntheses/make-osc-p5-plus.rle ../../Patterns/Life/Syntheses/make-p11.rle ../../Patterns/Life/Syntheses/make-p18.rle ../../Patterns/Life/Syntheses/make-p33.rle ../../Patterns/Life/Syntheses/oscillator-syntheses.rle ../../Patterns/Life/Syntheses/slow-salvo-eater-recipes.rle ../../Patterns/Life/Syntheses/two-glider-collisions.rle ../../Patterns/Loops/Byl-Loop.rle ../../Patterns/Loops/Chou-Reggia-Loop-1.rle ../../Patterns/Loops/Chou-Reggia-Loop-2.rle ../../Patterns/Loops/Evoloop-finite.rle ../../Patterns/Loops/Evoloop.rle ../../Patterns/Loops/Langtons-Loops.rle ../../Patterns/Loops/Perrier-Loop.rle ../../Patterns/Loops/Perrier-Parenthesis-Checker.rle ../../Patterns/Loops/SDSR-Loop.rle ../../Patterns/Loops/Tempesti-Loop.rle ../../Patterns/Margolus/BBM.rle ../../Patterns/Margolus/CrittersCircle.rle ../../Patterns/Margolus/CrittersOscillators.rle ../../Patterns/Margolus/DLA.rle ../../Patterns/Margolus/HPP_large.rle ../../Patterns/Margolus/HPP.rle ../../Patterns/Margolus/Sand.rle ../../Patterns/Margolus/Sand-Test.rle ../../Patterns/Margolus/TMGas_largeWithHole.rle ../../Patterns/Margolus/TMGas.rle ../../Patterns/Margolus/TripATron_BlockAligned.rle ../../Patterns/Margolus/TripATron.rle ../../Patterns/Other-Rules/Ed-rep.rle ../../Patterns/Other-Rules/golly-ants.rle ../../Patterns/Other-Rules/HPP-demo.rle ../../Patterns/Other-Rules/HPP-demo-small.rle ../../Patterns/Other-Rules/Langtons-Ant.rle ../../Patterns/Other-Rules/life-on-the-edge.rle ../../Patterns/Other-Rules/life-on-the-slope.rle ../../Patterns/Patersons-Worms/worm-1040512.rle ../../Patterns/Patersons-Worms/worm-1042015.rle ../../Patterns/Patersons-Worms/worm-1042020.rle ../../Patterns/Patersons-Worms/worm-1252121.rle ../../Patterns/Patersons-Worms/worm-1525115.rle ../../Patterns/Turmites/AlienCounter.rle ../../Patterns/Turmites/ComputerArt.rle ../../Patterns/Turmites/Extinction.rle ../../Patterns/Turmites/FibonacciSpiral.rle ../../Patterns/Turmites/Highway2074575.rle ../../Patterns/Turmites/LangtonsAnt_LLRR.rle ../../Patterns/Turmites/Perfectionist.rle ../../Patterns/Turmites/TriangularAnt_period92.rle ../../Patterns/Turmites/TriangularLangtonsAnt.rle ../../Patterns/Turmites/WormTrails.rle ../../Patterns/WireWorld/circuit.mcl ../../Patterns/WireWorld/clocks.mcl ../../Patterns/WireWorld/flip-flop.mcl ../../Patterns/WireWorld/gate-AND.mcl ../../Patterns/WireWorld/gate-NOT.mcl ../../Patterns/WireWorld/gate-OR.mcl ../../Patterns/WireWorld/gate-XOR.mcl ../../Patterns/WireWorld/Langtons-ant.zip ../../Patterns/WireWorld/memory-cell.mcl ../../Patterns/WireWorld/NickGardner.mcl ../../Patterns/WireWorld/NylesHeise.mcl ../../Patterns/WireWorld/primes.mc ../../Patterns/WireWorld/unary-multiplier.mcl ../../Rules/AbsoluteTurmite_0N21S10E00S01W11N2.rule ../../Rules/AbsoluteTurmite_0S11W11E21S21W00N0.rule ../../Rules/AbsoluteTurmite_1N10S11S30N21W01N11S20E1.rule ../../Rules/Banks-III.rule ../../Rules/Banks-II.rule ../../Rules/Banks-I.rule ../../Rules/Banks-IV.rule ../../Rules/BBM-Margolus-emulated.rule ../../Rules/BriansBrain.rule ../../Rules/Byl-Loop.rule ../../Rules/Caterpillars.rule ../../Rules/Chou-Reggia-1.rule ../../Rules/Chou-Reggia-2.rule ../../Rules/Codd2.rule ../../Rules/Codd.rule ../../Rules/CrittersMargolus_emulated.rule ../../Rules/Devore.rule ../../Rules/DLA-Margolus-emulated.rule ../../Rules/Ed-rep.rule ../../Rules/Evoloop-finite.rule ../../Rules/Evoloop.rule ../../Rules/HPPMargolus_emulated.rule ../../Rules/HPP.rule ../../Rules/LangtonsAnt_LLRR.rule ../../Rules/Langtons-Ant.rule ../../Rules/Langtons-Loops.rule ../../Rules/LifeHistory.rule ../../Rules/LifeOnTheEdge.rule ../../Rules/LifeOnTheSlope.rule ../../Rules/Life.rule ../../Rules/Perrier.rule ../../Rules/Sand-Margolus-emulated.rule ../../Rules/Sand-square4cyclic_emulated.rule ../../Rules/SDSR-Loop.rule ../../Rules/StarWars.rule ../../Rules/TableGenerators/make-ruletable.cpp ../../Rules/Tempesti.rule ../../Rules/TMGasMargolus_emulated.rule ../../Rules/TreeGenerators/LifeOnTheEdge.cpp ../../Rules/TreeGenerators/LifeOnTheSlope.cpp ../../Rules/TreeGenerators/RuleTreeGen.cpp ../../Rules/TreeGenerators/RuleTreeGen.java ../../Rules/TreeGenerators/RuleTreeGen.pl ../../Rules/TreeGenerators/RuleTreeGen.py ../../Rules/TripATronMargolus_emulated.rule ../../Rules/TriTurmite_120010.rule ../../Rules/Turmite_1202822111121111812a0281282.rule ../../Rules/Turmite_121181121020.rule ../../Rules/Turmite_180121020081.rule ../../Rules/Turmite_181181121010.rule ../../Rules/WireWorld.rule ../../Rules/Worm-1040512.rule ../../Rules/Worm-1042015.rule ../../Rules/Worm-1042020.rule ../../Rules/Worm-1252121.rule ../../Rules/Worm-1525115.rule ../../Rules/Worm-complement.rule ../../Rules/Worm-shared.rule ../../Scripts/Perl/density.pl ../../Scripts/Perl/envelope.pl ../../Scripts/Perl/giffer.pl ../../Scripts/Perl/goto.pl ../../Scripts/Perl/invert.pl ../../Scripts/Perl/make-torus.pl ../../Scripts/Perl/oscar.pl ../../Scripts/Perl/p1100-MWSS-gun.pl ../../Scripts/Perl/pop-plot.pl ../../Scripts/Perl/shift.pl ../../Scripts/Perl/tile.pl ../../Scripts/Perl/tile-with-clip.pl ../../Scripts/Python/bricklayer.py ../../Scripts/Python/density.py ../../Scripts/Python/draw-lines.py ../../Scripts/Python/envelope.py ../../Scripts/Python/flood-fill.py ../../Scripts/Python/glife/base.py ../../Scripts/Python/glife/BuiltinIcons.py ../../Scripts/Python/glife/EmulateHexagonal.py ../../Scripts/Python/glife/EmulateMargolus.py ../../Scripts/Python/glife/EmulateOneDimensional.py ../../Scripts/Python/glife/EmulateTriangular.py ../../Scripts/Python/glife/gun24.py ../../Scripts/Python/glife/gun256.py ../../Scripts/Python/glife/gun30.py ../../Scripts/Python/glife/gun46.py ../../Scripts/Python/glife/herschel.py ../../Scripts/Python/glife/__init__.py ../../Scripts/Python/glife/ReadRuleTable.py ../../Scripts/Python/glife/RuleTree.py ../../Scripts/Python/glife/text.py ../../Scripts/Python/glife/WriteBMP.py ../../Scripts/Python/glife/WriteRuleTable.py ../../Scripts/Python/goto_expression.py ../../Scripts/Python/goto.py ../../Scripts/Python/gun-demo.py ../../Scripts/Python/heisenburp.py ../../Scripts/Python/invert.py ../../Scripts/Python/life-integer-gun30.py ../../Scripts/Python/make-Banks-IV-constructor.py ../../Scripts/Python/make-Codd-constructor.py ../../Scripts/Python/make-Devore-tape.py ../../Scripts/Python/make-torus.py ../../Scripts/Python/Margolus/convert-MCell-string.py ../../Scripts/Python/Margolus/export.py ../../Scripts/Python/Margolus/import.py ../../Scripts/Python/metafier.py ../../Scripts/Python/move-object.py ../../Scripts/Python/move-selection.py ../../Scripts/Python/oscar.py ../../Scripts/Python/p1100-MWSS-gun.py ../../Scripts/Python/pd-glider.py ../../Scripts/Python/pop-plot.py ../../Scripts/Python/Rule-Generators/AbsoluteHexTurmite-gen.py ../../Scripts/Python/Rule-Generators/AbsoluteTurmite-gen.py ../../Scripts/Python/Rule-Generators/FredkinModN-gen.py ../../Scripts/Python/Rule-Generators/HexTurmite-gen.py ../../Scripts/Python/Rule-Generators/icon-exporter.py ../../Scripts/Python/Rule-Generators/icon-importer.py ../../Scripts/Python/Rule-Generators/Langtons-Ant-gen.py ../../Scripts/Python/Rule-Generators/make-ruletree.py ../../Scripts/Python/Rule-Generators/RuleTableToTree.py ../../Scripts/Python/Rule-Generators/TriTurmite-gen.py ../../Scripts/Python/Rule-Generators/Turmite-gen.py ../../Scripts/Python/shift.py ../../Scripts/Python/slide-show.py ../../Scripts/Python/tile.py ../../Scripts/Python/tile-with-clip.py EXTRA_DIST = ../../gui-wx/makefile-gtk ../../gui-wx/makefile-mac ../../gui-wx/makefile-win ../../gui-wx/CMakeLists.txt ../../gui-wx/Info.plist.in ../../gui-wx/local-win-template.mk ../../gui-wx/golly.rc ../../gui-wx/configure/autogen.sh ../../gui-wx/icons ../../gui-wx/bitmaps ../../gui-common ../../gui-android/Golly/AndroidManifest.xml ../../gui-android/Golly/assets/readme.txt ../../gui-android/Golly/assets/triangle-down.png ../../gui-android/Golly/assets/triangle-right.png ../../gui-android/Golly/build.xml ../../gui-android/Golly/ic_launcher-web.png ../../gui-android/Golly/jni/Android.mk ../../gui-android/Golly/jni/Application.mk ../../gui-android/Golly/jni/jnicalls.cpp ../../gui-android/Golly/jni/jnicalls.h ../../gui-android/Golly/proguard-project.txt ../../gui-android/Golly/project.properties ../../gui-android/Golly/res/drawable-hdpi/ic_launcher.png ../../gui-android/Golly/res/drawable-ldpi/readme.txt ../../gui-android/Golly/res/drawable-mdpi/ic_launcher.png ../../gui-android/Golly/res/drawable-xhdpi/ic_launcher.png ../../gui-android/Golly/res/drawable-xxhdpi/ic_launcher.png ../../gui-android/Golly/res/layout/edit_layout.xml ../../gui-android/Golly/res/layout/help_layout.xml ../../gui-android/Golly/res/layout/info_layout.xml ../../gui-android/Golly/res/layout/main_layout_wide.xml ../../gui-android/Golly/res/layout/main_layout.xml ../../gui-android/Golly/res/layout/open_layout.xml ../../gui-android/Golly/res/layout/rule_layout.xml ../../gui-android/Golly/res/layout/settings_layout.xml ../../gui-android/Golly/res/layout/state_layout.xml ../../gui-android/Golly/res/menu/control_menu.xml ../../gui-android/Golly/res/menu/edit_menu.xml ../../gui-android/Golly/res/menu/main.xml ../../gui-android/Golly/res/menu/mode_menu.xml ../../gui-android/Golly/res/menu/paste_menu.xml ../../gui-android/Golly/res/menu/pastemode_menu.xml ../../gui-android/Golly/res/menu/selection_menu.xml ../../gui-android/Golly/res/menu/view_menu.xml ../../gui-android/Golly/res/values/dimens.xml ../../gui-android/Golly/res/values/strings.xml ../../gui-android/Golly/res/values/styles.xml ../../gui-android/Golly/res/values-sw600dp/dimens.xml ../../gui-android/Golly/res/values-sw720dp-land/dimens.xml ../../gui-android/Golly/res/values-v11/styles.xml ../../gui-android/Golly/res/values-v14/styles.xml ../../gui-android/Golly/src/net/sf/golly/BaseActivity.java ../../gui-android/Golly/src/net/sf/golly/BaseApp.java ../../gui-android/Golly/src/net/sf/golly/EditActivity.java ../../gui-android/Golly/src/net/sf/golly/HelpActivity.java ../../gui-android/Golly/src/net/sf/golly/InfoActivity.java ../../gui-android/Golly/src/net/sf/golly/MainActivity.java ../../gui-android/Golly/src/net/sf/golly/OpenActivity.java ../../gui-android/Golly/src/net/sf/golly/PatternGLSurfaceView.java ../../gui-android/Golly/src/net/sf/golly/RuleActivity.java ../../gui-android/Golly/src/net/sf/golly/SettingsActivity.java ../../gui-android/Golly/src/net/sf/golly/StateActivity.java ../../gui-android/Golly/src/net/sf/golly/StateGLSurfaceView.java ../../gui-ios/Golly/beep.aiff ../../gui-ios/Golly/Default-Landscape~ipad.png ../../gui-ios/Golly/Default-Portrait~ipad.png ../../gui-ios/Golly/en.lproj/InfoPlist.strings ../../gui-ios/Golly/GollyAppDelegate.h ../../gui-ios/Golly/GollyAppDelegate.m ../../gui-ios/Golly/Golly-Info.plist ../../gui-ios/Golly/Golly-Prefix.pch ../../gui-ios/Golly/help@2x.png ../../gui-ios/Golly/help.png ../../gui-ios/Golly/HelpViewController.h ../../gui-ios/Golly/HelpViewController.m ../../gui-ios/Golly/HelpViewController.xib ../../gui-ios/Golly/Icon@2x.png ../../gui-ios/Golly/Icon.png ../../gui-ios/Golly/InfoViewController.h ../../gui-ios/Golly/InfoViewController.m ../../gui-ios/Golly/InfoViewController.xib ../../gui-ios/Golly/iTunesArtwork ../../gui-ios/Golly/iTunesArtwork@2x ../../gui-ios/Golly/main.m ../../gui-ios/Golly/open@2x.png ../../gui-ios/Golly/open.png ../../gui-ios/Golly/OpenViewController.h ../../gui-ios/Golly/OpenViewController.m ../../gui-ios/Golly/OpenViewController.xib ../../gui-ios/Golly/pattern@2x.png ../../gui-ios/Golly/pattern.png ../../gui-ios/Golly/PatternViewController.h ../../gui-ios/Golly/PatternViewController.m ../../gui-ios/Golly/PatternViewController.xib ../../gui-ios/Golly/PatternView.h ../../gui-ios/Golly/PatternView.m ../../gui-ios/Golly/RuleViewController.h ../../gui-ios/Golly/RuleViewController.m ../../gui-ios/Golly/RuleViewController.xib ../../gui-ios/Golly/SaveViewController.h ../../gui-ios/Golly/SaveViewController.m ../../gui-ios/Golly/SaveViewController.xib ../../gui-ios/Golly/settings@2x.png ../../gui-ios/Golly/settings.png ../../gui-ios/Golly/SettingsViewController.h ../../gui-ios/Golly/SettingsViewController.m ../../gui-ios/Golly/SettingsViewController.xib ../../gui-ios/Golly/StatePickerController.h ../../gui-ios/Golly/StatePickerController.m ../../gui-ios/Golly/StatePickerController.xib ../../gui-ios/Golly/StatePickerView.h ../../gui-ios/Golly/StatePickerView.m ../../gui-ios/Golly/StateView.h ../../gui-ios/Golly/StateView.m ../../gui-ios/Golly/StatusView.h ../../gui-ios/Golly/StatusView.m ../../gui-ios/Golly/triangle-down.png ../../gui-ios/Golly/triangle-right.png ../../gui-ios/Golly.xcodeproj/project.pbxproj ../../gui-ios/Golly.xcodeproj/project.xcworkspace/contents.xcworkspacedata ../../gui-web/beep.wav ../../gui-web/Help/about.html ../../gui-web/Help/changes.html ../../gui-web/Help/help.html ../../gui-web/Help/index.html ../../gui-web/Help/keyboard.html ../../gui-web/Help/problems.html ../../gui-web/images/about.gif ../../gui-web/images/cursor_draw.png ../../gui-web/images/cursor_move.png ../../gui-web/images/cursor_pick.png ../../gui-web/images/cursor_zoomin.png ../../gui-web/images/cursor_zoomout.png ../../gui-web/images/faster.png ../../gui-web/images/favicon.ico ../../gui-web/images/fit.png ../../gui-web/images/full.png ../../gui-web/images/help.png ../../gui-web/images/info.png ../../gui-web/images/item_blank.png ../../gui-web/images/item_tick.png ../../gui-web/images/menu_down.png ../../gui-web/images/menu_right.png ../../gui-web/images/new.png ../../gui-web/images/next.png ../../gui-web/images/redo.png ../../gui-web/images/reset.png ../../gui-web/images/scale1to1.png ../../gui-web/images/slower.png ../../gui-web/images/start.png ../../gui-web/images/step1.png ../../gui-web/images/step.png ../../gui-web/images/stop.png ../../gui-web/images/triangle_down.png ../../gui-web/images/triangle_right.png ../../gui-web/images/undo.png ../../gui-web/images/zoomin.png ../../gui-web/images/zoomout.png ../../gui-web/jslib.js ../../gui-web/main.cpp ../../gui-web/Makefile ../../gui-web/patterns.py ../../gui-web/shell.html ../../gui-web/webcalls.cpp ../../gui-web/webcalls.h ../../gui-web/zlib/adler32.c ../../gui-web/zlib/compress.c ../../gui-web/zlib/crc32.c ../../gui-web/zlib/crc32.h ../../gui-web/zlib/deflate.c ../../gui-web/zlib/deflate.h ../../gui-web/zlib/gzclose.c ../../gui-web/zlib/gzguts.h ../../gui-web/zlib/gzlib.c ../../gui-web/zlib/gzread.c ../../gui-web/zlib/gzwrite.c ../../gui-web/zlib/infback.c ../../gui-web/zlib/inffast.c ../../gui-web/zlib/inffast.h ../../gui-web/zlib/inffixed.h ../../gui-web/zlib/inflate.c ../../gui-web/zlib/inflate.h ../../gui-web/zlib/inftrees.c ../../gui-web/zlib/inftrees.h ../../gui-web/zlib/README ../../gui-web/zlib/trees.c ../../gui-web/zlib/trees.h ../../gui-web/zlib/uncompr.c ../../gui-web/zlib/zconf.h ../../gui-web/zlib/zlib.h ../../gui-web/zlib/zutil.c ../../gui-web/zlib/zutil.h ../../docs golly-2.7-src/gui-wx/configure/depcomp0000755000175000017500000005064312536111506015004 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2012-03-27.16; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # A tabulation character. tab=' ' # A newline character. nl=' ' if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' "$nl" < "$tmpdepfile" | ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependent.h'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. # However on # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\': # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... # tcc 0.9.26 (FIXME still under development at the moment of writing) # will emit a similar output, but also prepend the continuation lines # with horizontal tabulation characters. "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form 'foo.o: dependent.h', # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. # Do two passes, one to just change these to # '$object: dependent.h' and one to simply 'dependent.h:'. sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ < "$tmpdepfile" > "$depfile" sed ' s/[ '"$tab"'][ '"$tab"']*/ /g s/^ *// s/ *\\*$// s/^[^:]*: *// /^$/d /:$/d s/$/ :/ ' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test "$stat" = 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' "$nl" < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: golly-2.7-src/gui-wx/wxview.h0000755000175000017500000002054612536111364013154 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXVIEW_H_ #define _WXVIEW_H_ #include "bigint.h" // for bigint #include "lifealgo.h" // for lifealgo #include "wxselect.h" // for Selection // Define a child window for viewing and editing patterns: class PatternView : public wxWindow { public: PatternView(wxWindow* parent, wxCoord x, wxCoord y, int wd, int ht, long style); ~PatternView(); // edit functions void CutSelection(); void CopySelection(); void ClearSelection(); void ClearOutsideSelection(); bool GetClipboardPattern(lifealgo** tempalgo, bigint* t, bigint* l, bigint* b, bigint* r); void PasteClipboard(bool toselection); void AbortPaste(); void CyclePasteLocation(); void CyclePasteMode(); void DisplaySelectionSize(); bool SelectionExists(); void SelectAll(); void RemoveSelection(); void ShrinkSelection(bool fit); void RandomFill(); bool FlipSelection(bool topbottom, bool inundoredo = false); bool RotateSelection(bool clockwise, bool inundoredo = false); void SetCursorMode(wxCursor* curs); void CycleCursorMode(); bool CopyRect(int top, int left, int bottom, int right, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, const wxString& progmsg); void CopyAllRect(int top, int left, int bottom, int right, lifealgo* srcalgo, lifealgo* destalgo, const wxString& progmsg); void SaveCurrentSelection(); void RememberNewSelection(const wxString& action); bool OutsideLimits(bigint& t, bigint& l, bigint& b, bigint& r); // return true if given rect is outside getcell/setcell limits bool GetCellPos(bigint& xpos, bigint& ypos); // return true and get mouse location's cell coords if over viewport bool PointInView(int x, int y); // return true if given screen position is in viewport // view functions void ZoomOut(); void ZoomIn(); void SetPixelsPerCell(int pxlspercell); void FitPattern(); void FitSelection(); void ViewOrigin(); void ChangeOrigin(); void RestoreOrigin(); void SetViewSize(int wd, int ht); bool GridVisible(); void ToggleGridLines(); void ToggleCellIcons(); void ToggleCellColors(); void ToggleBuffering(); void UpdateScrollBars(); // update thumb positions void CheckCursor(bool active); // make sure cursor is up to date int GetMag(); // get magnification (..., -1=2:1, 0=1:1, 1=1:2, ...) void SetMag(int newmag); void SetPosMag(const bigint& x, const bigint& y, int mag); void GetPos(bigint& x, bigint& y); void FitInView(int force); bool CellVisible(const bigint& x, const bigint& y); bool CellInGrid(const bigint& x, const bigint& y); bool PointInGrid(int x, int y); void TestAutoFit(); // process keyboard and mouse events void ProcessKey(int key, int modifiers); void ProcessClick(int x, int y, int button, int modifiers); void ProcessClickedControl(); // data bool waitingforclick; // waiting for paste click? bool drawingcells; // drawing cells due to dragging mouse? bool selectingcells; // selecting cells due to dragging mouse? bool movingview; // moving view due to dragging mouse? bool nopattupdate; // disable pattern updates? bool showcontrols; // draw translucent controls? wxRect controlsrect; // location of translucent controls wxRect pasterect; // area to be pasted wxCursor* oldcursor; // non-NULL if shift key has toggled cursor wxCursor* restorecursor; // non-NULL if cursor changed due to middle button click int tileindex; // if the tileindex is >= 0 then this is a tiled window (such windows // lie on top of the main viewport window when tilelayers is true); // the tileindex matches the layer position private: // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() // event handlers void OnPaint(wxPaintEvent& event); void OnSize(wxSizeEvent& event); void OnKeyDown(wxKeyEvent& event); void OnKeyUp(wxKeyEvent& event); void OnChar(wxKeyEvent& event); void OnMouseDown(wxMouseEvent& event); void OnMouseUp(wxMouseEvent& event); #if wxCHECK_VERSION(2, 8, 0) void OnMouseCaptureLost(wxMouseCaptureLostEvent& event); #endif void OnMouseWheel(wxMouseEvent& event); void OnMouseMotion(wxMouseEvent& event); void OnMouseEnter(wxMouseEvent& event); void OnMouseExit(wxMouseEvent& event); void OnDragTimer(wxTimerEvent& event); void OnScroll(wxScrollWinEvent& event); void OnEraseBackground(wxEraseEvent& event); // edit functions void ShowDrawing(); void DrawOneCell(wxDC& dc, int cx, int cy, int oldstate, int newstate); void StartDrawingCells(int x, int y); void DrawCells(int x, int y); void PickCell(int x, int y); void StartSelectingCells(int x, int y, bool shiftdown); void SelectCells(int x, int y); void StartMovingView(int x, int y); void MoveView(int x, int y); void StopDraggingMouse(); void RestoreSelection(); void ZoomInPos(int x, int y); void ZoomOutPos(int x, int y); void SetPasteRect(wxRect& rect, bigint& wd, bigint& ht); void PasteTemporaryToCurrent(bool toselection, bigint top, bigint left, bigint bottom, bigint right); bool FlipPastePattern(bool topbottom); bool RotatePastePattern(bool clockwise); // scroll functions void PanUp(int amount); void PanDown(int amount); void PanLeft(int amount); void PanRight(int amount); void PanNE(); void PanNW(); void PanSE(); void PanSW(); int SmallScroll(int xysize); int BigScroll(int xysize); // data wxBitmap* viewbitmap; // viewport bitmap used in OnPaint int viewbitmapwd; // width of viewport bitmap int viewbitmapht; // height of viewport bitmap wxTimer* dragtimer; // timer used while dragging mouse int cellx, celly; // current cell's 32-bit position bigint bigcellx, bigcelly; // current cell's position int initselx, initsely; // location of initial selection click bool forceh; // resize selection horizontally? bool forcev; // resize selection vertically? bigint anchorx, anchory; // anchor cell of current selection Selection prevsel; // previous selection int drawstate; // new cell state (0..255) wxBrush* cellbrush; // brush used to draw live cells int pastex, pastey; // where user wants to paste clipboard pattern int hthumb, vthumb; // current thumb box positions int realkey; // key code set by OnKeyDown wxString debugkey; // display debug info for OnKeyDown and OnChar }; const wxString empty_pattern = _("All cells are dead."); const wxString empty_selection = _("There are no live cells in the selection."); const wxString empty_outside = _("There are no live cells outside the selection."); const wxString no_selection = _("There is no selection."); const wxString selection_too_big = _("Selection is outside +/- 10^9 boundary."); const wxString pattern_too_big = _("Pattern is outside +/- 10^9 boundary."); const wxString origin_restored = _("Origin restored."); #endif golly-2.7-src/gui-wx/wxview.cpp0000644000175000017500000034337312536111364013512 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #if wxUSE_TOOLTIPS #include "wx/tooltip.h" // for wxToolTip #endif #include "wx/file.h" // for wxFile #include "wx/dcbuffer.h" // for wxBufferedPaintDC #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "viewport.h" #include "wxgolly.h" // for mainptr, statusptr #include "wxutils.h" // for Warning, Fatal, Beep #include "wxprefs.h" // for showgridlines, canchangerule, etc #include "wxhelp.h" // for ShowHelp, LoadRule #include "wxmain.h" // for mainptr->... #include "wxstatus.h" // for statusptr->... #include "wxrender.h" // for CreatePasteImage, DrawView, DrawSelection, etc #include "wxscript.h" // for inscript, PassKeyToScript, PassClickToScript #include "wxselect.h" // for Selection #include "wxedit.h" // for UpdateEditBar, ToggleEditBar, etc #include "wxundo.h" // for currlayer->undoredo->... #include "wxalgos.h" // for algo_type, *_ALGO, CreateNewUniverse, etc #include "wxlayer.h" // for currlayer, ResizeLayers, etc #include "wxtimeline.h" // for StartStopRecording, DeleteTimeline, etc #include "wxview.h" #if defined(__WXMAC__) && !defined(__WXOSX_COCOA__) #include // for Button #endif // This module implements a viewport window for editing and viewing patterns. // ----------------------------------------------------------------------------- const int DRAG_RATE = 20; // call OnDragTimer 50 times per sec static bool stopdrawing = false; // terminate a draw done while generating? static bool slowdraw = false; // do slow cell drawing via UpdateView? static wxString oldrule; // rule before readclipboard is called static wxString newrule; // rule after readclipboard is called static lifealgo* pastealgo; // temporary universe with pattern to be pasted static wxRect pastebox; // bounding box for paste pattern static int pastetype; // algo type for pastealgo // remember which translucent button was clicked, and when static control_id clickedcontrol = NO_CONTROL; static long clicktime; // panning buttons are treated differently #define PANNING_CONTROL (clickedcontrol >= NW_CONTROL && \ clickedcontrol <= SE_CONTROL && \ clickedcontrol != MIDDLE_CONTROL) // ----------------------------------------------------------------------------- // event table and handlers: BEGIN_EVENT_TABLE(PatternView, wxWindow) EVT_PAINT ( PatternView::OnPaint) EVT_SIZE ( PatternView::OnSize) EVT_KEY_DOWN ( PatternView::OnKeyDown) EVT_KEY_UP ( PatternView::OnKeyUp) EVT_CHAR ( PatternView::OnChar) EVT_LEFT_DOWN ( PatternView::OnMouseDown) EVT_LEFT_DCLICK ( PatternView::OnMouseDown) EVT_RIGHT_DOWN ( PatternView::OnMouseDown) EVT_RIGHT_DCLICK ( PatternView::OnMouseDown) EVT_MIDDLE_DOWN ( PatternView::OnMouseDown) EVT_MIDDLE_DCLICK ( PatternView::OnMouseDown) EVT_LEFT_UP ( PatternView::OnMouseUp) EVT_RIGHT_UP ( PatternView::OnMouseUp) EVT_MIDDLE_UP ( PatternView::OnMouseUp) #if wxCHECK_VERSION(2, 8, 0) EVT_MOUSE_CAPTURE_LOST ( PatternView::OnMouseCaptureLost) #endif EVT_MOTION ( PatternView::OnMouseMotion) EVT_ENTER_WINDOW ( PatternView::OnMouseEnter) EVT_LEAVE_WINDOW ( PatternView::OnMouseExit) EVT_MOUSEWHEEL ( PatternView::OnMouseWheel) EVT_TIMER (wxID_ANY, PatternView::OnDragTimer) EVT_SCROLLWIN ( PatternView::OnScroll) EVT_ERASE_BACKGROUND ( PatternView::OnEraseBackground) END_EVENT_TABLE() // ----------------------------------------------------------------------------- static void UpdateView() { // update main viewport window, including all tile windows if they exist // (tile windows are children of bigview) bigview->Refresh(false); bigview->Update(); } // ----------------------------------------------------------------------------- static void RefreshView() { // refresh main viewport window, including all tile windows if they exist // (tile windows are children of bigview) bigview->Refresh(false); } // ----------------------------------------------------------------------------- // most editing operations are limited to absolute coordinates <= 10^9 because // getcell and setcell only take int parameters (the limits must be smaller // than INT_MIN and INT_MAX to avoid boundary conditions) static bigint min_coord = -1000000000; static bigint max_coord = +1000000000; bool PatternView::OutsideLimits(bigint& t, bigint& l, bigint& b, bigint& r) { return ( t < min_coord || l < min_coord || b > max_coord || r > max_coord ); } // ----------------------------------------------------------------------------- bool PatternView::SelectionExists() { return currlayer->currsel.Exists(); } // ----------------------------------------------------------------------------- bool PatternView::CopyRect(int itop, int ileft, int ibottom, int iright, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, const wxString& progmsg) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; double maxcount = (double)wd * (double)ht; int cntr = 0; int v = 0; bool abort = false; // copy (and erase if requested) live cells from given rect // in source universe to same rect in destination universe BeginProgress(progmsg); for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = srcalgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; destalgo->setcell(cx, cy, v); if (erasesrc) srcalgo->setcell(cx, cy, 0); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, wxEmptyString); if (abort) break; } } if (abort) break; } if (erasesrc) srcalgo->endofpattern(); destalgo->endofpattern(); EndProgress(); return !abort; } // ----------------------------------------------------------------------------- void PatternView::CopyAllRect(int itop, int ileft, int ibottom, int iright, lifealgo* srcalgo, lifealgo* destalgo, const wxString& progmsg) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; // copy all cells from given rect in srcalgo to same rect in destalgo BeginProgress(progmsg); for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { destalgo->setcell(cx, cy, srcalgo->getcell(cx, cy)); cntr++; if ((cntr % 4096) == 0) { abort = AbortProgress((double)cntr / maxcount, wxEmptyString); if (abort) break; } } if (abort) break; } destalgo->endofpattern(); EndProgress(); } // ----------------------------------------------------------------------------- void PatternView::ClearSelection() { currlayer->currsel.Clear(); } // ----------------------------------------------------------------------------- void PatternView::ClearOutsideSelection() { currlayer->currsel.ClearOutside(); } // ----------------------------------------------------------------------------- void PatternView::CutSelection() { if (!SelectionExists()) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_CUT); return; } currlayer->currsel.CopyToClipboard(true); } // ----------------------------------------------------------------------------- void PatternView::CopySelection() { if (!SelectionExists()) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_COPY); return; } currlayer->currsel.CopyToClipboard(false); } // ----------------------------------------------------------------------------- bool PatternView::CellInGrid(const bigint& x, const bigint& y) { // return true if cell at x,y is within bounded grid if (currlayer->algo->gridwd > 0 && (x < currlayer->algo->gridleft || x > currlayer->algo->gridright)) return false; if (currlayer->algo->gridht > 0 && (y < currlayer->algo->gridtop || y > currlayer->algo->gridbottom)) return false; return true; } // ----------------------------------------------------------------------------- bool PatternView::PointInGrid(int x, int y) { // is given viewport location also in grid? if (currlayer->algo->gridwd == 0 && currlayer->algo->gridht == 0) { // unbounded grid return true; } pair cellpos = currlayer->view->at(x, y); return CellInGrid(cellpos.first, cellpos.second); } // ----------------------------------------------------------------------------- void PatternView::SetPasteRect(wxRect& rect, bigint& wd, bigint& ht) { int x, y, pastewd, pasteht; int mag = currlayer->view->getmag(); // find cell coord of current paste cursor position pair pcell = currlayer->view->at(pastex, pastey); // determine bottom right cell bigint right = pcell.first; right += wd; right -= 1; bigint bottom = pcell.second; bottom += ht; bottom -= 1; // best to use same method as in Selection::Visible pair lt = currlayer->view->screenPosOf(pcell.first, pcell.second, currlayer->algo); pair rb = currlayer->view->screenPosOf(right, bottom, currlayer->algo); if (mag > 0) { // move rb to pixel at bottom right corner of cell rb.first += (1 << mag) - 1; rb.second += (1 << mag) - 1; if (mag > 1) { // avoid covering gaps at scale 1:4 and above rb.first--; rb.second--; } } x = lt.first; y = lt.second; pastewd = rb.first - lt.first + 1; pasteht = rb.second - lt.second + 1; // this should never happen but play safe if (pastewd <= 0) pastewd = 1; if (pasteht <= 0) pasteht = 1; rect = wxRect(x, y, pastewd, pasteht); int xoffset, yoffset; int cellsize = 1 << mag; // only used if mag > 0 int gap = 1; // ditto if (mag == 1) gap = 0; // but no gap between cells at scale 1:2 switch (plocation) { case TopLeft: break; case TopRight: xoffset = mag > 0 ? -(pastewd - cellsize + gap) : -pastewd + 1; rect.Offset(xoffset, 0); break; case BottomRight: xoffset = mag > 0 ? -(pastewd - cellsize + gap) : -pastewd + 1; yoffset = mag > 0 ? -(pasteht - cellsize + gap) : -pasteht + 1; rect.Offset(xoffset, yoffset); break; case BottomLeft: yoffset = mag > 0 ? -(pasteht - cellsize + gap) : -pasteht + 1; rect.Offset(0, yoffset); break; case Middle: xoffset = mag > 0 ? -(pastewd / cellsize / 2) * cellsize : -pastewd / 2; yoffset = mag > 0 ? -(pasteht / cellsize / 2) * cellsize : -pasteht / 2; rect.Offset(xoffset, yoffset); break; } } // ----------------------------------------------------------------------------- void PatternView::PasteTemporaryToCurrent(bool toselection, bigint top, bigint left, bigint bottom, bigint right) { // make sure given edges are within getcell/setcell limits if ( OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Clipboard pattern is too big.")); return; } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); bigint wd = iright - ileft + 1; bigint ht = ibottom - itop + 1; if ( toselection ) { if ( !currlayer->currsel.CanPaste(wd, ht, top, left) ) { statusptr->ErrorMessage(_("Clipboard pattern is bigger than selection.")); return; } // top and left have been set to the selection's top left corner } else { // ask user where to paste the clipboard pattern statusptr->DisplayMessage(_("Click where you want to paste...")); // temporarily change cursor to cross wxCursor* savecurs = currlayer->curs; currlayer->curs = curs_cross; CheckCursor(true); // create image for drawing pattern to be pasted; note that pastebox // is not necessarily the minimal bounding box because clipboard pattern // might have blank borders (in fact it could be empty) pastebox = wxRect(ileft, itop, wd.toint(), ht.toint()); CreatePasteImage(pastealgo, pastebox); waitingforclick = true; mainptr->UpdateMenuAccelerators(); // remove all accelerators so keyboard shortcuts can be used mainptr->EnableAllMenus(false); // disable all menu items mainptr->UpdateToolBar(); // disable all tool bar buttons UpdateLayerBar(); // disable all layer bar buttons UpdateEditBar(); // disable all edit bar buttons CaptureMouse(); // get mouse down event even if outside view pasterect = wxRect(-1,-1,0,0); while (waitingforclick) { wxPoint pt = ScreenToClient( wxGetMousePosition() ); pastex = pt.x; pastey = pt.y; if (PointInView(pt.x, pt.y)) { // determine new paste rectangle wxRect newrect; if (wd.toint() != pastebox.width || ht.toint() != pastebox.height) { // RotatePastePattern was called itop = pastebox.y; ileft = pastebox.x; ibottom = itop + pastebox.height - 1; iright = ileft + pastebox.width - 1; wd = pastebox.width; ht = pastebox.height; } SetPasteRect(newrect, wd, ht); if (newrect != pasterect) { // draw new pasterect pasterect = newrect; Refresh(false); // don't update immediately } } else { // mouse outside viewport so erase old pasterect if necessary if ( pasterect.width > 0 ) { pasterect = wxRect(-1,-1,0,0); Refresh(false); // don't update immediately } } wxMilliSleep(10); // don't hog CPU wxGetApp().Yield(true); // make sure viewport retains focus so we can use keyboard shortcuts SetFocus(); // waitingforclick becomes false if OnMouseDown is called #if defined(__WXMAC__) && !defined(__WXOSX_COCOA__) // need to check for click here because OnMouseDown does not // get called if click is in menu bar or in another window if ( waitingforclick && Button() ) { pt = ScreenToClient( wxGetMousePosition() ); pastex = pt.x; pastey = pt.y; waitingforclick = false; // terminate while loop FlushEvents(mDownMask + mUpMask, 0); // avoid wx seeing click } #endif } if ( HasCapture() ) ReleaseMouse(); mainptr->EnableAllMenus(true); mainptr->UpdateMenuAccelerators(); // restore accelerators DestroyPasteImage(); // restore cursor currlayer->curs = savecurs; CheckCursor(mainptr->infront); if ( pasterect.width > 0 ) { // erase old pasterect Refresh(false); // no need to update immediately // Update(); } if ( !PointInView(pastex, pastey) || // allow paste if any corner of pasterect is within grid !( PointInGrid(pastex, pastey) || PointInGrid(pastex+pasterect.width-1, pastey) || PointInGrid(pastex, pastey+pasterect.height-1) || PointInGrid(pastex+pasterect.width-1, pastey+pasterect.height-1) ) ) { statusptr->DisplayMessage(_("Paste aborted.")); return; } // set paste rectangle's top left cell coord pair clickpos = currlayer->view->at(pastex, pastey); top = clickpos.second; left = clickpos.first; bigint halfht = ht; bigint halfwd = wd; halfht.div2(); halfwd.div2(); if (currlayer->view->getmag() > 1) { if (ht.even()) halfht -= 1; if (wd.even()) halfwd -= 1; } switch (plocation) { case TopLeft: /* no change*/ break; case TopRight: left -= wd; left += 1; break; case BottomRight: left -= wd; left += 1; top -= ht; top += 1; break; case BottomLeft: top -= ht; top += 1; break; case Middle: left -= halfwd; top -= halfht; break; } } // check that paste rectangle is within edit limits bottom = top; bottom += ht; bottom -= 1; right = left; right += wd; right -= 1; if ( OutsideLimits(top, left, bottom, right) ) { statusptr->ErrorMessage(_("Pasting is not allowed outside +/- 10^9 boundary.")); return; } // selection might change if grid becomes smaller, // so save current selection for RememberRuleChange/RememberAlgoChange SaveCurrentSelection(); // pasting clipboard pattern can cause a rule change int oldmaxstate = currlayer->algo->NumCellStates() - 1; if (canchangerule > 0 && oldrule != newrule) { const char* err = currlayer->algo->setrule( newrule.mb_str(wxConvLocal) ); // setrule can fail if readclipboard loaded clipboard pattern into // a different type of algo (pastetype) if (err) { // allow rule change to cause algo change mainptr->ChangeAlgorithm(pastetype, newrule); } else { // show new rule in title bar mainptr->SetWindowTitle(wxEmptyString); // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { mainptr->ClearOutsideGrid(); } // rule change might have changed the number of cell states; // if there are fewer states then pattern might change int newmaxstate = currlayer->algo->NumCellStates() - 1; if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { mainptr->ReduceCellStates(newmaxstate); } // switch to default colors for new rule UpdateLayerColors(); if (allowundo && !currlayer->stayclean) currlayer->undoredo->RememberRuleChange(oldrule); } } // set pastex,pastey to top left cell of paste rectangle pastex = left.toint(); pastey = top.toint(); // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; if (savecells && inscript) SavePendingChanges(); // don't paste cells outside bounded grid int gtop = currlayer->algo->gridtop.toint(); int gleft = currlayer->algo->gridleft.toint(); int gbottom = currlayer->algo->gridbottom.toint(); int gright = currlayer->algo->gridright.toint(); if (currlayer->algo->gridwd == 0) { // grid has infinite width gleft = INT_MIN; gright = INT_MAX; } if (currlayer->algo->gridht == 0) { // grid has infinite height gtop = INT_MIN; gbottom = INT_MAX; } // copy pattern from temporary universe to current universe int tx, ty, cx, cy; double maxcount = wd.todouble() * ht.todouble(); int cntr = 0; bool abort = false; bool pattchanged = false; bool reduced = false; lifealgo* curralgo = currlayer->algo; int maxstate = curralgo->NumCellStates() - 1; BeginProgress(_("Pasting pattern")); // we can speed up pasting sparse patterns by using nextcell in these cases: // - if using Or mode // - if current universe is empty // - if paste rect is outside current pattern edges bool usenextcell; if ( pmode == Or || curralgo->isEmpty() ) { usenextcell = true; } else { bigint ctop, cleft, cbottom, cright; curralgo->findedges(&ctop, &cleft, &cbottom, &cright); usenextcell = top > cbottom || bottom < ctop || left > cright || right < cleft; } if ( usenextcell && pmode == And ) { // current universe is empty or paste rect is outside current pattern edges // so don't change any cells } else if ( usenextcell ) { int newstate = 0; cy = pastey; for ( ty=itop; ty<=ibottom; ty++ ) { cx = pastex; for ( tx=ileft; tx<=iright; tx++ ) { int skip = pastealgo->nextcell(tx, ty, newstate); if (skip + tx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell so paste it into current universe tx += skip; cx += skip; if (cx >= gleft && cx <= gright && cy >= gtop && cy <= gbottom) { int currstate = curralgo->getcell(cx, cy); if (currstate != newstate) { if (newstate > maxstate) { newstate = maxstate; reduced = true; } curralgo->setcell(cx, cy, newstate); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, newstate); } } cx++; } else { tx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((ty - itop) * (double)(iright - ileft + 1) + (tx - ileft)) / maxcount; abort = AbortProgress(prog, wxEmptyString); if (abort) break; } } if (abort) break; cy++; } } else { // have to use slower getcell/setcell calls int tempstate, currstate; int numstates = curralgo->NumCellStates(); cy = pastey; for ( ty=itop; ty<=ibottom; ty++ ) { cx = pastex; for ( tx=ileft; tx<=iright; tx++ ) { tempstate = pastealgo->getcell(tx, ty); currstate = curralgo->getcell(cx, cy); if (cx >= gleft && cx <= gright && cy >= gtop && cy <= gbottom) { switch (pmode) { case And: if (tempstate != currstate && currstate > 0) { curralgo->setcell(cx, cy, 0); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, 0); } break; case Copy: if (tempstate != currstate) { if (tempstate > maxstate) { tempstate = maxstate; reduced = true; } curralgo->setcell(cx, cy, tempstate); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, tempstate); } break; case Or: // Or mode is done using above nextcell loop; // we only include this case to avoid compiler warning break; case Xor: if (tempstate == currstate) { if (currstate != 0) { curralgo->setcell(cx, cy, 0); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, 0); } } else { // tempstate != currstate int newstate = tempstate ^ currstate; // if xor overflows then don't change current state if (newstate >= numstates) newstate = currstate; if (currstate != newstate) { curralgo->setcell(cx, cy, newstate); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, newstate); } } break; } } cx++; cntr++; if ( (cntr % 4096) == 0 ) { abort = AbortProgress((double)cntr / maxcount, wxEmptyString); if (abort) break; } } if (abort) break; cy++; } } if (pattchanged) curralgo->endofpattern(); EndProgress(); // tidy up and display result statusptr->ClearMessage(); if (pattchanged) { if (savecells) currlayer->undoredo->RememberCellChanges(_("Paste"), currlayer->dirty); MarkLayerDirty(); // calls SetWindowTitle mainptr->UpdatePatternAndStatus(); } if (reduced) statusptr->ErrorMessage(_("Some cell states were reduced.")); } // ----------------------------------------------------------------------------- bool PatternView::GetClipboardPattern(lifealgo** tempalgo, bigint* t, bigint* l, bigint* b, bigint* r) { wxTextDataObject data; if ( !mainptr->GetTextFromClipboard(&data) ) return false; // copy clipboard data to temporary file so we can handle all formats supported by readclipboard wxFile tmpfile(mainptr->clipfile, wxFile::write); if ( !tmpfile.IsOpened() ) { Warning(_("Could not create temporary file for clipboard data!")); return false; } if ( !tmpfile.Write(data.GetText()) ) { Warning(_("Could not write clipboard data to temporary file! Maybe disk is full?")); tmpfile.Close(); return false; } tmpfile.Close(); // remember current rule oldrule = wxString(currlayer->algo->getrule(), wxConvLocal); const char* err = readclipboard(mainptr->clipfile.mb_str(wxConvLocal), **tempalgo, t, l, b, r); if (err) { // cycle thru all other algos until readclipboard succeeds for (int i = 0; i < NumAlgos(); i++) { if (i != currlayer->algtype) { delete *tempalgo; *tempalgo = CreateNewUniverse(i); err = readclipboard(mainptr->clipfile.mb_str(wxConvLocal), **tempalgo, t, l, b, r); if (!err) { pastetype = i; // remember algo type for later use in PasteTemporaryToCurrent break; } } } } if (!err && canchangerule > 0) { // set newrule for later use in PasteTemporaryToCurrent if (canchangerule == 1 && !currlayer->algo->isEmpty()) { // don't change rule if universe isn't empty newrule = oldrule; } else { // remember rule set by readclipboard newrule = wxString((*tempalgo)->getrule(), wxConvLocal); } } wxRemoveFile(mainptr->clipfile); if (err) { // error probably due to bad rule string in clipboard data Warning(_("Could not load clipboard pattern\n(probably due to unknown rule).")); return false; } return true; } // ----------------------------------------------------------------------------- static bool doing_paste = false; // inside PasteTemporaryToCurrent? void PatternView::PasteClipboard(bool toselection) { // prevent re-entrancy in PasteTemporaryToCurrent due to rapid pasting of large clipboard pattern if (doing_paste) return; if (waitingforclick || !mainptr->ClipboardHasText()) return; if (toselection && !SelectionExists()) return; if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(toselection ? ID_PASTE_SEL : ID_PASTE); return; } // if clipboard text starts with "@RULE rulename" then install rulename.rule // and switch to that rule if (mainptr->ClipboardContainsRule()) return; // create a temporary universe for storing the clipboard pattern; // GetClipboardPattern assumes it is same type as current universe pastealgo = CreateNewUniverse(currlayer->algtype); pastetype = currlayer->algtype; // read clipboard pattern into temporary universe bigint top, left, bottom, right; if ( GetClipboardPattern(&pastealgo, &top, &left, &bottom, &right) ) { // pastealgo might have been deleted and re-created as a different type of universe doing_paste = true; PasteTemporaryToCurrent(toselection, top, left, bottom, right); doing_paste = false; } delete pastealgo; } // ----------------------------------------------------------------------------- void PatternView::AbortPaste() { pastex = -1; pastey = -1; waitingforclick = false; // terminate while (waitingforclick) loop } // ----------------------------------------------------------------------------- void PatternView::CyclePasteLocation() { if (plocation == TopLeft) { plocation = TopRight; if (!waitingforclick) statusptr->DisplayMessage(_("Paste location is Top Right.")); } else if (plocation == TopRight) { plocation = BottomRight; if (!waitingforclick) statusptr->DisplayMessage(_("Paste location is Bottom Right.")); } else if (plocation == BottomRight) { plocation = BottomLeft; if (!waitingforclick) statusptr->DisplayMessage(_("Paste location is Bottom Left.")); } else if (plocation == BottomLeft) { plocation = Middle; if (!waitingforclick) statusptr->DisplayMessage(_("Paste location is Middle.")); } else { plocation = TopLeft; if (!waitingforclick) statusptr->DisplayMessage(_("Paste location is Top Left.")); } if (waitingforclick) { // force redraw of paste rectangle if mouse is inside viewport pasterect = wxRect(-1,-1,0,0); } } // ----------------------------------------------------------------------------- void PatternView::CyclePasteMode() { if (pmode == And) { pmode = Copy; if (!waitingforclick) statusptr->DisplayMessage(_("Paste mode is Copy.")); } else if (pmode == Copy) { pmode = Or; if (!waitingforclick) statusptr->DisplayMessage(_("Paste mode is Or.")); } else if (pmode == Or) { pmode = Xor; if (!waitingforclick) statusptr->DisplayMessage(_("Paste mode is Xor.")); } else { pmode = And; if (!waitingforclick) statusptr->DisplayMessage(_("Paste mode is And.")); } if (waitingforclick) { // force redraw of paste rectangle if mouse is inside viewport pasterect = wxRect(-1,-1,0,0); } } // ----------------------------------------------------------------------------- void PatternView::DisplaySelectionSize() { if (waitingforclick || inscript || currlayer->undoredo->doingscriptchanges) return; currlayer->currsel.DisplaySize(); } // ----------------------------------------------------------------------------- void PatternView::SaveCurrentSelection() { if (allowundo && !currlayer->stayclean) { currlayer->savesel = currlayer->currsel; } } // ----------------------------------------------------------------------------- void PatternView::RememberNewSelection(const wxString& action) { if (TimelineExists()) { // we allow selections while a timeline exists but we can't // remember them in the undo/redo history return; } if (allowundo && !currlayer->stayclean) { if (inscript) SavePendingChanges(); currlayer->undoredo->RememberSelection(action); } } // ----------------------------------------------------------------------------- void PatternView::SelectAll() { SaveCurrentSelection(); if (SelectionExists()) { currlayer->currsel.Deselect(); mainptr->UpdatePatternAndStatus(); } if (currlayer->algo->isEmpty()) { statusptr->ErrorMessage(empty_pattern); RememberNewSelection(_("Deselection")); return; } bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); currlayer->currsel.SetEdges(top, left, bottom, right); RememberNewSelection(_("Select All")); DisplaySelectionSize(); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void PatternView::RemoveSelection() { if (SelectionExists()) { SaveCurrentSelection(); currlayer->currsel.Deselect(); RememberNewSelection(_("Deselection")); mainptr->UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- void PatternView::ShrinkSelection(bool fit) { currlayer->currsel.Shrink(fit); } // ----------------------------------------------------------------------------- void PatternView::RandomFill() { currlayer->currsel.RandomFill(); } // ----------------------------------------------------------------------------- bool PatternView::FlipPastePattern(bool topbottom) { bool result; Selection pastesel(pastebox.GetTop(), pastebox.GetLeft(), pastebox.GetBottom(), pastebox.GetRight()); // flip the pattern in pastealgo lifealgo* savealgo = currlayer->algo; int savetype = currlayer->algtype; currlayer->algo = pastealgo; currlayer->algtype = pastetype; // pass in true for inundoredo parameter so flip won't be remembered // and layer won't be marked as dirty; also set inscript temporarily // so that viewport won't be updated inscript = true; result = pastesel.Flip(topbottom, true); // currlayer->algo might point to a *different* universe pastealgo = currlayer->algo; currlayer->algo = savealgo; currlayer->algtype = savetype; inscript = false; if (result) { CreatePasteImage(pastealgo, pastebox); UpdateView(); } return result; } // ----------------------------------------------------------------------------- bool PatternView::RotatePastePattern(bool clockwise) { bool result; Selection pastesel(pastebox.GetTop(), pastebox.GetLeft(), pastebox.GetBottom(), pastebox.GetRight()); // rotate the pattern in pastealgo lifealgo* savealgo = currlayer->algo; int savetype = currlayer->algtype; currlayer->algo = pastealgo; currlayer->algtype = pastetype; // pass in true for inundoredo parameter so rotate won't be remembered // and layer won't be marked as dirty; also set inscript temporarily // so that viewport won't be updated inscript = true; result = pastesel.Rotate(clockwise, true); // currlayer->algo might point to a *different* universe pastealgo = currlayer->algo; currlayer->algo = savealgo; currlayer->algtype = savetype; inscript = false; if (result) { // get rotated selection and update pastebox int x, y, wd, ht; pastesel.GetRect(&x, &y, &wd, &ht); pastebox = wxRect(x, y, wd, ht); CreatePasteImage(pastealgo, pastebox); UpdateView(); } return result; } // ----------------------------------------------------------------------------- bool PatternView::FlipSelection(bool topbottom, bool inundoredo) { if (waitingforclick) { // more useful to flip the pattern about to be pasted return FlipPastePattern(topbottom); } else { return currlayer->currsel.Flip(topbottom, inundoredo); } } // ----------------------------------------------------------------------------- bool PatternView::RotateSelection(bool clockwise, bool inundoredo) { if (waitingforclick) { // more useful to rotate the pattern about to be pasted return RotatePastePattern(clockwise); } else { return currlayer->currsel.Rotate(clockwise, inundoredo); } } // ----------------------------------------------------------------------------- void PatternView::SetCursorMode(wxCursor* cursor) { currlayer->curs = cursor; } // ----------------------------------------------------------------------------- void PatternView::CycleCursorMode() { if (drawingcells || selectingcells || movingview || waitingforclick) return; if (currlayer->curs == curs_pencil) currlayer->curs = curs_pick; else if (currlayer->curs == curs_pick) currlayer->curs = curs_cross; else if (currlayer->curs == curs_cross) currlayer->curs = curs_hand; else if (currlayer->curs == curs_hand) currlayer->curs = curs_zoomin; else if (currlayer->curs == curs_zoomin) currlayer->curs = curs_zoomout; else currlayer->curs = curs_pencil; } // ----------------------------------------------------------------------------- void PatternView::ZoomOut() { TestAutoFit(); currlayer->view->unzoom(); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ZoomIn() { TestAutoFit(); if (currlayer->view->getmag() < MAX_MAG) { currlayer->view->zoom(); mainptr->UpdateEverything(); } else { Beep(); } } // ----------------------------------------------------------------------------- void PatternView::SetPixelsPerCell(int pxlspercell) { int mag = 0; while (pxlspercell > 1) { mag++; pxlspercell >>= 1; } if (mag == currlayer->view->getmag()) return; TestAutoFit(); currlayer->view->setmag(mag); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::FitPattern() { currlayer->algo->fit(*currlayer->view, 1); // best not to call TestAutoFit mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::FitSelection() { if (!SelectionExists()) return; currlayer->currsel.Fit(); TestAutoFit(); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ViewOrigin() { // put 0,0 cell in middle of view if ( currlayer->originx == bigint::zero && currlayer->originy == bigint::zero ) { currlayer->view->center(); } else { // put cell saved by ChangeOrigin in middle currlayer->view->setpositionmag(currlayer->originx, currlayer->originy, currlayer->view->getmag()); } TestAutoFit(); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ChangeOrigin() { if (waitingforclick) return; // change cell under cursor to 0,0 wxPoint pt = ScreenToClient( wxGetMousePosition() ); if ( pt.x < 0 || pt.x > currlayer->view->getxmax() || pt.y < 0 || pt.y > currlayer->view->getymax() ) { statusptr->ErrorMessage(_("Origin not changed.")); } else { pair cellpos = currlayer->view->at(pt.x, pt.y); currlayer->originx = cellpos.first; currlayer->originy = cellpos.second; statusptr->DisplayMessage(_("Origin changed.")); if ( GridVisible() ) mainptr->UpdatePatternAndStatus(); else statusptr->UpdateXYLocation(); } } // ----------------------------------------------------------------------------- void PatternView::RestoreOrigin() { if (waitingforclick) return; if (currlayer->originx != bigint::zero || currlayer->originy != bigint::zero) { currlayer->originx = 0; currlayer->originy = 0; statusptr->DisplayMessage(origin_restored); if ( GridVisible() ) mainptr->UpdatePatternAndStatus(); else statusptr->UpdateXYLocation(); } } // ----------------------------------------------------------------------------- bool PatternView::GridVisible() { return ( showgridlines && currlayer->view->getmag() >= mingridmag ); } // ----------------------------------------------------------------------------- void PatternView::ToggleGridLines() { showgridlines = !showgridlines; if ( (currlayer->view->getmag() >= mingridmag) || // also update everything if drawing all layers (numlayers > 1 && (stacklayers || tilelayers)) ) mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ToggleCellIcons() { showicons = !showicons; mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ToggleCellColors() { swapcolors = !swapcolors; InvertCellColors(); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ToggleBuffering() { buffered = !buffered; mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- bool PatternView::GetCellPos(bigint& xpos, bigint& ypos) { wxPoint pt = ScreenToClient( wxGetMousePosition() ); if (PointInView(pt.x, pt.y)) { // get mouse location in cell coords pair cellpos = currlayer->view->at(pt.x, pt.y); xpos = cellpos.first; ypos = cellpos.second; // check if xpos,ypos is outside bounded grid if (!CellInGrid(xpos, ypos)) return false; return true; } else { // mouse not in viewport return false; } } // ----------------------------------------------------------------------------- bool PatternView::PointInView(int x, int y) { return ( x >= 0 && x <= currlayer->view->getxmax() && y >= 0 && y <= currlayer->view->getymax() ); } // ----------------------------------------------------------------------------- #ifdef __WXGTK__ // nicer to redraw entire viewport on Linux // otherwise we see partial drawing in some cases #define RefreshControls() Refresh(false) #else #define RefreshControls() RefreshRect(controlsrect,false) #endif void PatternView::CheckCursor(bool active) { if (active) { // make sure cursor is up to date wxPoint pt = ScreenToClient( wxGetMousePosition() ); if (PointInView(pt.x, pt.y)) { if (numlayers > 1 && tilelayers && tileindex != currindex) { // show arrow cursor if over tile border (ie. bigview) or non-current tile #ifdef __WXMAC__ // wxMac bug??? need this to fix probs after toggling status/tool bar wxSetCursor(*wxSTANDARD_CURSOR); #endif SetCursor(*wxSTANDARD_CURSOR); if (showcontrols) { showcontrols = false; RefreshControls(); } } else if ( (controlsrect.Contains(pt) || clickedcontrol > NO_CONTROL) && !(drawingcells || selectingcells || movingview || waitingforclick) ) { // cursor is over translucent controls, or user clicked in a control // and hasn't released mouse button yet #ifdef __WXMAC__ wxSetCursor(*wxSTANDARD_CURSOR); #endif SetCursor(*wxSTANDARD_CURSOR); if (!showcontrols) { showcontrols = true; RefreshControls(); } } else { // show current cursor mode #ifdef __WXMAC__ wxSetCursor(*currlayer->curs); #endif SetCursor(*currlayer->curs); if (showcontrols) { showcontrols = false; RefreshControls(); } } } else { // cursor is not in viewport #ifdef __WXMAC__ wxSetCursor(*wxSTANDARD_CURSOR); #endif SetCursor(*wxSTANDARD_CURSOR); if (showcontrols) { showcontrols = false; RefreshControls(); } } } else { // main window is not active so don't change cursor } } // ----------------------------------------------------------------------------- int PatternView::GetMag() { return currlayer->view->getmag(); } // ----------------------------------------------------------------------------- void PatternView::SetMag(int mag) { TestAutoFit(); if (mag > MAX_MAG) mag = MAX_MAG; currlayer->view->setmag(mag); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::SetPosMag(const bigint& x, const bigint& y, int mag) { currlayer->view->setpositionmag(x, y, mag); } // ----------------------------------------------------------------------------- void PatternView::GetPos(bigint& x, bigint& y) { x = currlayer->view->x; y = currlayer->view->y; } // ----------------------------------------------------------------------------- void PatternView::FitInView(int force) { currlayer->algo->fit(*currlayer->view, force); } // ----------------------------------------------------------------------------- bool PatternView::CellVisible(const bigint& x, const bigint& y) { return currlayer->view->contains(x, y) != 0; } // ----------------------------------------------------------------------------- // scrolling functions: void PatternView::PanUp(int amount) { TestAutoFit(); currlayer->view->move(0, -amount); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::PanDown(int amount) { TestAutoFit(); currlayer->view->move(0, amount); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::PanLeft(int amount) { TestAutoFit(); currlayer->view->move(-amount, 0); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::PanRight(int amount) { TestAutoFit(); currlayer->view->move(amount, 0); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::PanNE() { TestAutoFit(); int xamount = SmallScroll(currlayer->view->getwidth()); int yamount = SmallScroll(currlayer->view->getheight()); int amount = (xamount < yamount) ? xamount : yamount; currlayer->view->move(amount, -amount); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::PanNW() { TestAutoFit(); int xamount = SmallScroll(currlayer->view->getwidth()); int yamount = SmallScroll(currlayer->view->getheight()); int amount = (xamount < yamount) ? xamount : yamount; currlayer->view->move(-amount, -amount); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::PanSE() { TestAutoFit(); int xamount = SmallScroll(currlayer->view->getwidth()); int yamount = SmallScroll(currlayer->view->getheight()); int amount = (xamount < yamount) ? xamount : yamount; currlayer->view->move(amount, amount); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::PanSW() { TestAutoFit(); int xamount = SmallScroll(currlayer->view->getwidth()); int yamount = SmallScroll(currlayer->view->getheight()); int amount = (xamount < yamount) ? xamount : yamount; currlayer->view->move(-amount, amount); mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- int PatternView::SmallScroll(int xysize) { int amount; int mag = currlayer->view->getmag(); if (mag > 0) { // scroll an integral number of cells (1 cell = 2^mag pixels) if (mag < 3) { amount = ((xysize >> mag) / 20) << mag; if (amount == 0) amount = 1 << mag; return amount; } else { // grid lines are visible so scroll by only 1 cell return 1 << mag; } } else { // scroll by approx 5% of current wd/ht amount = xysize / 20; if (amount == 0) amount = 1; return amount; } } // ----------------------------------------------------------------------------- int PatternView::BigScroll(int xysize) { int amount; int mag = currlayer->view->getmag(); if (mag > 0) { // scroll an integral number of cells (1 cell = 2^mag pixels) amount = ((xysize >> mag) * 9 / 10) << mag; if (amount == 0) amount = 1 << mag; return amount; } else { // scroll by approx 90% of current wd/ht amount = xysize * 9 / 10; if (amount == 0) amount = 1; return amount; } } // ----------------------------------------------------------------------------- void PatternView::UpdateScrollBars() { if (mainptr->fullscreen) return; int viewwd, viewht; int mag = currlayer->view->getmag(); if (mag > 0) { // scroll by cells, so determine number of cells visible in viewport viewwd = currlayer->view->getwidth() >> mag; viewht = currlayer->view->getheight() >> mag; } else { // scroll by pixels, so get pixel dimensions of viewport viewwd = currlayer->view->getwidth(); viewht = currlayer->view->getheight(); } if (viewwd < 1) viewwd = 1; if (viewht < 1) viewht = 1; if (currlayer->algo->gridwd > 0) { // restrict scrolling to left/right edges of grid if its width is finite int range = currlayer->algo->gridwd; // avoid scroll bar disappearing if (range < 3) range = 3; hthumb = currlayer->view->x.toint() + range / 2; bigview->SetScrollbar(wxHORIZONTAL, hthumb, 1, range, true); } else { // keep thumb box in middle of scroll bar if grid width is infinite hthumb = (thumbrange - 1) * viewwd / 2; bigview->SetScrollbar(wxHORIZONTAL, hthumb, viewwd, thumbrange * viewwd, true); } if (currlayer->algo->gridht > 0) { // restrict scrolling to top/bottom edges of grid if its height is finite int range = currlayer->algo->gridht; // avoid scroll bar disappearing if (range < 3) range = 3; vthumb = currlayer->view->y.toint() + range / 2; bigview->SetScrollbar(wxVERTICAL, vthumb, 1, range, true); } else { // keep thumb box in middle of scroll bar if grid height is infinite vthumb = (thumbrange - 1) * viewht / 2; bigview->SetScrollbar(wxVERTICAL, vthumb, viewht, thumbrange * viewht, true); } } // ----------------------------------------------------------------------------- void PatternView::ProcessKey(int key, int modifiers) { mainptr->showbanner = false; // WARNING: ProcessKey can be called while running a script, or reading // a large pattern file, or waiting for a paste click etc, so we must avoid // doing any actions that could cause havoc at such times. bool busy = nopattupdate || waitingforclick || dragtimer->IsRunning(); bool timeline = TimelineExists(); action_info action = FindAction(key, modifiers); switch (action.id) { case DO_NOTHING: // any unassigned key turns off full screen mode if (mainptr->fullscreen) mainptr->ToggleFullScreen(); break; case DO_OPENFILE: if (IsHTMLFile(action.file)) { // show HTML file in help window if (!busy) ShowHelp(action.file); } else { // load pattern or run script if (!inscript && !busy) mainptr->OpenFile(action.file, true); } break; // File menu actions case DO_NEWPATT: if (!inscript && !busy) mainptr->NewPattern(); break; case DO_OPENPATT: if (!inscript && !busy) mainptr->OpenPattern(); break; case DO_OPENCLIP: if (!inscript && !busy) mainptr->OpenClipboard(); break; case DO_SAVE: if (!inscript && !busy) mainptr->SavePattern(); break; case DO_SAVEXRLE: if (!inscript) savexrle = !savexrle; break; case DO_RUNSCRIPT: if (!inscript && !timeline && !busy) mainptr->OpenScript(); break; case DO_RUNCLIP: if (!inscript && !timeline && !busy) mainptr->RunClipboard(); break; case DO_PREFS: if (!busy) mainptr->ShowPrefsDialog(); break; case DO_PATTDIR: if (!busy) mainptr->ChangePatternDir(); break; case DO_SCRIPTDIR: if (!busy) mainptr->ChangeScriptDir(); break; case DO_PATTERNS: mainptr->ToggleShowPatterns(); break; case DO_SCRIPTS: mainptr->ToggleShowScripts(); break; case DO_QUIT: mainptr->QuitApp(); break; // Edit menu actions case DO_UNDO: if (!inscript && !timeline && !busy) currlayer->undoredo->UndoChange(); break; case DO_REDO: if (!inscript && !timeline && !busy) currlayer->undoredo->RedoChange(); break; case DO_DISABLE: if (!inscript) mainptr->ToggleAllowUndo(); break; case DO_CUT: if (!inscript && !timeline) CutSelection(); break; case DO_COPY: if (!inscript) CopySelection(); break; case DO_CLEAR: if (!inscript && !timeline) ClearSelection(); break; case DO_CLEAROUT: if (!inscript && !timeline) ClearOutsideSelection(); break; case DO_PASTE: if (!inscript && !timeline && !busy) { // PasteClipboard(false) has a Yield loop so we do the following to avoid // calling ProcessKey re-entrantly as it causes problems on Mac OS X // and possibly the other platforms wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED, ID_PASTE); wxPostEvent(mainptr->GetEventHandler(), evt); return; } break; // case DO_PASTE: if (!inscript && !timeline && !busy) PasteClipboard(false); break; case DO_PASTESEL: if (!inscript && !timeline && !busy) PasteClipboard(true); break; case DO_SELALL: if (!inscript) SelectAll(); break; case DO_REMOVESEL: if (!inscript) RemoveSelection(); break; case DO_SHRINK: if (!inscript) ShrinkSelection(false); break; case DO_SHRINKFIT: if (!inscript) ShrinkSelection(true); break; case DO_RANDFILL: if (!inscript && !timeline) RandomFill(); break; case DO_FLIPTB: if (!inscript && !timeline) FlipSelection(true); break; case DO_FLIPLR: if (!inscript && !timeline) FlipSelection(false); break; case DO_ROTATECW: if (!inscript && !timeline) RotateSelection(true); break; case DO_ROTATEACW: if (!inscript && !timeline) RotateSelection(false); break; case DO_ADVANCE: if (!inscript && !timeline) currlayer->currsel.Advance(); break; case DO_ADVANCEOUT: if (!inscript && !timeline) currlayer->currsel.AdvanceOutside(); break; case DO_CURSDRAW: SetCursorMode(curs_pencil); break; case DO_CURSPICK: SetCursorMode(curs_pick); break; case DO_CURSSEL: SetCursorMode(curs_cross); break; case DO_CURSMOVE: SetCursorMode(curs_hand); break; case DO_CURSIN: SetCursorMode(curs_zoomin); break; case DO_CURSOUT: SetCursorMode(curs_zoomout); break; case DO_CURSCYCLE: CycleCursorMode(); break; case DO_PASTEMODE: CyclePasteMode(); break; case DO_PASTELOC: CyclePasteLocation(); break; case DO_NEXTHIGHER: CycleDrawingState(true); break; case DO_NEXTLOWER: CycleDrawingState(false); break; // Control menu actions case DO_STARTSTOP: if (!inscript) { if (timeline) { if (currlayer->algo->isrecording()) { StartStopRecording(); // stop recording } else { PlayTimeline(1); // play forwards or stop if already playing } } else if (mainptr->generating) { mainptr->Stop(); } else { mainptr->GeneratePattern(); } } break; case DO_NEXTGEN: if (!inscript && !timeline) mainptr->NextGeneration(false); break; case DO_NEXTSTEP: if (!inscript && !timeline) mainptr->NextGeneration(true); break; case DO_RESET: if (!inscript && !timeline && !busy) mainptr->ResetPattern(); break; case DO_SETGEN: if (!inscript && !timeline && !busy) mainptr->SetGeneration(); break; case DO_SETBASE: if (!inscript && !timeline && !busy) mainptr->SetBaseStep(); break; case DO_FASTER: mainptr->GoFaster(); break; case DO_SLOWER: mainptr->GoSlower(); break; case DO_AUTOFIT: mainptr->ToggleAutoFit(); break; case DO_HYPER: if (!timeline) mainptr->ToggleHyperspeed(); break; case DO_HASHINFO: mainptr->ToggleHashInfo(); break; case DO_RECORD: StartStopRecording(); break; case DO_DELTIME: DeleteTimeline(); break; case DO_PLAYBACK: if (!inscript && timeline) PlayTimeline(-1); break; case DO_SETRULE: if (!inscript && !timeline && !busy) mainptr->ShowRuleDialog(); break; case DO_TIMING: if (!inscript && !timeline) mainptr->DisplayTimingInfo(); break; case DO_HASHING: if (!inscript && !timeline && !busy) { if (currlayer->algtype != HLIFE_ALGO) mainptr->ChangeAlgorithm(HLIFE_ALGO); else mainptr->ChangeAlgorithm(QLIFE_ALGO); } break; // View menu actions case DO_LEFT: PanLeft( SmallScroll(currlayer->view->getwidth()) ); break; case DO_RIGHT: PanRight( SmallScroll(currlayer->view->getwidth()) ); break; case DO_UP: PanUp( SmallScroll(currlayer->view->getheight()) ); break; case DO_DOWN: PanDown( SmallScroll(currlayer->view->getheight()) ); break; case DO_NE: PanNE(); break; case DO_NW: PanNW(); break; case DO_SE: PanSE(); break; case DO_SW: PanSW(); break; case DO_FULLSCREEN: mainptr->ToggleFullScreen(); break; case DO_FIT: FitPattern(); break; case DO_FITSEL: FitSelection(); break; case DO_MIDDLE: ViewOrigin(); break; case DO_CHANGE00: ChangeOrigin(); break; case DO_RESTORE00: RestoreOrigin(); break; case DO_ZOOMIN: ZoomIn(); break; case DO_ZOOMOUT: ZoomOut(); break; case DO_SCALE1: SetPixelsPerCell(1); break; case DO_SCALE2: SetPixelsPerCell(2); break; case DO_SCALE4: SetPixelsPerCell(4); break; case DO_SCALE8: SetPixelsPerCell(8); break; case DO_SCALE16: SetPixelsPerCell(16); break; case DO_SCALE32: SetPixelsPerCell(32); break; case DO_SHOWTOOL: mainptr->ToggleToolBar(); break; case DO_SHOWLAYER: ToggleLayerBar(); break; case DO_SHOWEDIT: ToggleEditBar(); break; case DO_SHOWSTATES: ToggleAllStates(); break; case DO_SHOWSTATUS: mainptr->ToggleStatusBar(); break; case DO_SHOWEXACT: mainptr->ToggleExactNumbers(); break; case DO_SHOWICONS: ToggleCellIcons(); break; case DO_INVERT: ToggleCellColors(); break; case DO_SHOWGRID: ToggleGridLines(); break; case DO_BUFFERED: ToggleBuffering(); break; case DO_SHOWTIME: ToggleTimelineBar(); break; case DO_INFO: if (!busy) mainptr->ShowPatternInfo(); break; // Layer menu actions case DO_ADD: if (!inscript) AddLayer(); break; case DO_CLONE: if (!inscript) CloneLayer(); break; case DO_DUPLICATE: if (!inscript) DuplicateLayer(); break; case DO_DELETE: if (!inscript) DeleteLayer(); break; case DO_DELOTHERS: if (!inscript) DeleteOtherLayers(); break; case DO_MOVELAYER: if (!inscript && !busy) MoveLayerDialog(); break; case DO_NAMELAYER: if (!inscript && !busy) NameLayerDialog(); break; case DO_SETCOLORS: if (!inscript && !busy) SetLayerColors(); break; case DO_SYNCVIEWS: if (!inscript) ToggleSyncViews(); break; case DO_SYNCCURS: if (!inscript) ToggleSyncCursors(); break; case DO_STACK: if (!inscript) ToggleStackLayers(); break; case DO_TILE: if (!inscript) ToggleTileLayers(); break; // Help menu actions case DO_HELP: if (!busy) { // if help window is open then bring it to the front, // otherwise open it and display most recent help file ShowHelp(wxEmptyString); } break; case DO_ABOUT: if (!inscript && !busy) ShowAboutBox(); break; default: Warning(_("Bug detected in ProcessKey!")); } // note that we avoid updating viewport if inscript and action.id is DO_OPENFILE // otherwise problem can occur when rapidly repeating a keyboard shortcut that // runs a script if (inscript && action.id != DO_NOTHING && action.id != DO_OPENFILE) { // update viewport, status bar, scroll bars inscript = false; mainptr->UpdatePatternAndStatus(); bigview->UpdateScrollBars(); inscript = true; } mainptr->UpdateUserInterface(); } // ----------------------------------------------------------------------------- void PatternView::ShowDrawing() { currlayer->algo->endofpattern(); // update status bar if (showstatus) statusptr->Refresh(false); if (slowdraw) { // we have to draw by updating entire view slowdraw = false; UpdateView(); } MarkLayerDirty(); } // ----------------------------------------------------------------------------- void PatternView::DrawOneCell(wxDC& dc, int cx, int cy, int oldstate, int newstate) { // remember this cell change for later undo/redo if (allowundo) currlayer->undoredo->SaveCellChange(cx, cy, oldstate, newstate); if (numlayers > 1 && (stacklayers || (numclones > 0 && tilelayers))) { // drawing must be done via UpdateView in ShowDrawing slowdraw = true; return; } int cellsize = 1 << currlayer->view->getmag(); // convert given cell coords to view coords pair lefttop = currlayer->view->at(0, 0); wxCoord x = (cx - lefttop.first.toint()) * cellsize; wxCoord y = (cy - lefttop.second.toint()) * cellsize; if (cellsize > 2) cellsize--; // allow for gap between cells wxBitmap** iconmaps = NULL; if (currlayer->view->getmag() == 3) { iconmaps = currlayer->icons7x7; } else if (currlayer->view->getmag() == 4) { iconmaps = currlayer->icons15x15; } else if (currlayer->view->getmag() == 5) { iconmaps = currlayer->icons31x31; } if (showicons && drawstate > 0 && currlayer->view->getmag() > 2 && iconmaps && iconmaps[drawstate]) { DrawOneIcon(dc, x, y, iconmaps[drawstate], currlayer->cellr[0], currlayer->cellg[0], currlayer->cellb[0], currlayer->cellr[drawstate], currlayer->cellg[drawstate], currlayer->cellb[drawstate], currlayer->multicoloricons); } else { dc.DrawRectangle(x, y, cellsize, cellsize); } // overlay selection image if cell is within selection if (SelectionExists() && currlayer->currsel.ContainsCell(cx, cy)) { wxRect r = wxRect(x, y, cellsize, cellsize); DrawSelection(dc, r); } } // ----------------------------------------------------------------------------- void PatternView::StartDrawingCells(int x, int y) { pair cellpos = currlayer->view->at(x, y); // check that cellpos is within getcell/setcell limits if ( OutsideLimits(cellpos.second, cellpos.first, cellpos.second, cellpos.first) ) { statusptr->ErrorMessage(_("Drawing is not allowed outside +/- 10^9 boundary.")); return; } // ShowDrawing will call MarkLayerDirty so we need to save dirty state now // for later use by RememberCellChanges if (allowundo) currlayer->savedirty = currlayer->dirty; cellx = cellpos.first.toint(); celly = cellpos.second.toint(); int currstate = currlayer->algo->getcell(cellx, celly); // reset drawing state in case it's no longer valid (due to algo/rule change) if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) { currlayer->drawingstate = 1; } if (currstate == currlayer->drawingstate) { drawstate = 0; } else { drawstate = currlayer->drawingstate; } if (currstate != drawstate) { currlayer->algo->setcell(cellx, celly, drawstate); wxClientDC dc(this); dc.SetPen(*wxTRANSPARENT_PEN); cellbrush->SetColour(currlayer->cellr[drawstate], currlayer->cellg[drawstate], currlayer->cellb[drawstate]); dc.SetBrush(*cellbrush); DrawOneCell(dc, cellx, celly, currstate, drawstate); dc.SetBrush(wxNullBrush); dc.SetPen(wxNullPen); ShowDrawing(); } drawingcells = true; CaptureMouse(); // get mouse up event even if outside view dragtimer->Start(DRAG_RATE); // see OnDragTimer if (stopdrawing) { // mouse up event has already been seen so terminate drawing immediately stopdrawing = false; StopDraggingMouse(); } } // ----------------------------------------------------------------------------- void PatternView::DrawCells(int x, int y) { // make sure x,y is within viewport if (x < 0) x = 0; if (y < 0) y = 0; if (x > currlayer->view->getxmax()) x = currlayer->view->getxmax(); if (y > currlayer->view->getymax()) y = currlayer->view->getymax(); // make sure x,y is within bounded grid pair cellpos = currlayer->view->at(x, y); if (currlayer->algo->gridwd > 0) { if (cellpos.first < currlayer->algo->gridleft) cellpos.first = currlayer->algo->gridleft; if (cellpos.first > currlayer->algo->gridright) cellpos.first = currlayer->algo->gridright; } if (currlayer->algo->gridht > 0) { if (cellpos.second < currlayer->algo->gridtop) cellpos.second = currlayer->algo->gridtop; if (cellpos.second > currlayer->algo->gridbottom) cellpos.second = currlayer->algo->gridbottom; } if ( currlayer->view->getmag() < 0 || OutsideLimits(cellpos.second, cellpos.first, cellpos.second, cellpos.first) ) { return; } int newx = cellpos.first.toint(); int newy = cellpos.second.toint(); if ( newx != cellx || newy != celly ) { int currstate; wxClientDC dc(this); dc.SetPen(*wxTRANSPARENT_PEN); cellbrush->SetColour(currlayer->cellr[drawstate], currlayer->cellg[drawstate], currlayer->cellb[drawstate]); dc.SetBrush(*cellbrush); int numchanged = 0; // draw a line of cells using Bresenham's algorithm; // this code comes from Guillermo Garcia's Life demo supplied with wx int d, ii, jj, di, ai, si, dj, aj, sj; di = newx - cellx; ai = abs(di) << 1; si = (di < 0)? -1 : 1; dj = newy - celly; aj = abs(dj) << 1; sj = (dj < 0)? -1 : 1; ii = cellx; jj = celly; lifealgo* curralgo = currlayer->algo; if (ai > aj) { d = aj - (ai >> 1); while (ii != newx) { currstate = curralgo->getcell(ii, jj); if (currstate != drawstate) { curralgo->setcell(ii, jj, drawstate); DrawOneCell(dc, ii, jj, currstate, drawstate); numchanged++; } if (d >= 0) { jj += sj; d -= ai; } ii += si; d += aj; } } else { d = ai - (aj >> 1); while (jj != newy) { currstate = curralgo->getcell(ii, jj); if (currstate != drawstate) { curralgo->setcell(ii, jj, drawstate); DrawOneCell(dc, ii, jj, currstate, drawstate); numchanged++; } if (d >= 0) { ii += si; d -= aj; } jj += sj; d += ai; } } cellx = newx; celly = newy; currstate = curralgo->getcell(cellx, celly); if (currstate != drawstate) { curralgo->setcell(cellx, celly, drawstate); DrawOneCell(dc, cellx, celly, currstate, drawstate); numchanged++; } dc.SetBrush(wxNullBrush); // restore brush dc.SetPen(wxNullPen); // restore pen if (numchanged > 0) ShowDrawing(); } } // ----------------------------------------------------------------------------- void PatternView::PickCell(int x, int y) { pair cellpos = currlayer->view->at(x, y); if ( currlayer->view->getmag() < 0 || OutsideLimits(cellpos.second, cellpos.first, cellpos.second, cellpos.first) ) { return; } int cellx = cellpos.first.toint(); int celly = cellpos.second.toint(); currlayer->drawingstate = currlayer->algo->getcell(cellx, celly); UpdateEditBar(); } // ----------------------------------------------------------------------------- void PatternView::StartSelectingCells(int x, int y, bool shiftdown) { // make sure anchor cell is within bounded grid (x,y can be outside grid) pair cellpos = currlayer->view->at(x, y); if (currlayer->algo->gridwd > 0) { if (cellpos.first < currlayer->algo->gridleft) cellpos.first = currlayer->algo->gridleft; if (cellpos.first > currlayer->algo->gridright) cellpos.first = currlayer->algo->gridright; } if (currlayer->algo->gridht > 0) { if (cellpos.second < currlayer->algo->gridtop) cellpos.second = currlayer->algo->gridtop; if (cellpos.second > currlayer->algo->gridbottom) cellpos.second = currlayer->algo->gridbottom; } anchorx = cellpos.first; anchory = cellpos.second; // save original selection so it can be restored if user hits escape; // also used by RememberNewSelection currlayer->savesel = currlayer->currsel; // reset previous selection prevsel.Deselect(); // for avoiding 1x1 selection if mouse doesn't move much initselx = x; initsely = y; // allow changing size in any direction forceh = false; forcev = false; if (SelectionExists()) { if (shiftdown) { // modify current selection currlayer->currsel.Modify(cellpos.first, cellpos.second, anchorx, anchory, &forceh, &forcev); DisplaySelectionSize(); } else { // remove current selection currlayer->currsel.Deselect(); } // allow mouse interaction if script is running bool saveinscript = inscript; inscript = false; mainptr->UpdatePatternAndStatus(); inscript = saveinscript; } selectingcells = true; CaptureMouse(); // get mouse up event even if outside view dragtimer->Start(DRAG_RATE); // see OnDragTimer } // ----------------------------------------------------------------------------- void PatternView::SelectCells(int x, int y) { // only select cells within view if (x < 0) x = 0; if (y < 0) y = 0; if (x > currlayer->view->getxmax()) x = currlayer->view->getxmax(); if (y > currlayer->view->getymax()) y = currlayer->view->getymax(); if ( abs(initselx - x) < 2 && abs(initsely - y) < 2 && !SelectionExists() ) { // avoid 1x1 selection if mouse hasn't moved much return; } // make sure x,y is within bounded grid pair cellpos = currlayer->view->at(x, y); if (currlayer->algo->gridwd > 0) { if (cellpos.first < currlayer->algo->gridleft) cellpos.first = currlayer->algo->gridleft; if (cellpos.first > currlayer->algo->gridright) cellpos.first = currlayer->algo->gridright; } if (currlayer->algo->gridht > 0) { if (cellpos.second < currlayer->algo->gridtop) cellpos.second = currlayer->algo->gridtop; if (cellpos.second > currlayer->algo->gridbottom) cellpos.second = currlayer->algo->gridbottom; } if (!forcev) currlayer->currsel.SetLeftRight(cellpos.first, anchorx); if (!forceh) currlayer->currsel.SetTopBottom(cellpos.second, anchory); if (currlayer->currsel != prevsel) { // selection has changed DisplaySelectionSize(); prevsel = currlayer->currsel; // allow mouse interaction if script is running bool saveinscript = inscript; inscript = false; mainptr->UpdatePatternAndStatus(); inscript = saveinscript; } } // ----------------------------------------------------------------------------- void PatternView::StartMovingView(int x, int y) { pair cellpos = currlayer->view->at(x, y); bigcellx = cellpos.first; bigcelly = cellpos.second; movingview = true; if (waitingforclick) { // avoid calling CaptureMouse again (middle button was pressed) } else { CaptureMouse(); // get mouse up event even if outside view } dragtimer->Start(DRAG_RATE); // see OnDragTimer } // ----------------------------------------------------------------------------- void PatternView::MoveView(int x, int y) { pair cellpos = currlayer->view->at(x, y); bigint newx = cellpos.first; bigint newy = cellpos.second; bigint xdelta = bigcellx; bigint ydelta = bigcelly; xdelta -= newx; ydelta -= newy; int xamount, yamount; int mag = currlayer->view->getmag(); if (mag >= 0) { // move an integral number of cells xamount = xdelta.toint() << mag; yamount = ydelta.toint() << mag; } else { // convert cell deltas to screen pixels xdelta >>= -mag; ydelta >>= -mag; xamount = xdelta.toint(); yamount = ydelta.toint(); } if ( xamount != 0 || yamount != 0 ) { currlayer->view->move(xamount, yamount); // allow mouse interaction if script is running bool saveinscript = inscript; inscript = false; mainptr->UpdatePatternAndStatus(); inscript = saveinscript; cellpos = currlayer->view->at(x, y); bigcellx = cellpos.first; bigcelly = cellpos.second; } // need to update scroll bars if grid is bounded if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { UpdateScrollBars(); } } // ----------------------------------------------------------------------------- void PatternView::StopDraggingMouse() { if ( HasCapture() ) { if (movingview && waitingforclick) { // don't release mouse capture here (paste loop won't detect click outside view) } else { ReleaseMouse(); } } if ( dragtimer->IsRunning() ) dragtimer->Stop(); if (selectingcells) { if (allowundo) RememberNewSelection(_("Selection")); selectingcells = false; // tested by CanUndo mainptr->UpdateMenuItems(); // enable various Edit menu items if (allowundo) UpdateEditBar(); // update Undo/Redo buttons } if (drawingcells && allowundo) { // MarkLayerDirty (in ShowDrawing) has set dirty flag, so we need to // pass in the flag state saved before drawing started currlayer->undoredo->RememberCellChanges(_("Drawing"), currlayer->savedirty); drawingcells = false; // tested by CanUndo mainptr->UpdateMenuItems(); // enable Undo item UpdateEditBar(); // update Undo/Redo buttons } if (clickedcontrol > NO_CONTROL) { if (currcontrol == clickedcontrol && !PANNING_CONTROL) { // only do non-panning function when button is released ProcessClickedControl(); } clickedcontrol = NO_CONTROL; currcontrol = NO_CONTROL; RefreshRect(controlsrect, false); Update(); } if (movingview && restorecursor != NULL) { // restore cursor temporarily changed to curs_hand due to middle button click SetCursorMode(restorecursor); restorecursor = NULL; mainptr->UpdateMenuItems(); // enable Edit > Cursor Mode UpdateEditBar(); // update cursor mode buttons } drawingcells = false; selectingcells = false; movingview = false; CheckCursor(true); } // ----------------------------------------------------------------------------- void PatternView::RestoreSelection() { currlayer->currsel = currlayer->savesel; StopDraggingMouse(); // allow mouse interaction if script is running bool saveinscript = inscript; inscript = false; mainptr->UpdatePatternAndStatus(); inscript = saveinscript; statusptr->DisplayMessage(_("New selection aborted.")); } // ----------------------------------------------------------------------------- void PatternView::TestAutoFit() { if (currlayer->autofit && mainptr->generating) { // assume user no longer wants us to do autofitting currlayer->autofit = false; } } // ----------------------------------------------------------------------------- void PatternView::ZoomInPos(int x, int y) { // zoom in so that clicked cell stays under cursor TestAutoFit(); if (currlayer->view->getmag() < MAX_MAG) { currlayer->view->zoom(x, y); // allow mouse interaction if script is running bool saveinscript = inscript; inscript = false; mainptr->UpdatePatternAndStatus(); bigview->UpdateScrollBars(); inscript = saveinscript; } else { Beep(); // can't zoom in any further } } // ----------------------------------------------------------------------------- void PatternView::ZoomOutPos(int x, int y) { // zoom out so that clicked cell stays under cursor TestAutoFit(); currlayer->view->unzoom(x, y); // allow mouse interaction if script is running bool saveinscript = inscript; inscript = false; mainptr->UpdatePatternAndStatus(); bigview->UpdateScrollBars(); inscript = saveinscript; } // ----------------------------------------------------------------------------- void PatternView::SetViewSize(int wd, int ht) { // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; if (tileindex < 0) { // use main viewport window's size to reset viewport in each layer ResizeLayers(wd, ht); } // only autofit when generating if (currlayer->autofit && mainptr && mainptr->generating) currlayer->algo->fit(*currlayer->view, 0); // update position of translucent controls switch (controlspos) { case 1: // top left corner controlsrect = wxRect(0, 0, controlswd, controlsht); break; case 2: // top right corner controlsrect = wxRect(wd - controlswd, 0, controlswd, controlsht); break; case 3: // bottom right corner controlsrect = wxRect(wd - controlswd, ht - controlsht, controlswd, controlsht); break; case 4: // bottom left corner controlsrect = wxRect(0, ht - controlsht, controlswd, controlsht); break; default: // controlspos should be 0 (controls are disabled) controlsrect = wxRect(0, 0, 0, 0); } } // ----------------------------------------------------------------------------- void PatternView::OnPaint(wxPaintEvent& WXUNUSED(event)) { int wd, ht; GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; if ( numclones > 0 && numlayers > 1 && (stacklayers || tilelayers) ) SyncClones(); if ( numlayers > 1 && tilelayers ) { if ( tileindex >= 0 && ( wd != GetLayer(tileindex)->view->getwidth() || ht != GetLayer(tileindex)->view->getheight() ) ) { // might happen on Win/GTK??? GetLayer(tileindex)->view->resize(wd, ht); } } else if ( wd != currlayer->view->getwidth() || ht != currlayer->view->getheight() ) { // need to change viewport size; // can happen on Windows when resizing/maximizing main window SetViewSize(wd, ht); } #if defined(__WXMAC__) || defined(__WXGTK__) // windows on Mac OS X and GTK+ 2.0 are automatically buffered wxPaintDC dc(this); DrawView(dc, tileindex); #else if ( buffered || waitingforclick || GridVisible() || currlayer->currsel.Visible(NULL) || showcontrols || (numlayers > 1 && (stacklayers || tilelayers)) ) { // use wxWidgets buffering to avoid flicker if (wd != viewbitmapwd || ht != viewbitmapht) { // need to create a new bitmap for current viewport delete viewbitmap; viewbitmap = new wxBitmap(wd, ht); if (viewbitmap == NULL) Fatal(_("Not enough memory to do buffering!")); viewbitmapwd = wd; viewbitmapht = ht; } wxBufferedPaintDC dc(this, *viewbitmap); DrawView(dc, tileindex); } else { wxPaintDC dc(this); DrawView(dc, tileindex); } #endif } // ----------------------------------------------------------------------------- void PatternView::OnSize(wxSizeEvent& event) { int wd, ht; GetClientSize(&wd, &ht); // resize this viewport SetViewSize(wd, ht); event.Skip(); } // ----------------------------------------------------------------------------- #if defined(__WXMAC__) && wxCHECK_VERSION(2,9,0) // wxMOD_CONTROL has been changed to mean Command key down (sheesh!) #define wxMOD_CONTROL wxMOD_RAW_CONTROL #define ControlDown RawControlDown #endif void PatternView::OnKeyDown(wxKeyEvent& event) { #ifdef __WXMAC__ // close any open tool tip window (fixes wxMac bug?) wxToolTip::RemoveToolTips(); #endif statusptr->ClearMessage(); realkey = event.GetKeyCode(); int mods = event.GetModifiers(); // wxGTK 2.8.12 does not set modifier flag if shift key pressed by itself // so best to play safe and test wxMOD_SHIFT or wxMOD_NONE if (realkey == WXK_SHIFT && (mods == wxMOD_SHIFT || mods == wxMOD_NONE)) { // pressing unmodified shift key temporarily toggles the draw/pick cursors or // the zoom in/out cursors; note that Windows sends multiple key-down events // while shift key is pressed so we must be careful to toggle only once if (currlayer->curs == curs_pencil && oldcursor == NULL) { oldcursor = curs_pencil; SetCursorMode(curs_pick); mainptr->UpdateUserInterface(); } else if (currlayer->curs == curs_pick && oldcursor == NULL) { oldcursor = curs_pick; SetCursorMode(curs_pencil); mainptr->UpdateUserInterface(); } else if (currlayer->curs == curs_zoomin && oldcursor == NULL) { oldcursor = curs_zoomin; SetCursorMode(curs_zoomout); mainptr->UpdateUserInterface(); } else if (currlayer->curs == curs_zoomout && oldcursor == NULL) { oldcursor = curs_zoomout; SetCursorMode(curs_zoomin); mainptr->UpdateUserInterface(); } } else if (oldcursor) { // for any other key combo we restore the cursor immediately rather than // wait for the shift key to be released; this avoids problems with OnKeyUp // not being called if the shift key is used in a keyboard shortcut that // adds a new layer or opens another window SetCursorMode(oldcursor); oldcursor = NULL; mainptr->UpdateUserInterface(); } if (debuglevel == 1) { // set debugkey now but don't show it until OnChar debugkey = wxString::Format(_("OnKeyDown: key=%d (%c) mods=%d"), realkey, realkey < 128 ? wxChar(realkey) : wxChar('?'), mods); } // WARNING: logic must match that in KeyComboCtrl::OnKeyDown in wxprefs.cpp if (mods == wxMOD_NONE || realkey == WXK_ESCAPE || realkey > 127) { // tell OnChar handler to ignore realkey realkey = 0; } #ifdef __WXOSX__ // pass ctrl/cmd-key combos directly to OnChar if (realkey > 0 && ((mods & wxMOD_CONTROL) || (mods & wxMOD_CMD))) { OnChar(event); return; } #endif #ifdef __WXMAC__ // allow option-E/I/N/U/` (OnChar is not called for those key combos // although the prefs dialog KeyComboCtrl::OnChar *is* called) if (mods == wxMOD_ALT && (realkey == 'E' || realkey == 'I' || realkey == 'N' || realkey == 'U' || realkey == '`')) { OnChar(event); return; } #endif #ifdef __WXMSW__ // on Windows, OnChar is NOT called for some ctrl-key combos like // ctrl-0..9 or ctrl-alt-key, so we call OnChar ourselves if (realkey > 0 && (mods & wxMOD_CONTROL)) { OnChar(event); return; } #endif #ifdef __WXGTK__ if (realkey == ' ' && mods == wxMOD_SHIFT) { // fix wxGTK bug (curiously, the bug isn't seen in the prefs dialog); // OnChar won't see the shift modifier, so set realkey to a special // value to tell OnChar that shift-space was pressed realkey = -666; } #endif event.Skip(); } // ----------------------------------------------------------------------------- void PatternView::OnKeyUp(wxKeyEvent& event) { int key = event.GetKeyCode(); if (key == WXK_SHIFT) { // releasing shift key sets cursor back to original state if (oldcursor) { SetCursorMode(oldcursor); oldcursor = NULL; mainptr->UpdateUserInterface(); } } // no need to call event.Skip() here } // ----------------------------------------------------------------------------- void PatternView::OnChar(wxKeyEvent& event) { // get translated keyboard event int key = event.GetKeyCode(); int mods = event.GetModifiers(); if (debuglevel == 99 && insideYield) { if (mainptr->generating || waitingforclick) { // ignore this case (frequent and expected because Yield() is called in // a tight loop while generating a pattern or doing a paste) } else { // this is *possibly* an unwanted re-entrancy wxBell(); // ignore allowbeep } } if (debuglevel == 1) { debugkey += wxString::Format(_("\nOnChar: key=%d (%c) mods=%d"), key, key < 128 ? wxChar(key) : wxChar('?'), mods); Warning(debugkey); } // WARNING: logic must match that in KeyComboCtrl::OnChar in wxprefs.cpp if (realkey > 0 && mods != wxMOD_NONE) { #ifdef __WXGTK__ // sigh... wxGTK returns inconsistent results for shift-comma combos // so we assume that '<' is produced by pressing shift-comma // (which might only be true for US keyboards) if (key == '<' && (mods & wxMOD_SHIFT)) realkey = ','; #endif #ifdef __WXMSW__ // sigh... wxMSW returns inconsistent results for some shift-key combos // so again we assume we're using a US keyboard if (key == '~' && (mods & wxMOD_SHIFT)) realkey = '`'; if (key == '+' && (mods & wxMOD_SHIFT)) realkey = '='; #endif if (mods == wxMOD_SHIFT && key != realkey) { // use translated key code but remove shift key; // eg. we want shift-'/' to be seen as '?' mods = wxMOD_NONE; } else { // use key code seen by OnKeyDown key = realkey; if (key >= 'A' && key <= 'Z') key += 32; // convert A..Z to a..z } } #ifdef __WXGTK__ if (realkey == -666) { // OnKeyDown saw that shift-space was pressed but for some reason // OnChar doesn't see the modifier (ie. mods is wxMOD_NONE) key = ' '; mods = wxMOD_SHIFT; } #endif // do this check first because we allow user to make a selection while // generating a pattern or running a script if ( selectingcells && key == WXK_ESCAPE ) { RestoreSelection(); return; } if ( inscript && (passkeys || key == WXK_ESCAPE) ) { // let script decide what to do with the key PassKeyToScript(key, mods); return; } // test waitingforclick before mainptr->generating so user can cancel // a paste operation while generating if ( waitingforclick && key == WXK_ESCAPE ) { AbortPaste(); return; } if ( TimelineExists() && key == WXK_ESCAPE ) { if (currlayer->algo->isrecording()) { StartStopRecording(); // stop recording } else { PlayTimeline(0); // stop autoplay } return; } if ( mainptr->generating && key == WXK_ESCAPE ) { mainptr->Stop(); return; } ProcessKey(key, mods); } // ----------------------------------------------------------------------------- void PatternView::ProcessClickedControl() { switch (clickedcontrol) { case STEP1_CONTROL: if (TimelineExists()) { // reset autoplay speed to 0 (no delay, no frame skipping) ResetTimelineSpeed(); } else if (currlayer->currexpo != 0) { mainptr->SetStepExponent(0); statusptr->Refresh(false); } break; case SLOWER_CONTROL: mainptr->GoSlower(); break; case FASTER_CONTROL: mainptr->GoFaster(); break; case FIT_CONTROL: FitPattern(); break; case ZOOMIN_CONTROL: ZoomIn(); break; case ZOOMOUT_CONTROL: ZoomOut(); break; case NW_CONTROL: PanNW(); break; case UP_CONTROL: PanUp( SmallScroll(currlayer->view->getheight()) ); break; case NE_CONTROL: PanNE(); break; case LEFT_CONTROL: PanLeft( SmallScroll(currlayer->view->getwidth()) ); break; case MIDDLE_CONTROL: ViewOrigin(); break; case RIGHT_CONTROL: PanRight( SmallScroll(currlayer->view->getwidth()) ); break; case SW_CONTROL: PanSW(); break; case DOWN_CONTROL: PanDown( SmallScroll(currlayer->view->getheight()) ); break; case SE_CONTROL: PanSE(); break; default: // should never happen Warning(_("Bug detected in ProcessClickedControl!")); } // need to update viewport and status bar if script is running if (inscript) { inscript = false; mainptr->UpdatePatternAndStatus(); inscript = true; } } // ----------------------------------------------------------------------------- void PatternView::ProcessClick(int x, int y, int button, int modifiers) { // user has clicked x,y pixel in viewport if (button == wxMOUSE_BTN_LEFT) { if (currlayer->curs == curs_pencil) { if (!PointInGrid(x, y)) { // best not to clobber any status bar message displayed by script Warning(_("Drawing is not allowed outside grid.")); return; } if (inscript) { // best not to clobber any status bar message displayed by script Warning(_("Drawing is not allowed while a script is running.")); return; } if (TimelineExists()) { statusptr->ErrorMessage(_("Drawing is not allowed if there is a timeline.")); return; } if (currlayer->view->getmag() < 0) { statusptr->ErrorMessage(_("Drawing is not allowed at scales greater than 1 cell per pixel.")); return; } if (mainptr->generating) { // we allow drawing while generating mainptr->Stop(); mainptr->draw_pending = true; mainptr->mouseevent.m_x = x; mainptr->mouseevent.m_y = y; return; } StartDrawingCells(x, y); } else if (currlayer->curs == curs_pick) { if (!PointInGrid(x, y)) { // best not to clobber any status bar message displayed by script Warning(_("Picking is not allowed outside grid.")); return; } if (inscript) { // best not to clobber any status bar message displayed by script Warning(_("Picking is not allowed while a script is running.")); return; } if (currlayer->view->getmag() < 0) { statusptr->ErrorMessage(_("Picking is not allowed at scales greater than 1 cell per pixel.")); return; } PickCell(x, y); } else if (currlayer->curs == curs_cross) { TestAutoFit(); StartSelectingCells(x, y, (modifiers & wxMOD_SHIFT) != 0); } else if (currlayer->curs == curs_hand) { TestAutoFit(); StartMovingView(x, y); } else if (currlayer->curs == curs_zoomin) { ZoomInPos(x, y); } else if (currlayer->curs == curs_zoomout) { ZoomOutPos(x, y); } } else if (button == wxMOUSE_BTN_RIGHT) { // reverse the usual zoom direction if (currlayer->curs == curs_zoomin) { ZoomOutPos(x, y); } else if (currlayer->curs == curs_zoomout) { ZoomInPos(x, y); } } else if (button == wxMOUSE_BTN_MIDDLE) { // start panning, regardless of current cursor mode if (currlayer->curs != curs_hand) { restorecursor = currlayer->curs; SetCursorMode(curs_hand); } TestAutoFit(); StartMovingView(x, y); } mainptr->UpdateUserInterface(); } // ----------------------------------------------------------------------------- static int GetMouseModifiers(wxMouseEvent& event) { int modbits = wxMOD_NONE; if (event.AltDown()) modbits |= wxMOD_ALT; if (event.CmdDown()) modbits |= wxMOD_CMD; if (event.ControlDown()) modbits |= wxMOD_CONTROL; if (event.MetaDown()) modbits |= wxMOD_META; if (event.ShiftDown()) modbits |= wxMOD_SHIFT; return modbits; } // ----------------------------------------------------------------------------- void PatternView::OnMouseDown(wxMouseEvent& event) { int x = event.GetX(); int y = event.GetY(); int button = event.GetButton(); int modifiers = GetMouseModifiers(event); if (waitingforclick && button == wxMOUSE_BTN_LEFT) { // save paste location pastex = x; pastey = y; waitingforclick = false; // terminate while (waitingforclick) loop return; } statusptr->ClearMessage(); mainptr->showbanner = false; if (numlayers > 1 && tilelayers && tileindex < 0) { // ignore click in tile border return; } if (tileindex >= 0 && tileindex != currindex) { // switch current layer to clicked tile SwitchToClickedTile(tileindex); return; } if (showcontrols) { currcontrol = WhichControl(x - controlsrect.x, y - controlsrect.y); if (currcontrol > NO_CONTROL) { clickedcontrol = currcontrol; // remember which control was clicked clicktime = stopwatch->Time(); // remember when clicked (in millisecs) CaptureMouse(); // get mouse up event even if outside view dragtimer->Start(DRAG_RATE); // see OnDragTimer RefreshRect(controlsrect, false); // redraw clicked button #ifdef __WXGTK__ // nicer to see change immediately on Linux Update(); #endif if (PANNING_CONTROL) { // scroll immediately ProcessClickedControl(); } } return; } if (inscript && passclicks && PointInGrid(x, y)) { // let script decide what to do with click in grid pair cellpos = currlayer->view->at(x, y); PassClickToScript(cellpos.first, cellpos.second, button, modifiers); return; } ProcessClick(x, y, button, modifiers); } // ----------------------------------------------------------------------------- void PatternView::OnMouseUp(wxMouseEvent& WXUNUSED(event)) { if (drawingcells || selectingcells || movingview || clickedcontrol > NO_CONTROL) { StopDraggingMouse(); } else if (mainptr->draw_pending) { // this can happen if user does a quick click while pattern is generating, // so set a special flag to force drawing to terminate stopdrawing = true; } } // ----------------------------------------------------------------------------- #if wxCHECK_VERSION(2, 8, 0) // mouse capture can be lost on Windows before mouse-up event void PatternView::OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) { if (drawingcells || selectingcells || movingview || clickedcontrol > NO_CONTROL) { StopDraggingMouse(); } } #endif // ----------------------------------------------------------------------------- void PatternView::OnMouseMotion(wxMouseEvent& event) { statusptr->CheckMouseLocation(mainptr->infront); // check if translucent controls need to be shown/hidden if (mainptr->infront) { wxPoint pt( event.GetX(), event.GetY() ); bool show = (controlsrect.Contains(pt) || clickedcontrol > NO_CONTROL) && !(drawingcells || selectingcells || movingview || waitingforclick) && !(numlayers > 1 && tilelayers && tileindex != currindex); if (showcontrols != show) { // let CheckCursor set showcontrols and call RefreshRect CheckCursor(true); } } // we do the following test to ensure ReleaseMouse() gets called // (in case OnMouseUp doesn't get called when it should) if (drawingcells || selectingcells || movingview || clickedcontrol > NO_CONTROL) { // check if no mouse buttons are being pressed if (!event.Dragging()) StopDraggingMouse(); } } // ----------------------------------------------------------------------------- void PatternView::OnMouseEnter(wxMouseEvent& WXUNUSED(event)) { // wx bug???!!! we don't get this event if CaptureMouse has been called CheckCursor(mainptr->infront); // no need to call CheckMouseLocation here (OnMouseMotion will be called) } // ----------------------------------------------------------------------------- void PatternView::OnMouseExit(wxMouseEvent& WXUNUSED(event)) { // Win only bug??? we don't get this event if CaptureMouse has been called CheckCursor(mainptr->infront); statusptr->CheckMouseLocation(mainptr->infront); } // ----------------------------------------------------------------------------- void PatternView::OnMouseWheel(wxMouseEvent& event) { // wheelpos should be persistent, because in theory we should keep track of // the remainder if the amount scrolled was not an even number of deltas. static int wheelpos = 0; int delta, x, y; if (mousewheelmode == 0) { // ignore wheel, according to user preference event.Skip(); return; } // delta is the amount that represents one "step" of rotation. Normally 120. delta = event.GetWheelDelta(); x = event.GetX(); y = event.GetY(); if (mousewheelmode == 2) wheelpos -= event.GetWheelRotation(); else wheelpos += event.GetWheelRotation(); while (wheelpos >= delta) { wheelpos -= delta; TestAutoFit(); currlayer->view->unzoom(x, y); } while (wheelpos <= -delta) { wheelpos += delta; TestAutoFit(); if (currlayer->view->getmag() < MAX_MAG) { currlayer->view->zoom(x, y); } else { Beep(); wheelpos = 0; break; // best not to beep lots of times } } // allow mouse interaction if script is running bool saveinscript = inscript; inscript = false; mainptr->UpdatePatternAndStatus(); bigview->UpdateScrollBars(); inscript = saveinscript; // do following after restoring inscript so we don't change stop button if inscript mainptr->UpdateUserInterface(); } // ----------------------------------------------------------------------------- void PatternView::OnDragTimer(wxTimerEvent& WXUNUSED(event)) { // called periodically while drawing/selecting/moving // or if user has clicked a translucent control and button is still down wxPoint pt = ScreenToClient( wxGetMousePosition() ); int x = pt.x; int y = pt.y; if (clickedcontrol > NO_CONTROL) { control_id oldcontrol = currcontrol; currcontrol = WhichControl(x - controlsrect.x, y - controlsrect.y); if (currcontrol == clickedcontrol) { if (PANNING_CONTROL && stopwatch->Time() - clicktime > 300) { // panning can be repeated while button is pressed, but only after // a short pause (0.3 secs) from the time the button was clicked // (this matches the way scroll buttons work on Mac/Windows) ProcessClickedControl(); } } else { currcontrol = NO_CONTROL; } if (currcontrol != oldcontrol) RefreshRect(controlsrect, false); return; } // don't test "!PointInView(x, y)" here -- we want to allow scrolling // in full screen mode when mouse is at outer edge of view if ( x <= 0 || x >= currlayer->view->getxmax() || y <= 0 || y >= currlayer->view->getymax() ) { // user can disable scrolling if ( drawingcells && !scrollpencil ) { DrawCells(x, y); return; } if ( selectingcells && !scrollcross ) { SelectCells(x, y); return; } if ( movingview && !scrollhand ) { // make sure x,y is within viewport if (x < 0) x = 0; if (y < 0) y = 0; if (x > currlayer->view->getxmax()) x = currlayer->view->getxmax(); if (y > currlayer->view->getymax()) y = currlayer->view->getymax(); MoveView(x, y); return; } // scroll view int xamount = 0; int yamount = 0; if (x <= 0) xamount = -SmallScroll( currlayer->view->getwidth() ); if (y <= 0) yamount = -SmallScroll( currlayer->view->getheight() ); if (x >= currlayer->view->getxmax()) xamount = SmallScroll( currlayer->view->getwidth() ); if (y >= currlayer->view->getymax()) yamount = SmallScroll( currlayer->view->getheight() ); if ( drawingcells ) { currlayer->view->move(xamount, yamount); mainptr->UpdatePatternAndStatus(); } else if ( selectingcells ) { currlayer->view->move(xamount, yamount); // no need to call UpdatePatternAndStatus() here because // it will be called soon in SelectCells, except in this case: if (forceh || forcev || currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { // selection might not change so must update pattern RefreshView(); // need to update now if script is running if (inscript) { inscript = false; mainptr->UpdatePatternAndStatus(); inscript = true; } } } else if ( movingview ) { // scroll in opposite direction, and if both amounts are non-zero then // set both to same (larger) absolute value so user can scroll at 45 degrees if ( xamount != 0 && yamount != 0 ) { if ( abs(xamount) > abs(yamount) ) { yamount = yamount < 0 ? -abs(xamount) : abs(xamount); } else { xamount = xamount < 0 ? -abs(yamount) : abs(yamount); } } currlayer->view->move(-xamount, -yamount); // allow mouse interaction if script is running bool saveinscript = inscript; inscript = false; mainptr->UpdatePatternAndStatus(); inscript = saveinscript; // adjust x,y and bigcellx,bigcelly for MoveView call below x += xamount; y += yamount; pair cellpos = currlayer->view->at(x, y); bigcellx = cellpos.first; bigcelly = cellpos.second; } // need to update scroll bars if grid is bounded if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { UpdateScrollBars(); } } if ( drawingcells ) { DrawCells(x, y); } else if ( selectingcells ) { SelectCells(x, y); } else if ( movingview ) { MoveView(x, y); } } // ----------------------------------------------------------------------------- void PatternView::OnScroll(wxScrollWinEvent& event) { WXTYPE type = event.GetEventType(); int orient = event.GetOrientation(); if (type == wxEVT_SCROLLWIN_LINEUP) { if (orient == wxHORIZONTAL) PanLeft( SmallScroll(currlayer->view->getwidth()) ); else PanUp( SmallScroll(currlayer->view->getheight()) ); } else if (type == wxEVT_SCROLLWIN_LINEDOWN) { if (orient == wxHORIZONTAL) PanRight( SmallScroll(currlayer->view->getwidth()) ); else PanDown( SmallScroll(currlayer->view->getheight()) ); } else if (type == wxEVT_SCROLLWIN_PAGEUP) { if (orient == wxHORIZONTAL) PanLeft( BigScroll(currlayer->view->getwidth()) ); else PanUp( BigScroll(currlayer->view->getheight()) ); } else if (type == wxEVT_SCROLLWIN_PAGEDOWN) { if (orient == wxHORIZONTAL) PanRight( BigScroll(currlayer->view->getwidth()) ); else PanDown( BigScroll(currlayer->view->getheight()) ); } else if (type == wxEVT_SCROLLWIN_THUMBTRACK) { int newpos = event.GetPosition(); int amount = newpos - (orient == wxHORIZONTAL ? hthumb : vthumb); if (amount != 0) { TestAutoFit(); if (currlayer->view->getmag() > 0) { // amount is in cells so convert to pixels amount = amount << currlayer->view->getmag(); } if (orient == wxHORIZONTAL) { hthumb = newpos; currlayer->view->move(amount, 0); // don't call UpdateEverything here because it calls UpdateScrollBars RefreshView(); // don't Update() immediately -- more responsive } else { vthumb = newpos; currlayer->view->move(0, amount); // don't call UpdateEverything here because it calls UpdateScrollBars RefreshView(); // don't Update() immediately -- more responsive } } } else if (type == wxEVT_SCROLLWIN_THUMBRELEASE) { // now we can call UpdateScrollBars mainptr->UpdateEverything(); } // need an update if script is running if (inscript && type != wxEVT_SCROLLWIN_THUMBTRACK) { inscript = false; mainptr->UpdatePatternAndStatus(); bigview->UpdateScrollBars(); inscript = true; } } // ----------------------------------------------------------------------------- void PatternView::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { // do nothing because we'll be painting the entire viewport // why does this get called even though we always call Refresh(false)??? // and why does bg still get erased (on Mac and GTK, but not Windows)??? // note that eraseBack parameter in wxWindowMac::Refresh in window.cpp is never used! } // ----------------------------------------------------------------------------- // create the viewport window PatternView::PatternView(wxWindow* parent, wxCoord x, wxCoord y, int wd, int ht, long style) : wxWindow(parent, wxID_ANY, wxPoint(x,y), wxSize(wd,ht), style) { dragtimer = new wxTimer(this, wxID_ANY); if (dragtimer == NULL) Fatal(_("Failed to create drag timer!")); cellbrush = new wxBrush(*wxBLACK_BRUSH); if (cellbrush == NULL) Fatal(_("Failed to create cell brush!")); // avoid erasing background on GTK+ -- doesn't work!!! SetBackgroundStyle(wxBG_STYLE_CUSTOM); // force viewbitmap to be created in first OnPaint call viewbitmap = NULL; viewbitmapwd = -1; viewbitmapht = -1; drawingcells = false; // not drawing cells selectingcells = false; // not selecting cells movingview = false; // not moving view waitingforclick = false; // not waiting for user to click nopattupdate = false; // enable pattern updates showcontrols = false; // not showing translucent controls oldcursor = NULL; // for toggling cursor via shift key restorecursor = NULL; // for restoring cursor changed by middle button click } // ----------------------------------------------------------------------------- // destroy the viewport window PatternView::~PatternView() { delete dragtimer; delete viewbitmap; delete cellbrush; } golly-2.7-src/gui-wx/wxrule.h0000644000175000017500000000240212536111364013135 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXRULE_H_ #define _WXRULE_H_ bool ChangeRule(); // Open a dialog that lets the user change the current rule. // Return true if the rule change succeeds. Note that the // current algorithm might also change. wxString GetRuleName(const wxString& rulestring); // If given rule has a name then return name, otherwise return the rule. #endif golly-2.7-src/gui-wx/wxedit.h0000644000175000017500000000310112536111364013110 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXEDIT_H_ #define _WXEDIT_H_ // Edit bar routines: void CreateEditBar(wxWindow* parent); // Create edit bar window above given parent window, // but underneath layer bar if present. int EditBarHeight(); // Return height of edit bar. void ResizeEditBar(int wd); // Change width of edit bar. void UpdateEditBar(); // Update state of buttons in edit bar. void ToggleEditBar(); // Show/hide edit bar. void ToggleAllStates(); // Show/hide all cell states in expanded edit bar. void ShiftEditBar(int yamount); // Shift edit bar up/down by given amount. void CycleDrawingState(bool higher); // Cycle current drawing state to next higher/lower state. #endif golly-2.7-src/gui-wx/icons/0000755000175000017500000000000012536111364012633 500000000000000golly-2.7-src/gui-wx/icons/appicon48.ico0000644000175000017500000000413612536111364015060 0000000000000000((0`Àÿÿÿ¿¿¿¿¿¿¿¿¿ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»golly-2.7-src/gui-wx/icons/file-mc.icns0000644000175000017500000011434212536111364014752 00000000000000icns˜âics#Hðøüüþþþþþþþþþþþþðøüüþþþþþþþþþþþþis32€\tplf\6†òòîèáÓ»4…‚íðºz[„ƒðåz­Eƒô‚÷åzzn‚÷…ÿÎi‚ûÿ ÿ ÿð‡‚ûƒÿ ÿò”‚ûÿ ÿ ÿû›‚ûÿ ÿ ÿû¢‚ûÿ ƒÿþª‚ÿÿ ÿ ÿÿ¬‚‡ÿ­‚‡ÿ¯‚øïï€îííìô¥‚ &! #%€€\tplf\6†òòîèáÓ»4…‚íðºz[„ƒðåz­Eƒô‚÷åzzn‚÷…ÿÎi‚ûÿ2ÿ2ÿð‡‚ûƒÿ2ÿó”‚ûÿ2ÿ2ÿû›‚ûÿ2ÿ2ÿû¢‚ûÿ2ƒÿþª‚ÿÿ2ÿ2ÿÿ¬‚‡ÿ­‚‡ÿ¯‚øïï€îííìô¥‚ &! #%€€\tplf\6†òòîèáÓ»4…‚íðº{[„ƒðå{­Eƒô‚÷å{{n‚÷…#Îi‚û#ÿ#ÿ#ð‡‚ûƒ#ÿ#÷”‚û#ÿ#ÿ#û›‚û#ÿ#ÿ#û¢‚û#ÿƒ#þª‚ÿ#ÿ#ÿ#ÿ¬‚ÿ…#ÿ­‚‡ÿ¯‚øïï€îííìô¥‚ &! #%€s8mk<°¿¿¿¿¿©CQÿÿÿÿÿÿÿ©0Wÿÿÿÿÿÿÿÿ¯0Wÿÿÿÿÿÿÿÿø¯/WÿÿÿÿÿÿÿÿÿøžWÿÿÿÿÿÿÿÿÿÿÒ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ UÿÿÿÿÿÿÿÿÿÿÑ 1Š—————————{ICN#ÿüÿþÿÿ€ÿÿÀÿÿàÿÿàÿÿðÿÿðÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿüÿþÿÿ€ÿÿÀÿÿàÿÿàÿÿðÿÿðÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøil32a€ÿŠÿÖ ÓÏÍËÇÃÀ¸©¨ªª‰ÿãåâãâàßÝÛØÖÕÐóÈÁ€‡ÿ忀ä ãáàÞÛÙØÕδàÇÇ€†ÿåçå äâàÞÜÚØÓ½ÿÝÆÀ€…ÿçç‚åäãáßÞÛÕÃÿÿàÇÂ…ÿèéçææåãâáÞÙÆ€ÿÝÿ„ÿéêè€çæäãáÜËÿàÇ«„ÿêëƒéèèäãáÜÓ½¤——¼Ãµƒÿìí€ë…ê ÜÓÃþ¾²­ªƒÿîïíììŠÿ×ÕÌÁƒÿðñ€îÿ„ ÿÿ ÿßÝ×Ѓÿñò€ðÿ„ ÿÿ ÿìƒÿóôòññ‡ÿ ÿìƒÿõö€ô‡ÿ ÿ€îòƒÿ ÷øõøøÿ „ÿ ÿ€ðòƒÿøù€÷ÿ „ÿ ÿòƒÿ ùú÷÷øÿ „ÿ ÿñ€òƒÿùú€øÿ ‡ÿòñòîƒÿúû€ùÿ ‡ÿóóôðƒÿûü€ùÿ ÿÿ„ ÿôôõóƒÿûü€úÿ ÿÿ„ ÿõõöõƒÿûüûúúŠÿõõ÷õƒÿûýûú€ùø÷÷öøöƒÿüþûû€ÿWWûWWÿÒWW÷ÿ÷÷ø÷ƒÿüþýü€ÿWÒWÒWÿWúÿÒÿøøùøƒÿýÿýý€ÿWýWýWÿWûû÷ÿùùúùƒÿþÿþþ€ÿWýÒýWÿWüÿÒÿúúûùƒÿþÿþþ€ÿW€ý WÿÒWW÷ÿúúüùƒÿ“ÿƒÿ—ƒÿ—€ÿ€ÿŠÿÖ ÓÏÍËÇÃÀ¸©¨ªª‰ÿãåããâàßÝÛØÖÕÐóÈÁ€‡ÿ忀ä ãáàÞÛÙØÕδàÇÇ€†ÿåçå äâàÞÜÚØÓ½ÿÝÆÀ€…ÿçç‚åäãáßÞÛÕÃÿÿàÇÂ…ÿèéçææåãâáÞÙÆ€ÿÝÿ„ÿéê‚èççæäãàÜËÿàÇ«„ÿêëéèéèèäãàÜÒ½¤——¼Ãµƒÿìí€ë…ê ÜÒÃþ¾²­ªƒÿîïíììŠÿ×ÕÌÁƒÿðñ€îÿ„2 ÿÿ22ÿßÝ×Ѓÿñò€ðÿ„2ÿÿ22ÿìƒÿóôòññ‡ÿ22ÿìƒÿõö€ô‡ÿ22ÿ€îóƒÿ ÷øõøøÿ22„ÿ22ÿ€ðóƒÿøù€÷ÿ22„ÿ22ÿóƒÿ ùú÷÷øÿ22„ÿ22ÿñ€óƒÿùú€øÿ22‡ÿòñòîƒÿúû€ùÿ22‡ÿóóôðƒÿûü€ùÿ22ÿÿ„2ÿôôõóƒÿûü€úÿ22ÿÿ„2ÿõõöõƒÿûüûúúŠÿöõ÷õƒÿûýûú€ù€ø€÷öøöƒÿüþûû€ÿWWûWWÿÒWW÷ÿ÷÷ø÷ƒÿüÿýü€ÿWÒWÒWÿWúÿÒÿø÷ù÷ƒÿþÿýý€ÿWýWýWÿWûû÷ÿùùûùƒÿþÿþþ€ÿWýÒýWÿWüÿÒÿúúûùƒÿþÿþþ€ÿW€ý WÿÒWW÷ÿûúüùƒÿ“ÿƒÿ—ƒÿ—€ÿ€ÿŠÿÖ ÓÏÍËÇÃÀ¸©¨ªª‰ÿäåâãâàßÝÛØÖÕÐóÈÁ€‡ÿ忀ä ãáàÞÛÙØÕδàÇÇ€†ÿåçå äâàÞÜÚØÓ½ÿÝÆÀ€…ÿçç‚åäãáßÞÛÕÃÿÿàÇÂ…ÿèéçææåãâáÞÙÆ€ÿÝÿ„ÿéê‚èççæäãàÜËÿàÇ«„ÿëëéèéèèäãàÜÒ½¤——¼Ãµƒÿìí€ë…ê ÜÒÃþ¾²­ªƒÿîïíììŠ#×ÕÌÁƒÿðñ€î#„ÿ ##ÿÿ#ßÝ×Ѓÿñò€ð#„ÿ##ÿÿ#ìƒÿóôòññ‡#ÿÿ#ìƒÿõ÷€ô‡#ÿÿ#€îóƒÿ ÷øõøø#ÿÿ„#ÿÿ#€ðóƒÿøù€÷#ÿÿ„#ÿÿ#óƒÿ ùú÷÷ø#ÿÿ„#ÿÿ#ñ€óƒÿùú€ø#ÿÿ‡#òñòîƒÿúû€ù#ÿÿ‡#óóôðƒÿûü€ù#ÿÿ##„ÿ#ôôõóƒÿûü€ú#ÿÿ##„ÿ#õõöõƒÿûüûúúŠ#õõ÷õƒÿûýûú€ù€ø€÷öøöƒÿüþûû€ÿWWûWWÿÒWW÷ÿ÷÷ø÷ƒÿüÿüü€ÿWÒWÒWÿWúÿÒÿøøù÷ƒÿýÿýý€ÿWýWýWÿWûû÷ÿùùûùƒÿþÿþþ€ÿWýÒýWÿWüÿÒÿúúûùƒÿþÿþþ€ÿW€ý WÿÒWW÷ÿúúüùƒÿ“ÿƒÿ—ƒÿ—€ÿl8mk  8ÿÿÿÿÿÿÿÿÿÿÿÿÿô½ Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ[JÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÁJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ4JÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿîJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿDJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿSJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJKÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿKn—²°°°°°°°°°°°°°°°°°°²—n1@KJJJJJJJJJJJJJJJJJJK@1it32GùÿÿŒà†ß‚ÞÝ€Ü ÛÚÚÙÙØØ×ÖÖ€ÕÔÓÓÒÑÑÐÏÎÌÊÇÄ¿½¹¶®´¥UÄàá…àßàßàß‚ÞÝÝÜÜÛÚÚ€ÙØ×ÖÖÕÕÔÔÓÓÒÑÐÐÏÌÉÈÄÁ¿½¸´³°®£3Áˆáàáá€à€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÐÎËÈÅ¿¼¸µ²¬®¹cfÀââ…áâá€à€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÐÎËÈÆÂ¿¼¸´°««¶Ud¿âáâ€áâáàà€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÏÎÉÈÅÁ¾»¶±®©­±pU¾„âáá‚âáàà߀ÞÝÜÜÛ€ÚÙØØ×ÖÖ€ÕÔÓÓÒÑÏÌÊÈÅÀ½¹´¯ª¦¸¢¤H½Œâáàà߀ÞÝÜÜÛ€ÚÙØØ×ÖÖ€ÕÔÓÓÒÑÏÌÉÇÿ¼·±«¦§»ª´U¼âáà‚߀ÞÝÜÜÛ€ÚÙØ××ÖÖ€ÕÔÓÓÒÑÏÌÉÆÁ½¹²¬¦¢²´¼³H»Žãâáà߀ÞÝÜÜÛÚÙØØ××ÖÕÕÔÓÓÒÐÏÌÉÆÀº¶®¨¡ž°ÄʳUºãâáà߀ÞÝÜÜÛ€ÚÙÙØØ××ÖÕÕÔÓÓÑÐÎÊÇľ·±©¢›˜¸ÓʳU¹ãâá€àßßÞÞÝÝÜÜÛ€ÚÙÙØØ××ÖÕÕÔÓÓÑÐÍÉÅÀº²ª¢›”–ÝÓʳH¸‘ãâá€àßÞÞÝÝÜÛÛÚÙÙØØ×ÖÖ€ÕÔÓÑÐÍȼ´«£š“ØÝÓʳH·’ãâá€àßÞ€Ý ÜÛÛÚÙÙØØ×ÖÖ€ÕÓÓÑÎËž¶®¥›“‹ÉåÝÓʱH¶“äãâ€áààßßÞ€ÝÜÛÛ€ÚÙØØ××ÖÖÔÓÓÏÌÇÀ¹°¥”‹¾íåÝÓʱZµ”äãâ€áààßßÞ€ÝÜÛÛ€ÚÙØØ××ÖÔÔÓÑÎÈú±¨”гôíåÝÓʱZ´•äãâ€áà߀Þ!ÝÜÜÛÚÚÙØØ××ÕÔÔÑÏÌÅ¿µª ”‰§úôíåÝÓʱZ³–äãâ€áà߀Þ!ÝÜÜÛÚÚÙØØ××ÕÓÒÏÍÇÀ¶­¡–‹›ÿúôíåÝÓʱZ²—åäã€âá€à߀ÞÝÜÜÛ€ÚÙÙØÖÕÓÑÎȹ¯£—‹–ÿÿúôíåÝÓʱZ±˜åäã€âá€à߀ÞÝÜÜÛ€ÚÙÙ×ÕÕÒÏÉ»°¥˜Œ€ÿúôíåÝÓʱZ°˜åäãã€âá€à߀ÞÝÜÜÛ€Ú ÙØ×ÕÓÏÉû³¦šŽŽÿúôíåÝÓʱZ¯™åäãã€âáà€ßÞÝÝÜÛÛÚØØÖÓÐËﳍœ†‚ÿúôíåÝÓʱH®ææ…åæåäãã€âáà€ßÞÝÝÜÛÛÙØØÔÑÌÆ½µªž…ƒÿúôíåÝÓʱH­€ç„æçæåää€ãâ€áà€ßÞÝÝÜÛÚÙØÕÓÎÈÀµ«ž“†„ÿúôíåÝÓʱH¬ƒç€æ‚çŽæåää€ãâ€áà€ßÞÝÝÜÚÚØÕÓÎÈÀ·« “ˆ…ÿúôíåÝÓʱH«…çæ…çææç‰æåää€ãâ€á€àßßÞÞÜÛÚ×ÔÐʸ­¡•‰†ÿúôíåÝÓʲUª•ç†æåää€ãâ€á€à"ßÞÞÝÜÚÙÕÐʸ®¢—‹€von‚€€Š¢®ÀÑäÝÓʲU©’èççè‡çæåå€äã€â%áààßÞÝÝÛÙÖÐËĺ°¤™Ž„zrmheddehhlot•¶ÈʳH¨–è‡çæåå€äã€âáààßÝÝÜÚ×ÒÍż²¦œ’‡xrnk€j lnqsuzŽ©¬¯U§éšèƒçæåå€äã€âáààßÞÝÜØÔÏÈ¿¶« —…yvtr€s tvx{~…‰™™U¦ƒéšè€ç€æåå€ä)ããââáààßÝÜÚÖÐʹ°¦œ”‡ƒ€~}||}~~€‚„†‰Œš v3¥…éèé”è€ç‰æâ€àÜÛ×ÒÌŽ´«£›•ŒŠˆ‰‰€ˆ ‰‰ŠŒ‘”–Ÿªb¥Šêéèèéƒèƒåæââ€à âß×ÒÏÂÁº±ª¤ž›—•–€•”•–€—š›œ¬{n¤êŠéëéƒèëèè‚倿€âà€ß ×ÒÏ˾¹²­©¥¢‚¡£€¡ Ÿ ¡¡£³¤‘ê‡éèèååèé‚èåèèçç‚æââàà€ßØÏÏ˾¶¼·³°¯­­¬®®­®®«¬ª©©¨¦¦§¥¸y¤€ë‘êƒéëéƒèé„èçç€æååæâàáàßÞØÏÏ˺º¼»º¹¹¸¸¹ ·µµ³±°®­¬¬¯¦¤ƒë€êëë‹ê€é„ëƒèé‚èç€æ ååäââáßÞÛØÏÐË€ÂÃÂÃÂÁÁ¿½¼º·¶µ²±±­¤…ìëììŒëê‡ë€êéèèêéè ççææåäããáÞÞÛØÏ‚ËÊË€Ê ÉÈÇÅÂÁÀ½¼¹¶µ®¤‹ì‘ëêƒèêéè€ç ææääâáßÞÜÚØƒÐÑÐÏÐÏÐÏÏÍÌÊÇÄÄÁ¿¼¹¸¤ìŽë‚êîèƒêéè€ç ææääâáàßÞÜÛØØƒÖÕÔÕÔÔÓÒÐÍËÈÆÃÀ½º¤ííŽìƒë¥ÿáØØÖØØÙØÙØ××ÖÖÕÓÒÏÌÊÇľ¤îˆí€ì€íìëëÿ¥ýÿáÛÜÛÛÚÙÙØ×ÖÖÕÓÑÍËÈŤ„îííîîí€ì€íëëÿ€ýþÿÿýþÿÿýþÿÿýýÿÿþýÿÿþýÿÿþ‚ý€ÿý€ÿ€ýÿáÜÝÝÜÛÚÙÙØ××ÕÔÑÎÌÈŤŠîíí€ì‚íÿýýþøÔáÿúÖßþýÚÙýþÝØûÿãÔøÿåÓõÿ€ý ÿïÐíÿñÒêÿýýÿá„Ý ÜÛÛÚÚÙØØÕÕÑÎÍɤŒîíìì‚í,ÿýþöŠ@;³=9­¨H2šªE4޾S0}½Q5lòþýÿãi7RÇm9HÓÿýÿãƒßÞÞÝÜÜÛÚÚÙÙÖÔÒÎͤðïðð„ïðïìƒí-ÿýÿÕ4C;3B>EA.<;(%S9) C38Åÿýÿ¢-> S)E ÿýÿåäƒÞ ßÞÞÝÜÛÚÚÙÙÖÔÒϤð€ï€ð‚ï€ð‚í+ÿýÿâ3[>[THSA‘ÿýÿíììƒêéèèç€æåäããâá¤õò ÿýÿÐ!@:NôÿŽýÿš^ÿýÿîíìïƒê éèèçææåääãã⤔õ ÿýþúˆ ;Á¢(1²ÿþŽýÿæ_ZÖwKÖÿýÿïîíïïƒê éèèçææåääã⤆ö…õö‚õ ÿýýÿÀVnçÈZgÜÿýþúLô§O„ôþýÿððï„êééèççæååã¤÷‰ö‡õ ÿýÿâLG_MCgûÿŽý ÿ·>@x:Fšÿýÿ€ð‚ï€êëê€éèççæå夂÷ˆö„õ ÿýÿÖ#9)IõÿŽýÿ¡S}ÿýÿñðñ€ðïíïìêëëê€éèççæå¤„÷öö÷÷…öõ ÿýþ÷1¯ˆ)§ÿþŽý ÿáWLÄ\AÎÿýÿ€ñ ððòòîîíììëëê€éèççæ¤Œ÷„ö õÿýýÿÉXrðÕ[gãÿý þÿ£N•ü²K‰øþýÿ€ñðòòðï€îììëëê€éèçç¤ö÷ö ÿýÿáUFleDoûÿŽýÿºG<‰LB ÿýÿòòñðò€ðï€îíìëëê€éè礒÷ööÿýÿË"$87#JóÿŽý ÿ”U!#|ÿýÿ‚òðï€îíìëëê€éè¤÷øø÷ööÿýþóe ¢„–ÿþŽý ÿÕ95ºQ'Áÿýÿ‚òñðï€îíììëê€é¤öƒø÷÷øŠ÷ ÿýýÿÎ]}ôØeuèÿý ÿâ½ßÿëÁÙÿýýÿƒòñ€ðïï€îí€ìêéé¤öˆøˆ÷ ÿýÿê_B |b> }þþý€ÿý€ÿ€ýÿ„òññððïï€îí€ìëê¤õ‹ø…÷ ÿýÿÓ%)2((Eôÿšýÿ…òññððïï€îí€ìë¤öŠø†÷ÿýÿð_j Œÿþýý…ÿþ€ÿþ€ÿý€ÿþ€ÿþýýÿòòóƒò€ñðïï€îí€ì¤õ‹ø…÷'ÿýýÿÐStùÕUlêÿýýÿò®¦êú¹Ÿâý¼žÜÿÊ›ÒÿÏœÊÿÔÀýÿòõõ„òñïï€îíìì¤ôùˆøùƒ÷+ÿýÿíjF,‰oB+Šÿþýý…:(fšC&U”?/H©J.<¢S4- M7)·ÿýÿ€õòòó‚òñðï€îíì¤ôƒùøøùùƒøù-÷÷ÿýÿÒ*3 3+3 Eóÿýö?-J+;), T%(J+/K5xÿýÿ„òóòñðð€îí¤ó‰ù‚ø‚ù+ÿýÿíN ‚[þÿýýy[L‹;£ //š/°ÿýÿ‚ò‚ó€òñððïîî¤òŒù€øù/ÿýýÿÐaö×btéÿýýÿêtaÙ÷†]Éü‹WÀÿ W®ÿ¬W£ÿ¶T•ûþýÿõõòô…óòòñððïî¤ñ“ù+ÿýÿïxC(™‰@(”ÿþýþ¢F,t¦P)`¯P2V³Z2E°c87´h:4Àÿýÿ€õ€ô…óòñððï¤ñú’ù+ÿýÿË*9 7:7 IóÿýøP1 D3I/.M-)>1/T)8|ÿýÿ…ô„óòñðð¤ðúù,ÿýÿå:rZpüÿýýzKy=…,‹%". ¢ÿýÿõ…ô…óò€ñð¤ïƒúùùúú‰ù+ÿýýÿÏ|“ñ݇Œåÿýýÿë•€×ò–zÌù¦zÂúªv·û´u®ûÄ|¡öþýÿ‚öƒô„óòòññ¤ï‰ú‡ùÿ€ý…ÿý…ÿþ€ÿþ€ÿþ€ÿþ€ÿþýýÿöõ…ôƒóòòñ¤î‹ú„ùöùÿ¥ýÿõöƒõ…ô‚óòò¤îŽú„ù¥ÿõõö…õ„ô‚óò¤î‘úˆùöö‚ù‚ø„ù€öù‚öùöõ€ö…õ…ôó¤íû’ú„ùöö„ùööù€öø‰ö†ùö†õƒô€ó¤íû“úù‚öùùö‡ùƒö†õ„ôó¤íƒûúúûú„ùƒöùƒö…ù†÷€ùƒö†õƒô¤í‰ûú†ù†ö‚ø…ù÷ööùùƒö…õ‚ô¤íŒûŽúŠù‰ø÷…ù…ö…õ€ô¤íûŽúŠù‰ø†÷‡ö…õó¤í’ûú‹ùˆø‡÷…ö„õô¤í”ûŽúˆùŠø†÷†ö‚õó¤íüü”ûŽú‰ùˆø‡÷…öõó¤í‚ü€ûüûú‰ùˆø†÷†öõõò¤íˆüûŽú‡ù‰ø†÷†öò¤îŠüûúûŒúˆùˆø…÷…öñ¤îü‘û‹úˆùˆø‡÷‚öð¤îüûŒú‡ùˆø†÷öð¤î…üýüý€üýüýüý‚ü‚ûÿüûü…û‚úû öÝÔÔßòúúùú‚ùøùƒø÷øøƒ÷ö÷î¤ï“ýüƒûÿûƒ€WÛüº€WúûüüãŽ\‚Woûúúÿÿú‡ù†ø÷÷î¤ï•ý‚ûÿûƒ€W¯üŽ€WúûüÕ_WWƒ¤©“xWûúúÿÿƒú‡ù†øí¤ï•ý‚ûÿûƒ€WxüWúûñgWZÍ‚üéûúúÿÿ…ú‡ù„øí¤ïþþ“ý‚ûÿûƒWmWWæüüÅWbWWúü°WWž…üúúÿÿ‡ú†ùƒøì¤ï‚þý‚ûÿûƒW¤WW»ýü™W™WWúü{WWä…üúúÿÿˆú‡ùøë¤ïˆþŠý‚ûÿûƒW°xWŽýýbx¯WWúü_Wb†üúúÿÿûû‡ú‡ù€øë¤ð‹þ‡ý‚ûÿûƒW°°WWòÆW°°WWúüWWm†üúúÿÿû‡ú†ùøøë¤ðþ…ý‚ûÿûƒW°çWWƤWç°WWúü_Wbýý„üúúÿÿƒû‡ú†ùë¤ðþ„ýûÿûƒW°ýmW™mmý°WWúü{WWâ€ýƒüúÿÿ…û†ú…ùê¤ð“þ€ýûÿûƒW°ý¤WbW¤ý°WWúü°WWœ‚ýüúÿÿ†û†ú„ùê¤ð•þýûÿûƒW°ýÜ€W Üý°WWúúòjWWµ‚ýÈîüúÿÿˆû†ú‚ùë¤ð–þû!ÿûƒW°ýýmWmýý°WWúúýÖ_WWsŸª—pWçúúÿÿüˆû†úùë¤ð–þûÿû„W°ýýÜÑÜýý°WWúúýýäŽ\Wb’õúúÿÿüüˆû‡úùùë¤ð•þ‚ûÿûþþ‰ýúýøß××ê€ý…üˆû†úùë¤ðŸþý‹üˆû†úë¤ð¡þýŠü‰û„úë¤ðÿ£þýŠüˆûƒúë¤ðÿ¢þýŠü‡û‚úì¤ð„ÿþÿŸþŽýŠü‡ûúìÿÿÿÿÿÿÿÿÿÿŒ‚à…ß‚ÞÝ€Ü ÛÚÚÙÙØØ×ÖÖ€ÕÔÓÓÒÑÑÐÏÎÌÊÇÄ¿½¹¶®´¥Uăàßàßàßààß‚ÞÝÜÝÝÜ€ÚØÙÙ××ÖÖÕÕ€ÔÓÒÑÐÐÎÌÊÈÄÁ¿½¹µ³±®£3Áˆáàáà€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÐÎËÈÅ¿¼¸µ²¬®¹cfÀââ„áââ‚áàà€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÐÎËÈÆÂ¿¼¸´°««¶Ud¿€âáâáâáàà€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÏÎÉÈÅÁ¾»¶±®©­±pU¾„âáá‚âáàà߀ÞÝÜÜÛ€ÚÙØØ×ÖÖ€ÕÔÓÓÒÑÏÌÊÈÅÀ½¹´¯ª¦¸¢¤H½Œâáàà߀ÞÝÜÜÛ€ÚÙØØ×ÖÖ€ÕÔÓÓÒÑÏÌÉÇÿ¼·±«¦§»ª´U¼âáà‚߀ÞÝÜÜÛ€ÚÙØ××ÖÖ€ÕÔÓÓÒÑÏÌÉÆÁ½¹²¬¦¢²´¼³H»Žãâáà߀ÞÝÜÜÛÚÙØØ××ÖÕÕÔÓÓÒÐÏÌÉÆÀº¶®¨¡ž°ÄʳUºãâáà߀ÞÝÜÜÛ€ÚÙÙØØ××ÖÕÕÔÓÓÑÐÎÊÇľ·±©¢›˜¸ÓʳU¹ãâá€àßßÞÞÝÝÜÜÛ€ÚÙÙØØ××ÖÕÕÔÓÓÑÐÍÉÅÀº²ª¢›”–ÝÓʳH¸‘ãâá€àßÞÞÝÝÜÛÛÚÙÙØØ×ÖÖ€ÕÔÓÑÐÍȼ´«£š“ØÝÓʳH·’ãâá€àßÞ€Ý ÜÛÛÚÙÙØØ×ÖÖ€ÕÓÓÑÎËž¶®¥›“‹ÉåÝÓʱH¶“äãâ€áààßßÞ€ÝÜÛÛ€ÚÙØØ××ÖÖÔÓÓÏÌÇÀ¹°¥”‹¾íåÝÓʱZµ”äãâ€áààßßÞ€ÝÜÛÛ€ÚÙØØ××ÖÔÔÓÑÎÈú±¨”гôíåÝÓʱZ´•äãâ€áà߀Þ!ÝÜÜÛÚÚÙØØ××ÕÔÔÑÏÌÅ¿µª ”‰§úôíåÝÓʱZ³–äãâ€áà߀Þ!ÝÜÜÛÚÚÙØØ××ÕÓÒÏÍÇÀ¶­¡–‹›ÿúôíåÝÓʱZ²—åäã€âá€à߀ÞÝÜÜÛ€ÚÙÙØÖÕÓÑÎȹ¯£—‹–ÿÿúôíåÝÓʱZ±˜åäã€âá€à߀ÞÝÜÜÛ€ÚÙÙ×ÕÕÒÏÉ»°¥˜Œ€ÿúôíåÝÓʱZ°˜åäãã€âá€à߀ÞÝÜÜÛ€Ú ÙØ×ÕÓÏÉû³¦šŽŽÿúôíåÝÓʱZ¯™åäãã€âáà€ßÞÝÝÜÛÛÚØØÖÓÐËﳍœ†‚ÿúôíåÝÓʱH®ææ…åæåäãã€âáà€ßÞÝÝÜÛÛÙØØÔÑÌÆ½µªž…ƒÿúôíåÝÓʱH­ç†æçæåää€ãâ€áà€ßÞÝÝÜÛÚÙØÕÓÎÈÀµ«ž“†„ÿúôíåÝÓʱH¬ƒç€æçæåää€ãâ€áà€ßÞÝÝÜÚÚØÕÓÎÈÀ·« “ˆ…ÿúôíåÝÓʱH«…çæ‚çæçç€æçˆæåää€ãâ€á€àßßÞÞÜÛÚ×ÔÐʸ­¡•‰†ÿúôíåÝÓʲUª“çæç†æåää€ãâ€á€à"ßÞÞÝÜÚÙÕÐʸ®¢—‹€von‚€€Š¢®ÀÑäÝÓʲU©”èˆçæåå€äã€â%áààßÞÝÝÛÙÖÐËĺ°¤™Ž„zrmheddehhlot•¶ÈʳH¨—èçè„çæåå€äã€âáààßÝÝÜÚ×ÒÍż²¦œ’‡xrnk€j lnqsuzŽ©¬¯U§éšèƒçæåå€äã€âáààßÞÝÜØÔÏÈ¿¶« —…yvtr€s tvx{~…‰™™U¦ƒé—èçèç€æåå€ä)ããââáààßÝÜÚÖÐʹ°¦œ”‡ƒ€~}||}~~€‚„†‰Œš v3¥…éèé”èçèç‰æâ€àÜÛ×ÒÌŽ´«£›•ŒŠˆ‰‰€ˆ ‰‰ŠŒ‘”–Ÿªb¥Œêéèèéƒèƒåæââ€à âß×ÒÏÂÁº±ª¤ž›—•–€•”•–€—š›œ¬{n¤êŠéëéƒèëèè‚倿€âà€ß ×ÒÏË¿¹²­©¦¢‚¡£€¡ Ÿ ¡¡£³¤‘ê‡éèèååèé‚èåèèçç‚æââàà€ßØÏÏË¿·¼·³°¯­­¬®®­®®«¬ª©©¨¦¦§¥¸y¤€ë‘êƒéëéƒèé„èçç€æååæâàáàßÞØÏÏ˺º¼»º¹¹¸¸¹ ·µµ³±°®­¬¬¯¦¤ƒë€êëë‹ê€é„ëƒèé‚èç€æ ååäââáßÞÛØÏÐË€ÂÃÂÃÂÁÁ¿½¼º·¶µ²±±­¤…ìëììŒëê‡ë€êéèèêéè ççææåäããáßÞÛØÏ‚ËÊË€Ê ÉÈÇÅÂÁÀ½¼¹¶µ®¤‹ì‘ëêƒèê€éèè€ç ææääâáßÞÜÚØƒÐÑÐÏÐÏ ÍÌÊÇÄÄÁ¿¼¹¸¤Žìë‚êîèƒêéè€ç ææääâáàÞÞÜÛØØƒÖÕÔÕÔÔÓÒÐÍËÈÆÃÀ½º¤ííŽìƒë¥ÿáØØÖØØÙØÙØ××ÖÖÕÓÒÏÌÊÇľ¤îˆí€ìíëëÿ¥ýÿáÛÜÛÛÚÙÙØ×ÖÖÕÓÑÍËÈŤ„îííîîí€ì€íëëÿ€ýþÿÿýýÿÿýþÿÿþýÿÿþýÿÿþýÿÿþ‚ý€ÿýþÿÿ€ýÿáÜÝÝÜÛÚÙÙØ××ÕÔÑÎÌÈŤŠîíí€ì‚íÿýýþúßèÿûáçþýäâþþæâüÿêÞùÿìÞ÷þ€ý ÿòÜðÿõÝïÿýýÿá„Ý ÜÛÛÚÚÙØØÕÕÑÎÍɤŒîíìì‚í,ÿýþùªvh¿®uj½À}d«Àzi¥Ï…e”Ì‚lŒóþýÿé“nvЕqsÛÿýÿãƒßÞÞÝ€ÜÚÚÙÙÖÔÒÎͤðïðð„ïðïìƒí-ÿýÿßjuBahuJ^suLTlp[K{qYIpjj:Ìÿýÿ¹en8v`u;”ÿýÿåäƒÞ ßÞÞÝÜÛÚÚÙÙÖÔÒϤð€ï€ð‚ï€ð‚í+ÿýÿéY/#oc,"ls1!\t0%Q†5$G7)5ÕÿýÿÅ?+'ˆF,% ÿýÿ„åáàßßÞÝÜÛÛÚÙÙÖÔÒ¤ƒðïï‚ð€ïðð‚î+ÿýýÿÂasæÈUfÞÛleÑàfUÈì~\¶ï{M¬ÿþýþûŸWó¥K„óþýÿ€åãááàßÞÞÝÜÜÛÚÙÙÖÔ¤‹ðïïòíòð€î-ÿýþú¹ƒuÊăvÄË‹pµÓŒt¯×”q Ü—u™óÿýÿî¥yƒÜ­{‚Þÿýÿæå€ãæããááàßßÞÝÝÜÛÚÙÙÖ¤ðò,ÿýÿÜit8dxtEdrvBR}rTPzsPCpb=Ðÿýÿµhg1lr9›ÿýÿç„ã âááàßßÞÝÜÜÛÚÚÙ¤òò€ñõòðñððò€ðCòòÿýÿàO*ig.bg.Tx1#Ix1@:(.Òÿýÿ¹<($…I1 ™ÿýÿèèææããææäãââáàßßÞÝÝÛÛÚ¤‚òõò…ðòò€ðÿ€ý,±YnÛÃkkÍÌc`ÆÙvd¶ÞrV®ç…b›ùýýÿõF‡í¤Wzèÿýÿèææçã€æ ääãâááààßÞÝÜÜÛ¤„ò€õòòðòððƒò.ðÿýýþÿôùÿÿøùÿÿ÷÷ÿÿû÷ÿÿùôÿÿýöÿþýýÿô§s‘å¬wìÿýÿéè€æã€æ ääãââáààßÞÝÝܤ†òõƒòðð‚òÿ€ýþÿÿýýÿÿýýÿÿýýÿÿþýÿÿþýÿÿþ€ýÿÀnu?‚h|Bžÿýÿëéè€ê€æ€ä ãââááàßßÝݤ…ôòòôõˆòÿ›ý ÿ¼?4$zD8#”ÿýÿ…êæ åääãâááàßÞ¤‡ôòòõòõõò ÿýýþÿùýÿÿúüÿý ÿò‡GvàŒ;käÿýÿ†ê èçææåääãâááàߤõõôõƒôòõò€õöÿ€ýÊ‹ÞÔŽ‰×ÿýþù³z™ï¼z•îÿýÿìêêì‚ê èèçææååäãââáअõôöòôô€õ€òõ ÿýÿâux=rƒxGzùÿŽýÿ¿rm8ŽvvA¥ÿýÿíììƒêéèèç€æåäãââá¤õò ÿýÿÚN?%\d@%föÿŽýÿ±B8$xLA$“ÿýÿîíìïƒê éèèçææåääããᤔõ ÿýþú—6LÈ®GHµÿþŽýÿër0iÛ‰A[Øÿýÿïîíïïƒê éèèçææåääã㤆ö…õö‚õ ÿýýÿÐ~‹êÖ…Šâÿýþû´u¥ó½|Ÿöþýÿððï„êééèççæååã¤÷‰ö‡õ ÿýÿè}L}}{RƒúÿŽý ÿÊvvG’p{J¬ÿýÿ€ð‚ï€êëê€éèççæå夂÷ˆö„õ ÿýÿßSG*YYG*`õÿŽýÿ¶EB&qGH%ÿýÿñðñ€ðïîïìêëëê€éèççæå¤„÷öö÷÷…öõ ÿýþù?F´™4<®ÿþŽý ÿæm9ZÈs/QÒÿýÿ€ñ ððòòîîíììëëê€éèççæ¤Œ÷„ö õÿýýÿ×ñÞ†æÿý þÿ»x¨üÃsŸùþýÿ€ñðòòðï€îììëëê€éèçç¤ö÷ö ÿýÿè„}G„‘|PˆûþŽýÿË|qEŸyL±ÿýÿòòñðò€ðï€îíìëëê€éè礒÷ööÿýÿ×RQ,WeR/eõÿŽý ÿ¬MH(rTR*ÿýÿ‚òðï€îíìëëê€éè¤÷øø÷ööÿýþõ|%4­•3/ÿþŽý ÿÝUIÃl-<Äÿýÿ‚òñðï€îíììëê€é¤öƒø÷÷øŠ÷ ÿýýÿØ}“õàˆ‘ëÿý ÿåÁáÿìËÝÿýýÿƒòñ€ðïï€îí€ìêéé¤öˆøˆ÷ ÿýÿïzS“xW–ýþý€ÿý€ÿ€ýÿ„òññððïï€îíììëëê¤ö‹ø…÷ ÿýÿÜYY3W[Y5_ôÿšýÿ…òññððïï€îí€ìë¤öŠø†÷ÿýþôw23˜‚+,–þþýýÿþ€ÿþ€ÿþ€ÿý€ÿþ€ÿþýýÿòòóƒòñïï€îí€ì¤õ‹ø…÷'ÿýýÿ×yŽøÝt„ëÿýýþõļïû˸çýϸäÿ×µÛÿܵÖþà·Ò€ýÿòõõ„òñïï€îíìì¤ô€ù‰øùƒ÷+ÿýÿñ•~]ž–|`¡þþýý¤s`…´|_u«vhn½hcµ†mZ±qZÄÿýÿ€õòòó‚òñðï€îíì¤ô‚ù€øùùƒøù-÷÷ÿýÿÜ^c8X_e"! 9yŒU7mnZ2 !$€ñ ððòòîîíììëëê€éèççæ¤Œ÷„ö õ"!!\¨…*O™Œ6! %|©j%hŸw' !$€ñðòòðï€îììëëê€éèçç¤ö÷ö "!7ÖÿÖs¾ÿï Ž!_ðý¼oåÿÚZ!$òòñðò€ðï€îíìëëê€éè礒÷öö"!=ÒÚ¯yÂçÂx# Ž! gãÑ¡zßݲ\!$‚òðï€îíìëëê€éè¤÷øø÷ öö"! +qtfCi›x:! ;tbD‚žg1 !$‚òñðï€îíììëê€é¤öƒø÷÷øŠ÷ "!" PŠs)J”„4! +*)!,:.€!$ƒòñ€ðïï€îí€ìêéé¤öˆøˆ÷ "!6Êÿät³ÿñy !€ ! €!$„òññððïï€îí€ìëê¤õŒø„÷ "!?ÛëÆÆõÔr! š!$…òññððïï€îí€ìë¤öŠø†÷'"! /€rBr‹rG" !!  !!!€!$òòóƒò€ñðïï€îí€ì¤õ‹ø…÷."!!M—u%C|t0!! 0im4(fn;%`qA"YsHUtM!MrX#!!$òõõ„òñðï€îíìì¤ôùˆøùƒ÷+"!4¿ûÛmªüêu !"Žùô‘†õù™xîú­qéþ³lÜþÁcÓÿÖR!$€õòòó‚òñðï€îíì¤ô‚ù€øùùƒøù-÷÷"!?ÞðÊŠÉûÝv! !%®üä‘¥øàŸŸ÷즌ö殕ëé¼…ìôÊT!$„òóòñðð€îí¤ó‰ù‚ø‚ù+"!1‹¬}H~œK"!!"kž„Vh©™U]œŠaX¢£`V™¦kI’“t:!$‚ò‚ó€òñððïîî¤òŒù€øù/"!" G…f$>kc. !! 1gi5+u};$alB$f„K`†Q!NnW#!!$õõòô…óòòñððïî¤ñ“ù "!/¶øÌ\ ûäi€!„óð‚yïì„kæøždàôŸ\Ô÷­VÈþÊH!$€õ€ô…óòñððï¤ñú’ù+"!?áïÁ‚ÎùÙ†# !%´ûÝ ¬úÙ”¡øä²–øá£Žîå±ïðÊe!$…ô„óòñðð¤ð€úù,"!2—šX‹¸ŽL# !$zµ™Yr¦Šfl°¥ea¦Žq]¡’wY£²|>!$õ…ô…óò€ñð¤ïƒúùùúú‰ù"€!6=:&5[I' €!-VQ**?:0&OW1%>:6$>:5$A[?"!!$‚öƒô„óòòññ¤ï‰ú‡ù"€!€!!" !   ! !€!€!$öõ„ô„óòòñ¤î‹ú„ùöù#¥!$õöƒõ…ô‚óòò¤îúƒù%£$%õõö…õ„ô‚óò¤î‘úˆùöö‚ù‚ø„ù€öù‚öùöõ€ö…õ…ôó¤íû’ú„ùöö„ùööù€öø‰ö†ù€ö†õ„ô€ó¤íû’ú‚ù‚öùùö‡ùƒö†õ„ôó¤íƒûúúûú„ùƒöùƒö…ù†÷€ùƒö†õƒô¤í‰ûú†ù†ö‚ø…ù÷ööùùƒö…õ‚ô¤íŒûŽúŠù‰ø÷…ù…ö…õ€ô¤íûŽúŠùˆø‡÷‡ö„õôó¤í’ûŽúŠù‡øˆ÷…ö„õô¤í”ûŽúˆù‰ø‡÷†ö‚õó¤í€ü“ûŽú‰ùˆø‡÷…öõó¤í‚ü”ûú‰ùˆø†÷†öõõò¤íˆüûúˆù‰ø†÷†öò¤îŠüûŽúˆù‡ø‡÷„öñ¤îüûúû‹úˆùˆø‡÷‚öð¤îüûú‡ùˆø†÷öð¤îƒüý„üý…üƒûÿüûüûü€ûú€û üûöÝÔÔßòûûùúùùøùù‚øùùø÷ø÷÷ø÷ööî¤ï“ýüƒûÿûƒ€WÛüº€WúûüüãŽ\‚Woûúúÿÿú‡ù†ø÷÷î¤ï•ý‚ûÿûƒ€W¯üŽ€WúûüÕ_WWƒ¤©“xWûúúÿÿƒú‡ù†øí¤ï•ý‚ûÿûƒ€WxüWúûñgWZÍ‚üéûúúÿÿ…ú†ù…øí¤ïþþ“ý‚ûÿûƒWmWWæüüÅWbWWúü°WWž…üúúÿÿ‡ú†ùƒøì¤ï‚þý‚ûÿûƒW¤WW»üü™W™WWúü{WWä…üúúÿÿ‡úˆùøë¤ïˆþŠý‚ûÿûƒW°xWŽýýbx¯WWúü_Wb†üúúÿÿûû‡ú‡ù€øë¤ð‹þ‡ý‚ûÿûƒW°°WWòÆW°°WWúüWWm†üúúÿÿû‡ú†ùøøë¤ðþ…ý‚ûÿûƒW°çWWƤWç°WWúü_Wbýý„üúúÿÿƒû‡ú†ùë¤ðþƒýûÿûƒW°ýmW™mmý°WWúü{WWâ€ýƒüúÿÿ…û†ú…ùê¤ð“þ€ýûÿûƒW°ý¤WbW¤ý°WWúü°WWœ‚ýüúÿÿ†û†ú„ùê¤ð•þýûÿûƒW°ýÜ€W Üý°WWúúòjWWµ‚ýÈîüúÿÿˆû†ú‚ùë¤ð–þû ÿûƒW°ýýmWmýý°WWúúýÖ_WWsŸª—pWçúúÿÿ‰û†úùë¤ð–þûÿû„W°ýýÜÑÜýý°WWúúýýäŽ\Wb’õúúÿÿü‰û‡úùùë¤ð•þ‚ûÿûþþ‰ýúýøß××ê€ý…üˆû†úùë¤ðŸþý‹üˆû†úë¤ð¡þý‹üˆû„úë¤ðÿ£þýŠüˆûƒúë¤ðÿ¢þýŠü‡û‚úì¤ð„ÿþÿŸþŽýŠü‡ûúìÿÿÿÿÿÿÿÿt8mk@    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúé°N   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÅI#  ,ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø~A  %6ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûƒV  *>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿó˜B .EÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿãÓC 1IÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáòB 3KÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúòC 3LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòB 3LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóB 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóB 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóB 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòìB 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëÈB 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿó£( 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿê„3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²v 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷l% 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨< 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÚO3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøW# 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ]( 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^, 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^/3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^13Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ[23MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿY33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿX33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿV33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿS33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿR33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQ33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿP33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿN33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33KÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿK31IÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿI1.EÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿE. *>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ>*  %6I[itz~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~zti[I6%  ,;IU]befffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb]UI;,   ,6>EIKLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLKIE>6,  %*.133333333333333333333333333333333333333333333333333333333333333333333333333333331.*%    golly-2.7-src/gui-wx/icons/appicon.ico0000755000175000017500000000525612536111364014713 00000000000000(6 è^00hF( Àÿÿÿ{{{{{{{{{½½½{{{ÿÿÿÿÿÿÿÿÿîîîîîîîîé™î™™™™žé™î™™™™žé™î™™™™žé™îîîîîîé™îîîîîîé™îîîé™îîîé™îîîé™îîîîîîîîîîîîî陙™™î™žé™™™™î™žé™™™™î™žîîîîîîîî¬ç8ì`|œÐÿþ°( @€ÿÿÿ{{{{{{{{{½½½{{{ÿÿÿÿÿÿÿÿÿîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîéž™îî™éž™éž™éžîîéž™îî™éž™éž™éžîîîîîîîîîîîîîîîîîîéž™îî™éž™éž™éžîîéž™îî™éž™éž™éžîîîîîîîîîîîîîîîîîîéž™îîîîîîîîîîîîîéž™îîîîîîîîîîîîîîîîîîîîîîîîîîîîîéž™îîîîîîîî™éžîîéž™îîîîîîîî™éžîîîîîîîîîîîîîîîîîîéž™îîîîîîîî™éžîîéž™îîîîîîîî™éžîîîîîîîîîîîîîîîîîîéž™îîîîîîîî™éžîîéž™îîîîîîîî™éžîîîîîîîîîîîîîîîîîîîîîîîîîîîîî™éžîîîîîîîîîîîîî™éžîîîîîîîîîîîîîîîîîî鞙鞙鞙îî™éžîî鞙鞙鞙îî™éžîîîîîîîîîîîîîîîîîî鞙鞙鞙îî™éžîî鞙鞙鞙îî™éžîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî(0`ÿÿÿ{{{{{{{{{½½½{{{ÿÿÿÿÿÿÿÿÿîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™îîîîîîîîîîîîîîîîîîîîîîîîî陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™îîîîîîîîîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîî陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîî陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîtîîîîîîîîîîî™îî™îî™îî™îîîîîîîî™îî™îî™îî™îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîgolly-2.7-src/gui-wx/icons/app.icns0000644000175000017500000012673712536111364014231 00000000000000icns­ßics#His32[Žÿ† ÿÿ€ ÿÿ† ÿÿ€ ÿÿ† ÿÿ€ Šÿ€ Šÿ€ ÿÿ€ …ÿ€ ÿÿ€ …ÿ€ ÿÿ€ …ÿ€ ÿÿ€ …ÿ€ ÿÿ€ Šÿ€ Šÿ€ ÿÿ† ÿÿ€ ÿÿ† ÿÿ€ ÿÿ† ŽÿŽÿ†2ÿÿ€2ÿÿ†2ÿÿ€2ÿÿ†2ÿÿ€2Šÿ€2Šÿ€2ÿÿ€2…ÿ€2ÿÿ€2…ÿ€2ÿÿ€2…ÿ€2ÿÿ€2…ÿ€2ÿÿ€2Šÿ€2Šÿ€2ÿÿ†2ÿÿ€2ÿÿ†2ÿÿ€2ÿÿ†2ŽÿŽ#†ÿ##€ÿ##†ÿ##€ÿ##†ÿ##€ÿŠ#€ÿŠ#€ÿ##€ÿ…#€ÿ##€ÿ…#€ÿ##€ÿ…#€ÿ##€ÿ…#€ÿ##€ÿŠ#€ÿŠ#€ÿ##†ÿ##€ÿ##†ÿ##€ÿ##†ÿŽ#s8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿICN#?ÿÿüÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþ?ÿÿü?ÿÿüÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþÿÿþ?ÿÿüil32‡Ÿ™ÿ€›ÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿ›ÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿ›ÿ”ÿ ÿ ÿÿ”ÿ ÿ ÿÿ›ÿÿÿ ÿ ÿ ÿ ÿÿÿÿ ÿ ÿ ÿ ÿÿ›ÿÿÿ ÿ ÿ ÿ ÿÿÿÿ ÿ ÿ ÿ ÿÿ›ÿÿÿ ÿ ÿ ÿ ÿÿÿÿ ÿ ÿ ÿ ÿÿ›ÿÿÿ ÿ ”ÿÿÿ ÿ ”ÿ›ÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿ›ÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿÿ›ÿ€™ÿŸŸ™ÿ€›ÿÿÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿÿÿÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿÿ›ÿÿÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿÿÿÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿÿ›ÿ”ÿ22ÿ22ÿÿ”ÿ22ÿ22ÿÿ›ÿÿÿ22ÿ22ÿ22ÿ22ÿÿÿÿ22ÿ22ÿ22ÿ22ÿÿ›ÿÿÿ22ÿ22ÿ22ÿ22ÿÿÿÿ22ÿ22ÿ22ÿ22ÿÿ›ÿÿÿ22ÿ22ÿ22ÿ22ÿÿÿÿ22ÿ22ÿ22ÿ22ÿÿ›ÿÿÿ22ÿ22”ÿÿÿ22ÿ22”ÿ›ÿÿÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿÿÿÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿÿ›ÿÿÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿÿÿÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿ22ÿÿ›ÿ€™ÿŸŸ™#€›###ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ####ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ##›###ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ####ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ##›#”#ÿÿ#ÿÿ##”#ÿÿ#ÿÿ##›###ÿÿ#ÿÿ#ÿÿ#ÿÿ####ÿÿ#ÿÿ#ÿÿ#ÿÿ##›###ÿÿ#ÿÿ#ÿÿ#ÿÿ####ÿÿ#ÿÿ#ÿÿ#ÿÿ##›###ÿÿ#ÿÿ#ÿÿ#ÿÿ####ÿÿ#ÿÿ#ÿÿ#ÿÿ##›###ÿÿ#ÿÿ”###ÿÿ#ÿÿ”#›###ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ####ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ##›###ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ####ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ#ÿÿ##›#€™#Ÿl8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿich#Hÿÿÿÿð?ÿÿÿÿü?ÿÿÿÿüÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþ?ÿÿÿÿü?ÿÿÿÿüÿÿÿÿðÿÿÿÿð?ÿÿÿÿü?ÿÿÿÿüÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþÿÿÿÿþ?ÿÿÿÿü?ÿÿÿÿüÿÿÿÿðih32ú®ÿÿ£ùÿÿ€úü¥ÿüúüÿ¥ýÿü€ùÿ€ýþÿÿýþÿÿýþÿÿýýÿÿþýÿÿþýÿÿþ‚ý€ÿý€ÿ€ý!ÿùùÿýýþøÔáÿúÖßþýÚÙýþÝØûÿãÔøÿåÓõÿ€ýÿïÐíÿñÒêÿýýÿùùÿýþöŠ@;³=9­¨H2šªE4޾S0}½Q5lòþýÿãi7RÇm9HÓÿýÿùùÿýÿÕ4C;3B>EA.<;(%S9) C38Åÿýÿ¢-> S)E ÿýÿùùÿýÿâ3[>[THSA‘ÿýÿùùÿýÿÐ!@:NôÿŽýÿš^ÿýÿùùÿýþúˆ ;Á¢(1²ÿþŽýÿæ_ZÖwKÖÿýÿùùÿýýÿÀVnçÈZgÜÿýþúLô§O„ôþýÿùùÿýÿâLG_MCgûÿŽýÿ·>@x:FšÿýÿùùÿýÿÖ#9)IõÿŽýÿ¡S}ÿýÿùùÿýþ÷1¯ˆ)§ÿþŽýÿáWLÄ\AÎÿýÿùùÿýýÿÉXrðÕ[gãÿýþÿ£N•ü²K‰øþýÿùùÿýÿáUFleDoûÿŽýÿºG<‰LB ÿýÿùùÿýÿË"$87#JóÿŽýÿ”U!#|ÿýÿùùÿýþóe ¢„–ÿþŽýÿÕ95ºQ'ÁÿýÿùùÿýýÿÎ]}ôØeuèÿýÿâ½ßÿëÁÙÿýýÿùùÿýÿê_B |b> }þþý€ÿý€ÿ€ýÿùùÿýÿÓ%)2((Eôÿšýÿùùÿýÿð_j Œÿþýý…ÿþ€ÿþ€ÿý€ÿþ€ÿ/þýýÿùùÿýýÿÐStùÕUlêÿýýÿò®¦êú¹Ÿâý¼žÜÿÊ›ÒÿÏœÊÿÔÀýÿùùÿýÿíjF,‰oB+Šÿþýý…:(fšC&U”?/H©J.<¢S4- M7)·ÿýÿùùÿýÿÒ*3 3+3 Eóÿýö?-J+;), T%(J+/K5xÿýÿùùÿýÿíN ‚[þÿýýy[L‹;£ //š/°ÿýÿùùÿýýÿÐaö×btéÿýýÿêtaÙ÷†]Éü‹WÀÿ W®ÿ¬W£ÿ¶T•ûþýÿùùÿýÿïxC(™‰@(”ÿþýþ¢F,t¦P)`¯P2V³Z2E°c87´h:4ÀÿýÿùùÿýÿË*9 7:7 IóÿýøP1 D3I/.M-)>1/T)8|ÿýÿùùÿýÿå:rZpüÿýýzKy=…,‹%". ¢ÿýÿùùÿýýÿÏ|“ñ݇Œåÿýýÿë•€×ò–zÌù¦zÂúªv·û´u®ûÄ|¡öþýÿùùÿ€ý…ÿý…ÿþ€ÿþ€ÿþ€ÿþ€ÿþýýÿù€üÿ¥ýÿüúü¥ÿüú€ÿÿ£ùÿÿ®®ÿÿ£ùÿÿ€úü¥ÿüúüÿ¥ýÿü€ùÿ€ýþÿÿýýÿÿýþÿÿþýÿÿþýÿÿþýÿÿþ‚ý€ÿýþÿÿ€ý!ÿùùÿýýþúßèÿûáçþýäâþþæâüÿêÞùÿìÞ÷þ€ýÿòÜðÿõÝïÿýýÿùùÿýþùªvh¿®uj½À}d«Àzi¥Ï…e”Ì‚lŒóþýÿé“nvЕqsÛÿýÿùùÿýÿßjuBahuJ^suLTlp[K{qYIpjj:Ìÿýÿ¹en8v`u;”ÿýÿùùÿýÿéY/#oc,"ls1!\t0%Q†5$G7)5ÕÿýÿÅ?+'ˆF,% ÿýÿùùÿýýÿÂasæÈUfÞÛleÑàfUÈì~\¶ï{M¬ÿþýþûŸWó¥K„óþýÿùùÿýþú¹ƒuÊăvÄË‹pµÓŒt¯×”q Ü—u™óÿýÿî¥yƒÜ­{‚Þÿýÿùù`ÿýÿÜit8dxtEdrvBR}rTPzsPCpb=Ðÿýÿµhg1lr9›ÿýÿùùÿýÿàO*ig.bg.Tx1#Ix1@:(.Òÿýÿ¹<($…I1 ™ÿýÿùùÿ€ý\±YnÛÃkkÍÌc`ÆÙvd¶ÞrV®ç…b›ùýýÿõF‡í¤Wzèÿýÿùùÿýýþÿôùÿÿøùÿÿ÷÷ÿÿû÷ÿÿùôÿÿýöÿþýýÿô§s‘å¬wìÿýÿùùÿ€ýþÿÿýýÿÿýýÿÿýýÿÿþýÿÿþýÿÿþ€ýÿÀnu?‚h|Bžÿýÿùùÿ›ýÿ¼?4$zD8#”ÿýÿùùÿýýþÿùýÿÿúüÿýÿò‡GvàŒ;käÿýÿùùÿ€ýÊ‹ÞÔŽ‰×ÿýþù³z™ï¼z•îÿýÿùùÿýÿâux=rƒxGzùÿŽýÿ¿rm8ŽvvA¥ÿýÿùùÿýÿÚN?%\d@%föÿŽýÿ±B8$xLA$“ÿýÿùùÿýþú—6LÈ®GHµÿþŽýÿër0iÛ‰A[ØÿýÿùùÿýýÿÐ~‹êÖ…Šâÿýþû´u¥ó½|Ÿöþýÿùùÿýÿè}L}}{RƒúÿŽýÿÊvvG’p{J¬ÿýÿùùÿýÿßSG*YYG*`õÿŽýÿ¶EB&qGH%ÿýÿùùÿýþù?F´™4<®ÿþŽýÿæm9ZÈs/QÒÿýÿùùÿýýÿ×ñÞ†æÿýþÿ»x¨üÃsŸùþýÿùùÿýÿè„}G„‘|PˆûþŽýÿË|qEŸyL±ÿýÿùùÿýÿ×RQ,WeR/eõÿŽýÿ¬MH(rTR*ÿýÿùùÿýþõ|%4­•3/ÿþŽýÿÝUIÃl-<ÄÿýÿùùÿýýÿØ}“õàˆ‘ëÿýÿåÁáÿìËÝÿýýÿùùÿýÿïzS“xW–ýþý€ÿý€ÿ€ýÿùùÿýÿÜYY3W[Y5_ôÿšýÿùùÿýþôw23˜‚+,–þþýýÿþ€ÿþ€ÿþ€ÿý€ÿþ€ÿ/þýýÿùùÿýýÿ×yŽøÝt„ëÿýýþõļïû˸çýϸäÿ×µÛÿܵÖþà·Ò€ýÿùùÿýÿñ•~]ž–|`¡þþýý¤s`…´|_u«vhn½hcµ†mZ±qZÄÿýÿùùÿýÿÜ^c8X_e"!9yŒU7mnZ2 !$ "!!\¨…*O™Œ6! %|©j%hŸw' !$ "!7ÖÿÖs¾ÿï Ž!_ðý¼oåÿÚZ!$ "!=ÒÚ¯yÂçÂx# Ž!gãÑ¡zßݲ\!$ "! +qtfCi›x:!;tbD‚žg1 !$ "!" PŠs)J”„4! +*)!,:.€!$ "!6Êÿät³ÿñy !€ ! €!$ "!?ÛëÆÆõÔr! š!,$ "! /€rBr‹rG" !!  !!!€!$ "!!M—u%C|t0!! 0im4(fn;%`qA"YsHUtM!MrX#!!$ "!4¿ûÛmªüêu !"Žùô‘†õù™xîú­qéþ³lÜþÁcÓÿÖR!$ "!?ÞðÊŠÉûÝv! !%®üä‘¥øàŸŸ÷즌ö殕ëé¼…ìôÊT!$ "!1‹¬}H~œK"!!"kž„Vh©™U]œŠaX¢£`V™¦kI’“t:!$ "!" G…f$>kc. !! 1gi5+u};$alB$f„K`†Q!NnW#!!$ "!/¶øÌ\ ûäi€!„óð‚yïì„kæøždàôŸ\Ô÷­VÈþÊH!$ "!?áïÁ‚ÎùÙ†# !%´ûÝ ¬úÙ”¡øä²–øá£Žîå±ïðÊe!$ "!2—šX‹¸ŽL# !$zµ™Yr¦Šfl°¥ea¦Žq]¡’wY£²|>!$ "€!6=:&5[I' €! -VQ**?:0&OW1%>:6$>:5$A[?"!!$ "€!€!!" !   ! !€!€!$€#¥!$ %£$% ƒ"£ "±h8mk `^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^`h¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼h¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ`^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ`¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼h¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼h`^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^`it32ACÿÿÿþïÿ‰óÿ‡óÿ†õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…Šÿ§h?§‚ÿ§W(O§‚ÿ§h?§‚ÿ§W(O§‚ÿ§h?§‚ÿ§W(O§ÿ§h?§‚ÿ§W(O§Šÿ…‰ÿ§h€ÿh€h€ÿ§h€ÿh€h€ÿ§h€ÿh€h‹ÿ§h€ÿh€h‰ÿ…ˆÿ@§WhFhÿ§OhO§ÿ§WhFhÿ§OhO§ÿ§WhFhÿ§OhO§‰ÿ§WhFhÿ§OhO§ˆÿ…ˆÿ@OFz‹h(ÿFz‹z((ÿOFz‹h(ÿFz‹z((ÿOFz‹h(ÿFz‹z((‰ÿOFz‹h(ÿFz‹z((ˆÿ…ˆÿ@(7hhFÿ((hhF(ÿ(7hhFÿ((hhF(ÿ(7hhFÿ((hhF(‰ÿ(7hhFÿ((hhF(ˆÿ…ˆÿ(7€ÿ(7ÿ(7€ÿ(7ÿ(7€ ÿ(7‰ÿ(7€ ÿ(7ˆÿ…ˆÿ?ƒÿƒÿ?ƒÿƒÿ?ƒÿƒ‰ÿ?ƒÿƒˆÿ…ˆÿ§hÿh€hÿ§hÿh€hÿ§hÿh€h‰ÿ§hÿh€hˆÿ…‰ÿh€ÿ?€(€ÿh€ÿ?€(€ÿh€ÿ?€(‹ÿh€ÿ?€(‰ÿ…Šÿ§h‚ÿhh‚ÿ§h‚ÿhh‚ÿ§h‚ÿhhÿ§h‚ÿhhŠÿ…õÿ…Šÿ§F((7§‚ÿ§h?§‚ÿ§F((7§‚ÿ§h?§‚ÿ§F((7§‚ÿ§h?§ÿ§F((7§‚ÿ§h?§Šÿ…‰ÿ§(?€ÿ§h€ÿ§(?€ÿ§h€ÿ§(?€ÿ§h‹ÿ§(?€ÿ§h‰ÿ…ˆÿ@§(hhFhÿ§WhFhÿ§(hhFhÿ§WhFhÿ§(hhFhÿ§WhFh‰ÿ§(hhFhÿ§WhFhˆÿ…ˆÿ@(h‹zFÿOFz‹h(ÿ(h‹zFÿOFz‹h(ÿ(h‹zFÿOFz‹h(‰ÿ(h‹zFÿOFz‹h(ˆÿ…ˆÿ@FhW7(ÿ(7hhFÿFhW7(ÿ(7hhFÿFhW7(ÿ(7hhF‰ÿFhW7(ÿ(7hhFˆÿ…ˆÿ((!ÿ(7€ÿ((!ÿ(7€ÿ((!ÿ(7€‰ÿ((!ÿ(7€ˆÿ…ˆÿ ÿ?ƒÿÿ?ƒÿÿ?ƒ‰ÿ ÿ?ƒˆÿ…ˆÿ@§?ÿ§hÿ§?ÿ§hÿ§?ÿ§h‰ÿ§?ÿ§hˆÿ…‰ÿ?€(€ÿh€ÿ?€(€ÿh€ÿ?€(€ÿh‹ÿ?€(€ÿh‰ÿ…Šÿ§h‚ÿ§h‚ÿ§h‚ÿ§h‚ÿ§h‚ÿ§hÿ§h‚ÿ§hŠÿ…õÿ…×ÿ§h?§‚ÿ§W(O§Šÿ…Öÿ§h€ÿh€h‰ÿ…Õÿ§WhFhÿ§OhO§ˆÿ…ÕÿOFz‹h(ÿFz‹z((ˆÿ…Õÿ(7hhFÿ((hhF(ˆÿ…Õÿ(7€ ÿ(7ˆÿ…Õÿ?ƒÿƒˆÿ…Õÿ§hÿh€hˆÿ…Öÿh€ÿ?€(‰ÿ…×ÿ§h‚ÿhhŠÿ…õÿ…Šÿ§F((7§‚ÿ§h?§¹ÿ§F((7§‚ÿ§h?§Šÿ…‰ÿ§(?€ÿ§h·ÿ§(?€ÿ§h‰ÿ…ˆÿ§(hhFhÿ§WhFhµÿ§(hhFhÿ§WhFhˆÿ…ˆÿ(h‹zFÿOFz‹h(µÿ(h‹zFÿOFz‹h(ˆÿ…ˆÿFhW7(ÿ(7hhFµÿFhW7(ÿ(7hhFˆÿ…ˆÿ((!ÿ(7€µÿ((!ÿ(7€ˆÿ…ˆÿ ÿ?ƒµÿ ÿ?ƒˆÿ…ˆÿ§?ÿ§hµÿ§?ÿ§hˆÿ…‰ÿ?€(€ÿh·ÿ?€(€ÿh‰ÿ…Šÿ§h‚ÿ§h¹ÿ§h‚ÿ§hŠÿ…õÿ…Šÿ§h?§‚ÿ§W(O§¹ÿ§h?§‚ÿ§W(O§Šÿ…‰ÿ§h€ÿh€h·ÿ§h€ÿh€h‰ÿ…ˆÿ§WhFhÿ§OhO§µÿ§WhFhÿ§OhO§ˆÿ…ˆÿOFz‹h(ÿFz‹z((µÿOFz‹h(ÿFz‹z((ˆÿ…ˆÿ(7hhFÿ((hhF(µÿ(7hhFÿ((hhF(ˆÿ…ˆÿ(7€ ÿ(7µÿ(7€ ÿ(7ˆÿ…ˆÿ?ƒÿƒµÿ?ƒÿƒˆÿ…ˆÿ§hÿh€hµÿ§hÿh€hˆÿ…‰ÿh€ÿ?€(·ÿh€ÿ?€(‰ÿ…Šÿ§h‚ÿhh¹ÿ§h‚ÿhhŠÿ…õÿ…Šÿ§F((7§‚ÿ§h?§¹ÿ§F((7§‚ÿ§h?§Šÿ…‰ÿ§(?€ÿ§h·ÿ§(?€ÿ§h‰ÿ…ˆÿ§(hhFhÿ§WhFhµÿ§(hhFhÿ§WhFhˆÿ…ˆÿ(h‹zFÿOFz‹h(µÿ(h‹zFÿOFz‹h(ˆÿ…ˆÿFhW7(ÿ(7hhFµÿFhW7(ÿ(7hhFˆÿ…ˆÿ((!ÿ(7€µÿ((!ÿ(7€ˆÿ…ˆÿ ÿ?ƒµÿ ÿ?ƒˆÿ…ˆÿ§?ÿ§hµÿ§?ÿ§hˆÿ…‰ÿ?€(€ÿh·ÿ?€(€ÿh‰ÿ…Šÿ§h‚ÿ§h¹ÿ§h‚ÿ§hŠÿ…õÿ…Šÿ§h?§‚ÿ§W(O§×ÿ…‰ÿ§h€ÿh€hÖÿ…ˆÿ§WhFhÿ§OhO§Õÿ…ˆÿOFz‹h(ÿFz‹z((Õÿ…ˆÿ(7hhFÿ((hhF(Õÿ…ˆÿ(7€ ÿ(7Õÿ…ˆÿ?ƒÿƒÕÿ…ˆÿ§hÿh€hÕÿ…‰ÿh€ÿ?€(Öÿ…Šÿ§h‚ÿhh×ÿ…õÿ…Šÿ§h?§‚ÿ§W(O§ÿ§W(O§‚ÿ§h?§‚ÿ§W(O§‚ÿ§h?§‚ÿ§h?§‚ÿ§W(O§Šÿ…‰ÿ§h€ÿh€h‹ÿh€h€ÿ§h€ÿh€h€ÿ§h€ÿ§h€ÿh€h‰ÿ…ˆÿ§WhFhÿ§OhO§‰ÿ@§OhO§ÿ§WhFhÿ§OhO§ÿ§WhFhÿ§WhFhÿ§OhO§ˆÿ…ˆÿOFz‹h(ÿFz‹z((‰ÿ@Fz‹z((ÿOFz‹h(ÿFz‹z((ÿOFz‹h(ÿOFz‹h(ÿFz‹z((ˆÿ…ˆÿ(7hhFÿ((hhF(‰ÿ@((hhF(ÿ(7hhFÿ((hhF(ÿ(7hhFÿ(7hhFÿ((hhF(ˆÿ…ˆÿ(7€ ÿ(7‰ÿ(7ÿ(7€ÿ(7ÿ(7€ÿ(7€ ÿ(7ˆÿ…ˆÿ?ƒÿƒ‰ÿƒÿ?ƒÿƒÿ?ƒÿ?ƒÿƒˆÿ…ˆÿ§hÿh€h‰ÿh€hÿ§hÿh€hÿ§hÿ§hÿh€hˆÿ…‰ÿh€ÿ?€(‹ÿ?€(€ÿh€ÿ?€(€ÿh€ÿh€ÿ?€(‰ÿ…Šÿ§h‚ÿhhÿhh‚ÿ§h‚ÿhh‚ÿ§h‚ÿ§h‚ÿhhŠÿ…õÿ…Šÿ§F((7§‚ÿ§h?§ÿ§h?§‚ÿ§F((7§‚ÿ§h?§‚ÿ§F((7§‚ÿ§F((7§‚ÿ§h?§Šÿ…‰ÿ§(?€ÿ§h‹ÿ§h€ÿ§(?€ÿ§h€ÿ§(?€ÿ§(?€ÿ§h‰ÿ…ˆÿ§(hhFhÿ§WhFh‰ÿ@§WhFhÿ§(hhFhÿ§WhFhÿ§(hhFhÿ§(hhFhÿ§WhFhˆÿ…ˆÿ(h‹zFÿOFz‹h(‰ÿ@OFz‹h(ÿ(h‹zFÿOFz‹h(ÿ(h‹zFÿ(h‹zFÿOFz‹h(ˆÿ…ˆÿFhW7(ÿ(7hhF‰ÿ@(7hhFÿFhW7(ÿ(7hhFÿFhW7(ÿFhW7(ÿ(7hhFˆÿ…ˆÿ((!ÿ(7€‰ÿ(7€ÿ((!ÿ(7€ÿ((!ÿ((!ÿ(7€ˆÿ…ˆÿ ÿ?ƒ‰ÿ?ƒÿÿ?ƒÿÿÿ?ƒˆÿ…ˆÿ§?ÿ§h‰ÿ@§hÿ§?ÿ§hÿ§?ÿ§?ÿ§hˆÿ…‰ÿ?€(€ÿh‹ÿh€ÿ?€(€ÿh€ÿ?€(€ÿ?€(€ÿh‰ÿ…Šÿ§h‚ÿ§hÿ§h‚ÿ§h‚ÿ§h‚ÿ§h‚ÿ§h‚ÿ§hŠÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ†óÿ‡óÿ‰ïÿÿÿÿþÿÿÿþïÿ‰óÿ‡óÿ†õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…Šÿ»‹O?h°‚ÿ»‹?Oz»‚ÿ»‹O?h°‚ÿ»‹?Oz»‚ÿ»‹O?h°‚ÿ»‹?Oz»ÿ»‹O?h°‚ÿ»‹?Oz»Šÿ…‰ÿ°F€WF7q€ÿ‹?€W?7q€ÿ°F€WF7q€ÿ‹?€W?7q€ÿ°F€WF7q€ÿ‹?€W?7q‹ÿ°F€WF7q€ÿ‹?€W?7q‰ÿ…ˆÿ@»?h‹žzW7(qÿ°7WzžzW77°ÿ»?h‹žzW7(qÿ°7WzžzW77°ÿ»?h‹žzW7(qÿ°7WzžzW77°‰ÿ»?h‹žzW7(qÿ°7WzžzW77°ˆÿ…ˆÿ@zWz§°‹O77Fÿ?Wz§°žW?7FÿzWz§°‹O77Fÿ?Wz§°žW?7FÿzWz§°‹O77Fÿ?Wz§°žW?7F‰ÿzWz§°‹O77Fÿ?Wz§°žW?7Fˆÿ…ˆÿ@Ohh‹žhF7F7ÿ7hW‹žzW7(ÿOhh‹žhF7F7ÿ7hW‹žzW7(ÿOhh‹žhF7F7ÿ7hW‹žzW7(‰ÿOhh‹žhF7F7ÿ7hW‹žzW7(ˆÿ…ˆÿ@?FFWW?7(7(ÿ?FFWWF77(ÿ?FFWW?7(7(ÿ?FFWWF77(ÿ?FFWW?7(7(ÿ?FFWWF77(‰ÿ?FFWW?7(7(ÿ?FFWWF77(ˆÿ…ˆÿ_‚7(!!ÿ0‚7((!ÿ_‚7(!!ÿ0‚7((!ÿ_‚7(!!ÿ0‚7((!‰ÿ_‚7(!!ÿ0‚7((!ˆÿ…ˆÿ»!(hÿq0?(qÿ»!(hÿq0?(qÿ»!(hÿq0?(q‰ÿ»!(hÿq0?(qˆÿ…‰ÿq!70!€ÿW‚0€ÿq!70!€ÿW‚0€ÿq!70!€ÿW‚0‹ÿq!70!€ÿW‚0‰ÿ…Šÿ§07((h‚ÿq!!q‚ÿ§07((h‚ÿq!!q‚ÿ§07((h‚ÿq!!qÿ§07((h‚ÿq!!qŠÿ…õÿ…Šÿ»‚OO_°‚ÿ»‹O?h°‚ÿ»‚OO_°‚ÿ»‹O?h°‚ÿ»‚OO_°‚ÿ»‹O?h°ÿ»‚OO_°‚ÿ»‹O?h°Šÿ…‰ÿ»?hhW?(W€ÿ°F€WF7q€ÿ»?hhW?(W€ÿ°F€WF7q€ÿ»?hhW?(W€ÿ°F€WF7q‹ÿ»?hhW?(W€ÿ°F€WF7q‰ÿ…ˆÿ@»Fh‹žzF70qÿ»?h‹žzW7(qÿ»Fh‹žzF70qÿ»?h‹žzW7(qÿ»Fh‹žzF70qÿ»?h‹žzW7(q‰ÿ»Fh‹žzF70qÿ»?h‹žzW7(qˆÿ…ˆÿ@OW‹°§zF(7!ÿzWz§°‹O77FÿOW‹°§zF(7!ÿzWz§°‹O77FÿOW‹°§zF(7!ÿzWz§°‹O77F‰ÿOW‹°§zF(7!ÿzWz§°‹O77Fˆÿ…ˆÿ@?Fzž‹W7(W(ÿOhh‹žhF7F7ÿ?Fzž‹W7(W(ÿOhh‹žhF7F7ÿ?Fzž‹W7(W(ÿOhh‹žhF7F7‰ÿ?Fzž‹W7(W(ÿOhh‹žhF7F7ˆÿ…ˆÿ@7?WWF70(7!ÿ?FFWW?7(7(ÿ7?WWF70(7!ÿ?FFWW?7(7(ÿ7?WWF70(7!ÿ?FFWW?7(7(‰ÿ7?WWF70(7!ÿ?FFWW?7(7(ˆÿ…ˆÿ‚7((ÿ_‚7(!!ÿ‚7((ÿ_‚7(!!ÿ‚7((ÿ_‚7(!!‰ÿ‚7((ÿ_‚7(!!ˆÿ…ˆÿ§(!?!Wÿ»!(hÿ§(!?!Wÿ»!(hÿ§(!?!Wÿ»!(h‰ÿ§(!?!Wÿ»!(hˆÿ…‰ÿW€0€ÿq!70!€ÿW€0€ÿq!70!€ÿW€0€ÿq!70!‹ÿW€0€ÿq!70!‰ÿ…Šÿ§h‚ÿ§07((h‚ÿ§h‚ÿ§07((h‚ÿ§h‚ÿ§07((hÿ§h‚ÿ§07((hŠÿ…õÿ…×ÿ»‹O?h°‚ÿ»‹?Oz»Šÿ…Öÿ°F€WF7q€ÿ‹?€W?7q‰ÿ…Õÿ»?h‹žzW7(qÿ°7WzžzW77°ˆÿ…ÕÿzWz§°‹O77Fÿ?Wz§°žW?7Fˆÿ…ÕÿOhh‹žhF7F7ÿ7hW‹žzW7(ˆÿ…Õÿ?FFWW?7(7(ÿ?FFWWF77(ˆÿ…Õÿ_‚7(!!ÿ0‚7((!ˆÿ…Õÿ»!(hÿq0?(qˆÿ…Öÿq!70!€ÿW‚0‰ÿ…×ÿ§07((h‚ÿq!!qŠÿ…õÿ…Šÿ»‚OO_°‚ÿ»‹O?h°¹ÿ»‚OO_°‚ÿ»‹O?h°Šÿ…‰ÿ»?hhW?(W€ÿ°F€WF7q·ÿ»?hhW?(W€ÿ°F€WF7q‰ÿ…ˆÿ»Fh‹žzF70qÿ»?h‹žzW7(qµÿ»Fh‹žzF70qÿ»?h‹žzW7(qˆÿ…ˆÿOW‹°§zF(7!ÿzWz§°‹O77FµÿOW‹°§zF(7!ÿzWz§°‹O77Fˆÿ…ˆÿ?Fzž‹W7(W(ÿOhh‹žhF7F7µÿ?Fzž‹W7(W(ÿOhh‹žhF7F7ˆÿ…ˆÿ7?WWF70(7!ÿ?FFWW?7(7(µÿ7?WWF70(7!ÿ?FFWW?7(7(ˆÿ…ˆÿ‚7((ÿ_‚7(!!µÿ‚7((ÿ_‚7(!!ˆÿ…ˆÿ§(!?!Wÿ»!(hµÿ§(!?!Wÿ»!(hˆÿ…‰ÿW€0€ÿq!70!·ÿW€0€ÿq!70!‰ÿ…Šÿ§h‚ÿ§07((h¹ÿ§h‚ÿ§07((hŠÿ…õÿ…Šÿ»‹O?h°‚ÿ»‹?Oz»¹ÿ»‹O?h°‚ÿ»‹?Oz»Šÿ…‰ÿ°F€WF7q€ÿ‹?€W?7q·ÿ°F€WF7q€ÿ‹?€W?7q‰ÿ…ˆÿ»?h‹žzW7(qÿ°7WzžzW77°µÿ»?h‹žzW7(qÿ°7WzžzW77°ˆÿ…ˆÿzWz§°‹O77Fÿ?Wz§°žW?7FµÿzWz§°‹O77Fÿ?Wz§°žW?7Fˆÿ…ˆÿOhh‹žhF7F7ÿ7hW‹žzW7(µÿOhh‹žhF7F7ÿ7hW‹žzW7(ˆÿ…ˆÿ?FFWW?7(7(ÿ?FFWWF77(µÿ?FFWW?7(7(ÿ?FFWWF77(ˆÿ…ˆÿ_‚7(!!ÿ0‚7((!µÿ_‚7(!!ÿ0‚7((!ˆÿ…ˆÿ»!(hÿq0?(qµÿ»!(hÿq0?(qˆÿ…‰ÿq!70!€ÿW‚0·ÿq!70!€ÿW‚0‰ÿ…Šÿ§07((h‚ÿq!!q¹ÿ§07((h‚ÿq!!qŠÿ…õÿ…Šÿ»‚OO_°‚ÿ»‹O?h°¹ÿ»‚OO_°‚ÿ»‹O?h°Šÿ…‰ÿ»?hhW?(W€ÿ°F€WF7q·ÿ»?hhW?(W€ÿ°F€WF7q‰ÿ…ˆÿ»Fh‹žzF70qÿ»?h‹žzW7(qµÿ»Fh‹žzF70qÿ»?h‹žzW7(qˆÿ…ˆÿOW‹°§zF(7!ÿzWz§°‹O77FµÿOW‹°§zF(7!ÿzWz§°‹O77Fˆÿ…ˆÿ?Fzž‹W7(W(ÿOhh‹žhF7F7µÿ?Fzž‹W7(W(ÿOhh‹žhF7F7ˆÿ…ˆÿ7?WWF70(7!ÿ?FFWW?7(7(µÿ7?WWF70(7!ÿ?FFWW?7(7(ˆÿ…ˆÿ‚7((ÿ_‚7(!!µÿ‚7((ÿ_‚7(!!ˆÿ…ˆÿ§(!?!Wÿ»!(hµÿ§(!?!Wÿ»!(hˆÿ…‰ÿW€0€ÿq!70!·ÿW€0€ÿq!70!‰ÿ…Šÿ§h‚ÿ§07((h¹ÿ§h‚ÿ§07((hŠÿ…õÿ…Šÿ»‹O?h°‚ÿ»‹?Oz»×ÿ…‰ÿ°F€WF7q€ÿ‹?€W?7qÖÿ…ˆÿ»?h‹žzW7(qÿ°7WzžzW77°Õÿ…ˆÿzWz§°‹O77Fÿ?Wz§°žW?7FÕÿ…ˆÿOhh‹žhF7F7ÿ7hW‹žzW7(Õÿ…ˆÿ?FFWW?7(7(ÿ?FFWWF77(Õÿ…ˆÿ_‚7(!!ÿ0‚7((!Õÿ…ˆÿ»!(hÿq0?(qÕÿ…‰ÿq!70!€ÿW‚0Öÿ…Šÿ§07((h‚ÿq!!q×ÿ…õÿ…Šÿ»‹O?h°‚ÿ»‹?Oz»ÿ»‹?Oz»‚ÿ»‹O?h°‚ÿ»‹?Oz»‚ÿ»‹O?h°‚ÿ»‹O?h°‚ÿ»‹?Oz»Šÿ…‰ÿ°F€WF7q€ÿ‹?€W?7q‹ÿ‹?€W?7q€ÿ°F€WF7q€ÿ‹?€W?7q€ÿ°F€WF7q€ÿ°F€WF7q€ÿ‹?€W?7q‰ÿ…ˆÿ»?h‹žzW7(qÿ°7WzžzW77°‰ÿ@°7WzžzW77°ÿ»?h‹žzW7(qÿ°7WzžzW77°ÿ»?h‹žzW7(qÿ»?h‹žzW7(qÿ°7WzžzW77°ˆÿ…ˆÿzWz§°‹O77Fÿ?Wz§°žW?7F‰ÿ@?Wz§°žW?7FÿzWz§°‹O77Fÿ?Wz§°žW?7FÿzWz§°‹O77FÿzWz§°‹O77Fÿ?Wz§°žW?7Fˆÿ…ˆÿOhh‹žhF7F7ÿ7hW‹žzW7(‰ÿ@7hW‹žzW7(ÿOhh‹žhF7F7ÿ7hW‹žzW7(ÿOhh‹žhF7F7ÿOhh‹žhF7F7ÿ7hW‹žzW7(ˆÿ…ˆÿ?FFWW?7(7(ÿ?FFWWF77(‰ÿ@?FFWWF77(ÿ?FFWW?7(7(ÿ?FFWWF77(ÿ?FFWW?7(7(ÿ?FFWW?7(7(ÿ?FFWWF77(ˆÿ…ˆÿ_‚7(!!ÿ0‚7((!‰ÿ0‚7((!ÿ_‚7(!!ÿ0‚7((!ÿ_‚7(!!ÿ_‚7(!!ÿ0‚7((!ˆÿ…ˆÿ»!(hÿq0?(q‰ÿq0?(qÿ»!(hÿq0?(qÿ»!(hÿ»!(hÿq0?(qˆÿ…‰ÿq!70!€ÿW‚0‹ÿW‚0€ÿq!70!€ÿW‚0€ÿq!70!€ÿq!70!€ÿW‚0‰ÿ…Šÿ§07((h‚ÿq!!qÿq!!q‚ÿ§07((h‚ÿq!!q‚ÿ§07((h‚ÿ§07((h‚ÿq!!qŠÿ…õÿ…Šÿ»‚OO_°‚ÿ»‹O?h°ÿ»‹O?h°‚ÿ»‚OO_°‚ÿ»‹O?h°‚ÿ»‚OO_°‚ÿ»‚OO_°‚ÿ»‹O?h°Šÿ…‰ÿ»?hhW?(W€ÿ°F€WF7q‹ÿ°F€WF7q€ÿ»?hhW?(W€ÿ°F€WF7q€ÿ»?hhW?(W€ÿ»?hhW?(W€ÿ°F€WF7q‰ÿ…ˆÿ»Fh‹žzF70qÿ»?h‹žzW7(q‰ÿ@»?h‹žzW7(qÿ»Fh‹žzF70qÿ»?h‹žzW7(qÿ»Fh‹žzF70qÿ»Fh‹žzF70qÿ»?h‹žzW7(qˆÿ…ˆÿOW‹°§zF(7!ÿzWz§°‹O77F‰ÿ@zWz§°‹O77FÿOW‹°§zF(7!ÿzWz§°‹O77FÿOW‹°§zF(7!ÿOW‹°§zF(7!ÿzWz§°‹O77Fˆÿ…ˆÿ?Fzž‹W7(W(ÿOhh‹žhF7F7‰ÿ@Ohh‹žhF7F7ÿ?Fzž‹W7(W(ÿOhh‹žhF7F7ÿ?Fzž‹W7(W(ÿ?Fzž‹W7(W(ÿOhh‹žhF7F7ˆÿ…ˆÿ7?WWF70(7!ÿ?FFWW?7(7(‰ÿ@?FFWW?7(7(ÿ7?WWF70(7!ÿ?FFWW?7(7(ÿ7?WWF70(7!ÿ7?WWF70(7!ÿ?FFWW?7(7(ˆÿ…ˆÿ‚7((ÿ_‚7(!!‰ÿ_‚7(!!ÿ‚7((ÿ_‚7(!!ÿ‚7((ÿ‚7((ÿ_‚7(!!ˆÿ…ˆÿ§(!?!Wÿ»!(h‰ÿ»!(hÿ§(!?!Wÿ»!(hÿ§(!?!Wÿ§(!?!Wÿ»!(hˆÿ…‰ÿW€0€ÿq!70!‹ÿq!70!€ÿW€0€ÿq!70!€ÿW€0€ÿW€0€ÿq!70!‰ÿ…Šÿ§h‚ÿ§07((hÿ§07((h‚ÿ§h‚ÿ§07((h‚ÿ§h‚ÿ§h‚ÿ§07((hŠÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ…õÿ†óÿ‡óÿ‰ïÿÿÿÿþÿÿÿþï#‰ó#‡ó#†õ#…õ#…õ#…õ#…õ#…õ#…õ#…õ#…Š#âÿë×ëÄ‚#âÿ××ÿâ‚#âÿë×ëÄ‚#âÿ××ÿâ‚#âÿë×ëÄ‚#âÿ××ÿâ#âÿë×ëÄ‚#âÿ××ÿâŠ#…‰#Äëÿ×§€#ÿ×€ÿâ×§€#Äëÿ×§€#ÿ×€ÿâ×§€#Äëÿ×§€#ÿ×€ÿâ×§‹#Äëÿ×§€#ÿ×€ÿâ×§‰#…ˆ#ââ‚ÿâ§§#Äׂÿâ×Ä#ââ‚ÿâ§§#Äׂÿâ×Ä#ââ‚ÿâ§§#Äׂÿâ×ĉ#ââ‚ÿâ§§#Äׂÿâ×Ĉ#…ˆ#ƒÿë×ו#׃ÿâÄ•#ƒÿë×ו#׃ÿâÄ•#ƒÿë×ו#׃ÿâÄ•‰#ƒÿë×ו#׃ÿâÄ•ˆ#…ˆ#ׂÿëÄ×Í#׃ÿ×Äz#ׂÿëÄ×Í#׃ÿ×Äz#ׂÿëÄ×Í#׃ÿ×Äz‰#ׂÿëÄ×Í#׃ÿ×Äzˆ#…ˆ#@Äëëÿë×ħĞ#×ÿëÿëë×Äžh#Äëëÿë×ħĞ#×ÿëÿëë×Äžh#Äëëÿë×ħĞ#×ÿëÿëë×Äžh‰#Äëëÿë×ħĞ#×ÿëÿëë×Äžhˆ#…ˆ#»€×Äħ‹‹_#‹××Ä×ħž‹O#»€×Äħ‹‹_#‹××Ä×ħž‹O#»€×Äħ‹‹_#‹××Ä×ħž‹O‰#»€×Äħ‹‹_#‹××Ä×ħž‹Oˆ#…ˆ#@âzž§§ž‹h?‚#§ž×§§žžzW§#âzž§§ž‹h?‚#§ž×§§žžzW§#âzž§§ž‹h?‚#§ž×§§žžzW§‰#âzž§§ž‹h?‚#§ž×§§žžzW§ˆ#…‰#§h‹Ä°hWO€#‹h€zWF_€#§h‹Ä°hWO€#‹h€zWF_€#§h‹Ä°hWO€#‹h€zWF_‹#§h‹Ä°hWO€#‹h€zWF_‰#…Š#°z»žz‚‚#§€?O§‚#°z»žz‚‚#§€?O§‚#°z»žz‚‚#§€?O§#°z»žz‚‚#§€?O§Š#…õ#…Š#âÿ××ëÄ‚#âÿë×ëÄ‚#âÿ××ëÄ‚#âÿë×ëÄ‚#âÿ××ëÄ‚#âÿë×ëÄ#âÿ××ëÄ‚#âÿë×ëÄŠ#…‰#ââ€ÿâÄ•€#Äëÿ×§€#ââ€ÿâÄ•€#Äëÿ×§€#ââ€ÿâÄ•€#Äëÿ×§‹#ââ€ÿâÄ•€#Äëÿ×§‰#…ˆ#â‚ÿëמ§#ââ‚ÿâ§§#â‚ÿëמ§#ââ‚ÿâ§§#â‚ÿëמ§#ââ‚ÿâ§§‰#â‚ÿëמ§#ââ‚ÿâ§§ˆ#…ˆ#ׂÿ×ÄÄ_#ƒÿë×ו#ׂÿ×ÄÄ_#ƒÿë×ו#ׂÿ×ÄÄ_#ƒÿë×ו‰#ׂÿ×ÄÄ_#ƒÿë×וˆ#…ˆ#×õ€ÿë×§ëž#ׂÿëÄ×Í#×õ€ÿë×§ëž#ׂÿëÄ×Í#×õ€ÿë×§ëž#ׂÿëÄ×͉#×õ€ÿë×§ëž#ׂÿëÄ×͈#…ˆ#@×âÿëâͰžÄ‹#Äëëÿë×ħĞ#×âÿëâͰžÄ‹#Äëëÿë×ħĞ#×âÿëâͰžÄ‹#Äëëÿë×ħЉ#×âÿëâͰžÄ‹#Äëëÿë×ħЈ#…ˆ# °××Äħžh‹?#»€×Äħ‹‹_#°××Äħžh‹?#»€×Äħ‹‹_#°××Äħžh‹?#»€×Äħ‹‹_‰# °××Äħžh‹?#»€×Äħ‹‹_ˆ#…ˆ#@°ž§§ž‹hÄz‹#âzž§§ž‹h?‚#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚‰#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚ˆ#…‰#•hzhWWzW€#§h‹Ä°hWO€#•hzhWWzW€#§h‹Ä°hWO€#•hzhWWzW€#§h‹Ä°hWO‹#•hzhWWzW€#§h‹Ä°hWO‰#…Š#°W??W‚‚#°z»žz‚‚#°W??W‚‚#°z»žz‚‚#°W??W‚‚#°z»žz‚#°W??W‚‚#°z»žz‚Š#…õ#…×#âÿë×ëÄ‚#âÿ××ÿâŠ#…Ö#Äëÿ×§€#ÿ×€ÿâ×§‰#…Õ#ââ‚ÿâ§§#Äׂÿâ×Ĉ#…Õ#ƒÿë×ו#׃ÿâÄ•ˆ#…Õ#ׂÿëÄ×Í#׃ÿ×Äzˆ#…Õ#Äëëÿë×ħĞ#×ÿëÿëë×Äžhˆ#…Õ#»€×Äħ‹‹_#‹××Ä×ħž‹Oˆ#…Õ#âzž§§ž‹h?‚#§ž×§§žžzW§ˆ#…Ö#§h‹Ä°hWO€#‹h€zWF_‰#…×#°z»žz‚‚#§€?O§Š#…õ#…Š#âÿ××ëÄ‚#âÿë×ëĹ#âÿ××ëÄ‚#âÿë×ëÄŠ#…‰#ââ€ÿâÄ•€#Äëÿ×§·#ââ€ÿâÄ•€#Äëÿ×§‰#…ˆ#â‚ÿëמ§#ââ‚ÿâ§§µ#â‚ÿëמ§#ââ‚ÿâ§§ˆ#…ˆ#ׂÿ×ÄÄ_#ƒÿë×וµ#ׂÿ×ÄÄ_#ƒÿë×וˆ#…ˆ#×õ€ÿë×§ëž#ׂÿëÄ×͵#×õ€ÿë×§ëž#ׂÿëÄ×͈#…ˆ#×âÿëâͰžÄ‹#Äëëÿë×ħе#×âÿëâͰžÄ‹#Äëëÿë×ħЈ#…ˆ# °××Äħžh‹?#»€×Äħ‹‹_µ# °××Äħžh‹?#»€×Äħ‹‹_ˆ#…ˆ#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚µ#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚ˆ#…‰#•hzhWWzW€#§h‹Ä°hWO·#•hzhWWzW€#§h‹Ä°hWO‰#…Š#°W??W‚‚#°z»žz‚¹#°W??W‚‚#°z»žz‚Š#…õ#…Š#âÿë×ëÄ‚#âÿ××ÿâ¹#âÿë×ëÄ‚#âÿ××ÿâŠ#…‰#Äëÿ×§€#ÿ×€ÿâ×§·#Äëÿ×§€#ÿ×€ÿâ×§‰#…ˆ#ââ‚ÿâ§§#Äׂÿâ×ĵ#ââ‚ÿâ§§#Äׂÿâ×Ĉ#…ˆ#ƒÿë×ו#׃ÿâÄ•µ#ƒÿë×ו#׃ÿâÄ•ˆ#…ˆ#ׂÿëÄ×Í#׃ÿ×Äzµ#ׂÿëÄ×Í#׃ÿ×Äzˆ#…ˆ#Äëëÿë×ħĞ#×ÿëÿëë×Äžhµ#Äëëÿë×ħĞ#×ÿëÿëë×Äžhˆ#…ˆ#»€×Äħ‹‹_#‹××Ä×ħž‹Oµ#»€×Äħ‹‹_#‹××Ä×ħž‹Oˆ#…ˆ#âzž§§ž‹h?‚#§ž×§§žžzW§µ#âzž§§ž‹h?‚#§ž×§§žžzW§ˆ#…‰#§h‹Ä°hWO€#‹h€zWF_·#§h‹Ä°hWO€#‹h€zWF_‰#…Š#°z»žz‚‚#§€?O§¹#°z»žz‚‚#§€?O§Š#…õ#…Š#âÿ××ëÄ‚#âÿë×ëĹ#âÿ××ëÄ‚#âÿë×ëÄŠ#…‰#ââ€ÿâÄ•€#Äëÿ×§·#ââ€ÿâÄ•€#Äëÿ×§‰#…ˆ#â‚ÿëמ§#ââ‚ÿâ§§µ#â‚ÿëמ§#ââ‚ÿâ§§ˆ#…ˆ#ׂÿ×ÄÄ_#ƒÿë×וµ#ׂÿ×ÄÄ_#ƒÿë×וˆ#…ˆ#×õ€ÿë×§ëž#ׂÿëÄ×͵#×õ€ÿë×§ëž#ׂÿëÄ×͈#…ˆ#×âÿëâͰžÄ‹#Äëëÿë×ħе#×âÿëâͰžÄ‹#Äëëÿë×ħЈ#…ˆ# °××Äħžh‹?#»€×Äħ‹‹_µ# °××Äħžh‹?#»€×Äħ‹‹_ˆ#…ˆ#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚µ#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚ˆ#…‰#•hzhWWzW€#§h‹Ä°hWO·#•hzhWWzW€#§h‹Ä°hWO‰#…Š#°W??W‚‚#°z»žz‚¹#°W??W‚‚#°z»žz‚Š#…õ#…Š#âÿë×ëÄ‚#âÿ××ÿâ×#…‰#Äëÿ×§€#ÿ×€ÿâ×§Ö#…ˆ#ââ‚ÿâ§§#Äׂÿâ×ÄÕ#…ˆ#ƒÿë×ו#׃ÿâÄ•Õ#…ˆ#ׂÿëÄ×Í#׃ÿ×ÄzÕ#…ˆ#Äëëÿë×ħĞ#×ÿëÿëë×ÄžhÕ#…ˆ#»€×Äħ‹‹_#‹××Ä×ħž‹OÕ#…ˆ#âzž§§ž‹h?‚#§ž×§§žžzW§Õ#…‰#§h‹Ä°hWO€#‹h€zWF_Ö#…Š#°z»žz‚‚#§€?O§×#…õ#…Š#âÿë×ëÄ‚#âÿ××ÿâ#âÿ××ÿâ‚#âÿë×ëÄ‚#âÿ××ÿâ‚#âÿë×ëÄ‚#âÿë×ëÄ‚#âÿ××ÿâŠ#…‰#Äëÿ×§€#ÿ×€ÿâ×§‹#ÿ×€ÿâ×§€#Äëÿ×§€#ÿ×€ÿâ×§€#Äëÿ×§€#Äëÿ×§€#ÿ×€ÿâ×§‰#…ˆ#ââ‚ÿâ§§#Äׂÿâ×ĉ#Äׂÿâ×Ä#ââ‚ÿâ§§#Äׂÿâ×Ä#ââ‚ÿâ§§#ââ‚ÿâ§§#Äׂÿâ×Ĉ#…ˆ#ƒÿë×ו#׃ÿâÄ•‰#׃ÿâÄ•#ƒÿë×ו#׃ÿâÄ•#ƒÿë×ו#ƒÿë×ו#׃ÿâÄ•ˆ#…ˆ#ׂÿëÄ×Í#׃ÿ×Äz‰#׃ÿ×Äz#ׂÿëÄ×Í#׃ÿ×Äz#ׂÿëÄ×Í#ׂÿëÄ×Í#׃ÿ×Äzˆ#…ˆ#Äëëÿë×ħĞ#×ÿëÿëë×Äžh‰#@×ÿëÿëë×Äžh#Äëëÿë×ħĞ#×ÿëÿëë×Äžh#Äëëÿë×ħĞ#Äëëÿë×ħĞ#×ÿëÿëë×Äžhˆ#…ˆ#»€×Äħ‹‹_#‹××Ä×ħž‹O‰# ‹××Ä×ħž‹O#»€×Äħ‹‹_#‹××Ä×ħž‹O#»€×Äħ‹‹_#»€×Äħ‹‹_#‹××Ä×ħž‹Oˆ#…ˆ#âzž§§ž‹h?‚#§ž×§§žžzW§‰#@§ž×§§žžzW§#âzž§§ž‹h?‚#§ž×§§žžzW§#âzž§§ž‹h?‚#âzž§§ž‹h?‚#§ž×§§žžzW§ˆ#…‰#§h‹Ä°hWO€#‹h€zWF_‹#‹h€zWF_€#§h‹Ä°hWO€#‹h€zWF_€#§h‹Ä°hWO€#§h‹Ä°hWO€#‹h€zWF_‰#…Š#°z»žz‚‚#§€?O§#§€?O§‚#°z»žz‚‚#§€?O§‚#°z»žz‚‚#°z»žz‚‚#§€?O§Š#…õ#…Š#âÿ××ëÄ‚#âÿë×ëÄ#âÿë×ëÄ‚#âÿ××ëÄ‚#âÿë×ëÄ‚#âÿ××ëÄ‚#âÿ××ëÄ‚#âÿë×ëÄŠ#…‰#ââ€ÿâÄ•€#Äëÿ×§‹#Äëÿ×§€#ââ€ÿâÄ•€#Äëÿ×§€#ââ€ÿâÄ•€#ââ€ÿâÄ•€#Äëÿ×§‰#…ˆ#â‚ÿëמ§#ââ‚ÿâ§§‰#ââ‚ÿâ§§#â‚ÿëמ§#ââ‚ÿâ§§#â‚ÿëמ§#â‚ÿëמ§#ââ‚ÿâ§§ˆ#…ˆ#ׂÿ×ÄÄ_#ƒÿë×ו‰#ƒÿë×ו#ׂÿ×ÄÄ_#ƒÿë×ו#ׂÿ×ÄÄ_#ׂÿ×ÄÄ_#ƒÿë×וˆ#…ˆ#×õ€ÿë×§ëž#ׂÿëÄ×͉#ׂÿëÄ×Í#×õ€ÿë×§ëž#ׂÿëÄ×Í#×õ€ÿë×§ëž#×õ€ÿë×§ëž#ׂÿëÄ×͈#…ˆ#×âÿëâͰžÄ‹#Äëëÿë×ħЉ#@Äëëÿë×ħĞ#×âÿëâͰžÄ‹#Äëëÿë×ħĞ#×âÿëâͰžÄ‹#×âÿëâͰžÄ‹#Äëëÿë×ħЈ#…ˆ# °××Äħžh‹?#»€×Äħ‹‹_‰#»€×Äħ‹‹_#°××Äħžh‹?#»€×Äħ‹‹_#°××Äħžh‹?#°××Äħžh‹?#»€×Äħ‹‹_ˆ#…ˆ#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚‰#@âzž§§ž‹h?‚#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚#°ž§§ž‹hÄz‹#°ž§§ž‹hÄz‹#âzž§§ž‹h?‚ˆ#…‰#•hzhWWzW€#§h‹Ä°hWO‹#§h‹Ä°hWO€#•hzhWWzW€#§h‹Ä°hWO€#•hzhWWzW€#•hzhWWzW€#§h‹Ä°hWO‰#…Š#°W??W‚‚#°z»žz‚#°z»žz‚‚#°W??W‚‚#°z»žz‚‚#°W??W‚‚#°W??W‚‚#°z»žz‚Š#…õ#…õ#…õ#…õ#…õ#…õ#…õ#…õ#†ó#‡ó#‰ï#ÿÿÿþt8mk@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿgolly-2.7-src/gui-wx/icons/file-rle.icns0000644000175000017500000011400012536111364015124 00000000000000icns˜ICN#ÿÀÿøÿüÿÿÿÿ€ÿÿÀÿÿÀÿÿàÿÿàÿÿðÿÿðÿÿðÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿüÿþÿÿ€ÿÿÀÿÿàÿÿàÿÿðÿÿðÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøÿÿøil32j€ÿŒàŠÿÖÓÏÍËÇÃÀ¸©€ªàà‰ÿãåâãâàßÝÛØÖÕÐÃ³ÈÆ€à‡ÿ忀äãáàÞÛÙØÕδàÇÊàà†ÿåçåäâàÞÜÚØÓ½ÿÝÆÃàà…ÿçç‚åäãáßÞÛÕÃÿÿàÇÅà…ÿèéçææåãâáÞÙÆ€ÿÝÃÂàà„ÿéêè€çæäãáÜËÿàǵà„ÿêëƒéèèäãáÜÓ½¤——¼Ã·ààƒÿìí€ë…ê ÜÓÃþ¾²­ªàƒÿîïíììŠÿ×ÕÌÁàƒÿðñ€îÿ„ ÿÿ ÿßÝ×Ðàƒÿñò€ðÿ„ ÿÿ ÿìƒÿóôòññ‡ÿ ÿìƒÿõö€ô‡ÿ ÿ€îòƒÿ ÷øõøøÿ „ÿ ÿ€ðòƒÿøù€÷ÿ „ÿ ÿòƒÿ ùú÷÷øÿ „ÿ ÿñ€òƒÿùú€øÿ ‡ÿòñòîƒÿúû€ùÿ ‡ÿóóôðƒÿûü€ùÿ ÿÿ„ ÿôôõóƒÿûü€úÿ ÿÿ„ ÿõõöõƒÿûüûúúŠÿõõ÷õƒÿûýûú€ùø÷÷öøöƒÿüþûWWÒÿW€ù WWÒÿ÷÷ø÷ƒÿüþýüüûWüWÿWúúùWøøÿøøùøƒÿýÿ€ýûWWãÿWûûùWWãÿùùúùƒÿþÿþþýûWýWÿWüüùWûûÿúúûùƒÿþÿ€þûWýWÿ€Wù€Wÿúúüùƒÿ“ÿƒÿ—ƒÿ—€ÿ€ÿŒàŠÿÖÓÏÍËÇÃÀ¸©€ªàà‰ÿãåããâàßÝÛØÖÕÐÃ³ÈÆ€à‡ÿ忀äãáàÞÛÙØÕδàÇÊàà†ÿåçåäâàÞÜÚØÓ½ÿÝÆÃàà…ÿçç‚åäãáßÞÛÕÃÿÿàÇÅà…ÿèéçææåãâáÞÙÆ€ÿÝÃÂàà„ÿéê‚èççæäãàÜËÿàǵà„ÿêëéèéèèäãàÜÒ½¤——¼Ã·ààƒÿìí€ë…ê ÜÒÃþ¾²­ªàƒÿîïíììŠÿ×ÕÌÁàƒÿðñ€îÿ„2 ÿÿ22ÿßÝ×Ðàƒÿñò€ðÿ„2ÿÿ22ÿìƒÿóôòññ‡ÿ22ÿìƒÿõö€ô‡ÿ22ÿ€îóƒÿ ÷øõøøÿ22„ÿ22ÿ€ðóƒÿøù€÷ÿ22„ÿ22ÿóƒÿ ùú÷÷øÿ22„ÿ22ÿñ€óƒÿùú€øÿ22‡ÿòñòîƒÿúû€ùÿ22‡ÿóóôðƒÿûü€ùÿ22ÿÿ„2ÿôôõóƒÿûü€úÿ22ÿÿ„2ÿõõöõƒÿûüûúúŠÿöõ÷õƒÿûýûú€ù€ø€÷öøöƒÿüþûWWÒÿW€ù WWÒÿ÷÷ø÷ƒÿüÿýüüûWüWÿWúúùWùøÿø÷ù÷ƒÿþÿ€ýûWWãÿWûûùWWãÿùùûùƒÿþÿþþýûWýWÿWüüùWûûÿúúûùƒÿþÿ€þûWýWÿ€Wù€Wÿûúüùƒÿ“ÿƒÿ—ƒÿ—€ÿ€ÿŒàŠÿÖÓÏÍËÇÃÀ¸©€ªàà‰ÿäåâãâàßÝÛØÖÕÐÃ³ÈÆ€à‡ÿ忀äãáàÞÛÙØÕδàÇÊàà†ÿåçåäâàÞÜÚØÓ½ÿÝÆÃàà…ÿçç‚åäãáßÞÛÕÃÿÿàÇÅà…ÿèéçææåãâáÞÙÆ€ÿÝÃÂàà„ÿéê‚èççæäãàÜËÿàǵà„ÿëëéèéèèäãàÜÒ½¤——¼Ã·ààƒÿìí€ë…ê ÜÒÃþ¾²­ªàƒÿîïíììŠ#×ÕÌÁàƒÿðñ€î#„ÿ ##ÿÿ#ßÝ×Ðàƒÿñò€ð#„ÿ##ÿÿ#ìƒÿóôòññ‡#ÿÿ#ìƒÿõ÷€ô‡#ÿÿ#€îóƒÿ ÷øõøø#ÿÿ„#ÿÿ#€ðóƒÿøù€÷#ÿÿ„#ÿÿ#óƒÿ ùú÷÷ø#ÿÿ„#ÿÿ#ñ€óƒÿùú€ø#ÿÿ‡#òñòîƒÿúû€ù#ÿÿ‡#óóôðƒÿûü€ù#ÿÿ##„ÿ#ôôõóƒÿûü€ú#ÿÿ##„ÿ#õõöõƒÿûüûúúŠ#õõ÷õƒÿûýûú€ù€ø€÷öøöƒÿüþûWWÒÿW€ù WWÒÿ÷÷ø÷ƒÿüÿ€üûWüWÿWúúùWùøÿøøù÷ƒÿýÿ€ýûWWãÿWûûùWWãÿùùûùƒÿþÿþþýûWýWÿWüüùWûûÿúúûùƒÿþÿ€þûWýWÿ€Wù€Wÿúúüùƒÿ“ÿƒÿ—ƒÿ—€ÿl8mk  8ÿÿÿÿÿÿÿÿÿÿÿÿÿô½ Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ[JÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÁJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬Jÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ4JÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿîJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿDJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿSJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJKÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿKn—²°°°°°°°°°°°°°°°°°°²—n1@KJJJJJJJJJJJJJJJJJJK@1ics#Hðøüüþþþþþþþþþþþþðøüüþþþþþþþþþþþþis32€^uqmh]7†òòîèáÓ»6…‚íðºz]„ƒðåz®Gƒô‚÷åzzo‚÷…ÿÎj‚ûÿ ÿ ÿðˆ‚ûƒÿ ÿò•‚ûÿ ÿ ÿûœ‚ûÿ ÿ ÿû¤‚ûÿ ƒÿþª‚ÿÿ ÿ ÿÿ­‚‡ÿ®‚‡ÿ±‚øïï€îííìô§‚ ( #! %&€€^uqmh]7†òòîèáÓ»6…‚íðºz]„ƒðåz®Gƒô‚÷åzzo‚÷…ÿÎj‚ûÿ2ÿ2ÿðˆ‚ûƒÿ2ÿó•‚ûÿ2ÿ2ÿûœ‚ûÿ2ÿ2ÿû¤‚ûÿ2ƒÿþª‚ÿÿ2ÿ2ÿÿ­‚‡ÿ®‚‡ÿ±‚øïï€îííìô§‚ ( #! %&€€^uqmh]7†òòîèáÓ»6…‚íðº{]„ƒðå{®Gƒô‚÷å{{o‚÷…#Îj‚û#ÿ#ÿ#ðˆ‚ûƒ#ÿ#÷•‚û#ÿ#ÿ#ûœ‚û#ÿ#ÿ#û¤‚û#ÿƒ#þª‚ÿ#ÿ#ÿ#ÿ­‚ÿ…#ÿ®‚‡ÿ±‚øïï€îííìô§‚ ( #! %&€s8mk<°¿¿¿¿¿©CQÿÿÿÿÿÿÿ©0Wÿÿÿÿÿÿÿÿ¯0Wÿÿÿÿÿÿÿÿø¯/WÿÿÿÿÿÿÿÿÿøžWÿÿÿÿÿÿÿÿÿÿÒ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ WÿÿÿÿÿÿÿÿÿÿÕ UÿÿÿÿÿÿÿÿÿÿÑ 1Š—————————{it32GÿÿŒà†ß‚ÞÝ€Ü ÛÚÚÙÙØØ×ÖÖ€ÕÔÓÓÒÑÑÐÏÎÌÊÇÄ¿½¹¶°¶¨UÄàá…àßàßàß‚ÞÝÝÜÜÛÚÚ€ÙØ×ÖÖÕÕÔÔÓÓÒÑÐÐÏÌÉÈÄÁ¿½¸´³°°¥"3Áˆáàáá€à€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÐÎËÈÅ¿¼¸µ²¬®»gfÀââ…áâá€à€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÐÎËÈÆÂ¿¼¸´°««¸Yj¿âáâ€áâáàà€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÏÎÉÈÅÁ¾»¶±®©­³sU¾„âáá‚âáàà߀ÞÝÜÜÛ€ÚÙØØ×ÖÖ€ÕÔÓÓÒÑÏÌÊÈÅÀ½¹´¯ª¦¸¥¦O½Œâáàà߀ÞÝÜÜÛ€ÚÙØØ×ÖÖ€ÕÔÓÓÒÑÏÌÉÇÿ¼·±«¦§»ª¶U¼âáà‚߀ÞÝÜÜÛ€ÚÙØ××ÖÖ€ÕÔÓÓÒÑÏÌÉÆÁ½¹²¬¦¢²´¾µO»Žãâáà߀ÞÝÜÜÛÚÙØØ××ÖÕÕÔÓÓÒÐÏÌÉÆÀº¶®¨¡ž°ÄʵUºãâáà߀ÞÝÜÜÛ€ÚÙÙØØ××ÖÕÕÔÓÓÑÐÎÊÇľ·±©¢›˜¸ÓʵU¹ãâá€àßßÞÞÝÝÜÜÛ€ÚÙÙØØ××ÖÕÕÔÓÓÑÐÍÉÅÀº²ª¢›”–ÝÓʵO¸‘ãâá€àßÞÞÝÝÜÛÛÚÙÙØØ×ÖÖ€ÕÔÓÑÐÍȼ´«£š“ØÝÓʵO·’ãâá€àßÞ€Ý ÜÛÛÚÙÙØØ×ÖÖ€ÕÓÓÑÎËž¶®¥›“‹ÉåÝÓʳO¶“äãâ€áààßßÞ€ÝÜÛÛ€ÚÙØØ××ÖÖÔÓÓÏÌÇÀ¹°¥”‹¾íåÝÓʳZµ”äãâ€áààßßÞ€ÝÜÛÛ€ÚÙØØ××ÖÔÔÓÑÎÈú±¨”гôíåÝÓʳZ´•äãâ€áà߀Þ!ÝÜÜÛÚÚÙØØ××ÕÔÔÑÏÌÅ¿µª ”‰§úôíåÝÓʳZ³–äãâ€áà߀Þ!ÝÜÜÛÚÚÙØØ××ÕÓÒÏÍÇÀ¶­¡–‹›ÿúôíåÝÓʳZ²—åäã€âá€à߀ÞÝÜÜÛ€ÚÙÙØÖÕÓÑÎȹ¯£—‹–ÿÿúôíåÝÓʳZ±˜åäã€âá€à߀ÞÝÜÜÛ€ÚÙÙ×ÕÕÒÏÉ»°¥˜Œ€ÿúôíåÝÓʳZ°˜åäãã€âá€à߀ÞÝÜÜÛ€Ú ÙØ×ÕÓÏÉû³¦šŽŽÿúôíåÝÓʳZ¯™åäãã€âáà€ßÞÝÝÜÛÛÚØØÖÓÐËﳍœ†‚ÿúôíåÝÓʳO®ææ…åæåäãã€âáà€ßÞÝÝÜÛÛÙØØÔÑÌÆ½µªž…ƒÿúôíåÝÓʳO­€ç„æçæåää€ãâ€áà€ßÞÝÝÜÛÚÙØÕÓÎÈÀµ«ž“†„ÿúôíåÝÓʳO¬ƒç€æ‚çŽæåää€ãâ€áà€ßÞÝÝÜÚÚØÕÓÎÈÀ·« “ˆ…ÿúôíåÝÓʳO«…çæ…çææç‰æåää€ãâ€á€àßßÞÞÜÛÚ×ÔÐʸ­¡•‰†ÿúôíåÝÓÊ´Uª•ç†æåää€ãâ€á€à"ßÞÞÝÜÚÙÕÐʸ®¢—‹€von‚€€Š¢®ÀÑäÝÓÊ´U©’èççè‡çæåå€äã€â%áààßÞÝÝÛÙÖÐËĺ°¤™Ž„zrmheddehhlot•¶ÈʵO¨–è‡çæåå€äã€âáààßÝÝÜÚ×ÒÍż²¦œ’‡xrnk€j lnqsuzŽ©®±U§éšèƒçæåå€äã€âáààßÞÝÜØÔÏÈ¿¶« —…yvtr€s tvx{~…‰ššU¦ƒéšè€ç€æåå€ä)ããââáààßÝÜÚÖÐʹ°¦œ”‡ƒ€~}||}~~€‚„†‰Œš¢z3¥…éèé”è€ç‰æâ€àÜÛ×ÒÌŽ´«£›•ŒŠˆ‰‰€ˆ ‰‰ŠŒ‘”–Ÿªf¥Šêéèèéƒèƒåæââ€à âß×ÒÏÂÁº±ª¤ž›—•–€•”•–€—š›œ¬~r¤êŠéëéƒèëèè‚倿€âà€ß ×ÒÏ˾¹²­©¥¢‚¡£€¡ Ÿ ¡¡£µ#¤‘ê‡éèèååèé‚èåèèçç‚æââàà€ßØÏÏ˾¶¼·³°¯­­¬®®­®®«¬ª©©¨¦¦§¥¸|¤€ë‘êƒéëéƒèé„èçç€æååæâàáàßÞØÏÏ˺º¼»º¹¹¸¸¹ ·µµ³±°®­¬¬¯¨¤ƒë€êëë‹ê€é„ëƒèé‚èç€æ ååäââáßÞÛØÏÐË€ÂÃÂÃÂÁÁ¿½¼º·¶µ²±±¯¤…ìëììŒëê‡ë€êéèèêéè ççææåäããáÞÞÛØÏ‚ËÊË€Ê ÉÈÇÅÂÁÀ½¼¹¶µ°¤‹ì‘ëêƒèêéè€ç ææääâáßÞÜÚØƒÐÑÐÏÐÏÐÏÏÍÌÊÇÄÄÁ¿¼¹¸¤ìŽë‚êîèƒêéè€ç ææääâáàßÞÜÛØØƒÖÕÔÕÔÔÓÒÐÍËÈÆÃÀ½º¤ííŽìƒë¥ÿáØØÖØØÙØÙØ××ÖÖÕÓÒÏÌÊÇľ¤îˆí€ì€íìëëÿ¥ýÿáÛÜÛÛÚÙÙØ×ÖÖÕÓÑÍËÈŤ„îííîîí€ì€íëëÿ€ýþÿÿýþÿÿýþÿÿýýÿÿþýÿÿþýÿÿþ‚ý€ÿý€ÿ€ýÿáÜÝÝÜÛÚÙÙØ××ÕÔÑÎÌÈŤŠîíí€ì‚íÿýýþøÔáÿúÖßþýÚÙýþÝØûÿãÔøÿåÓõÿ€ý ÿïÐíÿñÒêÿýýÿá„Ý ÜÛÛÚÚÙØØÕÕÑÎÍɤŒîíìì‚í,ÿýþöŠ@;³=9­¨H2šªE4޾S0}½Q5lòþýÿãi7RÇm9HÓÿýÿãƒßÞÞÝÜÜÛÚÚÙÙÖÔÒÎͤðïðð„ïðïìƒí-ÿýÿÕ4C;3B>EA.<;(%S9) C38Åÿýÿ¢-> S)E ÿýÿåäƒÞ ßÞÞÝÜÛÚÚÙÙÖÔÒϤð€ï€ð‚ï€ð‚í+ÿýÿâ3[>[THSA‘ÿýÿíììƒêéèèç€æåäããâá¤õò ÿýÿÐ!@:NôÿŽýÿš^ÿýÿîíìïƒê éèèçææåääãã⤔õ ÿýþúˆ ;Á¢(1²ÿþŽýÿæ_ZÖwKÖÿýÿïîíïïƒê éèèçææåääã⤆ö…õö‚õ ÿýýÿÀVnçÈZgÜÿýþúLô§O„ôþýÿððï„êééèççæååã¤÷‰ö‡õ ÿýÿâLG_MCgûÿŽý ÿ·>@x:Fšÿýÿ€ð‚ï€êëê€éèççæå夂÷ˆö„õ ÿýÿÖ#9)IõÿŽýÿ¡S}ÿýÿñðñ€ðïíïìêëëê€éèççæå¤„÷öö÷÷…öõ ÿýþ÷1¯ˆ)§ÿþŽý ÿáWLÄ\AÎÿýÿ€ñ ððòòîîíììëëê€éèççæ¤Œ÷„ö õÿýýÿÉXrðÕ[gãÿý þÿ£N•ü²K‰øþýÿ€ñðòòðï€îììëëê€éèçç¤ö÷ö ÿýÿáUFleDoûÿŽýÿºG<‰LB ÿýÿòòñðò€ðï€îíìëëê€éè礒÷ööÿýÿË"$87#JóÿŽý ÿ”U!#|ÿýÿ‚òðï€îíìëëê€éè¤÷øø÷ööÿýþóe ¢„–ÿþŽý ÿÕ95ºQ'Áÿýÿ‚òñðï€îíììëê€é¤öƒø÷÷øŠ÷ ÿýýÿÎ]}ôØeuèÿý ÿâ½ßÿëÁÙÿýýÿƒòñ€ðïï€îí€ìêéé¤öˆøˆ÷ ÿýÿê_B |b> }þþý€ÿý€ÿ€ýÿ„òññððïï€îí€ìëê¤õ‹ø…÷ ÿýÿÓ%)2((Eôÿšýÿ…òññððïï€îí€ìë¤öŠø†÷ÿýÿð_j Œÿþýý…ÿþ€ÿþ€ÿý€ÿþ€ÿþýýÿòòóƒò€ñðïï€îí€ì¤õ‹ø…÷'ÿýýÿÐStùÕUlêÿýýÿò®¦êú¹Ÿâý¼žÜÿÊ›ÒÿÏœÊÿÔÀýÿòõõ„òñïï€îíìì¤ôùˆøùƒ÷+ÿýÿíjF,‰oB+Šÿþýý…:(fšC&U”?/H©J.<¢S4- M7)·ÿýÿ€õòòó‚òñðï€îíì¤ôƒùøøùùƒøù-÷÷ÿýÿÒ*3 3+3 Eóÿýö?-J+;), T%(J+/K5xÿýÿ„òóòñðð€îí¤ó‰ù‚ø‚ù+ÿýÿíN ‚[þÿýýy[L‹;£ //š/°ÿýÿ‚ò‚ó€òñððïîî¤òŒù€øù/ÿýýÿÐaö×btéÿýýÿêtaÙ÷†]Éü‹WÀÿ W®ÿ¬W£ÿ¶T•ûþýÿõõòô…óòòñððïî¤ñ“ù+ÿýÿïxC(™‰@(”ÿþýþ¢F,t¦P)`¯P2V³Z2E°c87´h:4Àÿýÿ€õ€ô…óòñððï¤ñú’ù+ÿýÿË*9 7:7 IóÿýøP1 D3I/.M-)>1/T)8|ÿýÿ…ô„óòñðð¤ðúù,ÿýÿå:rZpüÿýýzKy=…,‹%". ¢ÿýÿõ…ô…óò€ñð¤ïƒúùùúú‰ù+ÿýýÿÏ|“ñ݇Œåÿýýÿë•€×ò–zÌù¦zÂúªv·û´u®ûÄ|¡öþýÿ‚öƒô„óòòññ¤ï‰ú‡ùÿ€ý…ÿý…ÿþ€ÿþ€ÿþ€ÿþ€ÿþýýÿöõ…ôƒóòòñ¤î‹ú„ùöùÿ¥ýÿõöƒõ…ô‚óòò¤îŽú„ù¥ÿõõö…õ„ô‚óò¤î‘úˆùöö‚ù‚ø„ù€öù‚öùöõ€ö…õ…ôó¤íû’ú„ùöö„ùööù€öø‰ö†ùö†õƒô€ó¤íû“úù‚öùùö‡ùƒö†õ„ôó¤íƒûúúûú„ùƒöùƒö…ù†÷€ùƒö†õƒô¤í‰ûú†ù†ö‚ø…ù÷ööùùƒö…õ‚ô¤íŒûŽúŠù‰ø÷…ù…ö…õ€ô¤íûŽúŠù‰ø†÷‡ö…õó¤í’ûú‹ùˆø‡÷…ö„õô¤í”ûŽúˆùŠø†÷†ö‚õó¤íüü”ûŽú‰ùˆø‡÷…öõó¤í‚ü€ûüûú‰ùˆø†÷†öõõò¤íˆüûŽú‡ù‰ø†÷†öò¤îŠüûúûŒúˆùˆø…÷…öñ¤îü‘û‹úˆùˆø‡÷‚öð¤îüûŒú‡ùˆø†÷öð¤î…üýüý€üýüýüý‚ü‚ûüûü…û†úû‚úùú‚ùøùƒø÷øøƒ÷ö÷î¤ï“ýü„ûƒWxÅüüûWWƒ„û…WÕÿÿú‡ù†ø÷÷î¤ï•ýƒûWWbƒx€WÐüûWWƒ„ûWWb‚ƒÝÿÿƒú‡ù†øí¤ï•ýƒû WWƒüüÐWWŽüüWWƒ„ûWWƒƒûÿÿ…ú‡ù„øí¤ïþþ“ýƒûWWƒýýüWWƒüüWWƒüƒûWW„ü‚ûÿÿ‡ú†ùƒøì¤ï‚þýƒû WWƒýýÜWW¤üüWWƒ€üûWW„€ü€ûÿÿˆú‡ùøë¤ïˆþŠýƒû WWƒýÜxWbçýüWWƒ‚üûûWWm©éûÿÿûû‡ú‡ù€øë¤ð‹þ‡ýƒûƒWmÜýýüWWƒ„ü„WÖüÿÿû‡ú†ùøøë¤ðþ…ýƒûWWbƒWWŽ€ýüWWƒ„üWWyÖñüÿÿƒû‡ú†ùë¤ðþ„ý‚û WWƒýŽWWÆýýüWWƒ„üWW„ƒüÿÿ…û†ú…ùê¤ð“þ€ý‚û WWƒýòbWbòýýWWƒ„üWW„ƒüÿÿ†û†ú„ùê¤ð•þý‚û WWƒýý°WWŽýýWWƒ„üWW„ƒüÿÿˆû†ú‚ùë¤ð–þ‚ûWWƒ€ýxWWÆýWWb‚ƒºüWWb‚„°ÿÿüˆû†úùë¤ð–þ‚û WW„þýýÜWWbý…W¯ü…W“ÿÿüüˆû‡úùùë¤ð•þƒûþþýŒüˆû†úùë¤ðŸþý‹üˆû†úë¤ð¡þýŠü‰û„úë¤ðÿ£þýŠüˆûƒúë¤ðÿ¢þýŠü‡û‚úì¤ð„ÿþÿŸþŽýŠü‡ûúìÿÿÿÿÿÿÿÿÿÿŒ‚à…ß‚ÞÝ€Ü ÛÚÚÙÙØØ×ÖÖ€ÕÔÓÓÒÑÑÐÏÎÌÊÇÄ¿½¹¶°¶¨Uăàßàßàßààß‚ÞÝÜÝÝÜ€ÚØÙÙ××ÖÖÕÕ€ÔÓÒÑÐÐÎÌÊÈÄÁ¿½¹µ³±°¥"3Áˆáàáà€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÐÎËÈÅ¿¼¸µ²¬®»gfÀââ„áââ‚áàà€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÐÎËÈÆÂ¿¼¸´°««¸Yj¿€âáâáâáàà€ßÞ€ÝÜÛÛÚÙØØ×ÖÖÕÔÔÓÒÒÑÑÏÎÉÈÅÁ¾»¶±®©­³sU¾„âáá‚âáàà߀ÞÝÜÜÛ€ÚÙØØ×ÖÖ€ÕÔÓÓÒÑÏÌÊÈÅÀ½¹´¯ª¦¸¥¦O½Œâáàà߀ÞÝÜÜÛ€ÚÙØØ×ÖÖ€ÕÔÓÓÒÑÏÌÉÇÿ¼·±«¦§»ª¶U¼âáà‚߀ÞÝÜÜÛ€ÚÙØ××ÖÖ€ÕÔÓÓÒÑÏÌÉÆÁ½¹²¬¦¢²´¾µO»Žãâáà߀ÞÝÜÜÛÚÙØØ××ÖÕÕÔÓÓÒÐÏÌÉÆÀº¶®¨¡ž°ÄʵUºãâáà߀ÞÝÜÜÛ€ÚÙÙØØ××ÖÕÕÔÓÓÑÐÎÊÇľ·±©¢›˜¸ÓʵU¹ãâá€àßßÞÞÝÝÜÜÛ€ÚÙÙØØ××ÖÕÕÔÓÓÑÐÍÉÅÀº²ª¢›”–ÝÓʵO¸‘ãâá€àßÞÞÝÝÜÛÛÚÙÙØØ×ÖÖ€ÕÔÓÑÐÍȼ´«£š“ØÝÓʵO·’ãâá€àßÞ€Ý ÜÛÛÚÙÙØØ×ÖÖ€ÕÓÓÑÎËž¶®¥›“‹ÉåÝÓʳO¶“äãâ€áààßßÞ€ÝÜÛÛ€ÚÙØØ××ÖÖÔÓÓÏÌÇÀ¹°¥”‹¾íåÝÓʳZµ”äãâ€áààßßÞ€ÝÜÛÛ€ÚÙØØ××ÖÔÔÓÑÎÈú±¨”гôíåÝÓʳZ´•äãâ€áà߀Þ!ÝÜÜÛÚÚÙØØ××ÕÔÔÑÏÌÅ¿µª ”‰§úôíåÝÓʳZ³–äãâ€áà߀Þ!ÝÜÜÛÚÚÙØØ××ÕÓÒÏÍÇÀ¶­¡–‹›ÿúôíåÝÓʳZ²—åäã€âá€à߀ÞÝÜÜÛ€ÚÙÙØÖÕÓÑÎȹ¯£—‹–ÿÿúôíåÝÓʳZ±˜åäã€âá€à߀ÞÝÜÜÛ€ÚÙÙ×ÕÕÒÏÉ»°¥˜Œ€ÿúôíåÝÓʳZ°˜åäãã€âá€à߀ÞÝÜÜÛ€Ú ÙØ×ÕÓÏÉû³¦šŽŽÿúôíåÝÓʳZ¯™åäãã€âáà€ßÞÝÝÜÛÛÚØØÖÓÐËﳍœ†‚ÿúôíåÝÓʳO®ææ…åæåäãã€âáà€ßÞÝÝÜÛÛÙØØÔÑÌÆ½µªž…ƒÿúôíåÝÓʳO­ç†æçæåää€ãâ€áà€ßÞÝÝÜÛÚÙØÕÓÎÈÀµ«ž“†„ÿúôíåÝÓʳO¬ƒç€æçæåää€ãâ€áà€ßÞÝÝÜÚÚØÕÓÎÈÀ·« “ˆ…ÿúôíåÝÓʳO«…çæ‚çæçç€æçˆæåää€ãâ€á€àßßÞÞÜÛÚ×ÔÐʸ­¡•‰†ÿúôíåÝÓÊ´Uª“çæç†æåää€ãâ€á€à"ßÞÞÝÜÚÙÕÐʸ®¢—‹€von‚€€Š¢®ÀÑäÝÓÊ´U©”èˆçæåå€äã€â%áààßÞÝÝÛÙÖÐËĺ°¤™Ž„zrmheddehhlot•¶ÈʵO¨—èçè„çæåå€äã€âáààßÝÝÜÚ×ÒÍż²¦œ’‡xrnk€j lnqsuzŽ©®±U§éšèƒçæåå€äã€âáààßÞÝÜØÔÏÈ¿¶« —…yvtr€s tvx{~…‰ššU¦ƒé—èçèç€æåå€ä)ããââáààßÝÜÚÖÐʹ°¦œ”‡ƒ€~}||}~~€‚„†‰Œš¢z3¥…éèé”èçèç‰æâ€àÜÛ×ÒÌŽ´«£›•ŒŠˆ‰‰€ˆ ‰‰ŠŒ‘”–Ÿªf¥Œêéèèéƒèƒåæââ€à âß×ÒÏÂÁº±ª¤ž›—•–€•”•–€—š›œ¬~r¤êŠéëéƒèëèè‚倿€âà€ß ×ÒÏË¿¹²­©¦¢‚¡£€¡ Ÿ ¡¡£µ#¤‘ê‡éèèååèé‚èåèèçç‚æââàà€ßØÏÏË¿·¼·³°¯­­¬®®­®®«¬ª©©¨¦¦§¥¸|¤€ë‘êƒéëéƒèé„èçç€æååæâàáàßÞØÏÏ˺º¼»º¹¹¸¸¹ ·µµ³±°®­¬¬¯¨¤ƒë€êëë‹ê€é„ëƒèé‚èç€æ ååäââáßÞÛØÏÐË€ÂÃÂÃÂÁÁ¿½¼º·¶µ²±±¯¤…ìëììŒëê‡ë€êéèèêéè ççææåäããáßÞÛØÏ‚ËÊË€Ê ÉÈÇÅÂÁÀ½¼¹¶µ°¤‹ì‘ëêƒèê€éèè€ç ææääâáßÞÜÚØƒÐÑÐÏÐÏ ÍÌÊÇÄÄÁ¿¼¹¸¤Žìë‚êîèƒêéè€ç ææääâáàÞÞÜÛØØƒÖÕÔÕÔÔÓÒÐÍËÈÆÃÀ½º¤ííŽìƒë¥ÿáØØÖØØÙØÙØ××ÖÖÕÓÒÏÌÊÇľ¤îˆí€ìíëëÿ¥ýÿáÛÜÛÛÚÙÙØ×ÖÖÕÓÑÍËÈŤ„îííîîí€ì€íëëÿ€ýþÿÿýýÿÿýþÿÿþýÿÿþýÿÿþýÿÿþ‚ý€ÿýþÿÿ€ýÿáÜÝÝÜÛÚÙÙØ××ÕÔÑÎÌÈŤŠîíí€ì‚íÿýýþúßèÿûáçþýäâþþæâüÿêÞùÿìÞ÷þ€ý ÿòÜðÿõÝïÿýýÿá„Ý ÜÛÛÚÚÙØØÕÕÑÎÍɤŒîíìì‚í,ÿýþùªvh¿®uj½À}d«Àzi¥Ï…e”Ì‚lŒóþýÿé“nvЕqsÛÿýÿãƒßÞÞÝ€ÜÚÚÙÙÖÔÒÎͤðïðð„ïðïìƒí-ÿýÿßjuBahuJ^suLTlp[K{qYIpjj:Ìÿýÿ¹en8v`u;”ÿýÿåäƒÞ ßÞÞÝÜÛÚÚÙÙÖÔÒϤð€ï€ð‚ï€ð‚í+ÿýÿéY/#oc,"ls1!\t0%Q†5$G7)5ÕÿýÿÅ?+'ˆF,% ÿýÿ„åáàßßÞÝÜÛÛÚÙÙÖÔÒ¤ƒðïï‚ð€ïðð‚î+ÿýýÿÂasæÈUfÞÛleÑàfUÈì~\¶ï{M¬ÿþýþûŸWó¥K„óþýÿ€åãááàßÞÞÝÜÜÛÚÙÙÖÔ¤‹ðïïòíòð€î-ÿýþú¹ƒuÊăvÄË‹pµÓŒt¯×”q Ü—u™óÿýÿî¥yƒÜ­{‚Þÿýÿæå€ãæããááàßßÞÝÝÜÛÚÙÙÖ¤ðò,ÿýÿÜit8dxtEdrvBR}rTPzsPCpb=Ðÿýÿµhg1lr9›ÿýÿç„ã âááàßßÞÝÜÜÛÚÚÙ¤òò€ñõòðñððò€ðCòòÿýÿàO*ig.bg.Tx1#Ix1@:(.Òÿýÿ¹<($…I1 ™ÿýÿèèææããææäãââáàßßÞÝÝÛÛÚ¤‚òõò…ðòò€ðÿ€ý,±YnÛÃkkÍÌc`ÆÙvd¶ÞrV®ç…b›ùýýÿõF‡í¤Wzèÿýÿèææçã€æ ääãâááààßÞÝÜÜÛ¤„ò€õòòðòððƒò.ðÿýýþÿôùÿÿøùÿÿ÷÷ÿÿû÷ÿÿùôÿÿýöÿþýýÿô§s‘å¬wìÿýÿéè€æã€æ ääãââáààßÞÝÝܤ†òõƒòðð‚òÿ€ýþÿÿýýÿÿýýÿÿýýÿÿþýÿÿþýÿÿþ€ýÿÀnu?‚h|Bžÿýÿëéè€ê€æ€ä ãââááàßßÝݤ…ôòòôõˆòÿ›ý ÿ¼?4$zD8#”ÿýÿ…êæ åääãâááàßÞ¤‡ôòòõòõõò ÿýýþÿùýÿÿúüÿý ÿò‡GvàŒ;käÿýÿ†ê èçææåääãâááàߤõõôõƒôòõò€õöÿ€ýÊ‹ÞÔŽ‰×ÿýþù³z™ï¼z•îÿýÿìêêì‚ê èèçææååäãââáअõôöòôô€õ€òõ ÿýÿâux=rƒxGzùÿŽýÿ¿rm8ŽvvA¥ÿýÿíììƒêéèèç€æåäãââá¤õò ÿýÿÚN?%\d@%föÿŽýÿ±B8$xLA$“ÿýÿîíìïƒê éèèçææåääããᤔõ ÿýþú—6LÈ®GHµÿþŽýÿër0iÛ‰A[Øÿýÿïîíïïƒê éèèçææåääã㤆ö…õö‚õ ÿýýÿÐ~‹êÖ…Šâÿýþû´u¥ó½|Ÿöþýÿððï„êééèççæååã¤÷‰ö‡õ ÿýÿè}L}}{RƒúÿŽý ÿÊvvG’p{J¬ÿýÿ€ð‚ï€êëê€éèççæå夂÷ˆö„õ ÿýÿßSG*YYG*`õÿŽýÿ¶EB&qGH%ÿýÿñðñ€ðïîïìêëëê€éèççæå¤„÷öö÷÷…öõ ÿýþù?F´™4<®ÿþŽý ÿæm9ZÈs/QÒÿýÿ€ñ ððòòîîíììëëê€éèççæ¤Œ÷„ö õÿýýÿ×ñÞ†æÿý þÿ»x¨üÃsŸùþýÿ€ñðòòðï€îììëëê€éèçç¤ö÷ö ÿýÿè„}G„‘|PˆûþŽýÿË|qEŸyL±ÿýÿòòñðò€ðï€îíìëëê€éè礒÷ööÿýÿ×RQ,WeR/eõÿŽý ÿ¬MH(rTR*ÿýÿ‚òðï€îíìëëê€éè¤÷øø÷ööÿýþõ|%4­•3/ÿþŽý ÿÝUIÃl-<Äÿýÿ‚òñðï€îíììëê€é¤öƒø÷÷øŠ÷ ÿýýÿØ}“õàˆ‘ëÿý ÿåÁáÿìËÝÿýýÿƒòñ€ðïï€îí€ìêéé¤öˆøˆ÷ ÿýÿïzS“xW–ýþý€ÿý€ÿ€ýÿ„òññððïï€îíììëëê¤ö‹ø…÷ ÿýÿÜYY3W[Y5_ôÿšýÿ…òññððïï€îí€ìë¤öŠø†÷ÿýþôw23˜‚+,–þþýýÿþ€ÿþ€ÿþ€ÿý€ÿþ€ÿþýýÿòòóƒòñïï€îí€ì¤õ‹ø…÷'ÿýýÿ×yŽøÝt„ëÿýýþõļïû˸çýϸäÿ×µÛÿܵÖþà·Ò€ýÿòõõ„òñïï€îíìì¤ô€ù‰øùƒ÷+ÿýÿñ•~]ž–|`¡þþýý¤s`…´|_u«vhn½hcµ†mZ±qZÄÿýÿ€õòòó‚òñðï€îíì¤ô‚ù€øùùƒøù-÷÷ÿýÿÜ^c8X_e"! 9yŒU7mnZ2 !$€ñ ððòòîîíììëëê€éèççæ¤Œ÷„ö õ"!!\¨…*O™Œ6! %|©j%hŸw' !$€ñðòòðï€îììëëê€éèçç¤ö÷ö "!7ÖÿÖs¾ÿï Ž!_ðý¼oåÿÚZ!$òòñðò€ðï€îíìëëê€éè礒÷öö"!=ÒÚ¯yÂçÂx# Ž! gãÑ¡zßݲ\!$‚òðï€îíìëëê€éè¤÷øø÷ öö"! +qtfCi›x:! ;tbD‚žg1 !$‚òñðï€îíììëê€é¤öƒø÷÷øŠ÷ "!" PŠs)J”„4! +*)!,:.€!$ƒòñ€ðïï€îí€ìêéé¤öˆøˆ÷ "!6Êÿät³ÿñy !€ ! €!$„òññððïï€îí€ìëê¤õŒø„÷ "!?ÛëÆÆõÔr! š!$…òññððïï€îí€ìë¤öŠø†÷'"! /€rBr‹rG" !!  !!!€!$òòóƒò€ñðïï€îí€ì¤õ‹ø…÷."!!M—u%C|t0!! 0im4(fn;%`qA"YsHUtM!MrX#!!$òõõ„òñðï€îíìì¤ôùˆøùƒ÷+"!4¿ûÛmªüêu !"Žùô‘†õù™xîú­qéþ³lÜþÁcÓÿÖR!$€õòòó‚òñðï€îíì¤ô‚ù€øùùƒøù-÷÷"!?ÞðÊŠÉûÝv! !%®üä‘¥øàŸŸ÷즌ö殕ëé¼…ìôÊT!$„òóòñðð€îí¤ó‰ù‚ø‚ù+"!1‹¬}H~œK"!!"kž„Vh©™U]œŠaX¢£`V™¦kI’“t:!$‚ò‚ó€òñððïîî¤òŒù€øù/"!" G…f$>kc. !! 1gi5+u};$alB$f„K`†Q!NnW#!!$õõòô…óòòñððïî¤ñ“ù "!/¶øÌ\ ûäi€!„óð‚yïì„kæøždàôŸ\Ô÷­VÈþÊH!$€õ€ô…óòñððï¤ñú’ù+"!?áïÁ‚ÎùÙ†# !%´ûÝ ¬úÙ”¡øä²–øá£Žîå±ïðÊe!$…ô„óòñðð¤ð€úù,"!2—šX‹¸ŽL# !$zµ™Yr¦Šfl°¥ea¦Žq]¡’wY£²|>!$õ…ô…óò€ñð¤ïƒúùùúú‰ù"€!6=:&5[I' €!-VQ**?:0&OW1%>:6$>:5$A[?"!!$‚öƒô„óòòññ¤ï‰ú‡ù"€!€!!" !   ! !€!€!$öõ„ô„óòòñ¤î‹ú„ùöù#¥!$õöƒõ…ô‚óòò¤îúƒù%£$%õõö…õ„ô‚óò¤î‘úˆùöö‚ù‚ø„ù€öù‚öùöõ€ö…õ…ôó¤íû’ú„ùöö„ùööù€öø‰ö†ù€ö†õ„ô€ó¤íû’ú‚ù‚öùùö‡ùƒö†õ„ôó¤íƒûúúûú„ùƒöùƒö…ù†÷€ùƒö†õƒô¤í‰ûú†ù†ö‚ø…ù÷ööùùƒö…õ‚ô¤íŒûŽúŠù‰ø÷…ù…ö…õ€ô¤íûŽúŠùˆø‡÷‡ö„õôó¤í’ûŽúŠù‡øˆ÷…ö„õô¤í”ûŽúˆù‰ø‡÷†ö‚õó¤í€ü“ûŽú‰ùˆø‡÷…öõó¤í‚ü”ûú‰ùˆø†÷†öõõò¤íˆüûúˆù‰ø†÷†öò¤îŠüûŽúˆù‡ø‡÷„öñ¤îüûúû‹úˆùˆø‡÷‚öð¤îüûú‡ùˆø†÷öð¤îƒüý„üý…üƒûüûüûü€ûúûû†ú„ùúùùøùù‚øùùø÷ø÷÷ø÷ööî¤ï“ýü„ûƒWxÅüüûWWƒ„û…WÕÿÿú‡ù†ø÷÷î¤ï•ýƒûWWbƒx€WÐüûWWƒ„ûWWb‚ƒÝÿÿƒú‡ù†øí¤ï•ýƒû WWƒüüÐWWŽüüWWƒ„ûWWƒƒûÿÿ…ú†ù…øí¤ïþþ“ýƒûWWƒýýüWWƒüüWWƒüƒûWW„ü‚ûÿÿ‡ú†ùƒøì¤ï‚þýƒû WWƒýýÜWW¤üüWWƒ€üûWW„€ü€ûÿÿ‡úˆùøë¤ïˆþŠýƒû WWƒýÜxWbçýüWWƒ‚üûûWWm©éûÿÿûû‡ú‡ù€øë¤ð‹þ‡ýƒûƒWmÜýýüWWƒ„ü„WÖüÿÿû‡ú†ùøøë¤ðþ…ýƒûWWbƒWWŽ€ýüWWƒ„üWWyÖñüÿÿƒû‡ú†ùë¤ðþƒý‚û WWƒýŽWWÆýýüWWƒ„üWW„ƒüÿÿ…û†ú…ùê¤ð“þ€ý‚û WWƒýòbWbòýýWWƒ„üWW„ƒüÿÿ†û†ú„ùê¤ð•þý‚û WWƒýý°WWŽýýWWƒ„üWW„ƒüÿÿˆû†ú‚ùë¤ð–þ‚ûWWƒ€ýxWWÆýWWb‚ƒºüWWb‚„°ÿÿ‰û†úùë¤ð–þ‚û WW„þýýÜWWbý…W¯ü…W“ÿÿü‰û‡úùùë¤ð•þƒûþþýŒüˆû†úùë¤ðŸþý‹üˆû†úë¤ð¡þý‹üˆû„úë¤ðÿ£þýŠüˆûƒúë¤ðÿ¢þýŠü‡û‚úì¤ð„ÿþÿŸþŽýŠü‡ûúìÿÿÿÿÿÿÿÿt8mk@    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúé°N   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýÅI#  ,ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø~A  %6ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûƒV  *>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿó˜B .EÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿãÓC 1IÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáòB 3KÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúòC 3LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòB 3LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóB 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôD 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóB 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóB 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóC 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿòìB 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëÈB 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿó£( 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿê„3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²v 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷l% 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨< 3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÚO3MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøW# 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþ]( 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^, 3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^/3Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ^13Mÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ[23MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿY33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿX33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿV33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿS33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿR33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQ33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿP33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿN33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33MÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿM33LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33LÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿL33KÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿK31IÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿI1.EÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿE. *>ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ>*  %6I[itz~€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€~zti[I6%  ,;IU]befffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb]UI;,   ,6>EIKLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLKIE>6,  %*.133333333333333333333333333333333333333333333333333333333333333333333333333333331.*%    golly-2.7-src/gui-wx/icons/appicon16.ico0000644000175000017500000000053612536111364015053 00000000000000(( Àÿÿÿ¿¿¿¿¿¿¿¿¿ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿ»»»»»»»»¼Ì»ÌÌÌÌ˼̻ÌÌÌÌ˼̻ÌÌÌÌ˼̻»»»»»¼Ì»»»»»»¼Ì»»»»Ì˼̻»»»Ì˼̻»»»Ì˼̻»»»ÌË»»»»»»ÌË»»»»»»Ì˼ÌÌÌÌ»Ì˼ÌÌÌÌ»Ì˼ÌÌÌÌ»ÌË»»»»»»»»golly-2.7-src/gui-wx/icons/appicon32.ico0000644000175000017500000000177612536111364015060 00000000000000 h( @ÿÿÿ¿¿¿¿¿¿¿¿¿ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»¼ËÌ»»Ì¼Ë̼Ë̼˻»¼ËÌ»»Ì¼Ë̼Ë̼˻»»»»»»»»»»»»»»»»»¼ËÌ»»Ì¼Ë̼Ë̼˻»¼ËÌ»»Ì¼Ë̼Ë̼˻»»»»»»»»»»»»»»»»»¼ËÌ»»»»»»»»»»»»»¼ËÌ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»¼ËÌ»»»»»»»»Ì¼Ë»»¼ËÌ»»»»»»»»Ì¼Ë»»»»»»»»»»»»»»»»»»¼ËÌ»»»»»»»»Ì¼Ë»»¼ËÌ»»»»»»»»Ì¼Ë»»»»»»»»»»»»»»»»»»¼ËÌ»»»»»»»»Ì¼Ë»»¼ËÌ»»»»»»»»Ì¼Ë»»»»»»»»»»»»»»»»»»»»»»»»»»»»»Ì¼Ë»»»»»»»»»»»»»Ì¼Ë»»»»»»»»»»»»»»»»»»¼Ë̼Ë̼ËÌ»»Ì¼Ë»»¼Ë̼Ë̼ËÌ»»Ì¼Ë»»»»»»»»»»»»»»»»»»¼Ë̼Ë̼ËÌ»»Ì¼Ë»»¼Ë̼Ë̼ËÌ»»Ì¼Ë»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»golly-2.7-src/gui-wx/icons/appicon.xpm0000644000175000017500000000253012536111364014732 00000000000000/* XPM */ static const char *appicon_xpm[] = { /* width height ncolors chars_per_pixel */ "32 32 2 1", /* colors */ "A c #FFFFFFFF0000", "B c #00000000FFFF", /* pixels */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBABBABBABBABBAAAABBABBAAA", "AAABBABBABBABBABBABBAAAABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBABBABBABBABBAAAABBABBAAA", "AAABBABBABBABBABBABBAAAABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBAAAAAAAAAAAAAAAABBABBAAA", "AAABBABBAAAAAAAAAAAAAAAABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBAAAAAAAAAAAAAAAABBABBAAA", "AAABBABBAAAAAAAAAAAAAAAABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBAAAAAAAAAAAAAAAABBABBAAA", "AAABBABBAAAAAAAAAAAAAAAABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBAAAABBABBABBABBABBABBAAA", "AAABBABBAAAABBABBABBABBABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAABBABBAAAABBABBABBABBABBABBAAA", "AAABBABBAAAABBABBABBABBABBABBAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", }; golly-2.7-src/gui-wx/wxperl.cpp0000644000175000017500000030614712536111364013500 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /* Golly uses an embedded Perl interpreter to execute scripts. Perl is Copyright (C) 1993-2007, by Larry Wall and others. It is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" (http://dev.perl.org/licenses/artistic.html). */ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/filename.h" // for wxFileName #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "readpattern.h" #include "writepattern.h" #include "wxgolly.h" // for wxGetApp, mainptr, viewptr, statusptr #include "wxmain.h" // for mainptr->... #include "wxselect.h" // for Selection #include "wxview.h" // for viewptr->... #include "wxstatus.h" // for statusptr->... #include "wxutils.h" // for Warning, Note, GetString, etc #include "wxprefs.h" // for perllib, gollydir, etc #include "wxinfo.h" // for ShowInfo #include "wxhelp.h" // for ShowHelp #include "wxundo.h" // for currlayer->undoredo->... #include "wxalgos.h" // for *_ALGO, CreateNewUniverse, etc #include "wxlayer.h" // for AddLayer, currlayer, currindex, etc #include "wxscript.h" // for inscript, abortmsg, GSF_*, etc #include "wxperl.h" // ============================================================================= // Perl scripting support is implemented by embedding a Perl interpreter. // See "perldoc perlembed" for details. #ifndef __WXMAC__ #include "wx/dynlib.h" // for wxDynamicLibrary #endif // avoid warning about _ being redefined #undef _ #ifdef __WXMSW__ // on Windows, wxWidgets defines uid_t/gid_t which breaks Perl's typedefs: #undef uid_t #undef gid_t // can't do "#undef mode_t" for a typedef so use this hack: typedef unsigned short MODE1; // from C:\Perl\lib\CORE\win32.h typedef int MODE2; // from C:\wxWidgets\include\wx\filefn.h #define mode_t MODE1 #endif #include #include #include #ifdef __WXMSW__ #undef mode_t #define mode_t MODE2 #endif // restore wxWidgets definition for _ (from include/wx/intl.h) #undef _ #define _(s) wxGetTranslation(_T(s)) /* * Quoting Jan Dubois of Active State: * ActivePerl build 822 still identifies itself as 5.8.8 but already * contains many of the changes from the upcoming Perl 5.8.9 release. * * The changes include addition of two symbols (Perl_sv_2iv_flags, * Perl_newXS_flags) not present in earlier releases. * * Jan Dubois suggested the following guarding scheme: */ #if (ACTIVEPERL_VERSION >= 822) #define PERL589_OR_LATER #endif #if (PERL_REVISION == 5) && (PERL_VERSION == 8) && (PERL_SUBVERSION >= 9) #define PERL589_OR_LATER #endif #if (PERL_REVISION == 5) && (PERL_VERSION >= 9) #define PERL589_OR_LATER #endif // check if we're building with Perl 5.10 or later #if (ACTIVEPERL_VERSION >= 1000) #define PERL510_OR_LATER #endif #if (PERL_REVISION == 5) && (PERL_VERSION >= 10) #define PERL510_OR_LATER #endif // check if we're building with Perl 5.10.1 or later #if (PERL_REVISION == 5) && (PERL_VERSION == 10) && (PERL_SUBVERSION >= 1) #define PERL5101_OR_LATER #endif #if (PERL_REVISION == 5) && (PERL_VERSION >= 11) #define PERL5101_OR_LATER #endif // check if we're building with Perl 5.14 or later #if (PERL_REVISION == 5) && (PERL_VERSION >= 14) #define PERL514_OR_LATER #endif // Check if PL_thr_key is a real variable or instead a macro which calls // Perl_Gthr_key_ptr(NULL), which was the default before Perl 5.14: #ifdef PL_thr_key #define PERL_THR_KEY_FUNC 1 #endif static PerlInterpreter* my_perl = NULL; EXTERN_C void boot_DynaLoader(pTHX_ CV* cv); // ============================================================================= // On Windows and Linux we try to load the Perl library at runtime so Golly // will start up even if Perl isn't installed. // On Linux we can only load libperl dynamically if using Perl 5.10 or later. // In older Perl versions boot_DynaLoader is in DynaLoader.a and so libperl // has to be statically linked. #if defined(__WXMSW__) || (defined(__WXGTK__) && defined(PERL510_OR_LATER)) // load Perl lib at runtime #define USE_PERL_DYNAMIC #endif #ifdef USE_PERL_DYNAMIC // declare G_* wrappers for the functions we want to use from Perl lib extern "C" { #ifdef USE_ITHREADS #ifdef PERL_THR_KEY_FUNC perl_key*(*G_Perl_Gthr_key_ptr)(register PerlInterpreter*); #else perl_key *G_PL_thr_key; #endif #endif SV**(*G_Perl_av_fetch)(pTHX_ AV*, I32, I32); I32(*G_Perl_av_len)(pTHX_ AV*); void(*G_Perl_av_push)(pTHX_ AV*, SV*); void(*G_Perl_croak)(pTHX_ const char*, ...); void*(*G_Perl_get_context)(void); AV*(*G_Perl_newAV)(pTHX); SV*(*G_Perl_newRV)(pTHX_ SV*); SV*(*G_Perl_newSViv)(pTHX_ IV); SV*(*G_Perl_newSVpv)(pTHX_ const char*, STRLEN); CV*(*G_Perl_newXS)(pTHX_ char*, XSUBADDR_t, char*); SV**(*G_Perl_stack_grow)(pTHX_ SV**, SV**, int); IV(*G_Perl_sv_2iv)(pTHX_ SV*); SV*(*G_Perl_sv_2mortal)(pTHX_ SV*); char*(*G_Perl_sv_2pv_flags)(pTHX_ SV*, STRLEN*, I32); PerlInterpreter*(*G_perl_alloc)(void); void(*G_perl_construct)(PerlInterpreter*); int(*G_perl_destruct)(PerlInterpreter*); void(*G_perl_free)(PerlInterpreter*); int(*G_perl_parse)(PerlInterpreter*, XSINIT_t, int, char**, char**); int(*G_perl_run)(PerlInterpreter*); SV*(*G_Perl_eval_pv)(pTHX_ const char*, I32); #ifdef PERL589_OR_LATER IV(*G_Perl_sv_2iv_flags)(pTHX_ SV* sv, I32 flags); #endif #ifdef PERL510_OR_LATER void(*G_Perl_sys_init3)(int*, char***, char***); void(*G_Perl_sys_term)(void); #endif #ifdef PERL5101_OR_LATER SV*(*G_Perl_newSV_type)(pTHX_ svtype type); #endif void(*G_boot_DynaLoader)(pTHX_ CV*); #ifdef MULTIPLICITY #ifdef PERL510_OR_LATER SV***(*G_Perl_Istack_sp_ptr)(register PerlInterpreter*); SV***(*G_Perl_Istack_base_ptr)(register PerlInterpreter*); SV***(*G_Perl_Istack_max_ptr)(register PerlInterpreter*); I32**(*G_Perl_Imarkstack_ptr_ptr)(register PerlInterpreter*); #else SV***(*G_Perl_Tstack_sp_ptr)(register PerlInterpreter*); SV***(*G_Perl_Tstack_base_ptr)(register PerlInterpreter*); SV***(*G_Perl_Tstack_max_ptr)(register PerlInterpreter*); I32**(*G_Perl_Tmarkstack_ptr_ptr)(register PerlInterpreter*); #endif U8*(*G_Perl_Iexit_flags_ptr)(register PerlInterpreter*); signed char *(*G_Perl_Iperl_destruct_level_ptr)(register PerlInterpreter*); #else SV ***G_PL_stack_sp; SV ***G_PL_stack_base; SV ***G_PL_stack_max; I32 **G_PL_markstack_ptr; U8 *G_PL_exit_flags; signed char *G_PL_perl_destruct_level; #endif } // redefine Perl functions to their equivalent G_* wrappers #ifdef USE_ITHREADS #ifdef PERL_THR_KEY_FUNC #define Perl_Gthr_key_ptr G_Perl_Gthr_key_ptr #else #define PL_thr_key (*G_PL_thr_key) #endif #endif #define Perl_av_fetch G_Perl_av_fetch #define Perl_av_len G_Perl_av_len #define Perl_av_push G_Perl_av_push #define Perl_croak G_Perl_croak #define Perl_get_context G_Perl_get_context #define Perl_newAV G_Perl_newAV #define Perl_newRV G_Perl_newRV #define Perl_newSViv G_Perl_newSViv #define Perl_newSVpv G_Perl_newSVpv #define Perl_newXS G_Perl_newXS #define Perl_stack_grow G_Perl_stack_grow #define Perl_sv_2iv G_Perl_sv_2iv #define Perl_sv_2mortal G_Perl_sv_2mortal #define Perl_sv_2pv_flags G_Perl_sv_2pv_flags #define perl_alloc G_perl_alloc #define perl_construct G_perl_construct #define perl_destruct G_perl_destruct #define perl_free G_perl_free #define perl_parse G_perl_parse #define perl_run G_perl_run #define Perl_eval_pv G_Perl_eval_pv #ifdef PERL589_OR_LATER #define Perl_sv_2iv_flags G_Perl_sv_2iv_flags #endif #ifdef PERL510_OR_LATER #define Perl_sys_init3 G_Perl_sys_init3 #define Perl_sys_term G_Perl_sys_term #endif #ifdef MULTIPLICITY #ifdef PERL510_OR_LATER #define Perl_Imarkstack_ptr_ptr G_Perl_Imarkstack_ptr_ptr #define Perl_Istack_base_ptr G_Perl_Istack_base_ptr #define Perl_Istack_max_ptr G_Perl_Istack_max_ptr #define Perl_Istack_sp_ptr G_Perl_Istack_sp_ptr #else #define Perl_Tmarkstack_ptr_ptr G_Perl_Tmarkstack_ptr_ptr #define Perl_Tstack_base_ptr G_Perl_Tstack_base_ptr #define Perl_Tstack_max_ptr G_Perl_Tstack_max_ptr #define Perl_Tstack_sp_ptr G_Perl_Tstack_sp_ptr #endif #define Perl_Iexit_flags_ptr G_Perl_Iexit_flags_ptr #define Perl_Iperl_destruct_level_ptr G_Perl_Iperl_destruct_level_ptr #else /* no MULTIPLICITY */ #define PL_stack_sp (*G_PL_stack_sp) #define PL_stack_base (*G_PL_stack_base) #define PL_stack_max (*G_PL_stack_max) #define PL_markstack_ptr (*G_PL_markstack_ptr) #define PL_exit_flags (*G_PL_exit_flags) #define PL_perl_destruct_level (*G_PL_perl_destruct_level) #endif #ifdef PERL5101_OR_LATER #define Perl_newSV_type G_Perl_newSV_type #endif #define boot_DynaLoader G_boot_DynaLoader #ifdef __WXMSW__ #define PERL_PROC FARPROC #else #define PERL_PROC void * #endif #define PERL_FUNC(func) { _T(#func), (PERL_PROC*)&G_ ## func }, // store function names and their addresses in Perl lib static struct PerlFunc { const wxChar* name; // function name PERL_PROC* ptr; // function pointer } perlFuncs[] = { #ifdef USE_ITHREADS #ifdef PERL_THR_KEY_FUNC PERL_FUNC(Perl_Gthr_key_ptr) #else PERL_FUNC(PL_thr_key) #endif #endif PERL_FUNC(Perl_av_fetch) PERL_FUNC(Perl_av_len) PERL_FUNC(Perl_av_push) PERL_FUNC(Perl_croak) PERL_FUNC(Perl_get_context) PERL_FUNC(Perl_newAV) PERL_FUNC(Perl_newRV) PERL_FUNC(Perl_newSViv) PERL_FUNC(Perl_newSVpv) PERL_FUNC(Perl_newXS) PERL_FUNC(Perl_stack_grow) PERL_FUNC(Perl_sv_2iv) PERL_FUNC(Perl_sv_2mortal) PERL_FUNC(Perl_sv_2pv_flags) PERL_FUNC(perl_alloc) PERL_FUNC(perl_construct) PERL_FUNC(perl_destruct) PERL_FUNC(perl_free) PERL_FUNC(perl_parse) PERL_FUNC(perl_run) PERL_FUNC(Perl_eval_pv) #ifdef PERL589_OR_LATER PERL_FUNC(Perl_sv_2iv_flags) #endif #ifdef PERL510_OR_LATER PERL_FUNC(Perl_sys_init3) PERL_FUNC(Perl_sys_term) #endif #ifdef MULTIPLICITY #ifndef PERL514_OR_LATER // before Perl 5.14: PERL_FUNC(Perl_Iexit_flags_ptr) PERL_FUNC(Perl_Iperl_destruct_level_ptr) #ifdef PERL510_OR_LATER // Perl 5.10/5.12 only: PERL_FUNC(Perl_Imarkstack_ptr_ptr) PERL_FUNC(Perl_Istack_base_ptr) PERL_FUNC(Perl_Istack_max_ptr) PERL_FUNC(Perl_Istack_sp_ptr) #else // before Perl 5.10: PERL_FUNC(Perl_Tmarkstack_ptr_ptr) PERL_FUNC(Perl_Tstack_base_ptr) PERL_FUNC(Perl_Tstack_max_ptr) PERL_FUNC(Perl_Tstack_sp_ptr) #endif #endif #else /* no MULTIPLICITY */ /* N.B. these are actually variables, not functions, but the distinction does not matter for symbol resolution: */ PERL_FUNC(PL_stack_sp) PERL_FUNC(PL_stack_base) PERL_FUNC(PL_stack_max) PERL_FUNC(PL_markstack_ptr) PERL_FUNC(PL_exit_flags) PERL_FUNC(PL_perl_destruct_level) #endif #ifdef PERL5101_OR_LATER PERL_FUNC(Perl_newSV_type) #endif PERL_FUNC(boot_DynaLoader) { _T(""), NULL } }; // handle for Perl library static wxDllType perldll = NULL; static void FreePerlLib() { if ( perldll ) { wxDynamicLibrary::Unload(perldll); perldll = NULL; } } static bool LoadPerlLib() { // load the Perl library wxDynamicLibrary dynlib; // don't log errors in here wxLogNull noLog; // wxDL_GLOBAL corresponds to RTLD_GLOBAL on Linux (ignored on Windows) while ( !dynlib.Load(perllib, wxDL_NOW | wxDL_VERBATIM | wxDL_GLOBAL) ) { // prompt user for a different Perl library; // on Windows perllib should be something like "perl510.dll" // and on Linux it should be something like "libperl.so.5.10" Beep(); wxString str = _("If Perl isn't installed then you'll have to Cancel,"); str += _("\notherwise change the version numbers to match the"); str += _("\nversion installed on your system and try again."); #ifdef __WXMSW__ str += _("\n\nIf that fails, search your system for a perl*.dll"); str += _("\nfile and enter the full path to that file."); #endif wxTextEntryDialog dialog( wxGetActiveWindow(), str, _("Could not load the Perl library"), perllib, wxOK | wxCANCEL ); if (dialog.ShowModal() == wxID_OK) { perllib = dialog.GetValue(); } else { return false; } } if ( dynlib.IsLoaded() ) { // load all functions named in perlFuncs void* funcptr; PerlFunc* pf = perlFuncs; while ( pf->name[0] ) { funcptr = dynlib.GetSymbol(pf->name); if ( !funcptr ) { wxString err = _("The Perl library does not have this symbol:\n"); err += pf->name; err += _("\nYou need to install Perl "); #ifdef PERL510_OR_LATER err += _("5.10 or later."); #else err += _("5.8.x."); #endif Warning(err); return false; } *(pf++->ptr) = (PERL_PROC)funcptr; } perldll = dynlib.Detach(); } if ( perldll == NULL ) { // should never happen Warning(_("Oh dear, the Perl library is not loaded!")); } return perldll != NULL; } #endif // USE_PERL_DYNAMIC // ============================================================================= // some useful macros #define RETURN_IF_ABORTED if (PerlScriptAborted()) Perl_croak(aTHX_ NULL) #define PERL_ERROR(msg) { Perl_croak(aTHX_ "%s", msg); } #define CheckRGB(r,g,b,cmd) \ if (r < 0 || r > 255 || g < 0 || g > 255 || g < 0 || g > 255) { \ char msg[128]; \ sprintf(msg, "Bad rgb value in %s (%d,%d,%d).", cmd, r, g, b); \ PERL_ERROR(msg); \ } #ifdef __WXMSW__ #define IGNORE_UNUSED_PARAMS wxUnusedVar(cv); wxUnusedVar(my_perl); #else #define IGNORE_UNUSED_PARAMS #endif #ifdef __WXMAC__ // use decomposed UTF8 so fopen will work #define FILENAME wxString(filename,wxConvLocal).fn_str() #else #define FILENAME filename #endif // ----------------------------------------------------------------------------- void AbortPerlScript() { scripterr = wxString(abortmsg,wxConvLocal); // can't call Perl_croak here (done via RETURN_IF_ABORTED) } // ----------------------------------------------------------------------------- bool PerlScriptAborted() { if (allowcheck) wxGetApp().Poller()->checkevents(); // if user hit escape key then PassKeyToScript has called AbortPerlScript return !scripterr.IsEmpty(); } // ----------------------------------------------------------------------------- static void AddPadding(AV* array) { // assume array is multi-state and add an extra int if necessary so the array // has an odd number of ints (this is how we distinguish multi-state arrays // from one-state arrays -- the latter always have an even number of ints) int len = av_len(array) + 1; if (len == 0) return; // always return () rather than (0) if ((len & 1) == 0) { av_push(array, newSViv(0)); } } // ----------------------------------------------------------------------------- static const char* ExtractCellArray(AV* outarray, lifealgo* universe, bool shift = false) { // extract cell array from given universe if ( !universe->isEmpty() ) { bigint top, left, bottom, right; universe->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { return "Universe is too big to extract all cells!"; } bool multistate = universe->NumCellStates() > 2; int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int cx, cy; int v = 0; int cntr = 0; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = universe->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (shift) { // shift cells so that top left cell of bounding box is at 0,0 av_push(outarray, newSViv(cx - ileft)); av_push(outarray, newSViv(cy - itop)); } else { av_push(outarray, newSViv(cx)); av_push(outarray, newSViv(cy)); } if (multistate) av_push(outarray, newSViv(v)); } else { cx = iright; // done this row } cntr++; if ((cntr % 4096) == 0 && PerlScriptAborted()) return NULL; } } if (multistate) AddPadding(outarray); } return NULL; } // ============================================================================= // The following pl_* routines can be called from Perl scripts. XS(pl_open) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items < 1 || items > 2) PERL_ERROR("Usage: g_open($filename,$remember=0)."); STRLEN n_a; char* filename = SvPV(ST(0), n_a); int remember = 0; if (items > 1) remember = SvIV(ST(1)); const char* err = GSF_open(filename, remember); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_save) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items < 2 || items > 3) PERL_ERROR("Usage: g_save($filename,$format,$remember=0)."); STRLEN n_a; char* filename = SvPV(ST(0), n_a); char* format = SvPV(ST(1), n_a); int remember = 0; if (items > 2) remember = SvIV(ST(2)); const char* err = GSF_save(filename, format, remember); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_opendialog) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 5) PERL_ERROR("Usage: g_opendialog($title, $filetypes," "$initialdir, $initialfname, $mustexist=1)."); const char* title = "Choose a file"; const char* filetypes = "All files (*)|*"; const char* initialdir = ""; const char* initialfname = ""; int mustexist = 1; STRLEN n_a; if (items > 0) title = SvPV(ST(0), n_a); if (items > 1) filetypes = SvPV(ST(1), n_a); if (items > 2) initialdir = SvPV(ST(2), n_a); if (items > 3) initialfname = SvPV(ST(3), n_a); if (items > 4) mustexist = SvIV(ST(4)); wxString wxs_title(title, wxConvLocal); wxString wxs_filetypes(filetypes, wxConvLocal); wxString wxs_initialdir(initialdir, wxConvLocal); wxString wxs_initialfname(initialfname, wxConvLocal); wxString wxs_result = wxEmptyString; if (wxs_initialdir.IsEmpty()) wxs_initialdir = wxFileName::GetCwd(); if (wxs_filetypes == wxT("dir")) { // let user choose a directory wxDirDialog dirdlg(NULL, wxs_title, wxs_initialdir, wxDD_NEW_DIR_BUTTON); if (dirdlg.ShowModal() == wxID_OK) { wxs_result = dirdlg.GetPath(); if (wxs_result.Last() != wxFILE_SEP_PATH) wxs_result += wxFILE_SEP_PATH; } } else { // let user choose a file wxFileDialog opendlg(NULL, wxs_title, wxs_initialdir, wxs_initialfname, wxs_filetypes, wxFD_OPEN | (mustexist == 0 ? 0 : wxFD_FILE_MUST_EXIST) ); #ifdef __WXGTK__ // wxs_initialdir is ignored above (bug in wxGTK 2.8.0???) opendlg.SetDirectory(wxs_initialdir); #endif if (opendlg.ShowModal() == wxID_OK) wxs_result = opendlg.GetPath(); } XSRETURN_PV((const char*)wxs_result.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- XS(pl_savedialog) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 5) PERL_ERROR("Usage: g_savedialog($title, $filetypes," " $initialdir, $initialfname, $suppressprompt=0)."); const char* title = "Choose a save location and filename"; const char* filetypes = "All files (*)|*"; const char* initialdir = ""; const char* initialfname = ""; STRLEN n_a; if (items > 0) title = SvPV(ST(0), n_a); if (items > 1) filetypes = SvPV(ST(1), n_a); if (items > 2) initialdir = SvPV(ST(2), n_a); if (items > 3) initialfname = SvPV(ST(3), n_a); int suppressprompt = 0; if (items > 4) suppressprompt = SvIV(ST(4)); wxString wxs_title(title, wxConvLocal); wxString wxs_filetypes(filetypes, wxConvLocal); wxString wxs_initialdir(initialdir, wxConvLocal); wxString wxs_initialfname(initialfname, wxConvLocal); if (wxs_initialdir.IsEmpty()) wxs_initialdir = wxFileName::GetCwd(); // suppress Overwrite? popup if user just wants to retrieve the string wxFileDialog savedlg( NULL, wxs_title, wxs_initialdir, wxs_initialfname, wxs_filetypes, wxFD_SAVE | (suppressprompt == 0 ? wxFD_OVERWRITE_PROMPT : 0) ); #ifdef __WXGTK__ savedlg.SetDirectory(wxs_initialdir); #endif wxString wxs_savefname = wxEmptyString; if ( savedlg.ShowModal() == wxID_OK ) wxs_savefname = savedlg.GetPath(); XSRETURN_PV((const char*)wxs_savefname.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- XS(pl_load) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: $cells = g_load($filename)."); STRLEN n_a; char* filename = SvPV(ST(0), n_a); // create temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, allowcheck); // readpattern will call setrule // read pattern into temporary universe const char* err = readpattern(FILENAME, *tempalgo); if (err) { // try all other algos until readpattern succeeds for (int i = 0; i < NumAlgos(); i++) { if (i != currlayer->algtype) { delete tempalgo; tempalgo = CreateNewUniverse(i, allowcheck); err = readpattern(FILENAME, *tempalgo); if (!err) break; } } } if (err) { delete tempalgo; PERL_ERROR(err); } // convert pattern into a cell array, shifting cell coords so that the // bounding box's top left cell is at 0,0 AV* outarray = (AV*)sv_2mortal( (SV*)newAV() ); err = ExtractCellArray(outarray, tempalgo, true); delete tempalgo; if (err) PERL_ERROR(err); SP -= items; ST(0) = newRV( (SV*)outarray ); sv_2mortal(ST(0)); XSRETURN(1); } // ----------------------------------------------------------------------------- XS(pl_store) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: g_store($cells,$filename)."); SV* cells = ST(0); if ( (!SvROK(cells)) || (SvTYPE(SvRV(cells)) != SVt_PVAV) ) { PERL_ERROR("g_store error: 1st parameter is not a valid array reference."); } AV* inarray = (AV*)SvRV(cells); STRLEN n_a; char* filename = SvPV(ST(1), n_a); // create temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, allowcheck); const char* err = tempalgo->setrule(currlayer->algo->getrule()); if (err) tempalgo->setrule(tempalgo->DefaultRule()); // copy cell array into temporary universe bool multistate = ((av_len(inarray) + 1) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = (av_len(inarray) + 1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; int x = SvIV( *av_fetch(inarray, item, 0) ); int y = SvIV( *av_fetch(inarray, item + 1, 0) ); // check if x,y is outside bounded grid const char* err = GSF_checkpos(tempalgo, x, y); if (err) { delete tempalgo; PERL_ERROR(err); } if (multistate) { int state = SvIV( *av_fetch(inarray, item + 2, 0) ); if (tempalgo->setcell(x, y, state) < 0) { tempalgo->endofpattern(); delete tempalgo; PERL_ERROR("g_store error: state value is out of range."); } } else { tempalgo->setcell(x, y, 1); } if ((n % 4096) == 0 && PerlScriptAborted()) { tempalgo->endofpattern(); delete tempalgo; Perl_croak(aTHX_ NULL); } } tempalgo->endofpattern(); // write pattern to given file in RLE/XRLE format bigint top, left, bottom, right; tempalgo->findedges(&top, &left, &bottom, &right); pattern_format format = savexrle ? XRLE_format : RLE_format; // if grid is bounded then force XRLE_format so that position info is recorded if (tempalgo->gridwd > 0 || tempalgo->gridht > 0) format = XRLE_format; err = writepattern(FILENAME, *tempalgo, format, no_compression, top.toint(), left.toint(), bottom.toint(), right.toint()); delete tempalgo; if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- // deprecated (use pl_getdir) XS(pl_appdir) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $dir = g_appdir()."); XSRETURN_PV((const char*)gollydir.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- // deprecated (use pl_getdir) XS(pl_datadir) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $dir = g_datadir()."); XSRETURN_PV((const char*)datadir.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- XS(pl_setdir) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: g_setdir($dirname,$newdir)."); STRLEN n_a; char* dirname = SvPV(ST(0), n_a); char* newdir = SvPV(ST(1), n_a); const char* err = GSF_setdir(dirname, newdir); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getdir) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: $dir = g_getdir($dirname)."); STRLEN n_a; char* dirname = SvPV(ST(0), n_a); const char* dirstring = GSF_getdir(dirname); if (dirstring == NULL) PERL_ERROR("g_getdir error: unknown directory name."); XSRETURN_PV(dirstring); } // ----------------------------------------------------------------------------- XS(pl_new) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_new($title)."); STRLEN n_a; char* title = SvPV(ST(0), n_a); mainptr->NewPattern(wxString(title,wxConvLocal)); DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_cut) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_cut()."); if (viewptr->SelectionExists()) { viewptr->CutSelection(); DoAutoUpdate(); } else { PERL_ERROR("g_cut error: no selection."); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_copy) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_copy()."); if (viewptr->SelectionExists()) { viewptr->CopySelection(); DoAutoUpdate(); } else { PERL_ERROR("g_copy error: no selection."); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_clear) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_clear($where)."); int where = SvIV(ST(0)); if (viewptr->SelectionExists()) { if (where == 0) viewptr->ClearSelection(); else viewptr->ClearOutsideSelection(); DoAutoUpdate(); } else { PERL_ERROR("g_clear error: no selection."); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_paste) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 3) PERL_ERROR("Usage: g_paste($x,$y,$mode)."); int x = SvIV(ST(0)); int y = SvIV(ST(1)); STRLEN n_a; char* mode = SvPV(ST(2), n_a); const char* err = GSF_paste(x, y, mode); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_shrink) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_shrink()."); if (viewptr->SelectionExists()) { viewptr->ShrinkSelection(false); // false == don't fit in viewport DoAutoUpdate(); } else { PERL_ERROR("g_shrink error: no selection."); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_randfill) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_randfill($percentage)."); int perc = SvIV(ST(0)); if (perc < 1 || perc > 100) { PERL_ERROR("g_randfill error: percentage must be from 1 to 100."); } if (viewptr->SelectionExists()) { int oldperc = randomfill; randomfill = perc; viewptr->RandomFill(); randomfill = oldperc; DoAutoUpdate(); } else { PERL_ERROR("g_randfill error: no selection."); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_flip) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_flip($direction)."); int direction = SvIV(ST(0)); if (viewptr->SelectionExists()) { viewptr->FlipSelection(direction != 0); // 1 = top-bottom DoAutoUpdate(); } else { PERL_ERROR("g_flip error: no selection."); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_rotate) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_rotate($direction)."); int direction = SvIV(ST(0)); if (viewptr->SelectionExists()) { viewptr->RotateSelection(direction == 0); // 0 = clockwise DoAutoUpdate(); } else { PERL_ERROR("g_rotate error: no selection."); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_parse) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items < 1 || items > 7) PERL_ERROR("Usage: $outcells = g_parse($string,$x=0,$y=0,$axx=1,$axy=0,$ayx=0,$ayy=1)."); STRLEN n_a; char* s = SvPV(ST(0), n_a); // default values for optional params int x0 = 0; int y0 = 0; int axx = 1; int axy = 0; int ayx = 0; int ayy = 1; if (items > 1) x0 = SvIV(ST(1)); if (items > 2) y0 = SvIV(ST(2)); if (items > 3) axx = SvIV(ST(3)); if (items > 4) axy = SvIV(ST(4)); if (items > 5) ayx = SvIV(ST(5)); if (items > 6) ayy = SvIV(ST(6)); AV* outarray = (AV*)sv_2mortal( (SV*)newAV() ); int x = 0, y = 0; if (strchr(s, '*')) { // parsing 'visual' format int c = *s++; while (c) { switch (c) { case '\n': if (x) { x = 0; y++; } break; case '.': x++; break; case '*': av_push(outarray, newSViv(x0 + x * axx + y * axy)); av_push(outarray, newSViv(y0 + x * ayx + y * ayy)); x++; break; } c = *s++; } } else { // parsing RLE format; first check if multi-state data is present bool multistate = false; char* p = s; while (*p) { char c = *p++; if ((c == '.') || ('p' <= c && c <= 'y') || ('A' <= c && c <= 'X')) { multistate = true; break; } } int prefix = 0; bool done = false; int c = *s++; while (c && !done) { if (isdigit(c)) prefix = 10 * prefix + (c - '0'); else { prefix += (prefix == 0); switch (c) { case '!': done = true; break; case '$': x = 0; y += prefix; break; case 'b': x += prefix; break; case '.': x += prefix; break; case 'o': for (int k = 0; k < prefix; k++, x++) { av_push(outarray, newSViv(x0 + x * axx + y * axy)); av_push(outarray, newSViv(y0 + x * ayx + y * ayy)); if (multistate) av_push(outarray, newSViv(1)); } break; default: if (('p' <= c && c <= 'y') || ('A' <= c && c <= 'X')) { // multistate must be true int state; if (c < 'p') { state = c - 'A' + 1; } else { state = 24 * (c - 'p' + 1); c = *s++; if ('A' <= c && c <= 'X') { state = state + c - 'A' + 1; } else { // PERL_ERROR("g_parse error: illegal multi-char state."); // be more forgiving and treat 'p'..'y' like 'o' state = 1; s--; } } for (int k = 0; k < prefix; k++, x++) { av_push(outarray, newSViv(x0 + x * axx + y * axy)); av_push(outarray, newSViv(y0 + x * ayx + y * ayy)); av_push(outarray, newSViv(state)); } } } prefix = 0; } c = *s++; } if (multistate) AddPadding(outarray); } SP -= items; ST(0) = newRV( (SV*)outarray ); sv_2mortal(ST(0)); XSRETURN(1); } // ----------------------------------------------------------------------------- XS(pl_transform) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items < 3 || items > 7) PERL_ERROR("Usage: $outcells = g_transform($cells,$x,$y,$axx=1,$axy=0,$ayx=0,$ayy=1)."); SV* cells = ST(0); if ( (!SvROK(cells)) || (SvTYPE(SvRV(cells)) != SVt_PVAV) ) { PERL_ERROR("g_transform error: 1st parameter is not a valid array reference."); } AV* inarray = (AV*)SvRV(cells); int x0 = SvIV(ST(1)); int y0 = SvIV(ST(2)); // default values for optional params int axx = 1; int axy = 0; int ayx = 0; int ayy = 1; if (items > 3) axx = SvIV(ST(3)); if (items > 4) axy = SvIV(ST(4)); if (items > 5) ayx = SvIV(ST(5)); if (items > 6) ayy = SvIV(ST(6)); AV* outarray = (AV*)sv_2mortal( (SV*)newAV() ); bool multistate = ((av_len(inarray) + 1) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = (av_len(inarray) + 1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; int x = SvIV( *av_fetch(inarray, item, 0) ); int y = SvIV( *av_fetch(inarray, item + 1, 0) ); av_push(outarray, newSViv(x0 + x * axx + y * axy)); av_push(outarray, newSViv(y0 + x * ayx + y * ayy)); if (multistate) { int state = SvIV( *av_fetch(inarray, item + 2, 0) ); av_push(outarray, newSViv(state)); } if ((n % 4096) == 0 && PerlScriptAborted()) break; } if (multistate) AddPadding(outarray); SP -= items; ST(0) = newRV( (SV*)outarray ); sv_2mortal(ST(0)); XSRETURN(1); } // ----------------------------------------------------------------------------- XS(pl_evolve) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: $outcells = g_evolve($cells,$numgens)."); SV* cells = ST(0); if ( (!SvROK(cells)) || (SvTYPE(SvRV(cells)) != SVt_PVAV) ) { PERL_ERROR("g_evolve error: 1st parameter is not a valid array reference."); } AV* inarray = (AV*)SvRV(cells); int ngens = SvIV(ST(1)); if (ngens < 0) { PERL_ERROR("g_evolve error: number of generations is negative."); } // create a temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, allowcheck); const char* err = tempalgo->setrule(currlayer->algo->getrule()); if (err) tempalgo->setrule(tempalgo->DefaultRule()); // copy cell array into temporary universe bool multistate = ((av_len(inarray) + 1) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = (av_len(inarray) + 1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; int x = SvIV( *av_fetch(inarray, item, 0) ); int y = SvIV( *av_fetch(inarray, item + 1, 0) ); // check if x,y is outside bounded grid const char* err = GSF_checkpos(tempalgo, x, y); if (err) { delete tempalgo; PERL_ERROR(err); } if (multistate) { int state = SvIV( *av_fetch(inarray, item + 2, 0) ); if (tempalgo->setcell(x, y, state) < 0) { tempalgo->endofpattern(); delete tempalgo; PERL_ERROR("g_evolve error: state value is out of range."); } } else { tempalgo->setcell(x, y, 1); } if ((n % 4096) == 0 && PerlScriptAborted()) { tempalgo->endofpattern(); delete tempalgo; Perl_croak(aTHX_ NULL); } } tempalgo->endofpattern(); // advance pattern by ngens mainptr->generating = true; if (tempalgo->gridwd > 0 || tempalgo->gridht > 0) { // a bounded grid must use an increment of 1 so we can call // CreateBorderCells and DeleteBorderCells around each step() tempalgo->setIncrement(1); while (ngens > 0) { if (PerlScriptAborted()) { mainptr->generating = false; delete tempalgo; Perl_croak(aTHX_ NULL); } if (!mainptr->CreateBorderCells(tempalgo)) break; tempalgo->step(); if (!mainptr->DeleteBorderCells(tempalgo)) break; ngens--; } } else { tempalgo->setIncrement(ngens); tempalgo->step(); } mainptr->generating = false; // convert new pattern into a new cell array AV* outarray = (AV*)sv_2mortal( (SV*)newAV() ); err = ExtractCellArray(outarray, tempalgo); delete tempalgo; if (err) PERL_ERROR(err); SP -= items; ST(0) = newRV( (SV*)outarray ); sv_2mortal(ST(0)); XSRETURN(1); } // ----------------------------------------------------------------------------- static const char* BAD_STATE = "g_putcells error: state value is out of range."; XS(pl_putcells) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items < 1 || items > 8) PERL_ERROR("Usage: g_putcells($cells,$x=0,$y=0,$axx=1,$axy=0,$ayx=0,$ayy=1,$mode='or')."); SV* cells = ST(0); if ( (!SvROK(cells)) || (SvTYPE(SvRV(cells)) != SVt_PVAV) ) { PERL_ERROR("g_putcells error: 1st parameter is not a valid array reference."); } AV* inarray = (AV*)SvRV(cells); // default values for optional params int x0 = 0; int y0 = 0; int axx = 1; int axy = 0; int ayx = 0; int ayy = 1; // default for mode is 'or'; 'xor' mode is also supported; // for a one-state array 'copy' mode currently has the same effect as 'or' mode // because there is no bounding box to set dead cells, but a multi-state array can // have dead cells so in that case 'copy' mode is not the same as 'or' mode const char* mode = "or"; STRLEN n_a; if (items > 1) x0 = SvIV(ST(1)); if (items > 2) y0 = SvIV(ST(2)); if (items > 3) axx = SvIV(ST(3)); if (items > 4) axy = SvIV(ST(4)); if (items > 5) ayx = SvIV(ST(5)); if (items > 6) ayy = SvIV(ST(6)); if (items > 7) mode = SvPV(ST(7), n_a); wxString modestr = wxString(mode, wxConvLocal); if ( !( modestr.IsSameAs(wxT("or"), false) || modestr.IsSameAs(wxT("xor"), false) || modestr.IsSameAs(wxT("copy"), false) || modestr.IsSameAs(wxT("and"), false) || modestr.IsSameAs(wxT("not"), false)) ) { PERL_ERROR("g_putcells error: unknown mode."); } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; // use ChangeCell below and combine all changes due to consecutive setcell/putcells // if (savecells) SavePendingChanges(); // note that av_len returns max index or -1 if array is empty bool multistate = ((av_len(inarray) + 1) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = (av_len(inarray) + 1) / ints_per_cell; const char* err = NULL; bool pattchanged = false; lifealgo* curralgo = currlayer->algo; if (modestr.IsSameAs(wxT("copy"), false)) { // TODO: find bounds of cell array and call ClearRect here (to be added to wxedit.cpp) } if (modestr.IsSameAs(wxT("and"), false)) { if (!curralgo->isEmpty()) { int newstate = 1; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; int x = SvIV( *av_fetch(inarray, item, 0) ); int y = SvIV( *av_fetch(inarray, item + 1, 0) ); int newx = x0 + x * axx + y * axy; int newy = y0 + x * ayx + y * ayy; // check if newx,newy is outside bounded grid err = GSF_checkpos(curralgo, newx, newy); if (err) break; int oldstate = curralgo->getcell(newx, newy); if (multistate) { // multi-state lists can contain dead cells so newstate might be 0 newstate = SvIV( *av_fetch(inarray, item + 2, 0) ); } if (newstate != oldstate && oldstate > 0) { curralgo->setcell(newx, newy, 0); if (savecells) ChangeCell(newx, newy, oldstate, 0); pattchanged = true; } if ((n % 4096) == 0 && PerlScriptAborted()) break; } } } else if (modestr.IsSameAs(wxT("xor"), false)) { // loop code is duplicated here to allow 'or' case to execute faster int numstates = curralgo->NumCellStates(); for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; int x = SvIV( *av_fetch(inarray, item, 0) ); int y = SvIV( *av_fetch(inarray, item + 1, 0) ); int newx = x0 + x * axx + y * axy; int newy = y0 + x * ayx + y * ayy; // check if newx,newy is outside bounded grid err = GSF_checkpos(curralgo, newx, newy); if (err) break; int oldstate = curralgo->getcell(newx, newy); int newstate; if (multistate) { // multi-state arrays can contain dead cells so newstate might be 0 newstate = SvIV( *av_fetch(inarray, item + 2, 0) ); if (newstate == oldstate) { if (oldstate != 0) newstate = 0; } else { newstate = newstate ^ oldstate; // if xor overflows then don't change current state if (newstate >= numstates) newstate = oldstate; } if (newstate != oldstate) { // paste (possibly transformed) cell into current universe if (curralgo->setcell(newx, newy, newstate) < 0) { err = BAD_STATE; break; } if (savecells) ChangeCell(newx, newy, oldstate, newstate); pattchanged = true; } } else { // one-state arrays only contain live cells newstate = 1 - oldstate; // paste (possibly transformed) cell into current universe if (curralgo->setcell(newx, newy, newstate) < 0) { err = BAD_STATE; break; } if (savecells) ChangeCell(newx, newy, oldstate, newstate); pattchanged = true; } if ((n % 4096) == 0 && PerlScriptAborted()) break; } } else { bool negate = modestr.IsSameAs(wxT("not"), false); bool ormode = modestr.IsSameAs(wxT("or"), false); int newstate = negate ? 0 : 1; int maxstate = curralgo->NumCellStates() - 1; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; int x = SvIV( *av_fetch(inarray, item, 0) ); int y = SvIV( *av_fetch(inarray, item + 1, 0) ); int newx = x0 + x * axx + y * axy; int newy = y0 + x * ayx + y * ayy; // check if newx,newy is outside bounded grid err = GSF_checkpos(curralgo, newx, newy); if (err) break; int oldstate = curralgo->getcell(newx, newy); if (multistate) { // multi-state arrays can contain dead cells so newstate might be 0 newstate = SvIV( *av_fetch(inarray, item + 2, 0) ); if (negate) newstate = maxstate - newstate; if (ormode && newstate == 0) newstate = oldstate; } if (newstate != oldstate) { // paste (possibly transformed) cell into current universe if (curralgo->setcell(newx, newy, newstate) < 0) { err = BAD_STATE; break; } if (savecells) ChangeCell(newx, newy, oldstate, newstate); pattchanged = true; } if ((n % 4096) == 0 && PerlScriptAborted()) break; } } if (pattchanged) { curralgo->endofpattern(); MarkLayerDirty(); DoAutoUpdate(); } if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getcells) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0 && items != 4) PERL_ERROR("Usage: $cells = g_getcells(@rect)."); // convert pattern in given rect into a cell array (ie. array of live cell coords) AV* outarray = (AV*)sv_2mortal( (SV*)newAV() ); if (items == 0) { // return empty cell array } else { // items == 4 int x = SvIV(ST(0)); int y = SvIV(ST(1)); int wd = SvIV(ST(2)); int ht = SvIV(ST(3)); const char* err = GSF_checkrect(x, y, wd, ht); if (err) PERL_ERROR(err); int right = x + wd - 1; int bottom = y + ht - 1; int cx, cy; int v = 0; int cntr = 0; lifealgo* curralgo = currlayer->algo; bool multistate = curralgo->NumCellStates() > 2; for ( cy=y; cy<=bottom; cy++ ) { for ( cx=x; cx<=right; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row so add coords to outarray cx += skip; if (cx <= right) { av_push(outarray, newSViv(cx)); av_push(outarray, newSViv(cy)); if (multistate) av_push(outarray, newSViv(v)); } } else { cx = right; // done this row } cntr++; if ((cntr % 4096) == 0) RETURN_IF_ABORTED; } } if (multistate) AddPadding(outarray); } SP -= items; ST(0) = newRV( (SV*)outarray ); sv_2mortal(ST(0)); XSRETURN(1); } // ----------------------------------------------------------------------------- XS(pl_join) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: $outcells = g_join($cells1,$cells2)."); SV* cells1 = ST(0); SV* cells2 = ST(1); if ( (!SvROK(cells1)) || (SvTYPE(SvRV(cells1)) != SVt_PVAV) ) { PERL_ERROR("g_join error: 1st parameter is not a valid array reference."); } if ( (!SvROK(cells2)) || (SvTYPE(SvRV(cells2)) != SVt_PVAV) ) { PERL_ERROR("g_join error: 2nd parameter is not a valid array reference."); } AV* inarray1 = (AV*)SvRV(cells1); AV* inarray2 = (AV*)SvRV(cells2); bool multi1 = ((av_len(inarray1) + 1) & 1) == 1; bool multi2 = ((av_len(inarray2) + 1) & 1) == 1; bool multiout = multi1 || multi2; int ints_per_cell, num_cells; int x, y, state; AV* outarray = (AV*)sv_2mortal( (SV*)newAV() ); // append 1st array ints_per_cell = multi1 ? 3 : 2; num_cells = (av_len(inarray1) + 1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; x = SvIV( *av_fetch(inarray1, item, 0) ); y = SvIV( *av_fetch(inarray1, item + 1, 0) ); if (multi1) { state = SvIV( *av_fetch(inarray1, item + 2, 0) ); } else { state = 1; } av_push(outarray, newSViv(x)); av_push(outarray, newSViv(y)); if (multiout) av_push(outarray, newSViv(state)); if ((n % 4096) == 0 && PerlScriptAborted()) { Perl_croak(aTHX_ NULL); } } // append 2nd array ints_per_cell = multi2 ? 3 : 2; num_cells = (av_len(inarray2) + 1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; x = SvIV( *av_fetch(inarray2, item, 0) ); y = SvIV( *av_fetch(inarray2, item + 1, 0) ); if (multi2) { state = SvIV( *av_fetch(inarray2, item + 2, 0) ); } else { state = 1; } av_push(outarray, newSViv(x)); av_push(outarray, newSViv(y)); if (multiout) av_push(outarray, newSViv(state)); if ((n % 4096) == 0 && PerlScriptAborted()) { Perl_croak(aTHX_ NULL); } } if (multiout) AddPadding(outarray); SP -= items; ST(0) = newRV( (SV*)outarray ); sv_2mortal(ST(0)); XSRETURN(1); } // ----------------------------------------------------------------------------- XS(pl_hash) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 4) PERL_ERROR("Usage: $int = g_hash(@rect)."); int x = SvIV(ST(0)); int y = SvIV(ST(1)); int wd = SvIV(ST(2)); int ht = SvIV(ST(3)); const char* err = GSF_checkrect(x, y, wd, ht); if (err) PERL_ERROR(err); int hash = GSF_hash(x, y, wd, ht); XSRETURN_IV(hash); } // ----------------------------------------------------------------------------- XS(pl_getclip) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $cells = g_getclip()."); if (!mainptr->ClipboardHasText()) { PERL_ERROR("g_getclip error: no pattern in clipboard."); } // convert pattern in clipboard into a cell array, but where the first 2 items // are the pattern's width and height (not necessarily the minimal bounding box // because the pattern might have empty borders, or it might even be empty) AV* outarray = (AV*)sv_2mortal( (SV*)newAV() ); // create a temporary universe for storing clipboard pattern; // GetClipboardPattern assumes it is same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, allowcheck); const char* err = tempalgo->setrule(currlayer->algo->getrule()); if (err) tempalgo->setrule(tempalgo->DefaultRule()); // read clipboard pattern into temporary universe and set edges // (not a minimal bounding box if pattern is empty or has empty borders) bigint top, left, bottom, right; if ( viewptr->GetClipboardPattern(&tempalgo, &top, &left, &bottom, &right) ) { if ( viewptr->OutsideLimits(top, left, bottom, right) ) { delete tempalgo; PERL_ERROR("g_getclip error: pattern is too big."); } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; av_push(outarray, newSViv(wd)); av_push(outarray, newSViv(ht)); // extract cells from tempalgo bool multistate = tempalgo->NumCellStates() > 2; int cx, cy; int cntr = 0; int v = 0; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = tempalgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; // shift cells so that top left cell of bounding box is at 0,0 av_push(outarray, newSViv(cx - ileft)); av_push(outarray, newSViv(cy - itop)); if (multistate) av_push(outarray, newSViv(v)); } else { cx = iright; // done this row } cntr++; if ((cntr % 4096) == 0 && PerlScriptAborted()) { delete tempalgo; Perl_croak(aTHX_ NULL); } } } // if no live cells then return (wd,ht) rather than (wd,ht,0) if (multistate && (av_len(outarray) + 1) > 2) { AddPadding(outarray); } delete tempalgo; } else { // assume error message has been displayed delete tempalgo; Perl_croak(aTHX_ NULL); } SP -= items; ST(0) = newRV( (SV*)outarray ); sv_2mortal(ST(0)); XSRETURN(1); } // ----------------------------------------------------------------------------- XS(pl_select) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0 && items != 4) PERL_ERROR("Usage: g_select(@rect)."); if (items == 0) { // remove any existing selection GSF_select(0, 0, 0, 0); } else { // items == 4 int x = SvIV(ST(0)); int y = SvIV(ST(1)); int wd = SvIV(ST(2)); int ht = SvIV(ST(3)); const char* err = GSF_checkrect(x, y, wd, ht); if (err) PERL_ERROR(err); // set selection rect GSF_select(x, y, wd, ht); } DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getrect) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: @rect = g_getrect()."); if (!currlayer->algo->isEmpty()) { bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( viewptr->OutsideLimits(top, left, bottom, right) ) { PERL_ERROR("g_getrect error: pattern is too big."); } int x = left.toint(); int y = top.toint(); int wd = right.toint() - x + 1; int ht = bottom.toint() - y + 1; // items == 0 so no need to reset stack pointer // SP -= items; XPUSHs(sv_2mortal(newSViv(x))); XPUSHs(sv_2mortal(newSViv(y))); XPUSHs(sv_2mortal(newSViv(wd))); XPUSHs(sv_2mortal(newSViv(ht))); XSRETURN(4); } else { XSRETURN(0); } } // ----------------------------------------------------------------------------- XS(pl_getselrect) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: @rect = g_getselrect()."); if (viewptr->SelectionExists()) { if (currlayer->currsel.TooBig()) { PERL_ERROR("g_getselrect error: selection is too big."); } int x, y, wd, ht; currlayer->currsel.GetRect(&x, &y, &wd, &ht); // items == 0 so no need to reset stack pointer // SP -= items; XPUSHs(sv_2mortal(newSViv(x))); XPUSHs(sv_2mortal(newSViv(y))); XPUSHs(sv_2mortal(newSViv(wd))); XPUSHs(sv_2mortal(newSViv(ht))); XSRETURN(4); } else { XSRETURN(0); } } // ----------------------------------------------------------------------------- XS(pl_setcell) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 3) PERL_ERROR("Usage: g_setcell($x,$y,$state)."); int x = SvIV(ST(0)); int y = SvIV(ST(1)); int state = SvIV(ST(2)); const char* err = GSF_setcell(x, y, state); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getcell) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: $state = g_getcell($x,$y)."); int x = SvIV(ST(0)); int y = SvIV(ST(1)); // check if x,y is outside bounded grid const char* err = GSF_checkpos(currlayer->algo, x, y); if (err) PERL_ERROR(err); int state = currlayer->algo->getcell(x, y); XSRETURN_IV(state); } // ----------------------------------------------------------------------------- XS(pl_setcursor) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: $oldcurs = g_setcursor($newcurs)."); STRLEN n_a; const char* newcursor = SvPV(ST(0), n_a); const char* oldcursor = CursorToString(currlayer->curs); wxCursor* cursptr = StringToCursor(newcursor); if (cursptr) { viewptr->SetCursorMode(cursptr); // see the cursor change, including button in edit bar mainptr->UpdateUserInterface(); } else { PERL_ERROR("g_setcursor error: unknown cursor string."); } // return old cursor (simplifies saving and restoring cursor) XSRETURN_PV(oldcursor); } // ----------------------------------------------------------------------------- XS(pl_getcursor) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $string = g_getcursor()."); XSRETURN_PV(CursorToString(currlayer->curs)); } // ----------------------------------------------------------------------------- XS(pl_empty) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $bool = g_empty()."); XSRETURN_IV(currlayer->algo->isEmpty() ? 1 : 0); } // ----------------------------------------------------------------------------- XS(pl_run) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_run($numgens)."); int ngens = SvIV(ST(0)); if (ngens > 0 && !currlayer->algo->isEmpty()) { if (ngens > 1) { bigint saveinc = currlayer->algo->getIncrement(); currlayer->algo->setIncrement(ngens); mainptr->NextGeneration(true); // step by ngens currlayer->algo->setIncrement(saveinc); } else { mainptr->NextGeneration(false); // step 1 gen } DoAutoUpdate(); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_step) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_step()."); if (!currlayer->algo->isEmpty()) { mainptr->NextGeneration(true); // step by current increment DoAutoUpdate(); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_setstep) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setstep($int)."); mainptr->SetStepExponent(SvIV(ST(0))); DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getstep) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_getstep()."); XSRETURN_IV(currlayer->currexpo); } // ----------------------------------------------------------------------------- XS(pl_setbase) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setbase($int)."); int base = SvIV(ST(0)); if (base < 2) base = 2; if (base > MAX_BASESTEP) base = MAX_BASESTEP; currlayer->currbase = base; mainptr->SetGenIncrement(); DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getbase) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_getbase()."); XSRETURN_IV(currlayer->currbase); } // ----------------------------------------------------------------------------- XS(pl_advance) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: g_advance($where,$numgens)."); int where = SvIV(ST(0)); int ngens = SvIV(ST(1)); if (ngens > 0) { if (viewptr->SelectionExists()) { while (ngens > 0) { ngens--; if (where == 0) currlayer->currsel.Advance(); else currlayer->currsel.AdvanceOutside(); } DoAutoUpdate(); } else { PERL_ERROR("g_advance error: no selection."); } } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_reset) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_reset()."); if (currlayer->algo->getGeneration() != currlayer->startgen) { mainptr->ResetPattern(); DoAutoUpdate(); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_setgen) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setgen($string)."); STRLEN n_a; char* genstring = SvPV(ST(0), n_a); const char* err = GSF_setgen(genstring); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getgen) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 1) PERL_ERROR("Usage: $string = g_getgen($sepchar='')."); char sepchar = '\0'; if (items > 0) { STRLEN n_a; char* s = SvPV(ST(0), n_a); sepchar = s[0]; } XSRETURN_PV(currlayer->algo->getGeneration().tostring(sepchar)); } // ----------------------------------------------------------------------------- XS(pl_getpop) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 1) PERL_ERROR("Usage: $string = g_getpop($sepchar='')."); char sepchar = '\0'; if (items > 0) { STRLEN n_a; char* s = SvPV(ST(0), n_a); sepchar = s[0]; } XSRETURN_PV(currlayer->algo->getPopulation().tostring(sepchar)); } // ----------------------------------------------------------------------------- XS(pl_setalgo) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setalgo($string)."); STRLEN n_a; char* algostring = SvPV(ST(0), n_a); const char* err = GSF_setalgo(algostring); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getalgo) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 1) PERL_ERROR("Usage: $algo = g_getalgo($index=current)."); int index = currlayer->algtype; if (items > 0) index = SvIV(ST(0)); if (index < 0 || index >= NumAlgos()) { char msg[64]; sprintf(msg, "Bad g_getalgo index (%d).", index); PERL_ERROR(msg); } XSRETURN_PV(GetAlgoName(index)); } // ----------------------------------------------------------------------------- XS(pl_setrule) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setrule($string)."); STRLEN n_a; char* rulestring = SvPV(ST(0), n_a); const char* err = GSF_setrule(rulestring); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getrule) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $string = g_getrule()."); XSRETURN_PV(currlayer->algo->getrule()); } // ----------------------------------------------------------------------------- XS(pl_getwidth) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_getwidth()."); XSRETURN_IV(currlayer->algo->gridwd); } // ----------------------------------------------------------------------------- XS(pl_getheight) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_getheight()."); XSRETURN_IV(currlayer->algo->gridht); } // ----------------------------------------------------------------------------- XS(pl_numstates) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_numstates()."); XSRETURN_IV(currlayer->algo->NumCellStates()); } // ----------------------------------------------------------------------------- XS(pl_numalgos) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_numalgos()."); XSRETURN_IV(NumAlgos()); } // ----------------------------------------------------------------------------- XS(pl_setpos) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: g_setpos($xstring,$ystring)."); STRLEN n_a; char* x = SvPV(ST(0), n_a); char* y = SvPV(ST(1), n_a); const char* err = GSF_setpos(x, y); if (err) PERL_ERROR(err); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getpos) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 1) PERL_ERROR("Usage: @xy = g_getpos($sepchar='')."); char sepchar = '\0'; if (items > 0) { STRLEN n_a; char* s = SvPV(ST(0), n_a); sepchar = s[0]; } bigint bigx, bigy; viewptr->GetPos(bigx, bigy); // return position as x,y strings SP -= items; XPUSHs(sv_2mortal(newSVpv( bigx.tostring(sepchar), 0 ))); XPUSHs(sv_2mortal(newSVpv( bigy.tostring(sepchar), 0 ))); XSRETURN(2); } // ----------------------------------------------------------------------------- XS(pl_setmag) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setmag($int)."); int mag = SvIV(ST(0)); viewptr->SetMag(mag); DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getmag) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_getmag()."); XSRETURN_IV(viewptr->GetMag()); } // ----------------------------------------------------------------------------- XS(pl_fit) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_fit()."); viewptr->FitPattern(); DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_fitsel) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_fitsel()."); if (viewptr->SelectionExists()) { viewptr->FitSelection(); DoAutoUpdate(); } else { PERL_ERROR("g_fitsel error: no selection."); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_visrect) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 4) PERL_ERROR("Usage: $bool = g_visrect(@rect)."); int x = SvIV(ST(0)); int y = SvIV(ST(1)); int wd = SvIV(ST(2)); int ht = SvIV(ST(3)); const char* err = GSF_checkrect(x, y, wd, ht); if (err) PERL_ERROR(err); bigint left = x; bigint top = y; bigint right = x + wd - 1; bigint bottom = y + ht - 1; int visible = viewptr->CellVisible(left, top) && viewptr->CellVisible(right, bottom); XSRETURN_IV(visible); } // ----------------------------------------------------------------------------- XS(pl_update) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_update()."); GSF_update(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_autoupdate) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_autoupdate($bool)."); autoupdate = (SvIV(ST(0)) != 0); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_addlayer) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $newindex = g_addlayer()."); if (numlayers >= MAX_LAYERS) { PERL_ERROR("g_addlayer error: no more layers can be added."); } else { AddLayer(); DoAutoUpdate(); } // return index of new layer XSRETURN_IV(currindex); } // ----------------------------------------------------------------------------- XS(pl_clone) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $newindex = g_clone()."); if (numlayers >= MAX_LAYERS) { PERL_ERROR("g_clone error: no more layers can be added."); } else { CloneLayer(); DoAutoUpdate(); } // return index of new layer XSRETURN_IV(currindex); } // ----------------------------------------------------------------------------- XS(pl_duplicate) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $newindex = g_duplicate()."); if (numlayers >= MAX_LAYERS) { PERL_ERROR("g_duplicate error: no more layers can be added."); } else { DuplicateLayer(); DoAutoUpdate(); } // return index of new layer XSRETURN_IV(currindex); } // ----------------------------------------------------------------------------- XS(pl_dellayer) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: g_dellayer()."); if (numlayers <= 1) { PERL_ERROR("g_dellayer error: there is only one layer."); } else { DeleteLayer(); DoAutoUpdate(); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_movelayer) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: g_movelayer($from,$to)."); int fromindex = SvIV(ST(0)); int toindex = SvIV(ST(1)); if (fromindex < 0 || fromindex >= numlayers) { char msg[64]; sprintf(msg, "Bad g_movelayer fromindex (%d).", fromindex); PERL_ERROR(msg); } if (toindex < 0 || toindex >= numlayers) { char msg[64]; sprintf(msg, "Bad g_movelayer toindex (%d).", toindex); PERL_ERROR(msg); } MoveLayer(fromindex, toindex); DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_setlayer) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setlayer($index)."); int index = SvIV(ST(0)); if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "Bad g_setlayer index (%d).", index); PERL_ERROR(msg); } SetLayer(index); DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getlayer) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_getlayer()."); XSRETURN_IV(currindex); } // ----------------------------------------------------------------------------- XS(pl_numlayers) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_numlayers()."); XSRETURN_IV(numlayers); } // ----------------------------------------------------------------------------- XS(pl_maxlayers) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $int = g_maxlayers()."); XSRETURN_IV(MAX_LAYERS); } // ----------------------------------------------------------------------------- XS(pl_setname) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items < 1 || items > 2) PERL_ERROR("Usage: g_setname($name,$index=current)."); STRLEN n_a; char* name = SvPV(ST(0), n_a); int index = currindex; if (items > 1) index = SvIV(ST(1)); if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "Bad g_setname index (%d).", index); PERL_ERROR(msg); } GSF_setname(name, index); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getname) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 1) PERL_ERROR("Usage: $name = g_getname($index=current)."); int index = currindex; if (items > 0) index = SvIV(ST(0)); if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "Bad g_getname index (%d).", index); PERL_ERROR(msg); } XSRETURN_PV((const char*)GetLayer(index)->currname.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- XS(pl_setcolors) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setcolors($colors)."); SV* colors = ST(0); if ( (!SvROK(colors)) || (SvTYPE(SvRV(colors)) != SVt_PVAV) ) { PERL_ERROR("g_setcolors error: 1st parameter is not a valid array reference."); } AV* inarray = (AV*)SvRV(colors); int len = av_len(inarray) + 1; if (len == 0) { // restore default colors in current layer and its clones UpdateLayerColors(); } else if (len == 6) { // create gradient from r1,g1,b1 to r2,g2,b2 int r1 = SvIV( *av_fetch(inarray, 0, 0) ); int g1 = SvIV( *av_fetch(inarray, 1, 0) ); int b1 = SvIV( *av_fetch(inarray, 2, 0) ); int r2 = SvIV( *av_fetch(inarray, 3, 0) ); int g2 = SvIV( *av_fetch(inarray, 4, 0) ); int b2 = SvIV( *av_fetch(inarray, 5, 0) ); CheckRGB(r1, g1, b1, "g_setcolors"); CheckRGB(r2, g2, b2, "g_setcolors"); currlayer->fromrgb.Set(r1, g1, b1); currlayer->torgb.Set(r2, g2, b2); CreateColorGradient(); UpdateCloneColors(); } else if (len % 4 == 0) { int i = 0; while (i < len) { int s = SvIV( *av_fetch(inarray, i, 0) ); i++; int r = SvIV( *av_fetch(inarray, i, 0) ); i++; int g = SvIV( *av_fetch(inarray, i, 0) ); i++; int b = SvIV( *av_fetch(inarray, i, 0) ); i++; CheckRGB(r, g, b, "g_setcolors"); if (s == -1) { // set all LIVE states to r,g,b (best not to alter state 0) for (s = 1; s < currlayer->algo->NumCellStates(); s++) { currlayer->cellr[s] = r; currlayer->cellg[s] = g; currlayer->cellb[s] = b; } } else { if (s < 0 || s >= currlayer->algo->NumCellStates()) { char msg[64]; sprintf(msg, "Bad state in g_setcolors (%d).", s); PERL_ERROR(msg); } else { currlayer->cellr[s] = r; currlayer->cellg[s] = g; currlayer->cellb[s] = b; } } } UpdateCloneColors(); } else { PERL_ERROR("g_setcolors error: array length is not a multiple of 4."); } DoAutoUpdate(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getcolors) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 1) PERL_ERROR("Usage: $colors = g_getcolors($state=-1)."); int state = -1; if (items > 0) state = SvIV(ST(0)); AV* outarray = (AV*)sv_2mortal( (SV*)newAV() ); if (state == -1) { // return colors for ALL states, including state 0 for (state = 0; state < currlayer->algo->NumCellStates(); state++) { av_push(outarray, newSViv(state)); av_push(outarray, newSViv(currlayer->cellr[state])); av_push(outarray, newSViv(currlayer->cellg[state])); av_push(outarray, newSViv(currlayer->cellb[state])); } } else if (state >= 0 && state < currlayer->algo->NumCellStates()) { av_push(outarray, newSViv(state)); av_push(outarray, newSViv(currlayer->cellr[state])); av_push(outarray, newSViv(currlayer->cellg[state])); av_push(outarray, newSViv(currlayer->cellb[state])); } else { char msg[64]; sprintf(msg, "Bad g_getcolors state (%d).", state); PERL_ERROR(msg); } SP -= items; ST(0) = newRV( (SV*)outarray ); sv_2mortal(ST(0)); XSRETURN(1); } // ----------------------------------------------------------------------------- XS(pl_setoption) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 2) PERL_ERROR("Usage: $oldval = g_setoption($name,$newval)."); STRLEN n_a; char* optname = SvPV(ST(0), n_a); int newval = SvIV(ST(1)); int oldval; if (!GSF_setoption(optname, newval, &oldval)) { PERL_ERROR("g_setoption error: unknown option."); } // return old value (simplifies saving and restoring settings) XSRETURN_IV(oldval); } // ----------------------------------------------------------------------------- XS(pl_getoption) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: $int = g_getoption($name)."); STRLEN n_a; char* optname = SvPV(ST(0), n_a); int optval; if (!GSF_getoption(optname, &optval)) { PERL_ERROR("g_getoption error: unknown option."); } XSRETURN_IV(optval); } // ----------------------------------------------------------------------------- XS(pl_setcolor) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 4) PERL_ERROR("Usage: @oldrgb = g_setcolor($name,$r,$g,$b)."); STRLEN n_a; char* colname = SvPV(ST(0), n_a); wxColor newcol(SvIV(ST(1)), SvIV(ST(2)), SvIV(ST(3))); wxColor oldcol; if (!GSF_setcolor(colname, newcol, oldcol)) { PERL_ERROR("g_setcolor error: unknown color."); } // return old r,g,b values (simplifies saving and restoring colors) SP -= items; XPUSHs(sv_2mortal(newSViv(oldcol.Red()))); XPUSHs(sv_2mortal(newSViv(oldcol.Green()))); XPUSHs(sv_2mortal(newSViv(oldcol.Blue()))); XSRETURN(3); } // ----------------------------------------------------------------------------- XS(pl_getcolor) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: @rgb = g_getcolor($name)."); STRLEN n_a; char* colname = SvPV(ST(0), n_a); wxColor color; if (!GSF_getcolor(colname, color)) { PERL_ERROR("g_getcolor error: unknown color."); } // return r,g,b values SP -= items; XPUSHs(sv_2mortal(newSViv(color.Red()))); XPUSHs(sv_2mortal(newSViv(color.Green()))); XPUSHs(sv_2mortal(newSViv(color.Blue()))); XSRETURN(3); } // ----------------------------------------------------------------------------- XS(pl_setclipstr) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_setclipstr($string)."); STRLEN n_a; char* clipstr = SvPV(ST(0), n_a); wxString wxs_clip(clipstr, wxConvLocal); mainptr->CopyTextToClipboard(wxs_clip); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getclipstr) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 0) PERL_ERROR("Usage: $string = g_getclipstr()."); wxTextDataObject data; if ( !mainptr->GetTextFromClipboard(&data) ) PERL_ERROR("Could not get data from clipboard!"); wxString wxs_clipstr = data.GetText(); XSRETURN_PV((const char*)wxs_clipstr.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- XS(pl_getstring) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items < 1 || items > 3) PERL_ERROR("Usage: $string = g_getstring($prompt,$default='',$title='')."); STRLEN n_a; const char* prompt = SvPV(ST(0), n_a); const char* initial = ""; const char* title = ""; if (items > 1) initial = SvPV(ST(1),n_a); if (items > 2) title = SvPV(ST(2),n_a); wxString result; if ( !GetString(wxString(title,wxConvLocal), wxString(prompt,wxConvLocal), wxString(initial,wxConvLocal), result) ) { // user hit Cancel button AbortPerlScript(); Perl_croak(aTHX_ NULL); } XSRETURN_PV((const char*)result.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- XS(pl_getxy) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $string = g_getxy()."); statusptr->CheckMouseLocation(mainptr->infront); // sets mousepos if (viewptr->showcontrols) mousepos = wxEmptyString; XSRETURN_PV((const char*)mousepos.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- XS(pl_getevent) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 1) PERL_ERROR("Usage: $string = g_getevent($get=1)."); int get = 1; if (items > 0) get = SvIV(ST(0)); wxString event; GSF_getevent(event, get); XSRETURN_PV((const char*)event.mb_str(wxConvLocal)); } // ----------------------------------------------------------------------------- XS(pl_doevent) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_doevent($string)."); STRLEN n_a; char* event = SvPV(ST(0), n_a); if (event[0]) { const char* err = GSF_doevent(wxString(event,wxConvLocal)); if (err) PERL_ERROR(err); } XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_getkey) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 0) PERL_ERROR("Usage: $char = g_getkey()."); char s[2]; // room for char + NULL GSF_getkey(s); XSRETURN_PV(s); } // ----------------------------------------------------------------------------- XS(pl_dokey) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_dokey($char)."); STRLEN n_a; char* ascii = SvPV(ST(0), n_a); GSF_dokey(ascii); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_show) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_show($string)."); STRLEN n_a; char* s = SvPV(ST(0), n_a); inscript = false; statusptr->DisplayMessage(wxString(s,wxConvLocal)); inscript = true; // make sure status bar is visible if (!showstatus) mainptr->ToggleStatusBar(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_error) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_error($string)."); STRLEN n_a; char* s = SvPV(ST(0), n_a); inscript = false; statusptr->ErrorMessage(wxString(s,wxConvLocal)); inscript = true; // make sure status bar is visible if (!showstatus) mainptr->ToggleStatusBar(); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_warn) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_warn($string)."); STRLEN n_a; char* s = SvPV(ST(0), n_a); Warning(wxString(s,wxConvLocal)); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_note) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_note($string)."); STRLEN n_a; char* s = SvPV(ST(0), n_a); Note(wxString(s,wxConvLocal)); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_help) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_help($string)."); STRLEN n_a; char* htmlfile = SvPV(ST(0), n_a); ShowHelp(wxString(htmlfile,wxConvLocal)); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_check) { IGNORE_UNUSED_PARAMS; // don't call checkevents() here otherwise we can't safely write code like // if (g_getlayer() == target) { // g_check(0); // ... do stuff to target layer ... // g_check(1); // } // RETURN_IF_ABORTED; dXSARGS; if (items != 1) PERL_ERROR("Usage: g_check($bool)."); allowcheck = (SvIV(ST(0)) != 0); XSRETURN(0); } // ----------------------------------------------------------------------------- XS(pl_exit) { IGNORE_UNUSED_PARAMS; RETURN_IF_ABORTED; dXSARGS; if (items > 1) PERL_ERROR("Usage: g_exit($string='')."); STRLEN n_a; char* err = (items == 1) ? SvPV(ST(0),n_a) : NULL; GSF_exit(err); AbortPerlScript(); Perl_croak(aTHX_ NULL); } // ----------------------------------------------------------------------------- XS(pl_fatal) { IGNORE_UNUSED_PARAMS; // don't call RETURN_IF_ABORTED; dXSARGS; // don't call PERL_ERROR in here if (items != 1) Warning(_("Bug: usage is g_fatal($string)")); STRLEN n_a; char* err = SvPV(ST(0),n_a); if (scripterr == wxString(abortmsg,wxConvLocal)) { // this can happen in Perl 5.14 so don't change scripterr // otherwise a message box will appear } else { // store message in global string (shown after script finishes) scripterr = wxString(err, wxConvLocal); } XSRETURN(0); } // ----------------------------------------------------------------------------- // xs_init is passed into perl_parse and initializes statically linked extensions EXTERN_C void xs_init(pTHX) { #ifdef __WXMSW__ wxUnusedVar(my_perl); #endif const char* file = __FILE__; dXSUB_SYS; // DynaLoader allows dynamic loading of other Perl extensions newXS((char*)"DynaLoader::boot_DynaLoader", boot_DynaLoader, (char*)file); // filing newXS((char*)"g_open", pl_open, (char*)file); newXS((char*)"g_save", pl_save, (char*)file); newXS((char*)"g_opendialog", pl_opendialog, (char*)file); newXS((char*)"g_savedialog", pl_savedialog, (char*)file); newXS((char*)"g_load", pl_load, (char*)file); newXS((char*)"g_store", pl_store, (char*)file); newXS((char*)"g_setdir", pl_setdir, (char*)file); newXS((char*)"g_getdir", pl_getdir, (char*)file); // next two are deprecated (use g_getdir) newXS((char*)"g_appdir", pl_appdir, (char*)file); newXS((char*)"g_datadir", pl_datadir, (char*)file); // editing newXS((char*)"g_new", pl_new, (char*)file); newXS((char*)"g_cut", pl_cut, (char*)file); newXS((char*)"g_copy", pl_copy, (char*)file); newXS((char*)"g_clear", pl_clear, (char*)file); newXS((char*)"g_paste", pl_paste, (char*)file); newXS((char*)"g_shrink", pl_shrink, (char*)file); newXS((char*)"g_randfill", pl_randfill, (char*)file); newXS((char*)"g_flip", pl_flip, (char*)file); newXS((char*)"g_rotate", pl_rotate, (char*)file); newXS((char*)"g_parse", pl_parse, (char*)file); newXS((char*)"g_transform", pl_transform, (char*)file); newXS((char*)"g_evolve", pl_evolve, (char*)file); newXS((char*)"g_putcells", pl_putcells, (char*)file); newXS((char*)"g_getcells", pl_getcells, (char*)file); newXS((char*)"g_join", pl_join, (char*)file); newXS((char*)"g_hash", pl_hash, (char*)file); newXS((char*)"g_getclip", pl_getclip, (char*)file); newXS((char*)"g_select", pl_select, (char*)file); newXS((char*)"g_getrect", pl_getrect, (char*)file); newXS((char*)"g_getselrect", pl_getselrect, (char*)file); newXS((char*)"g_setcell", pl_setcell, (char*)file); newXS((char*)"g_getcell", pl_getcell, (char*)file); newXS((char*)"g_setcursor", pl_setcursor, (char*)file); newXS((char*)"g_getcursor", pl_getcursor, (char*)file); // control newXS((char*)"g_empty", pl_empty, (char*)file); newXS((char*)"g_run", pl_run, (char*)file); newXS((char*)"g_step", pl_step, (char*)file); newXS((char*)"g_setstep", pl_setstep, (char*)file); newXS((char*)"g_getstep", pl_getstep, (char*)file); newXS((char*)"g_setbase", pl_setbase, (char*)file); newXS((char*)"g_getbase", pl_getbase, (char*)file); newXS((char*)"g_advance", pl_advance, (char*)file); newXS((char*)"g_reset", pl_reset, (char*)file); newXS((char*)"g_setgen", pl_setgen, (char*)file); newXS((char*)"g_getgen", pl_getgen, (char*)file); newXS((char*)"g_getpop", pl_getpop, (char*)file); newXS((char*)"g_numstates", pl_numstates, (char*)file); newXS((char*)"g_numalgos", pl_numalgos, (char*)file); newXS((char*)"g_setalgo", pl_setalgo, (char*)file); newXS((char*)"g_getalgo", pl_getalgo, (char*)file); newXS((char*)"g_setrule", pl_setrule, (char*)file); newXS((char*)"g_getrule", pl_getrule, (char*)file); newXS((char*)"g_getwidth", pl_getwidth, (char*)file); newXS((char*)"g_getheight", pl_getheight, (char*)file); // viewing newXS((char*)"g_setpos", pl_setpos, (char*)file); newXS((char*)"g_getpos", pl_getpos, (char*)file); newXS((char*)"g_setmag", pl_setmag, (char*)file); newXS((char*)"g_getmag", pl_getmag, (char*)file); newXS((char*)"g_fit", pl_fit, (char*)file); newXS((char*)"g_fitsel", pl_fitsel, (char*)file); newXS((char*)"g_visrect", pl_visrect, (char*)file); newXS((char*)"g_update", pl_update, (char*)file); newXS((char*)"g_autoupdate", pl_autoupdate, (char*)file); // layers newXS((char*)"g_addlayer", pl_addlayer, (char*)file); newXS((char*)"g_clone", pl_clone, (char*)file); newXS((char*)"g_duplicate", pl_duplicate, (char*)file); newXS((char*)"g_dellayer", pl_dellayer, (char*)file); newXS((char*)"g_movelayer", pl_movelayer, (char*)file); newXS((char*)"g_setlayer", pl_setlayer, (char*)file); newXS((char*)"g_getlayer", pl_getlayer, (char*)file); newXS((char*)"g_numlayers", pl_numlayers, (char*)file); newXS((char*)"g_maxlayers", pl_maxlayers, (char*)file); newXS((char*)"g_setname", pl_setname, (char*)file); newXS((char*)"g_getname", pl_getname, (char*)file); newXS((char*)"g_setcolors", pl_setcolors, (char*)file); newXS((char*)"g_getcolors", pl_getcolors, (char*)file); // miscellaneous newXS((char*)"g_setoption", pl_setoption, (char*)file); newXS((char*)"g_getoption", pl_getoption, (char*)file); newXS((char*)"g_setcolor", pl_setcolor, (char*)file); newXS((char*)"g_getcolor", pl_getcolor, (char*)file); newXS((char*)"g_setclipstr", pl_setclipstr, (char*)file); newXS((char*)"g_getclipstr", pl_getclipstr, (char*)file); newXS((char*)"g_getstring", pl_getstring, (char*)file); newXS((char*)"g_getxy", pl_getxy, (char*)file); newXS((char*)"g_getevent", pl_getevent, (char*)file); newXS((char*)"g_doevent", pl_doevent, (char*)file); // next two are deprecated (use g_getevent and g_doevent) newXS((char*)"g_getkey", pl_getkey, (char*)file); newXS((char*)"g_dokey", pl_dokey, (char*)file); newXS((char*)"g_show", pl_show, (char*)file); newXS((char*)"g_error", pl_error, (char*)file); newXS((char*)"g_warn", pl_warn, (char*)file); newXS((char*)"g_note", pl_note, (char*)file); newXS((char*)"g_help", pl_help, (char*)file); newXS((char*)"g_check", pl_check, (char*)file); newXS((char*)"g_exit", pl_exit, (char*)file); // internal use only (don't document) newXS((char*)"g_fatal", pl_fatal, (char*)file); } // ============================================================================= #ifdef PERL510_OR_LATER static bool inited = false; #endif void RunPerlScript(const wxString &filepath) { // allow re-entrancy bool already_in_perl = (my_perl != NULL); if (!already_in_perl) { #ifdef USE_PERL_DYNAMIC if (perldll == NULL) { // try to load Perl library if ( !LoadPerlLib() ) return; } #endif // create a dummy environment for initializing the embedded interpreter static int argc = 3; static char arg1[] = "-e", arg2[] = "0"; static char *args[] = { NULL, arg1, arg2, NULL }, **argv = &args[0]; #ifdef PERL510_OR_LATER static char *ens[] = { NULL }, **env = &ens[0]; if (!inited) { PERL_SYS_INIT3(&argc, &argv, &env); inited = true; } #endif my_perl = perl_alloc(); if (!my_perl) { Warning(_("Could not create Perl interpreter!")); return; } PL_perl_destruct_level = 1; perl_construct(my_perl); // set PERL_EXIT_DESTRUCT_END flag so that perl_destruct will execute // any END blocks in given script (this flag requires Perl 5.7.2+) PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(my_perl, xs_init, argc, argv, NULL); perl_run(my_perl); } // convert any \ to \\ and then convert any ' to \' wxString fpath = filepath; fpath.Replace(wxT("\\"), wxT("\\\\")); fpath.Replace(wxT("'"), wxT("\\'")); // construct a command to run the given script file and capture errors wxString command = wxT("do '") + fpath + wxT("'; g_fatal($@) if $@;"); perl_eval_pv(command.mb_str(wxConvLocal), TRUE); if (!already_in_perl) { // any END blocks will now be executed by perl_destruct, so we temporarily // clear scripterr so that RETURN_IF_ABORTED won't call Perl_croak; // this allows g_* commands in END blocks to work after user hits escape // or if g_exit has been called wxString savestring = scripterr; scripterr = wxEmptyString; PL_perl_destruct_level = 1; perl_destruct(my_perl); scripterr = savestring; perl_free(my_perl); my_perl = NULL; } } // ----------------------------------------------------------------------------- void FinishPerlScripting() { #ifdef PERL510_OR_LATER if (inited) { PERL_SYS_TERM(); } #endif #ifdef USE_PERL_DYNAMIC // probably don't really need to do this FreePerlLib(); #endif } golly-2.7-src/gui-wx/makefile-mac0000644000175000017500000002615712536111364013711 00000000000000# Makefile for building a 64-bit Cocoa version of Golly using wxWidgets 3.x on Mac OS 10.6+. # It assumes you've built the wxWidgets libraries with commands like these: # # cd /HD/wxWidgets/wxWidgets-3.0.1 # mkdir build-osx # cd build-osx # ../configure --enable-unicode --disable-shared --with-osx_cocoa # make # In the lines below, change WX_DIR to where you installed wxWidgets, # change WXLIB_DIR to where you built the wx libraries, and change # WX_RELEASE to match your wxWidgets version (first two digits). WX_RELEASE = 3.0 WX_DIR = /HD/wxWidgets/wxWidgets-3.0.1 WXLIB_DIR = $(WX_DIR)/build-osx WXINC_DIR = $(WXLIB_DIR)/lib/wx/include/osx_cocoa-unicode-static-$(WX_RELEASE) WXUNICODEFLAG = u APP_NAME = Golly APP_VERSION = 2.7 # these directory paths are relative to the location of this makefile: EXEDIR = .. DOCSDIR = ../docs BASEDIR = ../gollybase CMDDIR = ../cmdline # for building binary and source distributions: RELEASENAME = $(EXEDIR)/golly-$(APP_VERSION) SHAREDFILES = $(EXEDIR)/Help $(EXEDIR)/Patterns $(EXEDIR)/Scripts $(EXEDIR)/Rules BINFILES = $(EXEDIR)/$(APP_NAME).app $(EXEDIR)/bgolly \ $(DOCSDIR)/ReadMe.html $(DOCSDIR)/License.html SRCFILES = $(DOCSDIR) $(BASEDIR) $(CMDDIR) GUIFILES = CMakeLists.txt makefile-gtk makefile-mac makefile-win local-win-template.mk \ golly.rc Info.plist.in wx*.h wx*.cpp configure bitmaps icons # for Perl script support: PERL_INCLUDE = $(shell /usr/bin/perl -MExtUtils::Embed -e ccopts) PERL_LINK = $(shell /usr/bin/perl -MExtUtils::Embed -e ldopts) # remove unwanted stuff (-arch i386 and -arch ppc): PERL_INCLUDE := $(subst -arch i386,,$(PERL_INCLUDE)) PERL_INCLUDE := $(subst -arch ppc,,$(PERL_INCLUDE)) PERL_LINK := $(subst -arch i386,,$(PERL_LINK)) PERL_LINK := $(subst -arch ppc,,$(PERL_LINK)) # for Python script support: PYTHON_INCLUDE = -I`/usr/bin/python -c "import distutils.sysconfig; print distutils.sysconfig.get_python_inc()"` PYTHON_LINK = `/usr/bin/python -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('LINKFORSHARED')"` # Variables: LIBDIRNAME = $(WXLIB_DIR)/lib TOOLKIT = OSX_COCOA TOOLKIT_LOWERCASE = osx_cocoa TOOLKIT_VERSION = CXXC = g++ -mmacosx-version-min=10.6 CPPFLAGS = -DWX_PRECOMP -DNO_GCC_PRAGMA -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES \ -I${WXINC_DIR} -I${WX_DIR}/include \ -I$(BASEDIR) CXXFLAGS = -arch x86_64 \ -D__WX$(TOOLKIT)__ -DVERSION=$(APP_VERSION) $(CPPFLAGS) \ -DZLIB -O3 -Wall -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor \ -fno-strict-aliasing -fno-common LDFLAGS = -arch x86_64 \ -Wl,-dead_strip -Wl,-S \ -framework IOKit -framework Carbon -framework Cocoa -framework System # for bgolly: CXXBASE = -arch x86_64 \ -DVERSION=$(APP_VERSION) -DZLIB -O3 -Wall -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor \ -fno-strict-aliasing -fno-common -I$(BASEDIR) LDBASE = -arch x86_64 -lz EXTRALIBS = -lz -lpthread -liconv EXTRALIBS_GUI = -framework WebKit -framework OpenGL -framework AudioToolbox OBJDIR = ObjOSX BASEH = $(BASEDIR)/bigint.h $(BASEDIR)/ghashbase.h $(BASEDIR)/hlifealgo.h $(BASEDIR)/jvnalgo.h \ $(BASEDIR)/lifealgo.h $(BASEDIR)/lifepoll.h $(BASEDIR)/liferender.h $(BASEDIR)/liferules.h \ $(BASEDIR)/platform.h $(BASEDIR)/qlifealgo.h $(BASEDIR)/readpattern.h $(BASEDIR)/util.h $(BASEDIR)/viewport.h \ $(BASEDIR)/writepattern.h $(BASEDIR)/ruletreealgo.h $(BASEDIR)/generationsalgo.h $(BASEDIR)/ruletable_algo.h \ $(BASEDIR)/ruleloaderalgo.h BASEOBJ = $(OBJDIR)/bigint.o $(OBJDIR)/lifealgo.o $(OBJDIR)/hlifealgo.o \ $(OBJDIR)/hlifedraw.o $(OBJDIR)/qlifealgo.o $(OBJDIR)/qlifedraw.o \ $(OBJDIR)/jvnalgo.o $(OBJDIR)/ruletreealgo.o $(OBJDIR)/ruletable_algo.o $(OBJDIR)/ruleloaderalgo.o \ $(OBJDIR)/ghashbase.o $(OBJDIR)/ghashdraw.o $(OBJDIR)/readpattern.o \ $(OBJDIR)/writepattern.o $(OBJDIR)/liferules.o $(OBJDIR)/util.o \ $(OBJDIR)/liferender.o $(OBJDIR)/viewport.o $(OBJDIR)/lifepoll.o \ $(OBJDIR)/generationsalgo.o WXH = wxalgos.h wxedit.h wxgolly.h wxhelp.h wxinfo.h wxlayer.h wxmain.h \ wxperl.h wxprefs.h wxpython.h wxrender.h wxrule.h wxscript.h wxselect.h wxstatus.h \ wxtimeline.h wxundo.h wxutils.h wxview.h WXOBJ = $(OBJDIR)/wxutils.o $(OBJDIR)/wxprefs.o $(OBJDIR)/wxalgos.o $(OBJDIR)/wxrule.o \ $(OBJDIR)/wxinfo.o $(OBJDIR)/wxhelp.o $(OBJDIR)/wxstatus.o $(OBJDIR)/wxview.o \ $(OBJDIR)/wxrender.o $(OBJDIR)/wxscript.o $(OBJDIR)/wxperl.o $(OBJDIR)/wxpython.o \ $(OBJDIR)/wxfile.o $(OBJDIR)/wxedit.o $(OBJDIR)/wxcontrol.o $(OBJDIR)/wxtimeline.o \ $(OBJDIR)/wxundo.o $(OBJDIR)/wxselect.o $(OBJDIR)/wxlayer.o $(OBJDIR)/wxmain.o $(OBJDIR)/wxgolly.o PORTNAME = $(TOOLKIT_LOWERCASE)$(TOOLKIT_VERSION) ###WXBASEPORT = _carbon ###WXDEBUGFLAG = d __WXLIB_HTML_p = -lwx_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)_html-$(WX_RELEASE) __WXLIB_ADV_p = -lwx_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)_adv-$(WX_RELEASE) __WXLIB_CORE_p = -lwx_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)_core-$(WX_RELEASE) __WXLIB_BASE_p = -lwx_base$(WXBASEPORT)$(WXUNICODEFLAG)$(WXDEBUGFLAG)-$(WX_RELEASE) __WXLIB_NET_p = -lwx_base$(WXBASEPORT)$(WXUNICODEFLAG)$(WXDEBUGFLAG)_net-$(WX_RELEASE) __LIB_TIFF_p = -lwxtiff$(WXDEBUGFLAG)-$(WX_RELEASE) __LIB_PNG_p = -lwxpng$(WXDEBUGFLAG)-$(WX_RELEASE) __LIB_JPEG_p = -lwxjpeg$(WXDEBUGFLAG)-$(WX_RELEASE) # Targets: all: $(OBJDIR) app.bin app_bundle bgolly $(BASEOBJ): $(BASEH) $(WXOBJ): $(BASEH) $(WXH) icons/appicon.xpm bitmaps/*.xpm $(OBJDIR): mkdir -p $(OBJDIR) clean: rm -f $(OBJDIR)/*.o $(EXEDIR)/bgolly $(EXEDIR)/RuleTableToTree rm -rf $(EXEDIR)/$(APP_NAME).app bgolly: $(BASEOBJ) $(OBJDIR)/bgolly.o $(CXXC) $(CXXBASE) -o $(EXEDIR)/bgolly $(BASEOBJ) $(OBJDIR)/bgolly.o $(LDBASE) RuleTableToTree: $(BASEOBJ) $(OBJDIR)/RuleTableToTree.o $(CXXC) $(CXXBASE) -o $(EXEDIR)/RuleTableToTree $(BASEOBJ) $(OBJDIR)/RuleTableToTree.o $(LDBASE) $(OBJDIR)/bgolly.o: $(CMDDIR)/bgolly.cpp $(CXXC) $(CXXBASE) -c -o $@ $(CMDDIR)/bgolly.cpp $(OBJDIR)/RuleTableToTree.o: $(CMDDIR)/RuleTableToTree.cpp $(CXXC) $(CXXBASE) -c -o $@ $(CMDDIR)/RuleTableToTree.cpp app.bin: $(BASEOBJ) $(WXOBJ) $(CXXC) -o $@ $(BASEOBJ) $(WXOBJ) $(LDFLAGS) -L$(LIBDIRNAME) $(__WXLIB_HTML_p) $(__WXLIB_ADV_p) \ $(__WXLIB_CORE_p) $(__WXLIB_BASE_p) $(__WXLIB_NET_p) $(__LIB_TIFF_p) $(__LIB_PNG_p) $(__LIB_JPEG_p) \ $(EXTRALIBS) $(EXTRALIBS_GUI) $(PERL_LINK) $(PYTHON_LINK) $(EXEDIR)/$(APP_NAME).app/Contents/PkgInfo: app.bin Info.plist.in \ icons/app.icns icons/file-mc.icns icons/file-rle.icns mkdir -p $(EXEDIR)/$(APP_NAME).app/Contents mkdir -p $(EXEDIR)/$(APP_NAME).app/Contents/MacOS mkdir -p $(EXEDIR)/$(APP_NAME).app/Contents/Resources sed -e "s/VERSION/$(APP_VERSION)/" \ Info.plist.in >$(EXEDIR)/$(APP_NAME).app/Contents/Info.plist echo -n "APPLGoLy" >$(EXEDIR)/$(APP_NAME).app/Contents/PkgInfo mv -f app.bin $(EXEDIR)/$(APP_NAME).app/Contents/MacOS/$(APP_NAME) cp -f icons/*.icns $(EXEDIR)/$(APP_NAME).app/Contents/Resources app_bundle: $(EXEDIR)/$(APP_NAME).app/Contents/PkgInfo $(OBJDIR)/bigint.o: $(BASEDIR)/bigint.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/bigint.cpp $(OBJDIR)/lifealgo.o: $(BASEDIR)/lifealgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/lifealgo.cpp $(OBJDIR)/hlifealgo.o: $(BASEDIR)/hlifealgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/hlifealgo.cpp $(OBJDIR)/hlifedraw.o: $(BASEDIR)/hlifedraw.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/hlifedraw.cpp $(OBJDIR)/qlifealgo.o: $(BASEDIR)/qlifealgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/qlifealgo.cpp $(OBJDIR)/qlifedraw.o: $(BASEDIR)/qlifedraw.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/qlifedraw.cpp $(OBJDIR)/jvnalgo.o: $(BASEDIR)/jvnalgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/jvnalgo.cpp $(OBJDIR)/ruleloaderalgo.o: $(BASEDIR)/ruleloaderalgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ruleloaderalgo.cpp $(OBJDIR)/ruletable_algo.o: $(BASEDIR)/ruletable_algo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ruletable_algo.cpp $(OBJDIR)/ruletreealgo.o: $(BASEDIR)/ruletreealgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ruletreealgo.cpp $(OBJDIR)/generationsalgo.o: $(BASEDIR)/generationsalgo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/generationsalgo.cpp $(OBJDIR)/ghashbase.o: $(BASEDIR)/ghashbase.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ghashbase.cpp $(OBJDIR)/ghashdraw.o: $(BASEDIR)/ghashdraw.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/ghashdraw.cpp $(OBJDIR)/liferules.o: $(BASEDIR)/liferules.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/liferules.cpp $(OBJDIR)/liferender.o: $(BASEDIR)/liferender.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/liferender.cpp $(OBJDIR)/readpattern.o: $(BASEDIR)/readpattern.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/readpattern.cpp $(OBJDIR)/writepattern.o: $(BASEDIR)/writepattern.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/writepattern.cpp $(OBJDIR)/util.o: $(BASEDIR)/util.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/util.cpp $(OBJDIR)/viewport.o: $(BASEDIR)/viewport.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/viewport.cpp $(OBJDIR)/lifepoll.o: $(BASEDIR)/lifepoll.cpp $(CXXC) $(CXXFLAGS) -c -o $@ $(BASEDIR)/lifepoll.cpp $(OBJDIR)/wxutils.o: wxutils.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxutils.cpp $(OBJDIR)/wxprefs.o: wxprefs.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxprefs.cpp $(OBJDIR)/wxalgos.o: wxalgos.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxalgos.cpp $(OBJDIR)/wxrule.o: wxrule.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxrule.cpp $(OBJDIR)/wxinfo.o: wxinfo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxinfo.cpp $(OBJDIR)/wxhelp.o: wxhelp.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxhelp.cpp $(OBJDIR)/wxstatus.o: wxstatus.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxstatus.cpp $(OBJDIR)/wxview.o: wxview.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxview.cpp $(OBJDIR)/wxrender.o: wxrender.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxrender.cpp $(OBJDIR)/wxperl.o: wxperl.cpp $(CXXC) $(CXXFLAGS) $(PERL_INCLUDE) -c -o $@ wxperl.cpp $(OBJDIR)/wxpython.o: wxpython.cpp $(CXXC) $(CXXFLAGS) $(PYTHON_INCLUDE) -c -o $@ wxpython.cpp $(OBJDIR)/wxscript.o: wxscript.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxscript.cpp $(OBJDIR)/wxfile.o: wxfile.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxfile.cpp $(OBJDIR)/wxedit.o: wxedit.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxedit.cpp $(OBJDIR)/wxselect.o: wxselect.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxselect.cpp $(OBJDIR)/wxcontrol.o: wxcontrol.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxcontrol.cpp $(OBJDIR)/wxtimeline.o: wxtimeline.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxtimeline.cpp $(OBJDIR)/wxundo.o: wxundo.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxundo.cpp $(OBJDIR)/wxlayer.o: wxlayer.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxlayer.cpp $(OBJDIR)/wxmain.o: wxmain.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxmain.cpp $(OBJDIR)/wxgolly.o: wxgolly.cpp $(CXXC) $(CXXFLAGS) -c -o $@ wxgolly.cpp srcdist: -rm -rf $(RELEASENAME)-src mkdir $(RELEASENAME)-src mkdir $(RELEASENAME)-src/gui-wx cp -rp $(SRCFILES) $(SHAREDFILES) $(RELEASENAME)-src cp -rp $(GUIFILES) $(RELEASENAME)-src/gui-wx find $(RELEASENAME)-src -name '.[^.]*' -delete find $(RELEASENAME)-src/Scripts/Python -name '*.pyc' -delete tar -cf - ./$(RELEASENAME)-src | gzip > $(RELEASENAME)-src.tar.gz bindist: all -rm -rf $(RELEASENAME)-mac mkdir $(RELEASENAME)-mac cp -rp $(BINFILES) $(SHAREDFILES) $(RELEASENAME)-mac find $(RELEASENAME)-mac -name '.[^.]*' -delete find $(RELEASENAME)-mac/Scripts/Python -name '*.pyc' -delete echo Now create zip archive of $(RELEASENAME)-mac golly-2.7-src/gui-wx/wxstatus.h0000755000175000017500000000723612536111364013526 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXSTATUS_H_ #define _WXSTATUS_H_ #include "bigint.h" // for bigint // Define a child window for status bar at top of main frame: class StatusBar : public wxWindow { public: StatusBar(wxWindow* parent, wxCoord xorg, wxCoord yorg, int wd, int ht); ~StatusBar(); void ClearMessage(); // erase bottom line of status bar void DisplayMessage(const wxString& s); // display message on bottom line of status bar void ErrorMessage(const wxString& s); // beep and display message on bottom line of status bar void SetMessage(const wxString& s); // set message string without displaying it (until next update) void UpdateXYLocation(); // XY location needs to be updated void CheckMouseLocation(bool active); // check location of mouse and update XY location if necessary wxString Stringify(const bigint& b); // convert given number to string suitable for display int GetCurrentDelay(); // return current delay (in millisecs) wxFont* GetStatusFont() { return statusfont; } int GetTextAscent() { return textascent; } int statusht; // status bar height (0 if not visible, else STATUS_HT or STATUS_EXHT) private: // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() // event handlers void OnPaint(wxPaintEvent& event); void OnMouseDown(wxMouseEvent& event); void OnEraseBackground(wxEraseEvent& event); bool ClickInGenBox(int x, int y); bool ClickInScaleBox(int x, int y); bool ClickInStepBox(int x, int y); void SetStatusFont(wxDC& dc); void DisplayText(wxDC& dc, const wxString& s, wxCoord x, wxCoord y); void DrawStatusBar(wxDC& dc, wxRect& updaterect); wxBitmap* statbitmap; // status bar bitmap int statbitmapwd; // width of status bar bitmap int statbitmapht; // height of status bar bitmap int h_gen; // horizontal position of "Generation" int h_pop; // horizontal position of "Population" int h_scale; // horizontal position of "Scale" int h_step; // horizontal position of "Step" int h_xy; // horizontal position of "XY" int textascent; // vertical adjustment used in DrawText calls wxString statusmsg; // for messages on bottom line bigint currx, curry; // cursor location in cell coords bool showxy; // show cursor's XY location? wxFont* statusfont; // status bar font }; extern const int STATUS_HT; // normal status bar height extern const int STATUS_EXHT; // height when showing exact numbers #endif golly-2.7-src/gui-wx/wxtimeline.h0000644000175000017500000000462212536111364014002 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXTIMELINE_H_ #define _WXTIMELINE_H_ // Timeline support: void CreateTimelineBar(wxWindow* parent); // Create timeline bar window at bottom of given parent window. int TimelineBarHeight(); // Return height of timeline bar. void ResizeTimelineBar(int y, int wd); // Move and/or resize timeline bar. void UpdateTimelineBar(); // Update state of buttons in timeline bar. void ToggleTimelineBar(); // Show/hide timeline bar. void StartStopRecording(); // If recording a timeline then stop, otherwise start a new recording // (if no timeline exists) or extend the existing timeline. void DeleteTimeline(); // Delete the existing timeline. void InitTimelineFrame(); // Go to the first frame in the recently loaded timeline. bool TimelineExists(); // Does a timeline exist in the current algorithm? bool AutoPlay(); // Called in MainFrame::OnIdle so we can check if the next // timeline frame needs to be displayed. Returns true if we are // in autoplay mode and so another idle event needs to be sent. void PlayTimeline(int direction); // Play timeline forwards if given direction is +ve, or backwards // if direction is -ve, or stop if direction is 0. void PlayTimelineFaster(); // Increase the rate at which timeline frames are displayed. void PlayTimelineSlower(); // Decrease the rate at which timeline frames are displayed. void ResetTimelineSpeed(); // Reset autoplay speed to 0 (no delay, no frame skipping). bool TimelineIsPlaying(); // Return true if timeline is in autoplay mode. #endif golly-2.7-src/gui-wx/wxhelp.cpp0000644000175000017500000012613212536111364013460 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/wxhtml.h" // for wxHtmlWindow #include "wx/file.h" // for wxFile #include "wx/protocol/http.h" // for wxHTTP #include "wx/wfstream.h" // for wxFileOutputStream, wxFileInputStream #include "wx/zipstrm.h" // for wxZipInputStream #include "lifealgo.h" // for lifealgo class #include "wxgolly.h" // for wxGetApp, mainptr, viewptr #include "wxmain.h" // for mainptr->... #include "wxview.h" // for viewptr->... #include "wxutils.h" // for Warning, BeginProgress, etc #include "wxprefs.h" // for GetShortcutTable, helpfontsize, gollydir, etc #include "wxscript.h" // for inscript #include "wxlayer.h" // for numlayers, GetLayer, etc #include "wxalgos.h" // for QLIFE_ALGO #include "wxhelp.h" // ----------------------------------------------------------------------------- // define a modeless help window: class HelpFrame : public wxFrame { public: HelpFrame(); void SetStatus(const wxString& text) { status->SetLabel(text); } bool infront; // help window is active? private: // ids for buttons in help window (see also wxID_CLOSE) enum { ID_BACK_BUTT = wxID_HIGHEST + 1, ID_FORWARD_BUTT, ID_CONTENTS_BUTT }; // event handlers void OnActivate(wxActivateEvent& event); void OnBackButton(wxCommandEvent& event); void OnForwardButton(wxCommandEvent& event); void OnContentsButton(wxCommandEvent& event); void OnCloseButton(wxCommandEvent& event); void OnClose(wxCloseEvent& event); wxStaticText* status; // status line at bottom of help window // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(HelpFrame, wxFrame) EVT_ACTIVATE ( HelpFrame::OnActivate) EVT_BUTTON (ID_BACK_BUTT, HelpFrame::OnBackButton) EVT_BUTTON (ID_FORWARD_BUTT, HelpFrame::OnForwardButton) EVT_BUTTON (ID_CONTENTS_BUTT, HelpFrame::OnContentsButton) EVT_BUTTON (wxID_CLOSE, HelpFrame::OnCloseButton) EVT_CLOSE ( HelpFrame::OnClose) END_EVENT_TABLE() // ----------------------------------------------------------------------------- // define a child window for displaying html info: class HtmlView : public wxHtmlWindow { public: HtmlView(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxHtmlWindow(parent, id, pos, size, style) { editlink = false; linkrect = wxRect(0,0,0,0); } virtual void OnLinkClicked(const wxHtmlLinkInfo& link); virtual void OnCellMouseHover(wxHtmlCell* cell, wxCoord x, wxCoord y); void ClearStatus(); // clear help window's status line void SetFontSizes(int size); void ChangeFontSizes(int size); void CheckAndLoad(const wxString& filepath); void StartTimer() { htmltimer = new wxTimer(this, wxID_ANY); // call OnTimer 10 times per sec htmltimer->Start(100, wxTIMER_CONTINUOUS); } void StopTimer() { htmltimer->Stop(); delete htmltimer; } bool editlink; // open clicked file in editor? bool canreload; // can OnSize call CheckAndLoad? private: #ifdef __WXMSW__ // see HtmlView::OnKeyUp for why we do this void OnKeyUp(wxKeyEvent& event); #else void OnKeyDown(wxKeyEvent& event); #endif void OnChar(wxKeyEvent& event); void OnSize(wxSizeEvent& event); void OnMouseMotion(wxMouseEvent& event); void OnMouseLeave(wxMouseEvent& event); void OnMouseDown(wxMouseEvent& event); void OnTimer(wxTimerEvent& event); wxTimer* htmltimer; wxRect linkrect; // rect for cell containing link // any class wishing to process wxWidgets events must use this macro DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(HtmlView, wxHtmlWindow) #ifdef __WXMSW__ // see HtmlView::OnKeyUp for why we do this EVT_KEY_UP (HtmlView::OnKeyUp) #else EVT_KEY_DOWN (HtmlView::OnKeyDown) #endif EVT_CHAR (HtmlView::OnChar) EVT_SIZE (HtmlView::OnSize) EVT_MOTION (HtmlView::OnMouseMotion) EVT_ENTER_WINDOW (HtmlView::OnMouseMotion) EVT_LEAVE_WINDOW (HtmlView::OnMouseLeave) EVT_LEFT_DOWN (HtmlView::OnMouseDown) EVT_RIGHT_DOWN (HtmlView::OnMouseDown) EVT_TIMER (wxID_ANY, HtmlView::OnTimer) END_EVENT_TABLE() // ----------------------------------------------------------------------------- HelpFrame* helpptr = NULL; // help window HtmlView* htmlwin = NULL; // html child window wxButton* backbutt; // back button wxButton* forwbutt; // forwards button wxButton* contbutt; // Contents button long whenactive; // when help window became active (elapsed millisecs) const wxString helphome = _("Help/index.html"); // contents page wxString currhelp = helphome; // current help file const wxString lexicon_name = _("lexicon"); // name of lexicon layer int lexlayer; // index of existing lexicon layer (-ve if not present) wxString lexpattern; // lexicon pattern data // prefix of most recent full URL in a html get ("get:http://.../foo.html") // to allow later relative gets ("get:foo.rle") wxString urlprefix = wxEmptyString; const wxString HTML_PREFIX = _("GET---"); // prepended to html filename // ----------------------------------------------------------------------------- wxFrame* GetHelpFrame() { return helpptr; } // ----------------------------------------------------------------------------- // create the help window HelpFrame::HelpFrame() : wxFrame(NULL, wxID_ANY, _(""), wxPoint(helpx,helpy), wxSize(helpwd,helpht)) { wxGetApp().SetFrameIcon(this); #ifdef __WXMSW__ // use current theme's background colour SetBackgroundColour(wxNullColour); #endif htmlwin = new HtmlView(this, wxID_ANY, // specify small size to avoid clipping scroll bar on resize wxDefaultPosition, wxSize(30,30), wxHW_DEFAULT_STYLE | wxSUNKEN_BORDER); htmlwin->StartTimer(); htmlwin->SetBorders(4); htmlwin->SetFontSizes(helpfontsize); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); wxBoxSizer* hbox = new wxBoxSizer(wxHORIZONTAL); backbutt = new wxButton(this, ID_BACK_BUTT, _("<"), wxDefaultPosition, wxSize(40,wxDefaultCoord)); hbox->Add(backbutt, 0, wxALL | wxALIGN_LEFT, 10); forwbutt = new wxButton(this, ID_FORWARD_BUTT, _(">"), wxDefaultPosition, wxSize(40,wxDefaultCoord)); hbox->Add(forwbutt, 0, wxTOP | wxBOTTOM | wxALIGN_LEFT, 10); contbutt = new wxButton(this, ID_CONTENTS_BUTT, _("Contents")); hbox->Add(contbutt, 0, wxALL | wxALIGN_LEFT, 10); hbox->AddStretchSpacer(1); wxButton* closebutt = new wxButton(this, wxID_CLOSE, _("Close")); closebutt->SetDefault(); hbox->Add(closebutt, 0, wxALL | wxALIGN_RIGHT, 10); vbox->Add(hbox, 0, wxALL | wxEXPAND | wxALIGN_TOP, 0); vbox->Add(htmlwin, 1, wxLEFT | wxRIGHT | wxEXPAND | wxALIGN_TOP, 10); status = new wxStaticText(this, wxID_STATIC, wxEmptyString); #ifdef __WXMAC__ status->SetWindowVariant(wxWINDOW_VARIANT_SMALL); #endif wxBoxSizer* statbox = new wxBoxSizer(wxHORIZONTAL); statbox->Add(status); vbox->AddSpacer(2); vbox->Add(statbox, 0, wxLEFT | wxALIGN_LEFT, 10); vbox->AddSpacer(4); SetMinSize(wxSize(minhelpwd, minhelpht)); SetSizer(vbox); // expand sizer now to avoid seeing small htmlwin and buttons in top left corner vbox->SetDimension(0, 0, helpwd, helpht); } // ----------------------------------------------------------------------------- void UpdateHelpButtons() { backbutt->Enable( htmlwin->HistoryCanBack() ); forwbutt->Enable( htmlwin->HistoryCanForward() ); // check for title used in Help/index.html contbutt->Enable( htmlwin->GetOpenedPageTitle() != _("Golly Help: Contents") ); wxString location = htmlwin->GetOpenedPage(); if ( !location.IsEmpty() ) { // set currhelp so user can close help window and then open same page currhelp = location; // if filename starts with HTML_PREFIX then set urlprefix to corresponding // url so any later relative "get:foo.rle" links will work wxString filename = location.AfterLast('/'); if (filename.StartsWith(HTML_PREFIX)) { // replace HTML_PREFIX with "http://" and convert spaces to '/' // (ie. reverse what we did in GetURL) urlprefix = filename; urlprefix.Replace(HTML_PREFIX, wxT("http://"), false); // do once urlprefix.Replace(wxT(" "), wxT("/")); urlprefix = urlprefix.BeforeLast('/'); urlprefix += wxT("/"); // must end in slash } } htmlwin->ClearStatus(); htmlwin->SetFocus(); // for keyboard shortcuts } // ----------------------------------------------------------------------------- void ShowHelp(const wxString& filepath) { // display given html file in help window if (helpptr) { // help window exists so bring it to front and display given file if (!filepath.IsEmpty()) { htmlwin->CheckAndLoad(filepath); UpdateHelpButtons(); } helpptr->Raise(); } else { helpptr = new HelpFrame(); if (helpptr == NULL) { Warning(_("Could not create help window!")); return; } // assume our .html files contain a tag htmlwin->SetRelatedFrame(helpptr, _("%s")); if (!filepath.IsEmpty()) { htmlwin->CheckAndLoad(filepath); } else { htmlwin->CheckAndLoad(currhelp); } // prevent HtmlView::OnSize calling CheckAndLoad twice htmlwin->canreload = false; helpptr->Show(true); UpdateHelpButtons(); // must be after Show to avoid hbar appearing on Mac // allow HtmlView::OnSize to call CheckAndLoad if window is resized htmlwin->canreload = true; } whenactive = 0; } // ----------------------------------------------------------------------------- void HelpFrame::OnActivate(wxActivateEvent& event) { // IsActive() is not always reliable so we set infront flag infront = event.GetActive(); if (infront) { // help window is being activated whenactive = stopwatch->Time(); // ensure correct menu items, esp after help window // is clicked while app is in background mainptr->UpdateMenuItems(); } event.Skip(); } // ----------------------------------------------------------------------------- void HelpFrame::OnBackButton(wxCommandEvent& WXUNUSED(event)) { if ( htmlwin->HistoryBack() ) { UpdateHelpButtons(); } else { Beep(); } } // ----------------------------------------------------------------------------- void HelpFrame::OnForwardButton(wxCommandEvent& WXUNUSED(event)) { if ( htmlwin->HistoryForward() ) { UpdateHelpButtons(); } else { Beep(); } } // ----------------------------------------------------------------------------- void HelpFrame::OnContentsButton(wxCommandEvent& WXUNUSED(event)) { ShowHelp(helphome); } // ----------------------------------------------------------------------------- void HelpFrame::OnCloseButton(wxCommandEvent& WXUNUSED(event)) { Close(true); } // ----------------------------------------------------------------------------- void HelpFrame::OnClose(wxCloseEvent& WXUNUSED(event)) { #ifdef __WXMSW__ if (!IsIconized()) { #endif // save current location and size for later use in SavePrefs wxRect r = GetRect(); helpx = r.x; helpy = r.y; helpwd = r.width; helpht = r.height; #ifdef __WXMSW__ } #endif // stop htmltimer immediately (if we do it in ~HtmlView dtor then timer // only stops when app becomes idle) htmlwin->StopTimer(); Destroy(); // also deletes all child windows (buttons, etc) helpptr = NULL; } // ----------------------------------------------------------------------------- void LoadRule(const wxString& rulestring) { // load recently installed .rule/table/tree/colors/icons file wxString oldrule = wxString(currlayer->algo->getrule(),wxConvLocal); int oldmaxstate = currlayer->algo->NumCellStates() - 1; // selection might change if grid becomes smaller, // so save current selection for RememberRuleChange/RememberAlgoChange viewptr->SaveCurrentSelection(); mainptr->Raise(); if (mainptr->generating) { Warning(_("Cannot change rule while generating a pattern.")); // or stop and create pending event??? see ID_LOAD_LEXICON return; } else if (inscript) { Warning(_("Cannot change rule while a script is running.")); return; } const char* err = currlayer->algo->setrule( rulestring.mb_str(wxConvLocal) ); if (err) { // try to find another algorithm that supports the given rule for (int i = 0; i < NumAlgos(); i++) { if (i != currlayer->algtype) { lifealgo* tempalgo = CreateNewUniverse(i); err = tempalgo->setrule( rulestring.mb_str(wxConvLocal) ); delete tempalgo; if (!err) { // change the current algorithm and switch to the new rule mainptr->ChangeAlgorithm(i, rulestring); if (i != currlayer->algtype) { RestoreRule(oldrule); Warning(_("Algorithm could not be changed (pattern is too big to convert).")); return; } else { mainptr->SetWindowTitle(wxEmptyString); mainptr->UpdateEverything(); return; } } } } // should only get here if .rule/table/tree file contains some sort of error RestoreRule(oldrule); Warning(_("Rule is not valid in any algorithm: ") + rulestring); return; } wxString newrule = wxString(currlayer->algo->getrule(),wxConvLocal); if (oldrule != newrule) { // show new rule in main window's title but don't change name mainptr->SetWindowTitle(wxEmptyString); // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { mainptr->ClearOutsideGrid(); } } // new rule might have changed the number of cell states; // if there are fewer states then pattern might change int newmaxstate = currlayer->algo->NumCellStates() - 1; if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { mainptr->ReduceCellStates(newmaxstate); } // update colors and/or icons for the new rule UpdateLayerColors(); // pattern might have changed or colors/icons might have changed mainptr->UpdateEverything(); if (oldrule != newrule) { if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberRuleChange(oldrule); } } } // ----------------------------------------------------------------------------- bool DownloadFile(const wxString& url, const wxString& filepath) { bool result = false; wxHTTP http; http.SetTimeout(5); // secs http.SetHeader(wxT("Accept") , wxT("*/*")); // any file type http.SetHeader(wxT("User-Agent"), wxT("Golly")); // Connect() wants a server address (eg. "www.foo.com"), not a full URL wxString temp = url.AfterFirst('/'); while (temp[0] == '/') temp = temp.Mid(1); size_t slashpos = temp.Find('/'); wxString server = temp.Left(slashpos); if (http.Connect(server, 80)) { // GetInputStream() wants everything after the server address wxString respath = temp.Right(temp.length() - slashpos); wxInputStream* instream = http.GetInputStream(respath); if (instream) { wxFileOutputStream outstream(filepath); if (outstream.Ok()) { // read and write in chunks so we can show a progress dialog const int BUFFER_SIZE = 4000; // seems ok (on Mac at least) char buf[BUFFER_SIZE]; size_t incount = 0; size_t outcount = 0; size_t lastread, lastwrite; double filesize = (double) instream->GetSize(); if (filesize <= 0.0) filesize = -1.0; // show indeterminate progress BeginProgress(_("Downloading file")); while (true) { instream->Read(buf, BUFFER_SIZE); lastread = instream->LastRead(); if (lastread == 0) break; outstream.Write(buf, lastread); lastwrite = outstream.LastWrite(); incount += lastread; outcount += lastwrite; if (incount != outcount) { Warning(_("Error occurred while writing file:\n") + filepath); break; } char msg[128]; sprintf(msg, "File size: %.2f MB", double(incount) / 1048576.0); if (AbortProgress((double)incount / filesize, wxString(msg,wxConvLocal))) { // force false result outcount = 0; break; } } EndProgress(); result = (incount == outcount); if (!result) { // delete incomplete filepath if (wxFileExists(filepath)) wxRemoveFile(filepath); } } else { Warning(_("Could not open output stream for file:\n") + filepath); } delete instream; } else { int err = http.GetError(); if (err == wxPROTO_NOFILE) { Warning(_("Remote file does not exist:\n") + url); } else { // we get wxPROTO_NETERR (generic network error) with some naughty servers // that use LF rather than CRLF to terminate HTTP header messages // eg: http://fano.ics.uci.edu/ca/rules/b0135s014/g1.lif // (wxProtocol::ReadLine needs to be made more tolerant) Warning(wxString::Format(_("Could not download file (error %d):\n"),err) + url); } } } else { Warning(_("Could not connect to server:\n") + server); } http.Close(); return result; } // ----------------------------------------------------------------------------- void GetURL(const wxString& url) { wxString fullurl; if (url.StartsWith(wxT("http:"))) { fullurl = url; } else { // relative get, so prepend prefix set earlier in UpdateHelpButtons fullurl = urlprefix + url; } wxString filename = fullurl.AfterLast('/'); // remove ugly stuff at start of file names downloaded from ConwayLife.com if (filename.StartsWith(wxT("download.php?f=")) || filename.StartsWith(wxT("pattern.asp?p=")) || filename.StartsWith(wxT("script.asp?s="))) { filename = filename.AfterFirst('='); } // create full path for downloaded file based on given url; // first remove initial "http://" wxString filepath = fullurl.AfterFirst('/'); while (filepath[0] == '/') filepath = filepath.Mid(1); if (IsHTMLFile(filename)) { // create special name for html file so UpdateHelpButtons can detect it // and set urlprefix filepath.Replace(wxT("/"), wxT(" ")); // assume url has no spaces filepath = HTML_PREFIX + filepath; } else { // no need for url info in file name filepath = filename; } #ifdef __WXMSW__ // replace chars that can appear in URLs but are not allowed in filenames on Windows filepath.Replace(wxT("*"), wxT("_")); filepath.Replace(wxT("?"), wxT("_")); #endif if (IsRuleFile(filename)) { // create file in user's rules directory (rulesdir might be read-only) filepath = userrules + filename; } else if (IsHTMLFile(filename)) { // nicer to store html files in temporary directory filepath = tempdir + filepath; } else { // all other files are stored in user's download directory filepath = downloaddir + filepath; } // try to download the file if ( !DownloadFile(fullurl, filepath) ) return; if (htmlwin->editlink) { if (IsRuleFile(filename) && filename.Lower().EndsWith(wxT(".icons"))) { // let user see b&w image in .icons file mainptr->Raise(); mainptr->OpenFile(filepath); } else { mainptr->EditFile(filepath); } return; } if (IsHTMLFile(filename)) { // display html file in help window; // search file for any simple img links and also download those files??? // maybe in version 3! htmlwin->LoadPage(filepath); } else if (IsRuleFile(filename)) { // load corresponding rule LoadRule(filename.BeforeLast('.')); } else if (IsTextFile(filename)) { // open text file in user's text editor mainptr->EditFile(filepath); } else if (IsZipFile(filename)) { // open zip file (don't raise main window here) mainptr->OpenFile(filepath); } else if (IsScriptFile(filename)) { // run script depending on safety check; if it is allowed to run // then we remember script in the Run Recent submenu mainptr->CheckBeforeRunning(filepath, true, wxEmptyString); } else { // assume pattern file, so try to load it mainptr->Raise(); mainptr->OpenFile(filepath); } if (helpptr && helpptr->infront) UpdateHelpButtons(); } // ----------------------------------------------------------------------------- void UnzipFile(const wxString& zippath, const wxString& entry) { wxString filename = entry.AfterLast(wxFILE_SEP_PATH); wxString tempfile = tempdir + filename; if ( IsRuleFile(filename) ) { // rule-related file should have already been extracted and installed // into userrules, so check that file exists and load rule wxString rulefile = userrules + filename; if (wxFileExists(rulefile)) { if (htmlwin->editlink) { if (filename.Lower().EndsWith(wxT(".icons"))) { // let user see b&w image in .icons file mainptr->Raise(); mainptr->OpenFile(rulefile); } else { mainptr->EditFile(rulefile); } } else { // load corresponding rule LoadRule(filename.BeforeLast('.')); } } else { Warning(_("Rule-related file was not installed:\n") + rulefile); } } else if ( mainptr->ExtractZipEntry(zippath, entry, tempfile) ) { if (htmlwin->editlink) { mainptr->EditFile(tempfile); } else if ( IsHTMLFile(filename) ) { // display html file htmlwin->LoadPage(tempfile); if (helpptr && helpptr->infront) UpdateHelpButtons(); } else if ( IsTextFile(filename) ) { // open text file in user's text editor mainptr->EditFile(tempfile); } else if ( IsScriptFile(filename) ) { // run script depending on safety check; note that because the script is // included in a zip file we don't remember it in the Run Recent submenu mainptr->CheckBeforeRunning(tempfile, false, zippath); } else { // open pattern but don't remember in Open Recent menu mainptr->Raise(); mainptr->OpenFile(tempfile, false); } } } // ----------------------------------------------------------------------------- void ClickLexiconPattern(const wxHtmlCell* htmlcell) { if (htmlcell) { wxHtmlContainerCell* parent = htmlcell->GetParent(); if (parent) { parent = parent->GetParent(); if (parent) { wxHtmlCell* container = parent->GetFirstChild(); // extract pattern data and store in lexpattern lexpattern.Clear(); while (container) { wxHtmlCell* cell = container->GetFirstChild(); while (cell) { wxString celltext = cell->ConvertToText(NULL); if (celltext.IsEmpty()) { // probably a formatting cell } else { lexpattern += celltext; // append eol char(s) #ifdef __WXMSW__ // use DOS line ending (CR+LF) on Windows lexpattern += '\r'; lexpattern += '\n'; #else // use LF on Linux or Mac lexpattern += '\n'; #endif } cell = cell->GetNext(); } container = container->GetNext(); } if (!lexpattern.IsEmpty()) { mainptr->Raise(); // look for existing lexicon layer lexlayer = -1; for (int i = 0; i < numlayers; i++) { if (GetLayer(i)->currname == lexicon_name) { lexlayer = i; break; } } if (lexlayer < 0 && numlayers == MAX_LAYERS) { Warning(_("Cannot create new layer for lexicon pattern.")); return; } if (mainptr->generating) { // terminate generating loop and set command_pending flag mainptr->Stop(); mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_LOAD_LEXICON); return; } LoadLexiconPattern(); } } } } } // ----------------------------------------------------------------------------- void LoadLexiconPattern() { // switch to existing lexicon layer or create a new such layer if (lexlayer >= 0) { SetLayer(lexlayer); } else { AddLayer(); mainptr->SetWindowTitle(lexicon_name); } // copy lexpattern data to tempstart file so we can handle // all formats supported by readpattern wxFile outfile(currlayer->tempstart, wxFile::write); if ( outfile.IsOpened() ) { outfile.Write(lexpattern); outfile.Close(); // all Life Lexicon patterns assume we're using Conway's Life so try // switching to B3/S23 or Life; if that fails then switch to QuickLife const char* err = currlayer->algo->setrule("B3/S23"); if (err) { // try "Life" in case current algo is RuleLoader and Life.table/tree exists // (also had to make a similar change to the loadpattern code in readpattern.cpp) err = currlayer->algo->setrule("Life"); } if (err) { mainptr->ChangeAlgorithm(QLIFE_ALGO, wxString("B3/S23",wxConvLocal)); } // load lexicon pattern into current layer mainptr->LoadPattern(currlayer->tempstart, lexicon_name); } else { Warning(_("Could not create tempstart file!")); } } // ----------------------------------------------------------------------------- void HtmlView::OnLinkClicked(const wxHtmlLinkInfo& link) { #ifdef __WXMAC__ if ( stopwatch->Time() - whenactive < 500 ) { // avoid problem on Mac: // ignore click in link if the help window was in the background; // this isn't fail safe because OnLinkClicked is only called AFTER // the mouse button is released (better soln would be to set an // ignoreclick flag in OnMouseDown handler if click occurred very // soon after activate) return; } #endif wxString url = link.GetHref(); if ( url.StartsWith(wxT("http:")) || url.StartsWith(wxT("mailto:")) ) { // pass http/mailto URL to user's preferred browser/emailer if ( !wxLaunchDefaultBrowser(url) ) Warning(_("Could not open URL in browser!")); } else if ( url.StartsWith(wxT("get:")) ) { if (mainptr->generating) { Warning(_("Cannot download file while generating a pattern.")); // or stop and create pending event??? see ID_LOAD_LEXICON } else if (inscript) { Warning(_("Cannot download file while a script is running.")); } else if (editlink && IsZipFile(url)) { Warning(_("Opening a zip file in a text editor is not a good idea.")); } else { // download clicked file GetURL( url.AfterFirst(':') ); } } else if ( url.StartsWith(wxT("unzip:")) ) { if (inscript) { Warning(_("Cannot extract zip entry while a script is running.")); } else { // extract clicked entry from zip file wxString zippath = url.AfterFirst(':'); wxString entry = url.AfterLast(':'); zippath = zippath.BeforeLast(':'); UnzipFile(zippath, entry); } } else if ( url.StartsWith(wxT("edit:")) ) { // open clicked file in user's preferred text editor wxString path = url.AfterFirst(':'); #ifdef __WXMSW__ path.Replace(wxT("/"), wxT("\\")); #endif wxFileName fname(path); if (!fname.IsAbsolute()) path = gollydir + path; mainptr->EditFile(path); } else if ( url.StartsWith(wxT("lexpatt:")) ) { if (inscript) { Warning(_("Cannot load lexicon pattern while a script is running.")); } else { // user clicked on pattern in Life Lexicon ClickLexiconPattern( link.GetHtmlCell() ); } } else if ( url.StartsWith(wxT("prefs:")) ) { if (inscript) { Warning(_("Cannot change preferences while a script is running.")); } else { // user clicked on link to Preferences dialog mainptr->ShowPrefsDialog( url.AfterFirst(':') ); } } else if ( url.StartsWith(wxT("open:")) ) { if (inscript) { Warning(_("Cannot open file while a script is running.")); } else { // open clicked file wxString path = url.AfterFirst(':'); #ifdef __WXMSW__ path.Replace(wxT("/"), wxT("\\")); #endif wxFileName fname(path); if (!fname.IsAbsolute()) path = gollydir + path; if (editlink) { mainptr->EditFile(path); } else { mainptr->Raise(); mainptr->OpenFile(path); } } } else if ( url.StartsWith(wxT("rule:")) ) { LoadRule( url.AfterFirst(':') ); } else { // assume it's a link to a local target or another help file CheckAndLoad(url); if (helpptr && helpptr->infront) UpdateHelpButtons(); } } // ----------------------------------------------------------------------------- void HtmlView::OnCellMouseHover(wxHtmlCell* cell, wxCoord x, wxCoord y) { if (helpptr && helpptr->infront && cell) { wxHtmlLinkInfo* link = cell->GetLink(x,y); if (link) { wxString href = link->GetHref(); href.Replace(wxT("&"), wxT("&&")); helpptr->SetStatus(href); wxPoint pt = ScreenToClient( wxGetMousePosition() ); linkrect = wxRect(pt.x-x, pt.y-y, cell->GetWidth(), cell->GetHeight()); } else { ClearStatus(); } } } // ----------------------------------------------------------------------------- void HtmlView::OnMouseMotion(wxMouseEvent& event) { if (helpptr && helpptr->infront && !linkrect.IsEmpty()) { int x = event.GetX(); int y = event.GetY(); if (!linkrect.Contains(x,y)) ClearStatus(); } event.Skip(); } // ----------------------------------------------------------------------------- void HtmlView::OnMouseLeave(wxMouseEvent& event) { if (helpptr && helpptr->infront) { ClearStatus(); } event.Skip(); } // ----------------------------------------------------------------------------- void HtmlView::ClearStatus() { if (helpptr) { helpptr->SetStatus(wxEmptyString); linkrect = wxRect(0,0,0,0); } } // ----------------------------------------------------------------------------- #if defined(__WXMAC__) && wxCHECK_VERSION(2,9,0) // wxMOD_CONTROL has been changed to mean Command key down (sheesh!) #define wxMOD_CONTROL wxMOD_RAW_CONTROL #define ControlDown RawControlDown #endif void HtmlView::OnMouseDown(wxMouseEvent& event) { // set flag so ctrl/right-clicked file can be opened in editor // (this is consistent with how we handle clicks in pattern/script pane) editlink = event.ControlDown() || event.RightDown(); event.Skip(); } // ----------------------------------------------------------------------------- void HtmlView::CheckAndLoad(const wxString& filepath) { if (filepath == SHOW_KEYBOARD_SHORTCUTS) { // build HTML string to display current keyboard shortcuts wxString contents = GetShortcutTable(); // write contents to file and call LoadPage so that back/forwards buttons work wxString htmlfile = tempdir + SHOW_KEYBOARD_SHORTCUTS; wxFile outfile(htmlfile, wxFile::write); if (outfile.IsOpened()) { outfile.Write(contents); outfile.Close(); LoadPage(htmlfile); } else { Warning(_("Could not create file:\n") + htmlfile); // might as well show contents SetPage(contents); currhelp = SHOW_KEYBOARD_SHORTCUTS; } } else if ( filepath.StartsWith(_("Help/")) ) { // prepend location of Golly so user can open help while running a script wxString fullpath = gollydir + filepath; LoadPage(fullpath); } else { // assume full path or local link LoadPage(filepath); } } // ----------------------------------------------------------------------------- #ifdef __WXMSW__ // we have to use OnKeyUp handler on Windows otherwise wxHtmlWindow's OnKeyUp // gets called which detects ctrl-C and clobbers our clipboard fix void HtmlView::OnKeyUp(wxKeyEvent& event) #else // we have to use OnKeyDown handler on Mac -- if OnKeyUp handler is used and // cmd-C is pressed quickly then key code is 400!!! void HtmlView::OnKeyDown(wxKeyEvent& event) #endif { int key = event.GetKeyCode(); if (event.CmdDown()) { // let cmd-A select all text if (key == 'A') { SelectAll(); return; } #ifdef __WXMAC__ // let cmd-W close help window or about box if (key == 'W') { GetParent()->Close(true); return; } #endif } if ( event.CmdDown() || event.AltDown() ) { if ( key == 'C' ) { // copy any selected text to the clipboard wxString text = SelectionToText(); if ( text.Length() > 0 ) { if ( helpptr && helpptr->infront && GetOpenedPageTitle().StartsWith(wxT("Life Lexicon")) ) { // avoid wxHTML bug when copying text inside <pre>...</pre>!!! // if there are at least 2 lines and the 1st line is twice // the size of the 2nd line then insert \n in middle of 1st line if ( text.Freq('\n') > 0 ) { wxString line1 = text.BeforeFirst('\n'); wxString aftern = text.AfterFirst('\n'); wxString line2 = aftern.BeforeFirst('\n'); size_t line1len = line1.Length(); size_t line2len = line2.Length(); if ( line1len == 2 * line2len ) { wxString left = text.Left(line2len); wxString right = text.Mid(line2len); text = left; text += '\n'; text += right; } } } mainptr->CopyTextToClipboard(text); } } else { event.Skip(); } } else { // this handler is also called from ShowAboutBox if ( helpptr == NULL || !helpptr->infront ) { if ( key == WXK_NUMPAD_ENTER || key == WXK_RETURN ) { // allow enter key or return key to close about box GetParent()->Close(true); return; } event.Skip(); return; } // let escape/return/enter key close help window if ( key == WXK_ESCAPE || key == WXK_RETURN || key == WXK_NUMPAD_ENTER ) { helpptr->Close(true); } else if ( key == WXK_HOME ) { ShowHelp(helphome); } else { event.Skip(); } } } // ----------------------------------------------------------------------------- void HtmlView::OnChar(wxKeyEvent& event) { // this handler is also called from ShowAboutBox if ( helpptr == NULL || !helpptr->infront ) { event.Skip(); return; } int key = event.GetKeyCode(); if ( key == '+' || key == '=' || key == WXK_ADD ) { if ( helpfontsize < maxfontsize ) { helpfontsize++; ChangeFontSizes(helpfontsize); } } else if ( key == '-' || key == WXK_SUBTRACT ) { if ( helpfontsize > minfontsize ) { helpfontsize--; ChangeFontSizes(helpfontsize); } } else if ( key == '[' || key == WXK_LEFT ) { if ( HistoryBack() ) { UpdateHelpButtons(); } } else if ( key == ']' || key == WXK_RIGHT ) { if ( HistoryForward() ) { UpdateHelpButtons(); } } else { event.Skip(); // so up/down arrows and pg up/down keys work } } // ----------------------------------------------------------------------------- // avoid scroll position being reset to top when wxHtmlWindow is resized void HtmlView::OnSize(wxSizeEvent& event) { int x, y; GetViewStart(&x, &y); // save current position wxHtmlWindow::OnSize(event); wxString currpage = GetOpenedPage(); if ( !currpage.IsEmpty() && canreload ) { CheckAndLoad(currpage); // reload page Scroll(x, y); // scroll to old position } // prevent wxHtmlWindow::OnSize being called again event.Skip(false); } // ----------------------------------------------------------------------------- void HtmlView::OnTimer(wxTimerEvent& WXUNUSED(event)) { if (helpptr && helpptr->infront) { // send idle event to html window so cursor gets updated // even while app is busy doing something else (eg. generating) wxIdleEvent idleevent; #if wxCHECK_VERSION(2,9,2) // SendIdleEvents is now in wxWindow SendIdleEvents(idleevent); #else wxGetApp().SendIdleEvents(this, idleevent); #endif } } // ----------------------------------------------------------------------------- void HtmlView::SetFontSizes(int size) { // set font sizes for <FONT SIZE=-2> to <FONT SIZE=+4> int f_sizes[7]; f_sizes[0] = int(size * 0.6); f_sizes[1] = int(size * 0.8); f_sizes[2] = size; f_sizes[3] = int(size * 1.2); f_sizes[4] = int(size * 1.4); f_sizes[5] = int(size * 1.6); f_sizes[6] = int(size * 1.8); #ifdef __WXOSX_COCOA__ SetFonts(wxT("Lucida Grande"), wxT("Monaco"), f_sizes); #else SetFonts(wxEmptyString, wxEmptyString, f_sizes); #endif } // ----------------------------------------------------------------------------- void HtmlView::ChangeFontSizes(int size) { // changing font sizes resets pos to top, so save and restore pos int x, y; GetViewStart(&x, &y); SetFontSizes(size); if (y > 0) Scroll(-1, y); } // ----------------------------------------------------------------------------- void ShowAboutBox() { if (viewptr->waitingforclick) return; wxBoxSizer* topsizer = new wxBoxSizer(wxVERTICAL); wxDialog dlg(mainptr, wxID_ANY, wxString(_("About Golly"))); HtmlView* html = new HtmlView(&dlg, wxID_ANY, wxDefaultPosition, #if wxCHECK_VERSION(2,9,0) // work around SetSize bug below!!! wxSize(400, 320), #elif defined(__WXGTK__) wxSize(460, 220), #else wxSize(386, 220), #endif wxHW_SCROLLBAR_NEVER | wxSUNKEN_BORDER); html->SetBorders(0); #ifdef __WXOSX_COCOA__ html->SetFontSizes(helpfontsize); #endif html->CheckAndLoad(_("Help/about.html")); // avoid HtmlView::OnSize calling CheckAndLoad again html->canreload = false; // this call seems to be ignored in __WXOSX_COCOA__!!! html->SetSize(html->GetInternalRepresentation()->GetWidth(), html->GetInternalRepresentation()->GetHeight()); topsizer->Add(html, 1, wxALL, 10); wxButton* okbutt = new wxButton(&dlg, wxID_OK, _("OK")); okbutt->SetDefault(); topsizer->Add(okbutt, 0, wxBOTTOM | wxALIGN_CENTER, 10); dlg.SetSizer(topsizer); topsizer->Fit(&dlg); dlg.Centre(); dlg.ShowModal(); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/golly.rc�����������������������������������������������������������������������0000755�0001750�0001750�00000000326�12536111364�013120� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// first icon file is used by Windows Explorer: aaaaaaaa ICON "icons/appicon.ico" // these icons are for the frame: appicon0 ICON "icons/appicon32.ico" appicon1 ICON "icons/appicon16.ico" #include "wx/msw/wx.rc" ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/CMakeLists.txt�����������������������������������������������������������������0000644�0001750�0001750�00000017044�12536111364�014206� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cmake_minimum_required(VERSION 2.6) project( golly ) set( APP_VERSION 2.7 ) if(APPLE OR WIN32) # app names are usually capitalized on Mac OS X and Windows set( APP_NAME Golly ) else() # Linux binaries are usually all lowercase set( APP_NAME golly ) endif() # low-level code used in all executables set(BASE_SOURCES ../gollybase/bigint.h ../gollybase/bigint.cpp ../gollybase/generationsalgo.h ../gollybase/generationsalgo.cpp ../gollybase/ghashbase.h ../gollybase/ghashbase.cpp ../gollybase/ghashdraw.cpp ../gollybase/hlifealgo.h ../gollybase/hlifealgo.cpp ../gollybase/hlifedraw.cpp ../gollybase/jvnalgo.h ../gollybase/jvnalgo.cpp ../gollybase/lifealgo.h ../gollybase/lifealgo.cpp ../gollybase/lifepoll.h ../gollybase/lifepoll.cpp ../gollybase/liferender.h ../gollybase/liferender.cpp ../gollybase/liferules.h ../gollybase/liferules.cpp ../gollybase/platform.h ../gollybase/qlifealgo.h ../gollybase/qlifealgo.cpp ../gollybase/qlifedraw.cpp ../gollybase/readpattern.h ../gollybase/readpattern.cpp ../gollybase/ruleloaderalgo.h ../gollybase/ruleloaderalgo.cpp ../gollybase/ruletable_algo.h ../gollybase/ruletable_algo.cpp ../gollybase/ruletreealgo.h ../gollybase/ruletreealgo.cpp ../gollybase/util.h ../gollybase/util.cpp ../gollybase/viewport.h ../gollybase/viewport.cpp ../gollybase/writepattern.h ../gollybase/writepattern.cpp ) include_directories( ../gollybase ) # high-level GUI code used in desktop Golly set(GUI_SOURCES wxalgos.h wxalgos.cpp wxcontrol.cpp wxedit.h wxedit.cpp wxfile.cpp wxgolly.h wxgolly.cpp wxhelp.h wxhelp.cpp wxinfo.h wxinfo.cpp wxlayer.h wxlayer.cpp wxmain.h wxmain.cpp wxperl.h wxperl.cpp wxprefs.h wxprefs.cpp wxpython.h wxpython.cpp wxrender.h wxrender.cpp wxrule.h wxrule.cpp wxscript.h wxscript.cpp wxselect.h wxselect.cpp wxstatus.h wxstatus.cpp wxtimeline.h wxtimeline.cpp wxundo.h wxundo.cpp wxutils.h wxutils.cpp wxview.h wxview.cpp ) set(RESOURCES golly.rc Info.plist.in icons/appicon.ico icons/appicon16.ico icons/appicon32.ico icons/appicon48.ico icons/appicon.xpm icons/app.icns icons/file-mc.icns icons/file-rle.icns ) if(APPLE) # on Mac OS X it's better to use locally installed wxWidgets headers and libs # (the pre-installed stuff tends to be out of date; eg. 10.6 has wxMac 2.8.8 and it's a 32-bit debug build) set( wxWidgets_CONFIG_EXECUTABLE /usr/local/bin/wx-config ) set( wxWidgets_wxrc_EXECUTABLE /usr/local/bin/wxrc ) # not used, but no harm leaving it in # to avoid statically linking the Perl library into the app we do these 2 steps: # 1. override PERL_INCLUDE_PATH to simplified output from "/usr/bin/perl -MExtUtils::Embed -e ccopts" # 2. override PERL_LIBRARY to simplified output from "/usr/bin/perl -MExtUtils::Embed -e ldopts" set( PERL_INCLUDE_PATH /System/Library/Perl/5.10.0/darwin-thread-multi-2level/CORE ) set( PERL_LIBRARY "-L/usr/local/lib -L/System/Library/Perl/5.10.0/darwin-thread-multi-2level/CORE -lperl -ldl -lm -lutil -lc" ) elseif(UNIX) # remove -rdynamic from link options on Linux to reduce golly size by about 1.2MB set( CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "" ) endif() find_package( wxWidgets REQUIRED html net adv core base ) if(WIN32) # use zlib library included in wxWidgets set( ZLIB_INCLUDE_DIR ${wxWidgets_ROOT_DIR}/src/zlib ) set( ZLIB_LIBRARY ${wxWidgets_LIB_DIR}/wxzlib.lib ) # PERL_LIBARY is not used in our Windows build but cmake needs a setting set( PERL_LIBRARY lib_not_used ) endif() find_package( ZLIB REQUIRED ) find_package( PerlLibs REQUIRED ) find_package( PythonLibs REQUIRED ) include_directories( ${ZLIB_INCLUDE_DIR} ${PERL_INCLUDE_PATH} ${PYTHON_INCLUDE_PATH} ) include( ${wxWidgets_USE_FILE} ) # pass extra settings to the compiler add_definitions(-DZLIB -DVERSION=${APP_VERSION}) if(APPLE) # support Mac OS 10.6 or later add_definitions(-mmacosx-version-min=10.6) endif() if(APPLE OR UNIX) # use same settings as in makefiles add_definitions(-D_LARGE_FILES -O5) endif() # workaround for wx2.9.3 wxAssert link errors, see http://trac.wxwidgets.org/ticket/12626 SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DwxDEBUG_LEVEL=0") # avoid security warnings if(MSVC) add_definitions(/D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS) endif() # set this to true if using Visual Leak Detector to find memory leaks set(USING_VISUAL_LEAK_DETECTOR FALSE) if(USING_VISUAL_LEAK_DETECTOR) set(VLD_INCLUDE_DIR "C:\Program Files\Visual Leak Detector\include") set(VLD_LIBRARIES "C:\Program Files\Visual Leak Detector\lib\Win32\vld.lib") add_definitions(/DUSING_VISUAL_LEAK_DETECTOR) endif() # put the executables in parent directory set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/..) # create base library used by all 3 executables add_library( gollybase STATIC ${BASE_SOURCES} ) add_executable( ${APP_NAME} WIN32 MACOSX_BUNDLE # build a properly bundled Mac app ${GUI_SOURCES} ${RESOURCES} ) add_executable( bgolly ../cmdline/bgolly.cpp ) target_link_libraries( ${APP_NAME} gollybase ${wxWidgets_LIBRARIES} ${ZLIB_LIBRARIES} ) target_link_libraries( bgolly gollybase ${ZLIB_LIBRARIES} ) if(APPLE) # create Info.plist (using Info.plist.in) and PkgInfo files inside .app bundle add_custom_target( app_bundle COMMAND sed -e "s/VERSION/${APP_VERSION}/" ${CMAKE_SOURCE_DIR}/Info.plist.in >${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Golly.app/Contents/Info.plist COMMAND echo -n "APPLGoLy" >${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Golly.app/Contents/PkgInfo ) add_dependencies( ${APP_NAME} app_bundle ) # copy *.icns files into Resources directory inside .app bundle set_source_files_properties( ${CMAKE_SOURCE_DIR}/icons/app.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) set_source_files_properties( ${CMAKE_SOURCE_DIR}/icons/file-mc.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) set_source_files_properties( ${CMAKE_SOURCE_DIR}/icons/file-rle.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) # strip out debug info (reduces app size by 1.6MB) target_link_libraries( ${APP_NAME} -Wl,-dead_strip -Wl,-S ) # only the Mac app needs to be linked against the Perl and Python libs # (on Windows and Linux those libs are dynamically loaded the first time a script is run) target_link_libraries( ${APP_NAME} ${PERL_LIBRARY} ${PYTHON_LIBRARIES} ) endif() # hack to get around the "Debug" and "Release" folders Visual Studio adds on Windows # http://stackoverflow.com/questions/543203/cmake-runtime-output-directory-on-windows if(MSVC_IDE) set_target_properties( ${APP_NAME} bgolly PROPERTIES PREFIX "../" ) endif() if(USING_VISUAL_LEAK_DETECTOR) include_directories( ${VLD_INCLUDE_DIR} ) target_link_libraries( ${APP_NAME} ${VLD_LIBRARIES} ) target_link_libraries( bgolly ${VLD_LIBRARIES} ) endif() # ensure we link the C runtime statically (N.B. still appears as /MD in the CMake gui but ignore this) # see: http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace foreach( var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO ) string( REGEX REPLACE "/MD" "/MT" ${var} "${${var}}" ) endforeach() ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/wxrule.cpp���������������������������������������������������������������������0000644�0001750�0001750�00000110434�12536111364�013475� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/wxhtml.h" // for wxHtmlWindow #include "lifealgo.h" #include "wxgolly.h" // for wxGetApp, mainptr #include "wxmain.h" // for mainptr->... #include "wxprefs.h" // for namedrules, gollydir, showalgohelp, etc #include "wxutils.h" // for Warning, Fatal, Beep #include "wxlayer.h" // for currlayer #include "wxalgos.h" // for NumAlgos, CreateNewUniverse, etc #include "wxrule.h" // ----------------------------------------------------------------------------- bool ValidRule(wxString& rule) { // return true if given rule is valid in at least one algorithm // and convert rule to canonical form for (int i = 0; i < NumAlgos(); i++) { lifealgo* tempalgo = CreateNewUniverse(i); const char* err = tempalgo->setrule( rule.mb_str(wxConvLocal) ); if (!err) { // convert rule to canonical form rule = wxString(tempalgo->getrule(),wxConvLocal); delete tempalgo; return true; } delete tempalgo; } return false; } // ----------------------------------------------------------------------------- wxString GetRuleName(const wxString& rulestring) { // search namedrules array for matching rule wxString rulename; // check for a suffix like ":T100,200" wxString ruleprefix = rulestring; wxString rulesuffix = wxEmptyString; if ( ruleprefix.Find(':') >= 0 ) { ruleprefix = ruleprefix.BeforeFirst(':'); rulesuffix = wxT(":") + rulestring.AfterFirst(':'); } // first look for given rulestring in namedrules; if user has created a name like // "Life on torus" for "B3/S23:T100,200" then this will find that name for (size_t i = 0; i < namedrules.GetCount(); i++) { wxString thisrule = namedrules[i].AfterFirst('|'); // rule is after '|' if ( rulestring.IsSameAs(thisrule,false) ) { rulename = namedrules[i].BeforeFirst('|'); // name is before '|' if ( rulesuffix.Length() > 0 ) { // still append suffix so user sees "Life on torus:T100,200" rulename += rulesuffix; } return rulename; } } if ( rulesuffix.Length() > 0 ) { // look for ruleprefix in namedrules; if there is no explicit name for // "B3/S23:T100,200" then this will find "Life" and user will see "Life:T100,200" for (size_t i = 0; i < namedrules.GetCount(); i++) { wxString thisrule = namedrules[i].AfterFirst('|'); // rule is after '|' if ( ruleprefix.IsSameAs(thisrule,false) ) { rulename = namedrules[i].BeforeFirst('|'); // name is before '|' rulename += rulesuffix; return rulename; } } } // given rulestring has not been named rulename = rulestring; return rulename; } // ----------------------------------------------------------------------------- // globals used in AlgoHelp and RuleDialog classes: static wxTextCtrl* ruletext = NULL; // text box for user to type in rule static wxStaticText* statusline = NULL; // status line at bottom of dialog // ----------------------------------------------------------------------------- // define a html window for displaying algo help: class AlgoHelp : public wxHtmlWindow { public: AlgoHelp(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxHtmlWindow(parent, id, pos, size, style) { editlink = false; linkrect = wxRect(0,0,0,0); } virtual void OnLinkClicked(const wxHtmlLinkInfo& link); virtual void OnCellMouseHover(wxHtmlCell* cell, wxCoord x, wxCoord y); void ClearStatus(); void DisplayFile(const wxString& filepath); void SetFontSizes(int size); bool editlink; // open clicked file in editor? private: void OnKeyUp(wxKeyEvent& event); void OnSize(wxSizeEvent& event); void OnMouseMotion(wxMouseEvent& event); void OnMouseLeave(wxMouseEvent& event); void OnMouseDown(wxMouseEvent& event); wxRect linkrect; // rect for cell containing link DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(AlgoHelp, wxHtmlWindow) #ifdef __WXGTK__ // don't call OnKeyUp in wxGTK because for some reason it prevents // copied help text being pasted into the rule box #else EVT_KEY_UP (AlgoHelp::OnKeyUp) #endif #ifdef __WXMAC__ // on the Mac OnKeyUp is also called on a key-down event because the // key-up handler gets a key code of 400 if cmd-C is pressed quickly EVT_KEY_DOWN (AlgoHelp::OnKeyUp) #endif EVT_MOTION (AlgoHelp::OnMouseMotion) EVT_ENTER_WINDOW (AlgoHelp::OnMouseMotion) EVT_LEAVE_WINDOW (AlgoHelp::OnMouseLeave) EVT_LEFT_DOWN (AlgoHelp::OnMouseDown) EVT_RIGHT_DOWN (AlgoHelp::OnMouseDown) EVT_SIZE (AlgoHelp::OnSize) END_EVENT_TABLE() // ----------------------------------------------------------------------------- void AlgoHelp::OnLinkClicked(const wxHtmlLinkInfo& link) { wxString url = link.GetHref(); if ( url.StartsWith(wxT("http:")) || url.StartsWith(wxT("mailto:")) ) { // pass http/mailto URL to user's preferred browser/emailer if ( !wxLaunchDefaultBrowser(url) ) Warning(_("Could not open URL in browser!")); } else if ( url.StartsWith(wxT("rule:")) ) { // copy clicked rule into rule box ruletext->SetValue( url.AfterFirst(':') ); ruletext->SetFocus(); ruletext->SetSelection(-1,-1); } else if ( url.StartsWith(wxT("open:")) ) { // open clicked pattern/script wxString clickedfile = url.AfterFirst(':'); #ifdef __WXMSW__ clickedfile.Replace(wxT("/"), wxT("\\")); #endif wxFileName fname(clickedfile); if (!fname.IsAbsolute()) clickedfile = gollydir + clickedfile; if (editlink) { mainptr->EditFile(clickedfile); } else { mainptr->pendingfiles.Add(clickedfile); // next OnIdle will call OpenFile // send OK event to close dialog wxCommandEvent okevent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK); wxWindow* buttwin = GetParent()->FindWindow(wxID_OK); if (buttwin) { okevent.SetEventObject(buttwin); buttwin->GetEventHandler()->ProcessEvent(okevent); } } } else { // assume it's a link to a local target or another help file DisplayFile(url); } } // ----------------------------------------------------------------------------- void AlgoHelp::OnCellMouseHover(wxHtmlCell* cell, wxCoord x, wxCoord y) { if (cell) { wxHtmlLinkInfo* link = cell->GetLink(x,y); if (link) { wxString href = link->GetHref(); href.Replace(wxT("&"), wxT("&&")); statusline->SetLabel(href); wxPoint pt = ScreenToClient( wxGetMousePosition() ); linkrect = wxRect(pt.x-x, pt.y-y, cell->GetWidth(), cell->GetHeight()); } else { ClearStatus(); } } } // ----------------------------------------------------------------------------- void AlgoHelp::OnMouseMotion(wxMouseEvent& event) { if (!linkrect.IsEmpty()) { int x = event.GetX(); int y = event.GetY(); if (!linkrect.Contains(x,y)) ClearStatus(); } event.Skip(); } // ----------------------------------------------------------------------------- void AlgoHelp::OnMouseLeave(wxMouseEvent& event) { ClearStatus(); event.Skip(); } // ----------------------------------------------------------------------------- void AlgoHelp::ClearStatus() { statusline->SetLabel(wxEmptyString); linkrect = wxRect(0,0,0,0); } // ----------------------------------------------------------------------------- #if defined(__WXMAC__) && wxCHECK_VERSION(2,9,0) // wxMOD_CONTROL has been changed to mean Command key down (sheesh!) #define wxMOD_CONTROL wxMOD_RAW_CONTROL #define ControlDown RawControlDown #endif void AlgoHelp::OnMouseDown(wxMouseEvent& event) { // set flag so ctrl/right-clicked file can be opened in editor // (this is consistent with how we handle clicks in pattern/script pane) editlink = event.ControlDown() || event.RightDown(); event.Skip(); } // ----------------------------------------------------------------------------- void AlgoHelp::DisplayFile(const wxString& filepath) { if ( filepath.IsEmpty() ) { wxString newrule = ruletext->GetValue(); wxString contents = wxT("<html><body bgcolor=\"#FFFFCE\">") wxT("<p>The given rule is not valid in any algorithm."); if (newrule.Contains(wxT(":"))) { // assume user is trying to specify a bounded grid contents += wxT("<p>The syntax for a bounded grid is described "); contents += wxT("<a href=\"Help/bounded.html\">here</a>."); } contents += wxT("</body></html>"); SetPage(contents); } else if ( filepath.StartsWith(gollydir) && !wxFileName::FileExists(filepath) ) { wxString contents = wxT("<html><body bgcolor=\"#FFFFCE\">") wxT("<p>There is no help available for this algorithm.") wxT("</body></html>"); SetPage(contents); } else { LoadPage(filepath); } } // ----------------------------------------------------------------------------- // we have to use a key-up handler otherwise wxHtmlWindow's key-up handler // gets called which detects cmd/ctrl-C and clobbers our clipboard fix void AlgoHelp::OnKeyUp(wxKeyEvent& event) { int key = event.GetKeyCode(); if (event.CmdDown()) { // let cmd-A select all text if (key == 'A') { SelectAll(); event.Skip(false); return; } #ifdef __WXMAC__ // let cmd-W close dialog if (key == 'W') { GetParent()->Close(true); event.Skip(false); return; } #endif } if ( event.CmdDown() || event.AltDown() ) { if ( key == 'C' ) { // copy any selected text to the clipboard wxString text = SelectionToText(); if ( text.Length() > 0 ) { // remove any leading/trailing white space while (text.GetChar(0) <= wxChar(' ')) { text = text.Mid(1); } while (text.GetChar(text.Length()-1) <= wxChar(' ')) { text.Truncate(text.Length()-1); } mainptr->CopyTextToClipboard(text); // don't call wxHtmlWindow's default key-up handler event.Skip(false); return; } } } event.Skip(); } // ----------------------------------------------------------------------------- void AlgoHelp::OnSize(wxSizeEvent& event) { // avoid scroll position being reset to top when wxHtmlWindow is resized int x, y; GetViewStart(&x, &y); // save current position wxHtmlWindow::OnSize(event); wxString currpage = GetOpenedPage(); if ( !currpage.IsEmpty() ) { DisplayFile(currpage); // reload page Scroll(x, y); // scroll to old position } // prevent wxHtmlWindow::OnSize being called again event.Skip(false); } // ----------------------------------------------------------------------------- void AlgoHelp::SetFontSizes(int size) { // set font sizes for <FONT SIZE=-2> to <FONT SIZE=+4> int f_sizes[7]; f_sizes[0] = int(size * 0.6); f_sizes[1] = int(size * 0.8); f_sizes[2] = size; f_sizes[3] = int(size * 1.2); f_sizes[4] = int(size * 1.4); f_sizes[5] = int(size * 1.6); f_sizes[6] = int(size * 1.8); #ifdef __WXOSX_COCOA__ SetFonts(wxT("Lucida Grande"), wxT("Monaco"), f_sizes); #else SetFonts(wxEmptyString, wxEmptyString, f_sizes); #endif } // ----------------------------------------------------------------------------- const wxString UNKNOWN = _("UNKNOWN"); // unknown algorithm const wxString UNNAMED = _("UNNAMED"); // unnamed rule const int HGAP = 12; const int BIGVGAP = 12; #if defined(__WXMAC__) && wxCHECK_VERSION(2,8,0) && !wxCHECK_VERSION(2,9,0) // fix wxALIGN_CENTER_VERTICAL bug in wxMac 2.8.x; // only happens when a wxStaticText/wxButton box is next to a wxChoice box #define FIX_ALIGN_BUG wxBOTTOM,4 #else #define FIX_ALIGN_BUG wxALL,0 #endif // ----------------------------------------------------------------------------- // define a modal dialog for changing the current rule class RuleDialog : public wxDialog { public: RuleDialog(wxWindow* parent); ~RuleDialog() { delete ruletext; delete statusline; } virtual bool TransferDataFromWindow(); // called when user hits OK private: enum { // control ids RULE_ALGO = wxID_HIGHEST + 1, RULE_NAME, RULE_TEXT, RULE_ADD_BUTT, RULE_ADD_TEXT, RULE_DEL_BUTT }; void CreateControls(); // initialize all the controls void UpdateAlgo(); // update algochoice depending on rule void UpdateName(); // update namechoice depending on rule void UpdateHelp(); // update algo help AlgoHelp* htmlwin; // html window for displaying algo help wxTextCtrl* addtext; // text box for user to type in name of rule wxChoice* algochoice; // lists the known algorithms but can have one // more item appended (UNKNOWN) wxChoice* namechoice; // kept in sync with namedrules but can have one // more item appended (UNNAMED) int algoindex; // current algochoice selection int startalgo; // look for a valid rule starting with this algo int nameindex; // current namechoice selection bool ignore_text_change; // prevent OnRuleTextChanged doing anything? bool expanded; // help button has expanded dialog? wxRect minrect; // window rect for unexpanded dialog // event handlers void OnRuleTextChanged(wxCommandEvent& event); void OnChooseAlgo(wxCommandEvent& event); void OnChooseName(wxCommandEvent& event); void OnHelpButton(wxCommandEvent& event); void OnAddName(wxCommandEvent& event); void OnDeleteName(wxCommandEvent& event); void OnUpdateAdd(wxUpdateUIEvent& event); void OnUpdateDelete(wxUpdateUIEvent& event); void OnSize(wxSizeEvent& event); void OnMove(wxMoveEvent& event); DECLARE_EVENT_TABLE() }; BEGIN_EVENT_TABLE(RuleDialog, wxDialog) EVT_CHOICE (RULE_ALGO, RuleDialog::OnChooseAlgo) EVT_CHOICE (RULE_NAME, RuleDialog::OnChooseName) EVT_TEXT (RULE_TEXT, RuleDialog::OnRuleTextChanged) EVT_BUTTON (wxID_HELP, RuleDialog::OnHelpButton) EVT_BUTTON (RULE_ADD_BUTT, RuleDialog::OnAddName) EVT_BUTTON (RULE_DEL_BUTT, RuleDialog::OnDeleteName) EVT_UPDATE_UI (RULE_ADD_BUTT, RuleDialog::OnUpdateAdd) EVT_UPDATE_UI (RULE_DEL_BUTT, RuleDialog::OnUpdateDelete) EVT_SIZE ( RuleDialog::OnSize) EVT_MOVE ( RuleDialog::OnMove) END_EVENT_TABLE() // ----------------------------------------------------------------------------- RuleDialog::RuleDialog(wxWindow* parent) : htmlwin( NULL ) { expanded = false; // tested in RuleDialog::OnSize (called by Create) Create(parent, wxID_ANY, _("Set Rule"), wxPoint(rulex,ruley), wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); htmlwin = new AlgoHelp(this, wxID_ANY, // specify small size to avoid clipping scroll bar on resize wxDefaultPosition, wxSize(30,30), wxHW_DEFAULT_STYLE | wxSUNKEN_BORDER); if (!htmlwin) Fatal(_("Could not create algo help window!")); htmlwin->SetBorders(4); htmlwin->SetFontSizes(helpfontsize); htmlwin->Show(false); ignore_text_change = true; CreateControls(); ignore_text_change = false; // dialog location is set to rulex,ruley // Centre(); minrect = GetRect(); // don't allow resizing when dialog isn't expanded SetMaxSize( wxSize(minrect.width,minrect.height) ); // select all of rule text ruletext->SetFocus(); ruletext->SetSelection(-1,-1); if (showalgohelp) { // send help button event to expand dialog wxCommandEvent buttevent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_HELP); wxWindow* buttwin = FindWindow(wxID_HELP); if (buttwin) { buttevent.SetEventObject(buttwin); buttwin->GetEventHandler()->ProcessEvent(buttevent); } } } // ----------------------------------------------------------------------------- void RuleDialog::CreateControls() { wxStaticText* textlabel = new wxStaticText(this, wxID_STATIC, _("Enter a new rule:")); wxStaticText* namelabel = new wxStaticText(this, wxID_STATIC, _("Or select a named rule:")); wxButton* helpbutt = new wxButton(this, wxID_HELP, wxEmptyString); wxButton* delbutt = new wxButton(this, RULE_DEL_BUTT, _("Delete")); wxButton* addbutt = new wxButton(this, RULE_ADD_BUTT, _("Add")); // create a choice menu to select algo wxArrayString algoarray; for (int i = 0; i < NumAlgos(); i++) { algoarray.Add( wxString(GetAlgoName(i),wxConvLocal) ); } algochoice = new wxChoice(this, RULE_ALGO, wxDefaultPosition, wxDefaultSize, algoarray); algoindex = currlayer->algtype; startalgo = currlayer->algtype; algochoice->SetSelection(algoindex); wxBoxSizer* hbox0 = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* algolabel = new wxBoxSizer(wxHORIZONTAL); algolabel->Add(new wxStaticText(this, wxID_STATIC, _("Algorithm:")), 0, FIX_ALIGN_BUG); hbox0->Add(algolabel, 0, wxALIGN_CENTER_VERTICAL, 0); hbox0->Add(algochoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 6); hbox0->AddSpacer(HGAP); wxBoxSizer* helpbox = new wxBoxSizer(wxHORIZONTAL); helpbox->Add(helpbutt, 0, FIX_ALIGN_BUG); hbox0->Add(helpbox, 0, wxALIGN_CENTER_VERTICAL, 0); int minwidth = 250; int algowd = hbox0->GetMinSize().GetWidth(); if (algowd > minwidth) minwidth = algowd; // create status line for showing link info statusline = new wxStaticText(this, wxID_STATIC, wxEmptyString); #ifdef __WXMAC__ statusline->SetWindowVariant(wxWINDOW_VARIANT_SMALL); #endif // create text box for entering new rule ruletext = new wxTextCtrl(this, RULE_TEXT, wxString(currlayer->algo->getrule(),wxConvLocal), wxDefaultPosition, wxSize(minwidth,wxDefaultCoord)); // create a choice menu to select named rule wxArrayString namearray; for (size_t i=0; i<namedrules.GetCount(); i++) { // remove "|..." part wxString name = namedrules[i].BeforeFirst('|'); namearray.Add(name); } namechoice = new wxChoice(this, RULE_NAME, wxDefaultPosition, wxSize(160,wxDefaultCoord), namearray); nameindex = -1; UpdateName(); // careful -- this uses ruletext addtext = new wxTextCtrl(this, RULE_ADD_TEXT, wxEmptyString, wxDefaultPosition, wxSize(160,wxDefaultCoord)); wxBoxSizer* hbox1 = new wxBoxSizer(wxHORIZONTAL); hbox1->Add(namechoice, 0, wxALIGN_CENTER_VERTICAL, 0); hbox1->AddSpacer(HGAP); wxBoxSizer* delbox = new wxBoxSizer(wxHORIZONTAL); delbox->Add(delbutt, 0, FIX_ALIGN_BUG); hbox1->Add(delbox, 0, wxALIGN_CENTER_VERTICAL, 0); wxBoxSizer* hbox2 = new wxBoxSizer(wxHORIZONTAL); hbox2->Add(addtext, 0, wxALIGN_CENTER_VERTICAL, 0); hbox2->AddSpacer(HGAP); hbox2->Add(addbutt, 0, wxALIGN_CENTER_VERTICAL, 0); wxSizer* stdbutts = CreateButtonSizer(wxOK | wxCANCEL); wxBoxSizer* vbox = new wxBoxSizer(wxVERTICAL); // can we avoid these fudges??? #ifdef __WXMAC__ minwidth += 24; #elif defined(__WXMSW__) minwidth += 16; #else minwidth += 12; #endif vbox->Add(minwidth, 0, 0); vbox->Add(stdbutts, 1, wxALIGN_RIGHT, 0); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); topSizer->AddSpacer(BIGVGAP); topSizer->Add(hbox0, 0, wxLEFT | wxRIGHT, HGAP); topSizer->AddSpacer(BIGVGAP); topSizer->Add(textlabel, 0, wxLEFT | wxRIGHT, HGAP); topSizer->AddSpacer(10); topSizer->Add(ruletext, 0, wxLEFT | wxRIGHT, HGAP); topSizer->AddSpacer(BIGVGAP); topSizer->Add(namelabel, 0, wxLEFT | wxRIGHT, HGAP); topSizer->AddSpacer(6); topSizer->Add(hbox1, 0, wxLEFT | wxRIGHT, HGAP); topSizer->AddSpacer(BIGVGAP); topSizer->Add(hbox2, 0, wxLEFT | wxRIGHT, HGAP); topSizer->AddSpacer(BIGVGAP); topSizer->Add(vbox, 0, wxTOP | wxBOTTOM, 10); SetSizer(topSizer); topSizer->SetSizeHints(this); // calls Fit } // ----------------------------------------------------------------------------- void RuleDialog::UpdateAlgo() { // may need to change selected algo depending on current rule text lifealgo* tempalgo; const char* err; wxString newrule = ruletext->GetValue(); if (newrule.IsEmpty()) newrule = wxT("B3/S23"); // first try new rule in starting algo (NOT necessarily the currently selected algo); // this ensures that typing in a rule achieves the same result as pasting a rule tempalgo = CreateNewUniverse(startalgo); err = tempalgo->setrule( newrule.mb_str(wxConvLocal) ); delete tempalgo; if (!err) { if (startalgo != algoindex) { if (algoindex >= NumAlgos()) { // remove UNKNOWN item from end of algochoice algochoice->Delete( algochoice->GetCount() - 1 ); } algoindex = startalgo; algochoice->SetSelection(algoindex); UpdateHelp(); } return; } // now try new rule in all the other algos int newindex; for (newindex = 0; newindex < NumAlgos(); newindex++) { if (newindex != startalgo) { tempalgo = CreateNewUniverse(newindex); err = tempalgo->setrule( newrule.mb_str(wxConvLocal) ); delete tempalgo; if (!err) { if (newindex != algoindex) { if (algoindex >= NumAlgos()) { // remove UNKNOWN item from end of algochoice algochoice->Delete( algochoice->GetCount() - 1 ); } algoindex = newindex; algochoice->SetSelection(algoindex); UpdateHelp(); } return; } } } // get here if new rule is not valid in any algo if (algoindex < NumAlgos()) { // append UNKNOWN item and select it algochoice->Append(UNKNOWN); algoindex = NumAlgos(); algochoice->SetSelection(algoindex); UpdateHelp(); } } // ----------------------------------------------------------------------------- void RuleDialog::UpdateHelp() { if (expanded) { if (algoindex < NumAlgos()) { // display Help/Algorithms/algoname.html wxString filepath = gollydir + wxT("Help"); filepath += wxFILE_SEP_PATH; filepath += wxT("Algorithms"); filepath += wxFILE_SEP_PATH; filepath += wxString(GetAlgoName(algoindex),wxConvLocal); filepath += wxT(".html"); htmlwin->DisplayFile(filepath); } else { // UNKNOWN algo htmlwin->DisplayFile(wxEmptyString); } } } // ----------------------------------------------------------------------------- void RuleDialog::UpdateName() { // may need to change named rule depending on current rule text int newindex; wxString newrule = ruletext->GetValue(); if ( newrule.IsEmpty() ) { // empty string is a quick way to restore normal Life newindex = 0; } else { // search namedrules array for matching rule newindex = -1; for (size_t i=0; i<namedrules.GetCount(); i++) { // extract rule after '|' wxString thisrule = namedrules[i].AfterFirst('|'); if ( newrule.IsSameAs(thisrule,false) ) { newindex = (int)i; break; } } } if (newindex >= 0) { // matching rule found so remove UNNAMED item if it exists // use (int) twice to avoid warnings on wx 2.6.x/2.7 if ( (int) namechoice->GetCount() > (int) namedrules.GetCount() ) { namechoice->Delete( namechoice->GetCount() - 1 ); } } else { // no match found so use index of UNNAMED item, // appending it if it doesn't exist; // use (int) twice to avoid warnings on wx 2.6.x/2.7 if ( (int) namechoice->GetCount() == (int) namedrules.GetCount() ) { namechoice->Append(UNNAMED); } newindex = namechoice->GetCount() - 1; } if (nameindex != newindex) { nameindex = newindex; namechoice->SetSelection(nameindex); } } // ----------------------------------------------------------------------------- void RuleDialog::OnRuleTextChanged(wxCommandEvent& WXUNUSED(event)) { if (ignore_text_change) return; UpdateName(); UpdateAlgo(); // check for spaces wxString newrule = ruletext->GetValue(); if (newrule.Contains(wxT(" "))) { Warning(_("Spaces are not allowed in rule strings.")); newrule.Replace(wxT(" "), wxEmptyString); ruletext->SetValue(newrule); ruletext->SetFocus(); } } // ----------------------------------------------------------------------------- void RuleDialog::OnChooseAlgo(wxCommandEvent& event) { int i = event.GetSelection(); if (i >= 0 && i < NumAlgos() && i != algoindex) { int oldindex = algoindex; algoindex = i; startalgo = i; // user has explicitly changed the preferred algo // check if the current rule is valid in newly selected algo wxString thisrule = ruletext->GetValue(); if (thisrule.IsEmpty()) thisrule = wxT("B3/S23"); lifealgo* tempalgo = CreateNewUniverse(algoindex); const char* err = tempalgo->setrule( thisrule.mb_str(wxConvLocal) ); if (err) { // rule is not valid so change rule text to selected algo's default rule wxString defrule = wxString(tempalgo->DefaultRule(), wxConvLocal); if (oldindex < NumAlgos() && thisrule.Find(':') >= 0) { // preserve valid topology so we can do things like switch from // "LifeHistory:T30,20" in RuleLoader to "B3/S23:T30,20" in QuickLife if (defrule.Find(':') >= 0) { // default rule shouldn't have a suffix but play safe and remove it defrule = defrule.BeforeFirst(':'); } defrule += wxT(":"); defrule += thisrule.AfterFirst(':'); } ignore_text_change = true; ruletext->SetValue(defrule); ruletext->SetFocus(); ruletext->SetSelection(-1,-1); ignore_text_change = false; if (oldindex >= NumAlgos()) { // remove UNKNOWN item from end of algochoice algochoice->Delete( algochoice->GetCount() - 1 ); } UpdateName(); } else { // rule is valid if (oldindex >= NumAlgos()) { Warning(_("Bug detected in OnChooseAlgo!")); } } delete tempalgo; UpdateHelp(); } } // ----------------------------------------------------------------------------- void RuleDialog::OnChooseName(wxCommandEvent& event) { int i = event.GetSelection(); if (i == nameindex) return; // update rule text based on chosen name nameindex = i; if ( nameindex == (int) namedrules.GetCount() ) { Warning(_("Bug detected in OnChooseName!")); UpdateAlgo(); return; } // remove UNNAMED item if it exists; // use (int) twice to avoid warnings in wx 2.6.x/2.7 if ( (int) namechoice->GetCount() > (int) namedrules.GetCount() ) { namechoice->Delete( namechoice->GetCount() - 1 ); } wxString rule = namedrules[nameindex].AfterFirst('|'); ignore_text_change = true; ruletext->SetValue(rule); ruletext->SetFocus(); ruletext->SetSelection(-1,-1); ignore_text_change = false; UpdateAlgo(); } // ----------------------------------------------------------------------------- void RuleDialog::OnAddName(wxCommandEvent& WXUNUSED(event)) { if ( nameindex < (int) namedrules.GetCount() ) { // OnUpdateAdd should prevent this but play safe Beep(); return; } // validate new rule and convert to canonical form wxString newrule = ruletext->GetValue(); if (!ValidRule(newrule)) { Warning(_("The new rule is not valid in any algorithm.")); ruletext->SetFocus(); ruletext->SetSelection(-1,-1); return; } // validate new name wxString newname = addtext->GetValue(); if ( newname.IsEmpty() ) { Warning(_("Type in a name for the new rule.")); addtext->SetFocus(); return; } else if ( newname.Find('|') >= 0 ) { Warning(_("Sorry, but rule names must not contain \"|\".")); addtext->SetFocus(); addtext->SetSelection(-1,-1); return; } else if ( newname == UNNAMED ) { Warning(_("You can't use that name smarty pants.")); addtext->SetFocus(); addtext->SetSelection(-1,-1); return; } else if ( namechoice->FindString(newname) != wxNOT_FOUND ) { Warning(_("That name is already used for another rule.")); addtext->SetFocus(); addtext->SetSelection(-1,-1); return; } // replace UNNAMED with new name namechoice->Delete( namechoice->GetCount() - 1 ); namechoice->Append( newname ); // append new name and rule to namedrules newname += '|'; newname += newrule; namedrules.Add(newname); // force a change to newly appended item nameindex = -1; UpdateName(); } // ----------------------------------------------------------------------------- void RuleDialog::OnDeleteName(wxCommandEvent& WXUNUSED(event)) { if ( nameindex <= 0 || nameindex >= (int) namedrules.GetCount() ) { // OnUpdateDelete should prevent this but play safe Beep(); return; } // remove current name namechoice->Delete(nameindex); namedrules.RemoveAt((size_t) nameindex); // force a change to UNNAMED item nameindex = -1; UpdateName(); } // ----------------------------------------------------------------------------- void RuleDialog::OnUpdateAdd(wxUpdateUIEvent& event) { // Add button is only enabled if UNNAMED item is selected event.Enable( nameindex == (int) namedrules.GetCount() ); } // ----------------------------------------------------------------------------- void RuleDialog::OnUpdateDelete(wxUpdateUIEvent& event) { // Delete button is only enabled if a non-Life named rule is selected event.Enable( nameindex > 0 && nameindex < (int) namedrules.GetCount() ); } // ----------------------------------------------------------------------------- void RuleDialog::OnHelpButton(wxCommandEvent& WXUNUSED(event)) { wxRect r = GetRect(); expanded = !expanded; showalgohelp = expanded; if (expanded) { int wd, ht; GetClientSize(&wd, &ht); wxRect htmlrect(minrect.width, 10, ruleexwd - 10, ht + ruleexht - 30); htmlwin->SetSize(htmlrect); r.width = minrect.width + ruleexwd; r.height = minrect.height + ruleexht; // call SetMinSize below (AFTER SetSize call) SetMaxSize( wxSize(-1,-1) ); } else { wxWindow* focus = FindFocus(); if (focus != ruletext && focus != addtext) { ruletext->SetFocus(); } r.width = minrect.width; r.height = minrect.height; SetMinSize( wxSize(minrect.width,minrect.height) ); SetMaxSize( wxSize(minrect.width,minrect.height) ); } UpdateHelp(); htmlwin->Show(expanded); SetSize(r); if (expanded) { SetMinSize( wxSize(minrect.width+100,minrect.height) ); } } // ----------------------------------------------------------------------------- void RuleDialog::OnSize(wxSizeEvent& event) { if (expanded) { // resize html window int wd, ht; GetClientSize(&wd, &ht); wxRect r = GetRect(); ruleexwd = r.width - minrect.width; ruleexht = r.height - minrect.height; wxRect htmlrect(minrect.width, 10, wd - minrect.width - 10, ht - 30); if( htmlwin ) { htmlwin->SetSize(htmlrect); } // position status line under bottom left corner if( statusline ) { statusline->Move(htmlrect.GetLeft(), htmlrect.GetBottom() + 4); } } event.Skip(); } // ----------------------------------------------------------------------------- void RuleDialog::OnMove(wxMoveEvent& event) { // save current location for later use in SavePrefs /* sigh... wxMac doesn't return correct position wxPoint pt = event.GetPosition(); rulex = pt.x; ruley = pt.y; */ wxRect r = GetRect(); rulex = r.x; ruley = r.y; event.Skip(); } // ----------------------------------------------------------------------------- bool RuleDialog::TransferDataFromWindow() { // get and validate new rule wxString newrule = ruletext->GetValue(); if (newrule.IsEmpty()) newrule = wxT("B3/S23"); if (algoindex >= NumAlgos()) { Warning(_("The new rule is not valid in any algorithm.")); ruletext->SetFocus(); ruletext->SetSelection(-1,-1); return false; } if (algoindex == currlayer->algtype) { // check if new rule is still valid in current algorithm const char* err = currlayer->algo->setrule( newrule.mb_str(wxConvLocal) ); if (err) { // this can happen if the rule's table/tree file was deleted, // or was edited and some sort of error introduced Warning(_("This rule is no longer valid!")); ruletext->SetFocus(); ruletext->SetSelection(-1,-1); return false; } else { return true; } } else { // change the current algorithm and switch to the new rule // (if the new rule is invalid then the algo's default rule will be used) mainptr->ChangeAlgorithm(algoindex, newrule); return true; } } // ----------------------------------------------------------------------------- bool ChangeRule() { wxArrayString oldnames = namedrules; wxString oldrule = wxString(currlayer->algo->getrule(),wxConvLocal); RuleDialog dialog( wxGetApp().GetTopWindow() ); if ( dialog.ShowModal() == wxID_OK ) { // TransferDataFromWindow has changed the current rule, // and possibly the current algorithm as well return true; } else { // user hit Cancel so restore name array and rule namedrules.Clear(); namedrules = oldnames; return !RestoreRule(oldrule); // note that we return true if RestoreRule failed and had to // switch to the current algorithm's default rule } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/wxhelp.h�����������������������������������������������������������������������0000644�0001750�0001750�00000003437�12536111364�013127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXHELP_H_ #define _WXHELP_H_ // Routines for displaying html help files stored in the Help folder: void ShowHelp(const wxString& filepath); // Open a modeless window and display the given html file. // If filepath is empty then either the help window is brought to the // front if it's open, or it is opened and the most recent html file // is displayed. const wxString SHOW_KEYBOARD_SHORTCUTS = wxT("keyboard.html"); // If ShowHelp is called with this string then a temporary HTML file // is created to show the user's current keyboard shortcuts. void ShowAboutBox(); // Open a modal dialog and display info about the app. void LoadLexiconPattern(); // Load the lexicon pattern clicked by user. void LoadRule(const wxString& rulestring); // Load recently installed .rule/table/tree/colors/icons file. wxFrame* GetHelpFrame(); // Return a pointer to the help window. #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/wxscript.cpp�������������������������������������������������������������������0000644�0001750�0001750�00000166102�12536111364�014035� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include <limits.h> // for INT_MAX #include "wx/filename.h" // for wxFileName #include "wxgolly.h" // for wxGetApp, mainptr, viewptr, statusptr #include "wxmain.h" // for mainptr->... #include "wxselect.h" // for Selection #include "wxedit.h" // for ToggleEditBar, ToggleAllStates, UpdateEditBar #include "wxview.h" // for viewptr->... #include "wxrender.h" // for SetSelectionColor #include "wxstatus.h" // for statusptr->... #include "wxutils.h" // for Warning, Beep, IsScriptFile #include "wxprefs.h" // for gollydir, allowundo, etc #include "wxundo.h" // for undoredo->... #include "wxalgos.h" // for *_ALGO, algoinfo #include "wxlayer.h" // for currlayer, SyncClones #include "wxtimeline.h" // for TimelineExists #include "wxperl.h" // for RunPerlScript, AbortPerlScript #include "wxpython.h" // for RunPythonScript, AbortPythonScript #include "wxscript.h" // ============================================================================= // exported globals: bool inscript = false; // a script is running? bool passkeys; // pass keyboard events to script? bool passclicks; // pass mouse events to script? bool canswitch; // can user switch layers while script is running? bool stop_after_script; // stop generating pattern after running script? bool autoupdate; // update display after each change to current universe? bool allowcheck; // allow event checking? wxString scripterr; // Perl/Python error message wxString mousepos; // current mouse position // local globals: static bool plscript = false; // a Perl script is running? static bool pyscript = false; // a Python script is running? static bool showtitle; // need to update window title? static bool updateedit; // need to update edit bar? static bool exitcalled; // GSF_exit was called? static wxString scriptchars; // non-escape chars saved by PassKeyToScript static wxString scriptloc; // location of script file static wxArrayString eventqueue; // FIFO queue for keyboard/mouse events // ----------------------------------------------------------------------------- void DoAutoUpdate() { if (autoupdate) { inscript = false; mainptr->UpdatePatternAndStatus(); if (showtitle) { mainptr->SetWindowTitle(wxEmptyString); showtitle = false; } inscript = true; } } // ----------------------------------------------------------------------------- void ShowTitleLater() { // called from SetWindowTitle when inscript is true; // show title at next update (or at end of script) showtitle = true; } // ----------------------------------------------------------------------------- void ChangeWindowTitle(const wxString& name) { if (autoupdate) { // update title bar right now inscript = false; mainptr->SetWindowTitle(name); inscript = true; showtitle = false; // update has been done } else { // show it later but must still update currlayer->currname and menu item mainptr->SetWindowTitle(name); // showtitle is now true } } // ============================================================================= // The following Golly Script Functions are used to reduce code duplication. // They are called by corresponding pl_* and py_* functions in wxperl.cpp // and wxpython.cpp respectively. const char* GSF_open(char* filename, int remember) { // convert non-absolute filename to absolute path relative to scriptloc wxString fname = wxString(filename,wxConvLocal); wxFileName fullname(fname); if (!fullname.IsAbsolute()) fullname = scriptloc + fname; // return error message here if file doesn't exist wxString fullpath = fullname.GetFullPath(); if (!wxFileName::FileExists(fullpath)) { return "Given file does not exist."; } // only add file to Open Recent submenu if remember flag is non-zero mainptr->OpenFile(fullpath, remember != 0); DoAutoUpdate(); return NULL; } // ----------------------------------------------------------------------------- const char* GSF_save(char* filename, char* format, int remember) { // convert non-absolute filename to absolute path relative to scriptloc wxString fname = wxString(filename,wxConvLocal); wxFileName fullname(fname); if (!fullname.IsAbsolute()) fullname = scriptloc + fname; // only add file to Open Recent submenu if remember flag is non-zero return mainptr->SaveFile(fullname.GetFullPath(), wxString(format,wxConvLocal), remember != 0); } // ----------------------------------------------------------------------------- const char* GSF_setdir(char* dirname, char* newdir) { wxString dirpath = wxString(newdir,wxConvLocal); if (dirpath.Last() != wxFILE_SEP_PATH) dirpath += wxFILE_SEP_PATH; if (!wxFileName::DirExists(dirpath)) { return "New directory does not exist."; } if (strcmp(dirname, "app") == 0) { return "Application directory cannot be changed."; } else if (strcmp(dirname, "data") == 0) { return "Data directory cannot be changed."; } else if (strcmp(dirname, "temp") == 0) { return "Temporary directory cannot be changed."; } else if (strcmp(dirname, "rules") == 0) { userrules = dirpath; } else if (strcmp(dirname, "patterns") == 0) { // change patterndir and update panel if currently shown mainptr->SetPatternDir(dirpath); } else if (strcmp(dirname, "scripts") == 0) { // change scriptdir and update panel if currently shown mainptr->SetScriptDir(dirpath); } else if (strcmp(dirname, "download") == 0) { downloaddir = dirpath; } else { return "Unknown directory name."; } return NULL; // success } // ----------------------------------------------------------------------------- const char* GSF_getdir(char* dirname) { wxString dirpath; if (strcmp(dirname, "app") == 0) dirpath = gollydir; else if (strcmp(dirname, "data") == 0) dirpath = datadir; else if (strcmp(dirname, "temp") == 0) dirpath = tempdir; else if (strcmp(dirname, "rules") == 0) dirpath = userrules; else if (strcmp(dirname, "patterns") == 0) dirpath = patterndir; else if (strcmp(dirname, "scripts") == 0) dirpath = scriptdir; else if (strcmp(dirname, "download") == 0) dirpath = downloaddir; else { return NULL; // unknown directory name } // make sure directory path ends with separator if (dirpath.Last() != wxFILE_SEP_PATH) dirpath += wxFILE_SEP_PATH; // need to be careful converting Unicode wxString to char* static wxCharBuffer dirbuff; #ifdef __WXMAC__ // we need to convert dirpath to decomposed UTF8 so fopen will work dirbuff = dirpath.fn_str(); #else dirbuff = dirpath.mb_str(wxConvLocal); #endif return (const char*) dirbuff; } // ----------------------------------------------------------------------------- const char* GSF_setalgo(char* algostring) { // find index for given algo name char* algoname = ReplaceDeprecatedAlgo(algostring); algo_type algoindex = -1; for (int i = 0; i < NumAlgos(); i++) { if (strcmp(algoname, GetAlgoName(i)) == 0) { algoindex = i; break; } } if (algoindex < 0) return "Unknown algorithm."; if (algoindex != currlayer->algtype) { mainptr->ChangeAlgorithm(algoindex); if (algoindex != currlayer->algtype) { return "Algorithm could not be changed (pattern is too big to convert)."; } else { // rule might have changed ChangeWindowTitle(wxEmptyString); // pattern might have changed or colors might have changed DoAutoUpdate(); } } return NULL; } // ----------------------------------------------------------------------------- const char* GSF_setrule(char* rulestring) { wxString oldrule = wxString(currlayer->algo->getrule(),wxConvLocal); int oldmaxstate = currlayer->algo->NumCellStates() - 1; // selection might change if grid becomes smaller, // so save current selection for RememberRuleChange/RememberAlgoChange viewptr->SaveCurrentSelection(); // inscript should be true but play safe if (allowundo && !currlayer->stayclean && inscript) { // note that we must save pending gen changes BEFORE changing rule // otherwise temporary files will store incorrect rule info SavePendingChanges(); } const char* err; if (rulestring == NULL || rulestring[0] == 0) { // set normal Life err = currlayer->algo->setrule("B3/S23"); } else { err = currlayer->algo->setrule(rulestring); } if (err) { // try to find another algorithm that supports the new rule for (int i = 0; i < NumAlgos(); i++) { if (i != currlayer->algtype) { lifealgo* tempalgo = CreateNewUniverse(i); err = tempalgo->setrule(rulestring); delete tempalgo; if (!err) { // change the current algorithm and switch to the new rule mainptr->ChangeAlgorithm(i, wxString(rulestring,wxConvLocal)); if (i != currlayer->algtype) { RestoreRule(oldrule); return "Algorithm could not be changed (pattern is too big to convert)."; } else { ChangeWindowTitle(wxEmptyString); DoAutoUpdate(); return NULL; } } } } RestoreRule(oldrule); return "Given rule is not valid in any algorithm."; } // check if the rule string changed, or the number of states changed // (the latter might happen if user edited a table/tree file) wxString newrule = wxString(currlayer->algo->getrule(),wxConvLocal); int newmaxstate = currlayer->algo->NumCellStates() - 1; if (oldrule != newrule || oldmaxstate != newmaxstate) { // show new rule in main window's title but don't change name ChangeWindowTitle(wxEmptyString); // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { mainptr->ClearOutsideGrid(); } // rule change might have changed the number of cell states; // if there are fewer states then pattern might change if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { mainptr->ReduceCellStates(newmaxstate); } if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberRuleChange(oldrule); } } // switch to default colors and icons for new rule (we need to do this even if // oldrule == newrule in case there's a new/changed .colors or .icons file) UpdateLayerColors(); // pattern or colors or icons might have changed DoAutoUpdate(); return NULL; } // ----------------------------------------------------------------------------- const char* GSF_setgen(char* genstring) { const char* err = mainptr->ChangeGenCount(genstring); if (!err) DoAutoUpdate(); return err; } // ----------------------------------------------------------------------------- const char* GSF_setpos(char* x, char* y) { // disallow alphabetic chars in x,y int i; int xlen = (int)strlen(x); for (i = 0; i < xlen; i++) if ( (x[i] >= 'a' && x[i] <= 'z') || (x[i] >= 'A' && x[i] <= 'Z') ) return "Illegal character in x value."; int ylen = (int)strlen(y); for (i = 0; i < ylen; i++) if ( (y[i] >= 'a' && y[i] <= 'z') || (y[i] >= 'A' && y[i] <= 'Z') ) return "Illegal character in y value."; bigint bigx(x); bigint bigy(y); // check if x,y is outside bounded grid if ( (currlayer->algo->gridwd > 0 && (bigx < currlayer->algo->gridleft || bigx > currlayer->algo->gridright)) || (currlayer->algo->gridht > 0 && (bigy < currlayer->algo->gridtop || bigy > currlayer->algo->gridbottom)) ) { return "Given position is outside grid boundary."; } viewptr->SetPosMag(bigx, bigy, viewptr->GetMag()); DoAutoUpdate(); return NULL; } // ----------------------------------------------------------------------------- void GSF_setname(char* name, int index) { if (name == NULL || name[0] == 0) return; // inscript should be true but play safe if (allowundo && !currlayer->stayclean && inscript) SavePendingChanges(); if (index == currindex) { // save old name for RememberNameChange wxString oldname = currlayer->currname; // show new name in main window's title; // also sets currlayer->currname and updates menu item ChangeWindowTitle(wxString(name,wxConvLocal)); if (allowundo && !currlayer->stayclean) { // note that currfile and savestart/dirty flags don't change currlayer->undoredo->RememberNameChange(oldname, currlayer->currfile, currlayer->savestart, currlayer->dirty); } } else { // temporarily change currlayer (used in RememberNameChange) Layer* savelayer = currlayer; currlayer = GetLayer(index); wxString oldname = currlayer->currname; currlayer->currname = wxString(name,wxConvLocal); if (allowundo && !currlayer->stayclean) { // note that currfile and savestart/dirty flags don't change currlayer->undoredo->RememberNameChange(oldname, currlayer->currfile, currlayer->savestart, currlayer->dirty); } // restore currlayer currlayer = savelayer; // show name in given layer's menu item mainptr->UpdateLayerItem(index); } } // ----------------------------------------------------------------------------- const char* GSF_setcell(int x, int y, int newstate) { // check if x,y is outside bounded grid if ( (currlayer->algo->gridwd > 0 && (x < currlayer->algo->gridleft.toint() || x > currlayer->algo->gridright.toint())) || (currlayer->algo->gridht > 0 && (y < currlayer->algo->gridtop.toint() || y > currlayer->algo->gridbottom.toint())) ) { return "Given cell is outside grid boundary."; } int oldstate = currlayer->algo->getcell(x, y); if (newstate != oldstate) { if (currlayer->algo->setcell(x, y, newstate) < 0) { return "State value is out of range."; } currlayer->algo->endofpattern(); if (allowundo && !currlayer->stayclean) { ChangeCell(x, y, oldstate, newstate); } MarkLayerDirty(); DoAutoUpdate(); } return NULL; } // ----------------------------------------------------------------------------- const char* GSF_paste(int x, int y, char* mode) { // check if x,y is outside bounded grid if ( (currlayer->algo->gridwd > 0 && (x < currlayer->algo->gridleft.toint() || x > currlayer->algo->gridright.toint())) || (currlayer->algo->gridht > 0 && (y < currlayer->algo->gridtop.toint() || y > currlayer->algo->gridbottom.toint())) ) { return "Given cell is outside grid boundary."; } if (!mainptr->ClipboardHasText()) return "No pattern in clipboard."; // temporarily change selection and paste mode Selection oldsel = currlayer->currsel; const char* oldmode = GetPasteMode(); wxString modestr = wxString(mode, wxConvLocal); if (modestr.IsSameAs(wxT("and"), false)) SetPasteMode("And"); else if (modestr.IsSameAs(wxT("copy"), false)) SetPasteMode("Copy"); else if (modestr.IsSameAs(wxT("or"), false)) SetPasteMode("Or"); else if (modestr.IsSameAs(wxT("xor"), false)) SetPasteMode("Xor"); else return "Unknown mode."; // create huge selection rect so no possibility of error message currlayer->currsel.SetRect(x, y, INT_MAX, INT_MAX); viewptr->PasteClipboard(true); // true = paste to selection // restore selection and paste mode currlayer->currsel = oldsel; SetPasteMode(oldmode); DoAutoUpdate(); return NULL; } // ----------------------------------------------------------------------------- const char* GSF_checkpos(lifealgo* algo, int x, int y) { // check that x,y is within bounded grid if ( (algo->gridwd > 0 && (x < algo->gridleft.toint() || x > algo->gridright.toint())) || (algo->gridht > 0 && (y < algo->gridtop.toint() || y > algo->gridbottom.toint())) ) { return "Cell is outside grid boundary."; } return NULL; } // ----------------------------------------------------------------------------- const char* GSF_checkrect(int x, int y, int wd, int ht) { if (wd <= 0) return "Rectangle width must be > 0."; if (ht <= 0) return "Rectangle height must be > 0."; // check that rect is completely within bounded grid if ( (currlayer->algo->gridwd > 0 && (x < currlayer->algo->gridleft.toint() || x > currlayer->algo->gridright.toint() || x+wd-1 < currlayer->algo->gridleft.toint() || x+wd-1 > currlayer->algo->gridright.toint())) || (currlayer->algo->gridht > 0 && (y < currlayer->algo->gridtop.toint() || y > currlayer->algo->gridbottom.toint() || y+ht-1 < currlayer->algo->gridtop.toint() || y+ht-1 > currlayer->algo->gridbottom.toint())) ) { return "Rectangle is outside grid boundary."; } return NULL; } // ----------------------------------------------------------------------------- int GSF_hash(int x, int y, int wd, int ht) { // calculate a hash value for pattern in given rect int hash = 31415962; int right = x + wd - 1; int bottom = y + ht - 1; int cx, cy; int v = 0; lifealgo* curralgo = currlayer->algo; bool multistate = curralgo->NumCellStates() > 2; for ( cy=y; cy<=bottom; cy++ ) { int yshift = cy - y; for ( cx=x; cx<=right; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row (v is >= 1 if multistate) cx += skip; if (cx <= right) { // need to use a good hash function for patterns like AlienCounter.rle hash = (hash * 1000003) ^ yshift; hash = (hash * 1000003) ^ (cx - x); if (multistate) hash = (hash * 1000003) ^ v; } } else { cx = right; // done this row } } } return hash; } // ----------------------------------------------------------------------------- void GSF_select(int x, int y, int wd, int ht) { if (wd < 1 || ht < 1) { // remove any existing selection viewptr->SaveCurrentSelection(); currlayer->currsel.Deselect(); viewptr->RememberNewSelection(_("Deselection")); } else { // set selection edges viewptr->SaveCurrentSelection(); currlayer->currsel.SetRect(x, y, wd, ht); viewptr->RememberNewSelection(_("Selection")); } } // ----------------------------------------------------------------------------- bool GSF_setoption(char* optname, int newval, int* oldval) { if (strcmp(optname, "autofit") == 0) { *oldval = currlayer->autofit ? 1 : 0; if (*oldval != newval) { mainptr->ToggleAutoFit(); // autofit option only applies to a generating pattern // DoAutoUpdate(); } } else if (strcmp(optname, "boldspacing") == 0) { *oldval = boldspacing; if (newval < 2) newval = 2; if (newval > MAX_SPACING) newval = MAX_SPACING; if (*oldval != newval) { boldspacing = newval; DoAutoUpdate(); } } else if (strcmp(optname, "drawingstate") == 0) { *oldval = currlayer->drawingstate; if (newval < 0) newval = 0; if (newval >= currlayer->algo->NumCellStates()) newval = currlayer->algo->NumCellStates() - 1; if (*oldval != newval) { currlayer->drawingstate = newval; if (autoupdate) { UpdateEditBar(); updateedit = false; } else { // update edit bar in next GSF_update call updateedit = true; } } } else if (strcmp(optname, "fullscreen") == 0) { *oldval = mainptr->fullscreen ? 1 : 0; if (*oldval != newval) { mainptr->ToggleFullScreen(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "hyperspeed") == 0) { *oldval = currlayer->hyperspeed ? 1 : 0; if (*oldval != newval) mainptr->ToggleHyperspeed(); } else if (strcmp(optname, "mindelay") == 0) { *oldval = mindelay; if (newval < 0) newval = 0; if (newval > MAX_DELAY) newval = MAX_DELAY; if (*oldval != newval) { mindelay = newval; mainptr->UpdateStepExponent(); DoAutoUpdate(); } } else if (strcmp(optname, "maxdelay") == 0) { *oldval = maxdelay; if (newval < 0) newval = 0; if (newval > MAX_DELAY) newval = MAX_DELAY; if (*oldval != newval) { maxdelay = newval; mainptr->UpdateStepExponent(); DoAutoUpdate(); } } else if (strcmp(optname, "opacity") == 0) { *oldval = opacity; if (newval < 1) newval = 1; if (newval > 100) newval = 100; if (*oldval != newval) { opacity = newval; DoAutoUpdate(); } } else if (strcmp(optname, "restoreview") == 0) { *oldval = restoreview ? 1 : 0; if (*oldval != newval) { restoreview = !restoreview; // no need for DoAutoUpdate(); } } else if (strcmp(optname, "savexrle") == 0) { *oldval = savexrle ? 1 : 0; if (*oldval != newval) { savexrle = !savexrle; // no need for DoAutoUpdate(); } } else if (strcmp(optname, "showallstates") == 0) { *oldval = showallstates ? 1 : 0; if (*oldval != newval) { ToggleAllStates(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "showboldlines") == 0) { *oldval = showboldlines ? 1 : 0; if (*oldval != newval) { showboldlines = !showboldlines; DoAutoUpdate(); } } else if (strcmp(optname, "showeditbar") == 0) { *oldval = showedit ? 1 : 0; if (*oldval != newval) { ToggleEditBar(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "showexact") == 0) { *oldval = showexact ? 1 : 0; if (*oldval != newval) { mainptr->ToggleExactNumbers(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "showgrid") == 0) { *oldval = showgridlines ? 1 : 0; if (*oldval != newval) { showgridlines = !showgridlines; DoAutoUpdate(); } } else if (strcmp(optname, "showhashinfo") == 0) { *oldval = currlayer->showhashinfo ? 1 : 0; if (*oldval != newval) mainptr->ToggleHashInfo(); } else if (strcmp(optname, "showicons") == 0) { *oldval = showicons ? 1 : 0; if (*oldval != newval) { viewptr->ToggleCellIcons(); DoAutoUpdate(); } } else if (strcmp(optname, "showlayerbar") == 0) { *oldval = showlayer ? 1 : 0; if (*oldval != newval) { ToggleLayerBar(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "showpatterns") == 0) { *oldval = showpatterns ? 1 : 0; if (*oldval != newval) { mainptr->ToggleShowPatterns(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "showscripts") == 0) { *oldval = showscripts ? 1 : 0; if (*oldval != newval) { mainptr->ToggleShowScripts(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "showtoolbar") == 0) { *oldval = showtool ? 1 : 0; if (*oldval != newval) { mainptr->ToggleToolBar(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "showstatusbar") == 0) { *oldval = showstatus ? 1 : 0; if (*oldval != newval) { mainptr->ToggleStatusBar(); // above always does an update (due to resizing viewport window) // DoAutoUpdate(); } } else if (strcmp(optname, "swapcolors") == 0) { *oldval = swapcolors ? 1 : 0; if (*oldval != newval) { viewptr->ToggleCellColors(); DoAutoUpdate(); } } else if (strcmp(optname, "synccursors") == 0) { *oldval = synccursors ? 1 : 0; if (*oldval != newval) { ToggleSyncCursors(); DoAutoUpdate(); } } else if (strcmp(optname, "syncviews") == 0) { *oldval = syncviews ? 1 : 0; if (*oldval != newval) { ToggleSyncViews(); DoAutoUpdate(); } } else if (strcmp(optname, "switchlayers") == 0) { *oldval = canswitch ? 1 : 0; if (*oldval != newval) { canswitch = !canswitch; // no need for DoAutoUpdate(); } } else if (strcmp(optname, "stacklayers") == 0) { *oldval = stacklayers ? 1 : 0; if (*oldval != newval) { ToggleStackLayers(); // above always does an update // DoAutoUpdate(); } } else if (strcmp(optname, "tilelayers") == 0) { *oldval = tilelayers ? 1 : 0; if (*oldval != newval) { ToggleTileLayers(); // above always does an update // DoAutoUpdate(); } // this option is deprecated (use setalgo command) } else if (strcmp(optname, "hashing") == 0) { *oldval = (currlayer->algtype == HLIFE_ALGO) ? 1 : 0; if (*oldval != newval) { mainptr->ChangeAlgorithm(newval ? HLIFE_ALGO : QLIFE_ALGO); DoAutoUpdate(); } } else { // unknown option return false; } if (*oldval != newval) { mainptr->UpdateMenuItems(); } return true; } // ----------------------------------------------------------------------------- bool GSF_getoption(char* optname, int* optval) { if (strcmp(optname, "autofit") == 0) *optval = currlayer->autofit ? 1 : 0; else if (strcmp(optname, "boldspacing") == 0) *optval = boldspacing; else if (strcmp(optname, "drawingstate") == 0) *optval = currlayer->drawingstate; else if (strcmp(optname, "fullscreen") == 0) *optval = mainptr->fullscreen ? 1 : 0; else if (strcmp(optname, "hyperspeed") == 0) *optval = currlayer->hyperspeed ? 1 : 0; else if (strcmp(optname, "mindelay") == 0) *optval = mindelay; else if (strcmp(optname, "maxdelay") == 0) *optval = maxdelay; else if (strcmp(optname, "opacity") == 0) *optval = opacity; else if (strcmp(optname, "restoreview") == 0) *optval = restoreview ? 1 : 0; else if (strcmp(optname, "savexrle") == 0) *optval = savexrle ? 1 : 0; else if (strcmp(optname, "showallstates") == 0) *optval = showallstates ? 1 : 0; else if (strcmp(optname, "showboldlines") == 0) *optval = showboldlines ? 1 : 0; else if (strcmp(optname, "showeditbar") == 0) *optval = showedit ? 1 : 0; else if (strcmp(optname, "showexact") == 0) *optval = showexact ? 1 : 0; else if (strcmp(optname, "showgrid") == 0) *optval = showgridlines ? 1 : 0; else if (strcmp(optname, "showhashinfo") == 0) *optval = currlayer->showhashinfo ? 1 : 0; else if (strcmp(optname, "showicons") == 0) *optval = showicons ? 1 : 0; else if (strcmp(optname, "showlayerbar") == 0) *optval = showlayer ? 1 : 0; else if (strcmp(optname, "showpatterns") == 0) *optval = showpatterns ? 1 : 0; else if (strcmp(optname, "showscripts") == 0) *optval = showscripts ? 1 : 0; else if (strcmp(optname, "showstatusbar") == 0) *optval = showstatus ? 1 : 0; else if (strcmp(optname, "showtoolbar") == 0) *optval = showtool ? 1 : 0; else if (strcmp(optname, "stacklayers") == 0) *optval = stacklayers ? 1 : 0; else if (strcmp(optname, "swapcolors") == 0) *optval = swapcolors ? 1 : 0; else if (strcmp(optname, "switchlayers") == 0) *optval = canswitch ? 1 : 0; else if (strcmp(optname, "synccursors") == 0) *optval = synccursors ? 1 : 0; else if (strcmp(optname, "syncviews") == 0) *optval = syncviews ? 1 : 0; else if (strcmp(optname, "tilelayers") == 0) *optval = tilelayers ? 1 : 0; // this option is deprecated (use getalgo command) else if (strcmp(optname, "hashing") == 0) *optval = (currlayer->algtype == HLIFE_ALGO) ? 1 : 0; else { // unknown option return false; } return true; } // ----------------------------------------------------------------------------- bool GSF_setcolor(char* colname, wxColor& newcol, wxColor& oldcol) { if (strncmp(colname, "livecells", 9) == 0) { // livecells0..livecells9 are deprecated; get and set color of state 1 oldcol.Set(currlayer->cellr[1], currlayer->cellg[1], currlayer->cellb[1]); if (oldcol != newcol) { currlayer->cellr[1] = newcol.Red(); currlayer->cellg[1] = newcol.Green(); currlayer->cellb[1] = newcol.Blue(); UpdateCloneColors(); DoAutoUpdate(); } } else if (strcmp(colname, "deadcells") == 0) { // deprecated; can now use setcolors([0,r,g,b]) oldcol.Set(currlayer->cellr[0], currlayer->cellg[0], currlayer->cellb[0]); if (oldcol != newcol) { currlayer->cellr[0] = newcol.Red(); currlayer->cellg[0] = newcol.Green(); currlayer->cellb[0] = newcol.Blue(); UpdateCloneColors(); DoAutoUpdate(); } } else if (strcmp(colname, "border") == 0) { oldcol = *borderrgb; if (oldcol != newcol) { *borderrgb = newcol; SetBrushesAndPens(); DoAutoUpdate(); } } else if (strcmp(colname, "paste") == 0) { oldcol = *pastergb; if (oldcol != newcol) { *pastergb = newcol; SetBrushesAndPens(); DoAutoUpdate(); } } else if (strcmp(colname, "select") == 0) { oldcol = *selectrgb; if (oldcol != newcol) { *selectrgb = newcol; SetBrushesAndPens(); SetSelectionColor(); // see wxrender.cpp DoAutoUpdate(); } } else if (strcmp(colname, "hashing") == 0) { // deprecated oldcol = algoinfo[HLIFE_ALGO]->statusrgb; if (oldcol != newcol) { algoinfo[HLIFE_ALGO]->statusrgb = newcol; SetBrushesAndPens(); DoAutoUpdate(); } } else if (strcmp(colname, "nothashing") == 0) { // deprecated oldcol = algoinfo[QLIFE_ALGO]->statusrgb; if (oldcol != newcol) { algoinfo[QLIFE_ALGO]->statusrgb = newcol; SetBrushesAndPens(); DoAutoUpdate(); } } else { // look for algo name char* algoname = ReplaceDeprecatedAlgo(colname); for (int i = 0; i < NumAlgos(); i++) { if (strcmp(algoname, GetAlgoName(i)) == 0) { oldcol = algoinfo[i]->statusrgb; if (oldcol != newcol) { algoinfo[i]->statusrgb = newcol; SetBrushesAndPens(); DoAutoUpdate(); } return true; } } // unknown color name return false; } return true; } // ----------------------------------------------------------------------------- bool GSF_getcolor(char* colname, wxColor& color) { if (strncmp(colname, "livecells", 9) == 0) { // livecells0..livecells9 are deprecated; return color of state 1 color.Set(currlayer->cellr[1], currlayer->cellg[1], currlayer->cellb[1]); } else if (strcmp(colname, "deadcells") == 0) { // deprecated; can now use getcolors(0) color.Set(currlayer->cellr[0], currlayer->cellg[0], currlayer->cellb[0]); } else if (strcmp(colname, "border") == 0) color = *borderrgb; else if (strcmp(colname, "paste") == 0) color = *pastergb; else if (strcmp(colname, "select") == 0) color = *selectrgb; // next two are deprecated else if (strcmp(colname, "hashing") == 0) color = algoinfo[HLIFE_ALGO]->statusrgb; else if (strcmp(colname, "nothashing") == 0) color = algoinfo[QLIFE_ALGO]->statusrgb; else { // look for algo name char* algoname = ReplaceDeprecatedAlgo(colname); for (int i = 0; i < NumAlgos(); i++) { if (strcmp(algoname, GetAlgoName(i)) == 0) { color = algoinfo[i]->statusrgb; return true; } } // unknown color name return false; } return true; } // ----------------------------------------------------------------------------- void GSF_getevent(wxString& event, int get) { if (get) { passkeys = true; // future keyboard events will call PassKeyToScript passclicks = true; // future mouse events will call PassClickToScript } else { // tell Golly to handle future keyboard and mouse events passkeys = false; passclicks = false; // clear any pending events so event is set to empty string below eventqueue.Clear(); } if (eventqueue.IsEmpty()) { event = wxEmptyString; } else { // get event at start of queue, then remove it event = eventqueue[0]; eventqueue.RemoveAt(0); } } // ----------------------------------------------------------------------------- #if defined(__WXMAC__) && wxCHECK_VERSION(2,9,0) // wxMOD_CONTROL has been changed to mean Command key down (sheesh!) #define wxMOD_CONTROL wxMOD_RAW_CONTROL #define ControlDown RawControlDown #endif static void AppendModifiers(int modifiers, wxString& event) { // reverse of GetModifiers if (modifiers == wxMOD_NONE) { event += wxT("none"); } else { if (modifiers & wxMOD_ALT) event += wxT("alt"); #ifdef __WXMAC__ if (modifiers & wxMOD_CMD) event += wxT("cmd"); if (modifiers & wxMOD_CONTROL) event += wxT("ctrl"); #else if (modifiers & wxMOD_CMD) event += wxT("ctrl"); if (modifiers & wxMOD_META) event += wxT("meta"); #endif if (modifiers & wxMOD_SHIFT) event += wxT("shift"); } } // ----------------------------------------------------------------------------- static int GetModifiers(const wxString& modstring) { // reverse of AppendModifiers int modifiers = wxMOD_NONE; if (modstring != wxT("none")) { if (modstring.Contains(wxT("alt"))) modifiers |= wxMOD_ALT; if (modstring.Contains(wxT("cmd"))) modifiers |= wxMOD_CMD; if (modstring.Contains(wxT("ctrl"))) modifiers |= wxMOD_CONTROL; if (modstring.Contains(wxT("meta"))) modifiers |= wxMOD_META; if (modstring.Contains(wxT("shift"))) modifiers |= wxMOD_SHIFT; } return modifiers; } // ----------------------------------------------------------------------------- const char* GSF_doevent(const wxString& event) { if (event.length() > 0) { if (event.StartsWith(wxT("key ")) && event.length() > 7) { // parse event string like "key x altshift" int key = event[4]; if (event[4] == 'f' && event[5] >= '1' && event[5] <= '9') { // parse function key (f1 to f24) if (event[6] == ' ') { // f1 to f9 key = WXK_F1 + (event[5] - '1'); } else if (event[6] >= '0' && event[6] <= '9') { // f10 to f24 key = WXK_F1 + 10 * (event[5] - '0') + (event[6] - '0') - 1; if (key > WXK_F24) return "Bad function key (must be f1 to f24)."; } else { return "Bad function key (must be f1 to f24)."; } } else if (event[5] != ' ') { // parse special char name like space, tab, etc // must match reverse conversion in PassKeyToScript if (event.Contains(wxT("space"))) key = ' '; else if (event.Contains(wxT("home"))) key = WXK_HOME; else if (event.Contains(wxT("end"))) key = WXK_END; else if (event.Contains(wxT("pageup"))) key = WXK_PAGEUP; else if (event.Contains(wxT("pagedown"))) key = WXK_PAGEDOWN; else if (event.Contains(wxT("help"))) key = WXK_HELP; else if (event.Contains(wxT("insert"))) key = WXK_INSERT; else if (event.Contains(wxT("delete"))) key = WXK_DELETE; else if (event.Contains(wxT("tab"))) key = WXK_TAB; else if (event.Contains(wxT("enter"))) key = WXK_RETURN; else if (event.Contains(wxT("return"))) key = WXK_RETURN; else if (event.Contains(wxT("left"))) key = WXK_LEFT; else if (event.Contains(wxT("right"))) key = WXK_RIGHT; else if (event.Contains(wxT("up"))) key = WXK_UP; else if (event.Contains(wxT("down"))) key = WXK_DOWN; else return "Unknown key."; } viewptr->ProcessKey(key, GetModifiers(event.AfterLast(' '))); if (showtitle) { // update window title inscript = false; mainptr->SetWindowTitle(wxEmptyString); inscript = true; showtitle = false; } } else if (event.StartsWith(wxT("click "))) { // parse event string like "click 10 20 left altshift" wxString xstr = event.AfterFirst(' '); wxString ystr = xstr.AfterFirst(' '); xstr = xstr.BeforeFirst(' '); ystr = ystr.BeforeFirst(' '); if (!xstr.IsNumber()) return "Bad x value."; if (!ystr.IsNumber()) return "Bad y value."; bigint x(xstr.mb_str(wxConvLocal)); bigint y(ystr.mb_str(wxConvLocal)); int button; if (event.Contains(wxT(" left "))) button = wxMOUSE_BTN_LEFT; else if (event.Contains(wxT(" middle "))) button = wxMOUSE_BTN_MIDDLE; else if (event.Contains(wxT(" right "))) button = wxMOUSE_BTN_RIGHT; else return "Unknown button."; if (viewptr->CellVisible(x, y) && viewptr->CellInGrid(x, y)) { // convert x,y cell position to pixel position in viewport pair<int,int> xy = currlayer->view->screenPosOf(x, y, currlayer->algo); int mods = GetModifiers(event.AfterLast(' ')); viewptr->ProcessClick(xy.first, xy.second, button, mods); if (showtitle) { // update window title inscript = false; mainptr->SetWindowTitle(wxEmptyString); inscript = true; showtitle = false; } } else { // ignore click if x,y is outside viewport or grid return NULL; } } else { return "Unknown event."; } } return NULL; } // ----------------------------------------------------------------------------- // the following is deprecated (use GSF_getevent) void GSF_getkey(char* s) { passkeys = true; // future keyboard events will call PassKeyToScript if (scriptchars.length() == 0) { // return empty string s[0] = '\0'; } else { // return first char in scriptchars and then remove it s[0] = scriptchars.GetChar(0); s[1] = '\0'; scriptchars = scriptchars.AfterFirst(s[0]); } } // ----------------------------------------------------------------------------- // the following is deprecated (use GSF_doevent) void GSF_dokey(char* ascii) { if (*ascii) { // convert ascii char to corresponding wx key code; // note that PassKeyToScript does the reverse conversion int key; switch (*ascii) { case 127: // treat delete like backspace case 8: key = WXK_BACK; break; case 9: key = WXK_TAB; break; case 10: // treat linefeed like return case 13: key = WXK_RETURN; break; case 28: key = WXK_LEFT; break; case 29: key = WXK_RIGHT; break; case 30: key = WXK_UP; break; case 31: key = WXK_DOWN; break; default: key = *ascii; } // we can't handle modifiers here viewptr->ProcessKey(key, wxMOD_NONE); if (showtitle) { // update window title inscript = false; mainptr->SetWindowTitle(wxEmptyString); inscript = true; showtitle = false; } } } // ----------------------------------------------------------------------------- void GSF_update() { // update viewport, status bar, and possibly other bars inscript = false; mainptr->UpdatePatternAndStatus(); if (showtitle) { mainptr->SetWindowTitle(wxEmptyString); showtitle = false; } if (updateedit) { UpdateEditBar(); updateedit = false; } inscript = true; } // ----------------------------------------------------------------------------- void GSF_exit(char* errmsg) { if (errmsg && errmsg[0] != 0) { // display given error message inscript = false; statusptr->ErrorMessage(wxString(errmsg,wxConvLocal)); inscript = true; // make sure status bar is visible if (!showstatus) mainptr->ToggleStatusBar(); } exitcalled = true; // prevent CheckScriptError changing message } // ============================================================================= void CheckScriptError(const wxString& ext) { if (scripterr.IsEmpty()) return; // no error if (scripterr.Find(wxString(abortmsg,wxConvLocal)) >= 0) { // error was caused by AbortPerlScript/AbortPythonScript // so don't display scripterr } else { wxString errtype; if (ext.IsSameAs(wxT("pl"), false)) { errtype = _("Perl error:"); scripterr.Replace(wxT(". at "), wxT("\nat ")); } else { errtype = _("Python error:"); scripterr.Replace(wxT(" File \"<string>\", line 1, in ?\n"), wxT("")); } Beep(); #ifdef __WXMAC__ wxSetCursor(*wxSTANDARD_CURSOR); #endif wxMessageBox(scripterr, errtype, wxOK | wxICON_EXCLAMATION, wxGetActiveWindow()); } // don't change status message if GSF_exit was used to stop script if (!exitcalled) statusptr->DisplayMessage(_("Script aborted.")); } // ----------------------------------------------------------------------------- void ChangeCell(int x, int y, int oldstate, int newstate) { // first check if there are any pending gen changes that need to be remembered if (currlayer->undoredo->savegenchanges) { currlayer->undoredo->savegenchanges = false; currlayer->undoredo->RememberGenFinish(); } // setcell/putcells command is changing state of cell at x,y currlayer->undoredo->SaveCellChange(x, y, oldstate, newstate); if (!currlayer->undoredo->savecellchanges) { currlayer->undoredo->savecellchanges = true; // save layer's dirty state for next RememberCellChanges call currlayer->savedirty = currlayer->dirty; } } // ----------------------------------------------------------------------------- void SavePendingChanges(bool checkgenchanges) { // this should only be called if inscript && allowundo && !currlayer->stayclean if ( !(inscript && allowundo && !currlayer->stayclean) ) Warning(_("Bug detected in SavePendingChanges!")); if (currlayer->undoredo->savecellchanges) { currlayer->undoredo->savecellchanges = false; // remember accumulated cell changes currlayer->undoredo->RememberCellChanges(_("bug1"), currlayer->savedirty); // action string should never be seen } if (checkgenchanges && currlayer->undoredo->savegenchanges) { currlayer->undoredo->savegenchanges = false; // remember accumulated gen changes currlayer->undoredo->RememberGenFinish(); } } // ----------------------------------------------------------------------------- void RunScript(const wxString& filename) { if (TimelineExists()) { statusptr->ErrorMessage(_("You can't run a script if there is a timeline.")); return; } // use these flags to allow re-entrancy bool already_inscript = inscript; bool in_plscript = plscript; bool in_pyscript = pyscript; wxString savecwd; if (!wxFileName::FileExists(filename)) { Warning(_("The script file does not exist:\n") + filename); return; } if (already_inscript) { // save current directory so we can restore it below savecwd = scriptloc; } else { mainptr->showbanner = false; statusptr->ClearMessage(); scripterr.Clear(); scriptchars.Clear(); eventqueue.Clear(); canswitch = false; stop_after_script = false; autoupdate = false; exitcalled = false; allowcheck = true; showtitle = false; updateedit = false; passkeys = false; passclicks = false; wxGetApp().PollerReset(); } // temporarily change current directory to location of script wxFileName fullname(filename); fullname.Normalize(); scriptloc = fullname.GetPath(); if ( scriptloc.Last() != wxFILE_SEP_PATH ) scriptloc += wxFILE_SEP_PATH; wxSetWorkingDirectory(scriptloc); wxString fpath = fullname.GetFullPath(); #ifdef __WXMAC__ // use decomposed UTF8 so interpreter can open names with non-ASCII chars fpath = wxString(fpath.fn_str(),wxConvLocal); #endif if (!already_inscript) { if (allowundo) { // save each layer's dirty state for use by next RememberCellChanges call for ( int i = 0; i < numlayers; i++ ) { Layer* layer = GetLayer(i); layer->savedirty = layer->dirty; // at start of script there are no pending cell/gen changes layer->undoredo->savecellchanges = false; layer->undoredo->savegenchanges = false; // add a special node to indicate that the script is about to start so // that all changes made by the script can be undone/redone in one go; // note that the UndoRedo ctor calls RememberScriptStart if the script // creates a new non-cloned layer, and we let RememberScriptStart handle // multiple calls if this layer is a clone layer->undoredo->RememberScriptStart(); } } inscript = true; mainptr->UpdateUserInterface(); // temporarily remove accelerators from all menu items // so keyboard shortcuts can be passed to script mainptr->UpdateMenuAccelerators(); } wxString ext = filename.AfterLast('.'); if (ext.IsSameAs(wxT("pl"), false)) { plscript = true; RunPerlScript(fpath); } else if (ext.IsSameAs(wxT("py"), false)) { pyscript = true; RunPythonScript(fpath); } else { // should never happen plscript = false; pyscript = false; Warning(_("Unexpected extension in script file:\n") + filename); } if (already_inscript) { // restore current directory saved above scriptloc = savecwd; wxSetWorkingDirectory(scriptloc); // display any Perl/Python error message CheckScriptError(ext); if (!scripterr.IsEmpty()) { if (in_pyscript) { // abort the calling Python script AbortPythonScript(); } else if (in_plscript) { // abort the calling Perl script AbortPerlScript(); } } plscript = in_plscript; pyscript = in_pyscript; } else { // already_inscript is false // tidy up the undo/redo history for each layer; note that some calls // use currlayer (eg. RememberGenFinish) so we temporarily set currlayer // to each layer -- this is a bit yukky but should be safe as long as we // synchronize clone info, especially currlayer->algo ptrs because they // can change if the script called new() SyncClones(); Layer* savelayer = currlayer; for ( int i = 0; i < numlayers; i++ ) { currlayer = GetLayer(i); if (allowundo) { if (currlayer->undoredo->savecellchanges) { currlayer->undoredo->savecellchanges = false; // remember pending cell change(s) if (currlayer->stayclean) currlayer->undoredo->ForgetCellChanges(); else currlayer->undoredo->RememberCellChanges(_("bug2"), currlayer->savedirty); // action string should never be seen } if (currlayer->undoredo->savegenchanges) { currlayer->undoredo->savegenchanges = false; // remember pending gen change(s); no need to test stayclean flag // (if it's true then NextGeneration called RememberGenStart) currlayer->undoredo->RememberGenFinish(); } // add special node to indicate that the script has finished; // we let RememberScriptFinish handle multiple calls if this // layer is a clone currlayer->undoredo->RememberScriptFinish(); } // reset the stayclean flag in case it was set by MarkLayerClean currlayer->stayclean = false; } currlayer = savelayer; // must reset inscript AFTER RememberGenFinish inscript = false; // restore current directory to location of Golly app wxSetWorkingDirectory(gollydir); plscript = false; pyscript = false; // update Undo/Redo items based on current layer's history if (allowundo) currlayer->undoredo->UpdateUndoRedoItems(); // display any Perl/Python error message CheckScriptError(ext); // update title, menu bar, cursor, viewport, status bar, tool bar, etc if (showtitle) mainptr->SetWindowTitle(wxEmptyString); mainptr->UpdateEverything(); // restore accelerators that were cleared above mainptr->UpdateMenuAccelerators(); } } // ----------------------------------------------------------------------------- void PassClickToScript(const bigint& x, const bigint& y, int button, int modifiers) { // build a string like "click 10 20 left altshift" and add to event queue // for possible consumption by GSF_getevent wxString clickinfo = wxT("click "); clickinfo += wxString(x.tostring('\0'),wxConvLocal); clickinfo += wxT(" "); clickinfo += wxString(y.tostring('\0'),wxConvLocal); if (button == wxMOUSE_BTN_LEFT) clickinfo += wxT(" left "); if (button == wxMOUSE_BTN_MIDDLE) clickinfo += wxT(" middle "); if (button == wxMOUSE_BTN_RIGHT) clickinfo += wxT(" right "); AppendModifiers(modifiers, clickinfo); eventqueue.Add(clickinfo); } // ----------------------------------------------------------------------------- void PassKeyToScript(int key, int modifiers) { if (key == WXK_ESCAPE) { if (mainptr->generating) { // interrupt a run() or step() command wxGetApp().PollerInterrupt(); } if (plscript) AbortPerlScript(); if (pyscript) AbortPythonScript(); } else { // build a string like "key x altshift" and add to event queue // for possible consumption by GSF_getevent wxString keyinfo = wxT("key "); if (key > ' ' && key <= '~') { // displayable ASCII keyinfo += wxChar(key); } else if (key >= WXK_F1 && key <= WXK_F24) { // function key keyinfo += wxString::Format(wxT("f%d"), key - WXK_F1 + 1); } else { // convert some special key codes to names like space, tab, delete, etc // (must match reverse conversion in GSF_doevent) switch (key) { case ' ': keyinfo += wxT("space"); break; case WXK_HOME: keyinfo += wxT("home"); break; case WXK_END: keyinfo += wxT("end"); break; case WXK_PAGEUP: keyinfo += wxT("pageup"); break; case WXK_PAGEDOWN: keyinfo += wxT("pagedown"); break; case WXK_HELP: keyinfo += wxT("help"); break; case WXK_INSERT: keyinfo += wxT("insert"); break; case WXK_BACK: // treat backspace like delete case WXK_DELETE: keyinfo += wxT("delete"); break; case WXK_TAB: keyinfo += wxT("tab"); break; case WXK_NUMPAD_ENTER: // treat enter like return case WXK_RETURN: keyinfo += wxT("return"); break; case WXK_LEFT: keyinfo += wxT("left"); break; case WXK_RIGHT: keyinfo += wxT("right"); break; case WXK_UP: keyinfo += wxT("up"); break; case WXK_DOWN: keyinfo += wxT("down"); break; case WXK_ADD: keyinfo += wxT("+"); break; case WXK_SUBTRACT: keyinfo += wxT("-"); break; case WXK_DIVIDE: keyinfo += wxT("/"); break; case WXK_MULTIPLY: keyinfo += wxT("*"); break; default: return; // ignore all other key codes } } keyinfo += wxT(" "); AppendModifiers(modifiers, keyinfo); eventqueue.Add(keyinfo); // NOTE: following code is for deprecated getkey() command // convert wx key code to corresponding ascii char (if possible) // so that scripts can be platform-independent; // note that GSF_dokey does the reverse conversion char ascii; if (key >= ' ' && key <= '~') { if (modifiers == wxMOD_SHIFT && key >= 'a' && key <= 'z') { // let script see A..Z ascii = key - 32; } else { ascii = key; } } else { switch (key) { case WXK_DELETE: // treat delete like backspace case WXK_BACK: ascii = 8; break; case WXK_TAB: ascii = 9; break; case WXK_NUMPAD_ENTER: // treat enter like return case WXK_RETURN: ascii = 13; break; case WXK_LEFT: ascii = 28; break; case WXK_RIGHT: ascii = 29; break; case WXK_UP: ascii = 30; break; case WXK_DOWN: ascii = 31; break; case WXK_ADD: ascii = '+'; break; case WXK_SUBTRACT: ascii = '-'; break; case WXK_DIVIDE: ascii = '/'; break; case WXK_MULTIPLY: ascii = '*'; break; default: return; // ignore all other key codes } } // save ascii char for possible consumption by GSF_getkey scriptchars += ascii; } } // ----------------------------------------------------------------------------- void FinishScripting() { // called when main window is closing (ie. app is quitting) if (inscript) { if (mainptr->generating) { // interrupt a run() or step() command wxGetApp().PollerInterrupt(); } if (plscript) AbortPerlScript(); if (pyscript) AbortPythonScript(); wxSetWorkingDirectory(gollydir); inscript = false; } FinishPerlScripting(); FinishPythonScripting(); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/wxprefs.h����������������������������������������������������������������������0000644�0001750�0001750�00000042133�12536111364�013312� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXPREFS_H_ #define _WXPREFS_H_ // Routines for getting, saving and changing user preferences: void GetPrefs(); // Read preferences from the GollyPrefs file. void SavePrefs(); // Write preferences to the GollyPrefs file. bool ChangePrefs(const wxString& page); // Open a modal dialog so user can change various preferences. // Returns true if the user hits OK (so client can call SavePrefs). void ChooseTextEditor(wxWindow* parent, wxString& result); // Let user select their preferred text editor. The result is the // path to the application or empty if the user cancels the dialog. char* ReplaceDeprecatedAlgo(char* algoname); // If given algo name is deprecated then return replacement name, // otherwise return same name. // Global preference data: extern wxString gollydir; // path of directory containing app extern wxString datadir; // path of directory for user-specific data extern wxString tempdir; // path of directory for temporary data extern wxString rulesdir; // path of directory for app's rule data extern wxString userrules; // path of directory for user's rule data extern wxString downloaddir; // path of directory for downloaded data extern int debuglevel; // for displaying debug info if > 0 extern int mainx; // main window's location extern int mainy; extern int mainwd; // main window's size extern int mainht; extern bool maximize; // maximize main window? extern int helpx; // help window's location extern int helpy; extern int helpwd; // help window's size extern int helpht; extern int helpfontsize; // font size in help window extern int infox; // info window's location extern int infoy; extern int infowd; // info window's size extern int infoht; extern int rulex; // rule dialog's location extern int ruley; extern int ruleexwd; // rule dialog's extra size extern int ruleexht; extern bool showalgohelp; // show algorithm help in rule dialog? extern char initrule[]; // initial rule extern bool initautofit; // initial autofit setting extern bool inithyperspeed; // initial hyperspeed setting extern bool initshowhashinfo; // initial showhashinfo setting extern bool savexrle; // save RLE file using XRLE format? extern bool showtips; // show button tips? extern bool showtool; // show tool bar? extern bool showlayer; // show layer bar? extern bool showedit; // show edit bar? extern bool showallstates; // show all cell states in edit bar? extern bool showstatus; // show status bar? extern bool showexact; // show exact numbers in status bar? extern bool showtimeline; // show timeline bar? extern bool showgridlines; // display grid lines? extern bool showicons; // display icons for cell states? extern bool swapcolors; // swap colors used for cell states? extern bool buffered; // use wxWdgets buffering to avoid flicker? extern bool scrollpencil; // scroll if pencil cursor is dragged outside view? extern bool scrollcross; // scroll if cross cursor is dragged outside view? extern bool scrollhand; // scroll if hand cursor is dragged outside view? extern bool allowundo; // allow undo/redo? extern bool restoreview; // should reset/undo restore view? extern bool allowbeep; // okay to play beep sound? extern int controlspos; // position of translucent controls extern int canchangerule; // if > 0 then paste can change rule extern int randomfill; // random fill percentage extern int opacity; // percentage opacity of live cells in overlays extern int tileborder; // width of tiled window borders extern int mingridmag; // minimum mag to draw grid lines extern int boldspacing; // spacing of bold grid lines extern bool showboldlines; // show bold grid lines? extern bool mathcoords; // show Y values increasing upwards? extern bool syncviews; // synchronize viewports? extern bool synccursors; // synchronize cursors? extern bool stacklayers; // stack all layers? extern bool tilelayers; // tile all layers? extern bool askonnew; // ask to save changes before creating new pattern? extern bool askonload; // ask to save changes before loading pattern file? extern bool askondelete; // ask to save changes before deleting layer? extern bool askonquit; // ask to save changes before quitting app? extern bool warn_on_save; // warn if saving non-starting generation? extern int newmag; // mag setting for new pattern extern bool newremovesel; // new pattern removes selection? extern bool openremovesel; // opening pattern removes selection? extern wxCursor* newcurs; // cursor after creating new pattern extern wxCursor* opencurs; // cursor after opening pattern extern int mousewheelmode; // 0:Ignore, 1:forward=ZoomOut, 2:forward=ZoomIn extern int thumbrange; // thumb box scrolling range in terms of view wd/ht extern int mindelay; // minimum millisec delay extern int maxdelay; // maximum millisec delay extern wxString opensavedir; // directory for Open and Save dialogs extern wxString rundir; // directory for Run Script dialog extern wxString icondir; // directory used by Load Icon File button extern wxString choosedir; // directory used by Choose File button extern wxString patterndir; // directory used by Show Patterns extern wxString scriptdir; // directory used by Show Scripts extern wxString texteditor; // path of user's preferred text editor extern wxString perllib; // name of Perl library (loaded at runtime) extern wxString pythonlib; // name of Python library (loaded at runtime) extern int dirwinwd; // width of pattern/script directory window extern bool showpatterns; // show pattern directory? extern bool showscripts; // show script directory? extern wxMenu* patternSubMenu; // submenu of recent pattern files extern wxMenu* scriptSubMenu; // submenu of recent script files extern int numpatterns; // current number of recent pattern files extern int numscripts; // current number of recent script files extern int maxpatterns; // maximum number of recent pattern files extern int maxscripts; // maximum number of recent script files extern wxArrayString namedrules; // We maintain an array of named rules, where each string is of the form // "name of rule|B.../S...". The first string is always "Life|B3/S23". // Keyboard shortcuts: // define the actions that can be invoked by various key combinations typedef enum { DO_NOTHING = 0, // null action must be zero DO_OPENFILE, // open a chosen pattern/script/html file // rest are in alphabetical order (well, almost) DO_ABOUT, // about Golly DO_ADD, // add layer DO_ADVANCEOUT, // advance outside DO_ADVANCE, // advance selection DO_AUTOFIT, // auto fit DO_BUFFERED, // buffered DO_CHANGE00, // change origin DO_CLEAROUT, // clear outside DO_CLEAR, // clear selection DO_CLONE, // clone layer DO_COPY, // copy selection DO_CURSDRAW, // cursor mode: draw DO_CURSMOVE, // cursor mode: move DO_CURSPICK, // cursor mode: pick DO_CURSSEL, // cursor mode: select DO_CURSIN, // cursor mode: zoom in DO_CURSOUT, // cursor mode: zoom out DO_CUT, // cut selection DO_CURSCYCLE, // cycle cursor mode DO_PASTELOC, // cycle paste location DO_PASTEMODE, // cycle paste mode DO_DELETE, // delete layer DO_DELOTHERS, // delete other layers DO_DELTIME, // delete timeline DO_DISABLE, // disable undo/redo DO_DUPLICATE, // duplicate layer DO_FASTER, // faster DO_FIT, // fit pattern DO_FITSEL, // fit selection DO_FLIPLR, // flip left-right DO_FLIPTB, // flip top-bottom DO_FULLSCREEN, // full screen DO_HYPER, // hyperspeed DO_INVERT, // invert colors DO_MIDDLE, // middle DO_MOVELAYER, // move layer... DO_NAMELAYER, // name layer... DO_NEWPATT, // new pattern DO_NEXTGEN, // next generation DO_NEXTSTEP, // next step DO_NEXTHIGHER, // next higher state DO_NEXTLOWER, // next lower state DO_OPENCLIP, // open clipboard DO_OPENPATT, // open pattern... DO_PASTE, // paste DO_PASTESEL, // paste to selection DO_INFO, // pattern info DO_PLAYBACK, // play timeline backwards DO_PREFS, // preferences... DO_QUIT, // quit Golly DO_RANDFILL, // random fill DO_REDO, // redo DO_REMOVESEL, // remove selection DO_RESET, // reset DO_RESTORE00, // restore origin DO_ROTATEACW, // rotate anticlockwise DO_ROTATECW, // rotate clockwise DO_RUNCLIP, // run clipboard DO_RUNSCRIPT, // run script... DO_SAVEXRLE, // save extended rle DO_SAVE, // save pattern... DO_DOWN, // scroll down DO_LEFT, // scroll left DO_RIGHT, // scroll right DO_UP, // scroll up DO_NE, // scroll NE DO_NW, // scroll NW DO_SE, // scroll SE DO_SW, // scroll SW DO_SELALL, // select all DO_SETBASE, // set base step... DO_SETGEN, // set generation... DO_SETCOLORS, // set layer colors... DO_PATTDIR, // set pattern folder... DO_SETRULE, // set rule... DO_SCALE1, // set scale 1:1 DO_SCALE2, // set scale 1:2 DO_SCALE4, // set scale 1:4 DO_SCALE8, // set scale 1:8 DO_SCALE16, // set scale 1:16 DO_SCALE32, // set scale 1:32 DO_SCRIPTDIR, // set script folder... DO_SHOWSTATES, // show all states DO_SHOWICONS, // show cell icons DO_SHOWEDIT, // show edit bar DO_SHOWEXACT, // show exact numbers DO_SHOWGRID, // show grid lines DO_HASHINFO, // show hash info DO_HELP, // show help DO_SHOWLAYER, // show layer bar DO_PATTERNS, // show patterns DO_SCRIPTS, // show scripts DO_SHOWSTATUS, // show status bar DO_SHOWTIME, // show timeline DO_TIMING, // show timing DO_SHOWTOOL, // show tool bar DO_SHRINKFIT, // shrink and fit DO_SHRINK, // shrink selection DO_SLOWER, // slower DO_STACK, // stack layers DO_STARTSTOP, // start/stop generating DO_RECORD, // start/stop recording DO_SYNCCURS, // synchronize cursors DO_SYNCVIEWS, // synchronize views DO_TILE, // tile layers DO_UNDO, // undo DO_HASHING, // use hashing DO_ZOOMIN, // zoom in DO_ZOOMOUT, // zoom out MAX_ACTIONS } action_id; typedef struct { action_id id; // one of the above wxString file; // non-empty if id is DO_OPENFILE } action_info; action_info FindAction(int key, int modifiers); // return the action info for the given key and modifier set wxString GetAccelerator(action_id action); // return a string, possibly empty, containing the menu item // accelerator(s) for the given action void RemoveAccelerator(wxMenuBar* mbar, int item, action_id action); // remove any accelerator from given menu item void SetAccelerator(wxMenuBar* mbar, int item, action_id action); // update accelerator for given menu item using given action wxString GetShortcutTable(); // return HTML data to display current keyboard shortcuts // Colors: extern wxColor* borderrgb; // color for border around bounded grid extern wxColor* selectrgb; // color for selected cells extern wxColor* pastergb; // color for pasted pattern extern wxBrush* borderbrush; // brush for filling grid border extern wxPen* pastepen; // pen for drawing paste rect void SetBrushesAndPens(); // update colors in above brushes and pens void FreeDefaultColors(); // deallocate memory allocated by CreateDefaultColors() // Various constants: const int minmainwd = 200; // main window's minimum width const int minmainht = 100; // main window's minimum height const int minhelpwd = 400; // help window's minimum width const int minhelpht = 100; // help window's minimum height const int minfontsize = 6; // minimum value of helpfontsize const int maxfontsize = 30; // maximum value of helpfontsize const int mininfowd = 400; // info window's minimum width const int mininfoht = 100; // info window's minimum height const int MAX_RECENT = 100; // maximum value of maxpatterns and maxscripts const int MAX_SPACING = 1000; // maximum value of boldspacing const int MIN_MEM_MB = 0; // minimum value of maximum memory const int MAX_MEM_MB = // maximum value of maximum memory sizeof(char*) <= 4 ? 4000 : 100000000; const int MAX_BASESTEP = 2000000000; // maximum base step const int MAX_DELAY = 5000; // maximum mindelay or maxdelay const int MAX_THUMBRANGE = 500; // maximum thumbrange const int MIN_DIRWD = 50; // minimum dirwinwd // Following are used by GetPrefs() before the view window is created: typedef enum { TopLeft, TopRight, BottomRight, BottomLeft, Middle } paste_location; typedef enum { And, Copy, Or, Xor } paste_mode; extern paste_location plocation; // location of cursor in paste rectangle extern paste_mode pmode; // logical paste mode // get/set plocation const char* GetPasteLocation(); void SetPasteLocation(const char* s); // get/set pmode const char* GetPasteMode(); void SetPasteMode(const char* s); // Cursor modes: extern wxCursor* curs_pencil; // for drawing cells extern wxCursor* curs_pick; // for picking cell states extern wxCursor* curs_cross; // for selecting cells extern wxCursor* curs_hand; // for moving view by dragging extern wxCursor* curs_zoomin; // for zooming in to a clicked cell extern wxCursor* curs_zoomout; // for zooming out from a clicked cell void FreeCursors(); // deallocate memory allocated by CreateCursors() const char* CursorToString(wxCursor* curs); // convert given cursor to corresponding string in Cursor Mode submenu wxCursor* StringToCursor(const char* s); // convert given string to a cursor (NULL if s is not valid) int CursorToIndex(wxCursor* curs); // convert given cursor to an index: 0 for curs_pencil, etc wxCursor* IndexToCursor(int i); // convert given index to a cursor (NULL if i is not in valid range) #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/�����������������������������������������������������������������������0000755�0001750�0001750�00000000000�12536111364�013157� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/cross_curs.xpm���������������������������������������������������������0000644�0001750�0001750�00000001027�12536111364�016012� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *cross_curs_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #FFFFFFFFFFFF", "B c None", "C c #000000000000", /* pixels */ "BBBBBBAAABBBBBBB", "BBBBBBACABBBBBBB", "BBBBBBACABBBBBBB", "BBBBBBACABBBBBBB", "BBBBBBACABBBBBBB", "BBBBBBACABBBBBBB", "AAAAAAACAAAAAAAB", "ACCCCCCCCCCCCCAB", "AAAAAAACAAAAAAAB", "BBBBBBACABBBBBBB", "BBBBBBACABBBBBBB", "BBBBBBACABBBBBBB", "BBBBBBACABBBBBBB", "BBBBBBACABBBBBBB", "BBBBBBAAABBBBBBB", "BBBBBBBBBBBBBBBB" }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/open.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001666�12536111364�014577� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *open_xpm[] = { /* width height ncolors chars_per_pixel */ "16 15 23 1", /* colors */ "A c #000000008080", "B c #212142427979", "C c #292951519393", "D c #35356969BFBF", "E c #3A3A7070CACA", "F c #55558484D1D1", "G c #5D5D8989D3D3", "H c #63638E8ED5D5", "I c #6E6E9696D8D8", "J c #77779D9DDBDB", "K c #8585A7A7DFDF", "L c #9090AFAFE2E2", "M c #9A9AEAEA5353", "N c #9F9FB9B9E5E5", "O c #A2A2BCBCE6E6", "P c #A9A9D0D06666", "Q c #AAAAC1C1E8E8", "R c #ADADC4C4E9E9", "S c #B2B2D5D58C8C", "T c #B3B3C8C8EBEB", "U c #BEBED0D0EEEE", "V c None", "W c #C6C6D6D6F0F0", /* pixels */ "VVVVVVVVVVVVVVVV", "VVVVVCCCCVVVVVVV", "AAAAVVCMMCVVVVVV", "AIIIAVVCMMCVVVVV", "AIIIDAAACMMBAAVV", "AIIIIIIICSMBOAVV", "AIAAAACCCPMBBBAA", "AIANQTCMMMMMMBWA", "AGALNQTCMMMMBTOA", "AAHKLNQQCMMBTWAG", "AAIJKLNQQCBTWWAN", "ADGIJKLNQQTWWRAV", "AEFGIJKLNQTUWAGV", "AAAAAAAAAAAAAAVV", "VVVVVVVVVVVVVVVV", }; ��������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/pick_down.xpm����������������������������������������������������������0000644�0001750�0001750�00000001034�12536111364�015600� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *pick_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000004040", "B c #494969699F9F", "C c #8C8C9696A6A6", /* pixels */ "CCCCCCCCCCCCAAAC", "CCCCCCCCCCCACAAA", "CCCCCCCCCCAAAAAA", "CCCCCCCCAAAAAAAA", "CCCCCCCCCAAAAAAC", "CCCCCCCCACAAAACC", "CCCCCCCACCCAACCC", "CCCCCCACCCACACCC", "CCCCCACCCACCCCCC", "CCCCACCCACCCCCCC", "CCCABBCACCCCCCCC", "CCABBBACCCCCCCCC", "CABBBACCCCCCCCCC", "ABBBACCCCCCCCCCC", "ABBACCCCCCCCCCCC", "AAACCCCCCCCCCCCC"}; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/select_down.xpm��������������������������������������������������������0000644�0001750�0001750�00000001014�12536111364�016127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *select_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000003030", "B c #8C8C9696A6A6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BAABAABAABAABAAB", "BBBBBBBBBBBBBBBB", "BABBBBBBBBBBBBAB", "BABBBBBBBBBBBBAB", "BBBBBBBBBBBBBBBB", "BABBBBBBBBBBBBAB", "BABBBBBBBBBBBBAB", "BBBBBBBBBBBBBBBB", "BABBBBBBBBBBBBAB", "BABBBBBBBBBBBBAB", "BBBBBBBBBBBBBBBB", "BAABAABAABAABAAB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/forwards.xpm�����������������������������������������������������������0000644�0001750�0001750�00000001022�12536111364�015447� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *forwards_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000008080", "B c #34346767BCBC", "C c None", /* pixels */ "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC", "CCCCAABCCCCCCCCC", "CCCCAAAABCCCCCCC", "CCCCAAAAAABCCCCC", "CCCCAAAAAAAABCCC", "CCCCAAAAAAAAAACC", "CCCCAAAAAAAAAACC", "CCCCAAAAAAAABCCC", "CCCCAAAAAABCCCCC", "CCCCAAAABCCCCCCC", "CCCCAABCCCCCCCCC", "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC"}; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/delete.xpm�������������������������������������������������������������0000644�0001750�0001750�00000000776�12536111364�015101� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *delete_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c None", "B c #000000008080", /* pixels */ "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAABBBBBBBBBBAAA", "AAABBBBBBBBBBAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", }; ��golly-2.7-src/gui-wx/bitmaps/autofit_down.xpm�������������������������������������������������������0000644�0001750�0001750�00000001011�12536111364�016320� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *autofit_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000004040", "B c #8C8C9696A6A6", /* pixels */ "AAAAAAAAAAAAAAAA", "ABBBBBBBBBBBBBBA", "ABAAAABBBBAAAABA", "ABAAABBBBBBAAABA", "ABAAAABBBBAAAABA", "ABABAAABBAAABABA", "ABBBBABBBBABBBBA", "ABBBBBBBBBBBBBBA", "ABBBBBBBBBBBBBBA", "ABBBBABBBBABBBBA", "ABABAAABBAAABABA", "ABAAAABBBBAAAABA", "ABAAABBBBBBAAABA", "ABAAAABBBBAAAABA", "ABBBBBBBBBBBBBBA", "AAAAAAAAAAAAAAAA"}; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/stopplay.xpm�����������������������������������������������������������0000644�0001750�0001750�00000000774�12536111364�015510� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *stopplay_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000008080", "B c None", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBAAAAAAAAAABBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB"}; ����golly-2.7-src/gui-wx/bitmaps/zoomout_curs.xpm�������������������������������������������������������0000644�0001750�0001750�00000001032�12536111364�016371� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *zoomout_curs_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #FFFFFFFFFFFF", "B c None", "C c #000000000000", /* pixels */ "BBBBCCCCBBBBBBBB", "BBCCAAAACCBBBBBB", "BCAAAAAAAACBBBBB", "BCAAAAAAAACBBBBB", "CAAAAAAAAAACBBBB", "CAACCCCCCAACBBBB", "CAACCCCCCAACBBBB", "CAAAAAAAAAACBBBB", "BCAAAAAAAACBBBBB", "BCAAAAAAAACCBBBB", "BBCCAAAACCCACBBB", "BBBBCCCCBCAAACBB", "BBBBBBBBBBCAAACB", "BBBBBBBBBBBCAAAC", "BBBBBBBBBBBBCAAC", "BBBBBBBBBBBBBCCB", }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/move.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001200�12536111364�014564� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *move_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 8 1", /* colors */ "A c #000000008080", "B c #52528282D0D0", "C c #71719898D9D9", "D c #A8A8C0C0E8E8", "E c None", "F c #D2D2DFDFF4F4", "G c #DCDCE6E6F6F6", "H c #E2E2EAEAF8F8", /* pixels */ "EEEEEEEEEEEEEEEE", "EEEEEEEAAEEEEEEE", "EEEEAEAGBAABEEEE", "EEEAGAAGDAHAEEEE", "EEEADGAGDAGABAEE", "EEEEAGAGGAHAGBAE", "EEABAGDFDGFCGFAE", "EAGGAFGFFFGGFGAE", "EAHGCFGGGGGGGAEE", "EEAGGGGGGFFDHAEE", "EEEAFFGGGGDFBAEE", "EEEADFGGFDFDAEEE", "EEEEAFDFFFFAEEEE", "EEEEEAFGFFDAEEEE", "EEEEEADFDDCAEEEE", "EEEEEEEEEEEEEEEE", }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/zoomout_down.xpm�������������������������������������������������������0000644�0001750�0001750�00000001015�12536111364�016365� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *zoomout_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000003030", "B c #8C8C9696A6A6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBAAAABBBBBBB", "BBBAABBBBAABBBBB", "BBABBBBBBBBABBBB", "BBABBBBBBBBABBBB", "BABBBBBBBBBBABBB", "BABBAAAAAABBABBB", "BABBAAAAAABBABBB", "BABBBBBBBBBBABBB", "BBABBBBBBBBABBBB", "BBABBBBBBBBAABBB", "BBBAABBBBAAABABB", "BBBBBAAAABABBBAB", "BBBBBBBBBBBABBAB", "BBBBBBBBBBBBAABB", "BBBBBBBBBBBBBBBB", }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/zoomin_down.xpm��������������������������������������������������������0000644�0001750�0001750�00000001014�12536111364�016163� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *zoomin_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000003030", "B c #8C8C9696A6A6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBAAAABBBBBBB", "BBBAABBBBAABBBBB", "BBABBBBBBBBABBBB", "BBABBBAABBBABBBB", "BABBBBAABBBBABBB", "BABBAAAAAABBABBB", "BABBAAAAAABBABBB", "BABBBBAABBBBABBB", "BBABBBAABBBABBBB", "BBABBBBBBBBAABBB", "BBBAABBBBAAABABB", "BBBBBAAAABABBBAB", "BBBBBBBBBBBABBAB", "BBBBBBBBBBBBAABB", "BBBBBBBBBBBBBBBB", }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/zoomin.xpm�������������������������������������������������������������0000644�0001750�0001750�00000001024�12536111364�015135� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *zoomin_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000008080", "B c None", "C c #DCDCE6E6F6F6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBAAAABBBBBBB", "BBBAACCCCAABBBBB", "BBACCCCCCCCABBBB", "BBACCCAACCCABBBB", "BACCCCAACCCCABBB", "BACCAAAAAACCABBB", "BACCAAAAAACCABBB", "BACCCCAACCCCABBB", "BBACCCAACCCABBBB", "BBACCCCCCCCAABBB", "BBBAACCCCAAACABB", "BBBBBAAAABACCCAB", "BBBBBBBBBBBACCAB", "BBBBBBBBBBBBAABB", "BBBBBBBBBBBBBBBB", }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/autofit.xpm������������������������������������������������������������0000644�0001750�0001750�00000001004�12536111364�015273� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *autofit_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000008080", "B c #DCDCE6E6F6F6", /* pixels */ "AAAAAAAAAAAAAAAA", "ABBBBBBBBBBBBBBA", "ABAAAABBBBAAAABA", "ABAAABBBBBBAAABA", "ABAAAABBBBAAAABA", "ABABAAABBAAABABA", "ABBBBABBBBABBBBA", "ABBBBBBBBBBBBBBA", "ABBBBBBBBBBBBBBA", "ABBBBABBBBABBBBA", "ABABAAABBAAABABA", "ABAAAABBBBAAAABA", "ABAAABBBBBBAAABA", "ABAAAABBBBAAAABA", "ABBBBBBBBBBBBBBA", "AAAAAAAAAAAAAAAA"}; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/zoomin_curs.xpm��������������������������������������������������������0000644�0001750�0001750�00000001031�12536111364�016167� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *zoomin_curs_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #FFFFFFFFFFFF", "B c None", "C c #000000000000", /* pixels */ "BBBBCCCCBBBBBBBB", "BBCCAAAACCBBBBBB", "BCAAAAAAAACBBBBB", "BCAAACCAAACBBBBB", "CAAAACCAAAACBBBB", "CAACCCCCCAACBBBB", "CAACCCCCCAACBBBB", "CAAAACCAAAACBBBB", "BCAAACCAAACBBBBB", "BCAAAAAAAACCBBBB", "BBCCAAAACCCACBBB", "BBBBCCCCBCAAACBB", "BBBBBBBBBBCAAACB", "BBBBBBBBBBBCAAAC", "BBBBBBBBBBBBCAAC", "BBBBBBBBBBBBBCCB", }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/info.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001120�12536111364�014552� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *info_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 6 1", /* colors */ "A c #000000008080", "B c #9A9AB6B6E4E4", "C c #A8A8C0C0E8E8", "D c None", "E c #C4C4D5D5F0F0", "F c #DCDCE6E6F6F6", /* pixels */ "DDDDDDDDDDDDDDDD", "DDDDDCAAAACDDDDD", "DDDDDAEFFEADDDDD", "DDDDDAFFFEADDDDD", "DDDDDAEFFEADDDDD", "DDDDDBAAAABDDDDD", "DDDDDAFFFEADDDDD", "DDDDDAFFFEADDDDD", "DDDDDAFFFEADDDDD", "DDDDDAFFFEADDDDD", "DDDDDAFFFEADDDDD", "DDDDDAFFFEADDDDD", "DDDDDAFFFEADDDDD", "DDDDDAFFFEADDDDD", "DDDDDAAAAAADDDDD", "DDDDDDDDDDDDDDDD"}; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/new.xpm����������������������������������������������������������������0000644�0001750�0001750�00000001302�12536111364�014412� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *new_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 11 1", /* colors */ "A c #000000008080", "B c #6B6B9494D7D7", "C c #8989A9A9DFDF", "D c #9A9AB6B6E4E4", "E c #A8A8C0C0E8E8", "F c #B8B8CCCCECEC", "G c None", "H c #C4C4D5D5F0F0", "I c #D2D2DFDFF4F4", "J c #DCDCE6E6F6F6", "K c #E2E2EAEAF8F8", /* pixels */ "GGAAAAAAAAAGGGGG", "GGAHHFEDCABAGGGG", "GGAIHHFEDAJDAGGG", "GGAIIHHFEAJJDAGG", "GGAIIIHHFAAAAAGG", "GGAJJJIIHFEDCAGG", "GGAJJJJJIHFEDAGG", "GGAJJJJKJIHFEAGG", "GGAJJJJJKJIHFAGG", "GGAJJJJJJKJIHAGG", "GGAJJJJJJJKJIAGG", "GGAJJJJJJJJJJAGG", "GGAJJJJJJJJJKAGG", "GGAJJJJJJJJJJAGG", "GGAAAAAAAAAAAAGG", "GGGGGGGGGGGGGGGG", }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/add.xpm����������������������������������������������������������������0000644�0001750�0001750�00000000773�12536111364�014364� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *add_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c None", "B c #000000008080", /* pixels */ "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAABBAAAAAAA", "AAAAAAABBAAAAAAA", "AAAAAAABBAAAAAAA", "AAAAAAABBAAAAAAA", "AAABBBBBBBBBBAAA", "AAABBBBBBBBBBAAA", "AAAAAAABBAAAAAAA", "AAAAAAABBAAAAAAA", "AAAAAAABBAAAAAAA", "AAAAAAABBAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", }; �����golly-2.7-src/gui-wx/bitmaps/move_down.xpm����������������������������������������������������������0000644�0001750�0001750�00000001114�12536111364�015617� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *move_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 5 1", /* colors */ "A c #000000004040", "B c #121242429090", "C c #313158589999", "D c #68688080A8A8", "E c #8C8C9696A6A6", /* pixels */ "EEEEEEEEEEEEEEEE", "EEEEEEEAAEEEEEEE", "EEEEAEAEBAABEEEE", "EEEAEAAEDAEAEEEE", "EEEADEAEDAEABAEE", "EEEEAEAEEAEAEBAE", "EEABAEDEDEECEEAE", "EAEEAEEEEEEEEEAE", "EAEECEEEEEEEEAEE", "EEAEEEEEEEEDEAEE", "EEEAEEEEEEDEBAEE", "EEEADEEEEDEDAEEE", "EEEEAEDEEEEAEEEE", "EEEEEAEEEEDAEEEE", "EEEEEADEDDCAEEEE", "EEEEEEEEEEEEEEEE", }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/scripts_down.xpm�������������������������������������������������������0000644�0001750�0001750�00000001307�12536111364�016344� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *scripts_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 11 1", /* colors */ "A c #000000003030", "B c #393959598F8F", "C c #4A4A66669494", "D c #585870709898", "E c #68687C7C9C9C", "F c #707070707070", "G c #74748585A0A0", "H c #82828F8FA4A4", "I c #8C8C9696A6A6", "J c #92929A9AA8A8", "K c None", /* pixels */ "FAAAAKKKKKKKKKKK", "AGGEDAKKKKKKKKKK", "AAAAAAAAAAAAAAAK", "AHHGGEEGGGEGECBA", "AHHHHHHHHHHHGDCA", "AIIAAAAAIIIIHGDA", "AIIIIIIIIIIIIHEA", "AIIIIAAAAAAIIIGA", "AIIIIIIIIIIIIIHA", "AIIIIIIAAAAAAIIA", "AIIIIIIIIIIIIIJA", "AIIIIIIAAAAAIIIA", "AIIIIIIIIIIIIIIA", "AIIIIAAAAIIIIIIA", "AIIIIIIIIIIIIIIA", "AAAAAAAAAAAAAAAA"}; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/allstates.xpm����������������������������������������������������������0000644�0001750�0001750�00000001077�12536111364�015626� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *allstates_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 5 1", /* colors */ "A c #000000008080", "B c #8989A9A9DFDF", "C c #A0A0A0A0A4A4", "D c None", "E c #E2E2EAEAF8F8", /* pixels */ "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DAAAADAAAADAAAAD", "DACCADAEEADABBAD", "DACCADAEEADABBAD", "DAAAADAAAADAAAAD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DAAAADAAAADAAAAD", "DADDADADDADADDAD", "DADDADADDADADDAD", "DAAAADAAAADAAAAD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD"}; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/controls.xpm�����������������������������������������������������������0000644�0001750�0001750�00000025174�12536111364�015501� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char* controls_xpm[] = { /* width height ncolors chars_per_pixel */ "78 130 4 1", /* colors */ "A c #00000000C8C8", "B c #8989A9A9DFDF", "C c #C4C4D5D5F0F0", "D c #000000000000", /* pixels */ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDAAAAAAAAAAAAAADDDDDDDDAAAAAAAAAAAAAADDDDDDDDDD", "DDDDDDDDDABBBBBBBBBBBBBBADDDDDDABBBBBBBBBBBBBBADDDDDDABBBBBBBBBBBBBBADDDDDDDDD", "DDDDDDDDABBCCCCCCCCCCCCBBADDDDABBCCCCCCCCCCCCBBADDDDABBCCCCCCCCCCCCBBADDDDDDDD", "DDDDDDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCCAACCCCCCBADDDDABCCCCCCCAAACCCCBADDDDABCCCCAAACCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCAAACCCCCCBADDDDABCCCCCCAAABCCCCBADDDDABCCCCBAAACCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCAAACCCCCCBADDDDABCCCCCAAABCCCCCBADDDDABCCCCCBAAACCCCCBADDDDDDDD", "DDDDDDDDABCCCCCCAACCCCCCBADDDDABCCCCAAABCCCCCCBADDDDABCCCCCCBAAACCCCBADDDDDDDD", "DDDDDDDDABCCCCCCAACCCCCCBADDDDABCCCCAAABCCCCCCBADDDDABCCCCCCBAAACCCCBADDDDDDDD", "DDDDDDDDABCCCCCCAACCCCCCBADDDDABCCCCCAAABCCCCCBADDDDABCCCCCBAAACCCCCBADDDDDDDD", "DDDDDDDDABCCCCCAAAACCCCCBADDDDABCCCCCCAAABCCCCBADDDDABCCCCBAAACCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCAAAACCCCCBADDDDABCCCCCCCAAACCCCBADDDDABCCCCAAACCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABBCCCCCCCCCCCCBBADDDDABBCCCCCCCCCCCCBBADDDDABBCCCCCCCCCCCCBBADDDDDDDD", "DDDDDDDDDABBBBBBBBBBBBBBADDDDDDABBBBBBBBBBBBBBADDDDDDABBBBBBBBBBBBBBADDDDDDDDD", "DDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDAAAAAAAAAAAAAADDDDDDDDAAAAAAAAAAAAAADDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDAAAAAAAAAAAAAADDDDDDDDAAAAAAAAAAAAAADDDDDDDDDD", "DDDDDDDDDABBBBBBBBBBBBBBADDDDDDABBBBBBBBBBBBBBADDDDDDABBBBBBBBBBBBBBADDDDDDDDD", "DDDDDDDDABBCCCCCCCCCCCCBBADDDDABBCCCCCCCCCCCCBBADDDDABBCCCCCCCCCCCCBBADDDDDDDD", "DDDDDDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCAAAAAACCCCBADDDDABCCCCCCAACCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCAAAAAACCCCBADDDDABCCCCCCAACCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCAACCCCCCCCBADDDDABCCCCCCAACCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCAAAAACCCCCBADDDDABCCCAAAAAAAACCCBADDDDABCCCAAAAAAAACCCBADDDDDDDD", "DDDDDDDDABCCCCAAAAACCCCCBADDDDABCCCAAAAAAAACCCBADDDDABCCCAAAAAAAACCCBADDDDDDDD", "DDDDDDDDABCCCCAACCCCCCCCBADDDDABCCCCCCAACCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCAACCCCCCCCBADDDDABCCCCCCAACCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCAACCCCCCCCBADDDDABCCCCCCAACCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDABCCCCCCCCCCCCCCBADDDDDDDD", "DDDDDDDDABBCCCCCCCCCCCCBBADDDDABBCCCCCCCCCCCCBBADDDDABBCCCCCCCCCCCCBBADDDDDDDD", "DDDDDDDDDABBBBBBBBBBBBBBADDDDDDABBBBBBBBBBBBBBADDDDDDABBBBBBBBBBBBBBADDDDDDDDD", "DDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDAAAAAAAAAAAAAADDDDDDDDAAAAAAAAAAAAAADDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDDDDDDABBADDDDDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDDD", "DDDDDDDDDDABBBBBBBBBBBADDDDDDDDDDDDDABBBBADDDDDDDDDDDDDABBBBBBBBBBBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCBADDDDDDDDDDDDDABBCCBBADDDDDDDDDDDDDABCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCBADDDDDDDDDDDDDABBCCCCBBADDDDDDDDDDDDDABCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCBBADDDDDDDDDDDABBCCCCCCBBADDDDDDDDDDDABBCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCBBADDDDDDDDDABBCCCCCCCCBBADDDDDDDDDABBCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCCBBADDDDDDDABBCCCCCCCCCCBBADDDDDDDABBCCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCCCBBADDDDDAAAABCCCCCCCCBAAAADDDDDABBCCCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCCBBADDDDDDDDDABCCCCCCCCBADDDDDDDDDABBCCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCBBCCCCCBBADDDDDDDDDDABCCCCCCCCBADDDDDDDDDDABBCCCCCBBCBADDDDDDDDDD", "DDDDDDDDDDABBABBCCCBBADDDDDDDDDDDABCCCCCCCCBADDDDDDDDDDDABBCCCBBABBADDDDDDDDDD", "DDDDDDDDDDABADABBCBBADDDDDDDDDDDDABCCCCCCCCBADDDDDDDDDDDDABBCBBADABADDDDDDDDDD", "DDDDDDDDDDAADDDABBBADDDDDDDDDDDDDABBBBBBBBBBADDDDDDDDDDDDDABBBADDDAADDDDDDDDDD", "DDDDDDDDDDADDDDDABADDDDDDDDDDDDDDAAAAAAAAAAAADDDDDDDDDDDDDDABADDDDDADDDDDDDDDD", "DDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDDDDDDDADDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDAADDDDDDDDDDDDDABBBBBBBBBBBBBBADDDDDDDDDDDDDAADDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDABADDDDDDDDDDDDABBCCCCCCCCCCCCBBADDDDDDDDDDDDABADDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDABBAAAAAAADDDDDDABCCCCCCCCCCCCCCBADDDDDDAAAAAAABBADDDDDDDDDDDDDD", "DDDDDDDDDDDDDABBCBBBBBBADDDDDDABCCCCCCCCCCCCCCBADDDDDDABBBBBBCBBADDDDDDDDDDDDD", "DDDDDDDDDDDDABBCCCCCCCBADDDDDDABCCCAACCCCAACCCBADDDDDDABCCCCCCCBBADDDDDDDDDDDD", "DDDDDDDDDDDABBCCCCCCCCBADDDDDDABCCCAAACCAAACCCBADDDDDDABCCCCCCCCBBADDDDDDDDDDD", "DDDDDDDDDDABBCCCCCCCCCBADDDDDDABCCCAAAAAAAACCCBADDDDDDABCCCCCCCCCBBADDDDDDDDDD", "DDDDDDDDDABBCCCCCCCCCCBADDDDDDABCCCAAAAAAAACCCBADDDDDDABCCCCCCCCCCBBADDDDDDDDD", "DDDDDDDDDABBCCCCCCCCCCBADDDDDDABCCCAACAACAACCCBADDDDDDABCCCCCCCCCCBBADDDDDDDDD", "DDDDDDDDDDABBCCCCCCCCCBADDDDDDABCCCAACCCCAACCCBADDDDDDABCCCCCCCCCBBADDDDDDDDDD", "DDDDDDDDDDDABBCCCCCCCCBADDDDDDABCCCAACCCCAACCCBADDDDDDABCCCCCCCCBBADDDDDDDDDDD", "DDDDDDDDDDDDABBCCCCCCCBADDDDDDABCCCAACCCCAACCCBADDDDDDABCCCCCCCBBADDDDDDDDDDDD", "DDDDDDDDDDDDDABBCBBBBBBADDDDDDABCCCCCCCCCCCCCCBADDDDDDABBBBBBCBBADDDDDDDDDDDDD", "DDDDDDDDDDDDDDABBAAAAAAADDDDDDABCCCCCCCCCCCCCCBADDDDDDAAAAAAABBADDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDABADDDDDDDDDDDDABBCCCCCCCCCCCCBBADDDDDDDDDDDDABADDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDAADDDDDDDDDDDDDABBBBBBBBBBBBBBADDDDDDDDDDDDDAADDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDDDDDDDADDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDADDDDDDDDDDDDDDDDD", "DDDDDDDDDDADDDDDABADDDDDDDDDDDDDDAAAAAAAAAAAADDDDDDDDDDDDDDABADDDDDADDDDDDDDDD", "DDDDDDDDDDAADDDABBBADDDDDDDDDDDDDABBBBBBBBBBADDDDDDDDDDDDDABBBADDDAADDDDDDDDDD", "DDDDDDDDDDABADABBCBBADDDDDDDDDDDDABCCCCCCCCBADDDDDDDDDDDDABBCBBADABADDDDDDDDDD", "DDDDDDDDDDABBABBCCCBBADDDDDDDDDDDABCCCCCCCCBADDDDDDDDDDDABBCCCBBABBADDDDDDDDDD", "DDDDDDDDDDABCBBCCCCCBBADDDDDDDDDDABCCCCCCCCBADDDDDDDDDDABBCCCCCBBCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCCBBADDDDDDDDDABCCCCCCCCBADDDDDDDDDABBCCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCCCBBADDDDDAAAABCCCCCCCCBAAAADDDDDABBCCCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCCBBADDDDDDDABBCCCCCCCCCCBBADDDDDDDABBCCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCBBADDDDDDDDDABBCCCCCCCCBBADDDDDDDDDABBCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCBBADDDDDDDDDDDABBCCCCCCBBADDDDDDDDDDDABBCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCBADDDDDDDDDDDDDABBCCCCBBADDDDDDDDDDDDDABCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABCCCCCCCCBADDDDDDDDDDDDDABBCCBBADDDDDDDDDDDDDABCCCCCCCCBADDDDDDDDDD", "DDDDDDDDDDABBBBBBBBBBBADDDDDDDDDDDDDABBBBADDDDDDDDDDDDDABBBBBBBBBBBADDDDDDDDDD", "DDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDDDDDDABBADDDDDDDDDDDDDAAAAAAAAAAAAAADDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDAADDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"}; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/zoomout.xpm������������������������������������������������������������0000644�0001750�0001750�00000001025�12536111364�015337� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *zoomout_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000008080", "B c None", "C c #DCDCE6E6F6F6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBAAAABBBBBBB", "BBBAACCCCAABBBBB", "BBACCCCCCCCABBBB", "BBACCCCCCCCABBBB", "BACCCCCCCCCCABBB", "BACCAAAAAACCABBB", "BACCAAAAAACCABBB", "BACCCCCCCCCCABBB", "BBACCCCCCCCABBBB", "BBACCCCCCCCAABBB", "BBBAACCCCAAACABB", "BBBBBAAAABACCCAB", "BBBBBBBBBBBACCAB", "BBBBBBBBBBBBAABB", "BBBBBBBBBBBBBBBB", }; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/reset.xpm��������������������������������������������������������������0000644�0001750�0001750�00000000772�12536111364�014755� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *reset_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000008080", "B c None", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBABBBBBBABB", "BBBBBAABBBBBAABB", "BBBBAAABBBBAAABB", "BBBAAAABBBAAAABB", "BBAAAAABBAAAAABB", "BBAAAAABBAAAAABB", "BBBAAAABBBAAAABB", "BBBBAAABBBBAAABB", "BBBBBAABBBBBAABB", "BBBBBBABBBBBBABB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB"}; ������golly-2.7-src/gui-wx/bitmaps/stack_down.xpm���������������������������������������������������������0000644�0001750�0001750�00000001013�12536111364�015754� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *stack_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000003030", "B c #8C8C9696A6A6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBAAAAAAAABBBBB", "BBBABBBBBBABBBBB", "BBBABAAAAAAAABBB", "BBBABABBBBABABBB", "BBBABABBBBABABBB", "BBBABABBBBABABBB", "BBBABABBBBABABBB", "BBBAAAAAAAABABBB", "BBBBBABBBBBBABBB", "BBBBBAAAAAAAABBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/scripts.xpm������������������������������������������������������������0000644�0001750�0001750�00000001254�12536111364�015316� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *scripts_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 10 1", /* colors */ "A c #000000008080", "B c #8989A9A9DFDF", "C c #9A9AB6B6E4E4", "D c #A8A8C0C0E8E8", "E c #B8B8CCCCECEC", "F c None", "G c #C4C4D5D5F0F0", "H c #D2D2DFDFF4F4", "I c #DCDCE6E6F6F6", "J c #E2E2EAEAF8F8", /* pixels */ "FAAAAFFFFFFFFFFF", "AGGEDAFFFFFFFFFF", "AAAAAAAAAAAAAAAF", "AHHGGEEGGGEGECBA", "AHHHHHHHHHHHGDCA", "AIIAAAAAIIIIHGDA", "AIIIIIIIIIIIIHEA", "AIIIJAAAAAAIIIGA", "AIIIIIIIIIIIIIHA", "AIIIIIIAAAAAAIIA", "AIIIIIIIIIIIIIJA", "AIIIIIIAAAAAIIIA", "AIIIIIIIIIIIIIIA", "AIIIIAAAAIIIIIIA", "AIIIIIIIIIIIIIIA", "AAAAAAAAAAAAAAAA"}; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/tile_down.xpm����������������������������������������������������������0000644�0001750�0001750�00000001012�12536111364�015603� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *tile_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000003030", "B c #8C8C9696A6A6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBAAAAAAAAAABBB", "BBBABBABBABBABBB", "BBBABBABBABBABBB", "BBBAAAAAAAAAABBB", "BBBABBABBABBABBB", "BBBABBABBABBABBB", "BBBAAAAAAAAAABBB", "BBBABBABBABBABBB", "BBBABBABBABBABBB", "BBBAAAAAAAAAABBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/patterns_down.xpm������������������������������������������������������0000644�0001750�0001750�00000001310�12536111364�016507� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *patterns_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 11 1", /* colors */ "A c #000000003030", "B c #393959598F8F", "C c #4A4A66669494", "D c #585870709898", "E c #68687C7C9C9C", "F c #707070707070", "G c #74748585A0A0", "H c #82828F8FA4A4", "I c #8C8C9696A6A6", "J c #92929A9AA8A8", "K c None", /* pixels */ "FAAAAKKKKKKKKKKK", "AGGEDAKKKKKKKKKK", "AAAAAAAAAAAAAAAK", "AHHGGEEGGGEGECBA", "AHHHHHHHHHHHGDCA", "AIIIIIIAAIAAHGDA", "AIIIIIIAAIAAIHEA", "AIIIIIIIIIIIIIGA", "AIIIAAIAAIIIIIHA", "AIIIAAIAAIIIIIIA", "AIIIIIIIIIIIIIJA", "AIIIIIIAAIIIIIIA", "AIIIIIIAAIIIIIIA", "AIIIIIIIIIIIIIIA", "AIIIIIIIIIIIIIIA", "AAAAAAAAAAAAAAAA"}; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/clone.xpm��������������������������������������������������������������0000644�0001750�0001750�00000000775�12536111364�014736� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *clone_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c None", "B c #000000008080", /* pixels */ "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAABBBBBBBBBBAAA", "AAABBBBBBBBBBAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAABBBBBBBBBBAAA", "AAABBBBBBBBBBAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", }; ���golly-2.7-src/gui-wx/bitmaps/help.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001072�12536111364�014555� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *help_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 5 1", /* colors */ "A c #000000008080", "B c #A8A8C0C0E8E8", "C c None", "D c #C4C4D5D5F0F0", "E c #DCDCE6E6F6F6", /* pixels */ "CCCCCCCCCCCCCCCC", "CCCCBAAAAAABCCCC", "CCCBADEEEEDABCCC", "CCCADEEEEEEDACCC", "CCCAEEEADEEDACCC", "CCCADEEADEEDACCC", "CCCBAAAAEEEABCCC", "CCCCCCAEEEDACCCC", "CCCCCADEEDABCCCC", "CCCCCAEEEDACCCCC", "CCCCCBAAAABCCCCC", "CCCCCAEEEDACCCCC", "CCCCCAEEEDACCCCC", "CCCCCADEEDACCCCC", "CCCCCBAAAABCCCCC", "CCCCCCCCCCCCCCCC"}; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/patterns.xpm�����������������������������������������������������������0000644�0001750�0001750�00000001255�12536111364�015470� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *patterns_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 10 1", /* colors */ "A c #000000008080", "B c #8989A9A9DFDF", "C c #9A9AB6B6E4E4", "D c #A8A8C0C0E8E8", "E c #B8B8CCCCECEC", "F c None", "G c #C4C4D5D5F0F0", "H c #D2D2DFDFF4F4", "I c #DCDCE6E6F6F6", "J c #E2E2EAEAF8F8", /* pixels */ "FAAAAFFFFFFFFFFF", "AGGEDAFFFFFFFFFF", "AAAAAAAAAAAAAAAF", "AHHGGEEGGGEGECBA", "AHHHHHHHHHHHGDCA", "AIIIIIIAAHAAHGDA", "AIIIIIIAAIAAIHEA", "AIIIIIIIIIIIIIGA", "AIIIAAIAAIIIIIHA", "AIIIAAIAAIIIIIIA", "AIIIIIIIIIIIIIJA", "AIIIIIIAAIIIIIIA", "AIIIIIIAAIIIIIIA", "AIIIIIIIIIIIIIIA", "AIIIIIIIIIIIIIIA", "AAAAAAAAAAAAAAAA"}; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/play.xpm���������������������������������������������������������������0000644�0001750�0001750�00000003122�12536111364�014570� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *play_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 39 2", /* colors */ "AA c #00004A4A0000", "BA c #000094940000", "CA c #00009C9C0000", "DA c #080852520808", "EA c #08085A5A0808", "FA c #080894940000", "GA c #08089C9C0000", "HA c #0808B5B50000", "IA c #10105A5A1010", "JA c #101073731010", "KA c #10107B7B0808", "LA c #101084840808", "MA c #10108C8C0808", "NA c #10108C8C1010", "OA c #101094941010", "PA c #181852522121", "AB c #181863631818", "BB c #18186B6B1818", "CB c #181873731818", "DB c #181884841010", "EB c #181894941010", "FB c #18189C9C1818", "GB c #21214A4A2121", "HB c #212152522121", "IB c #212152522929", "JB c #21215A5A2121", "KB c #21217B7B1818", "LB c #212184841818", "MB c #21218C8C1818", "NB c #21218C8C2121", "OB c #292952522929", "PB c #313142423131", "AC c #313152523131", "BC c #313184843131", "CC c #393963633939", "DC c #39396B6B3939", "EC c #7373B5B57B7B", "FC c #7373BDBD7B7B", "GC c None", /* pixels */ "GCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGC", "GCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGC", "GCGCECACFCGCGCGCGCGCGCGCGCGCGCGC", "GCGCOBHAHBHBECGCGCGCGCGCGCGCGCGC", "GCGCOBHAHAHAABJBFCGCGCGCGCGCGCGC", "GCGCOBHAKBNBHAHAABIAECGCGCGCGCGC", "GCGCHBHALBEBMALAHAHADAGBECGCGCGC", "GCGCHBHALBGAGAFBMAKAHAHAAALBGCGC", "GCGCHBHALBCABAFAOAEBBCDBCBPBGCGC", "GCGCIBHAMBBABANABACBAAAACCGCGCGC", "GCGCPAHALBBANAJAAAAADCGCGCGCGCGC", "GCGCAAHABBEAAAAACCGCGCGCGCGCGCGC", "GCGCCCDCAAAADCGCGCGCGCGCGCGCGCGC", "GCGCFCAACCGCGCGCGCGCGCGCGCGCGCGC", "GCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGC", "GCGCGCGCGCGCGCGCGCGCGCGCGCGCGCGC", }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/draw.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001076�12536111364�014566� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *draw_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 5 1", /* colors */ "A c #000000008080", "B c #8989A9A9DFDF", "C c #A0A0A0A0A4A4", "D c None", "E c #E2E2EAEAF8F8", /* pixels */ "DDDDDDDDDDDDDDDD", "DDDDDDDDDAAADDDD", "DDDDDDDDAEEEADDD", "DDDDDDDBAAEBADDD", "DDDDDDDABEAAADDD", "DDDDDDABEEEACDDD", "DDDDDBAEEEBADDDD", "DDDDDABEEEADDDDD", "DDDDBAEEEABDDDDD", "DDDDABEEBADDDDDD", "DDDDAEEEACDDDDDD", "DDDDAAEAADDDDDDD", "DDDDAAAADDDDDDDD", "DDDDAACDDDDDDDDD", "DDDCADDDDDDDDDDD", "DDDDDDDDDDDDDDDD", }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/stop.xpm���������������������������������������������������������������0000644�0001750�0001750�00000006632�12536111364�014621� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *stop_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 120 2", /* colors */ "AA c #63630B0B0909", "BA c #666605050000", "CA c #666617171313", "DA c #696921212424", "EA c #71710A0A0B0B", "FA c #727203030C0C", "GA c #72720F0F0909", "HA c #74740A0A0A0A", "IA c #767610100C0C", "JA c #797919191D1D", "KA c #838310101717", "LA c #85852F2F1818", "MA c #858530301B1B", "NA c #868600000000", "OA c #868638383838", "PA c #878703030000", "AB c #878726263131", "BB c #898902020909", "CB c #8B8B02020C0C", "DB c #8C8C00000202", "EB c #8E8E00000202", "FB c #8E8E00000404", "GB c #8F8F1D1D2525", "HB c #919122222828", "IB c #919124242121", "JB c #92922A2A3333", "KB c #969628282727", "LB c #979730302727", "MB c #98982C2C1F1F", "NB c #999924242C2C", "OB c #999928282020", "PB c #9C9C21212626", "AC c #9D9D35353434", "BC c #9E9E2C2C3434", "CC c #9F9F47475353", "DC c #A0A047474D4D", "EC c #A2A22B2B2F2F", "FC c #A2A237374141", "GC c #A4A412121F1F", "HC c #A6A623232B2B", "IC c #A6A627273030", "JC c #B8B81B1B2424", "KC c None", "LC c #C9C910102020", "MC c #CBCB35353434", "NC c #CDCD2D2D3939", "OC c #CECE0A0A1414", "PC c #D0D007071717", "AD c #D1D13C3C3E3E", "BD c #D4D40F0F1818", "CD c #D7D717172626", "DD c #D8D80B0B1A1A", "ED c #DADA0C0C1919", "FD c #DBDB3A3A4040", "GD c #DCDC46464747", "HD c #E0E011112121", "ID c #E3E32D2D3939", "JD c #E8E840403333", "KD c #EAEA06061717", "LD c #EAEA07071212", "MD c #EAEA3D3D2F2F", "ND c #EDED13132121", "OD c #EEEE5F5F4F4F", "PD c #EEEE5F5F5151", "AE c #EFEF57575454", "BE c #F0F005051414", "CE c #F0F07E7E7D7D", "DE c #F1F10B0B1515", "EE c #F1F132322828", "FE c #F2F262625A5A", "GE c #F3F373737272", "HE c #F5F507071616", "IE c #F5F53E3E2E2E", "JE c #F5F555555757", "KE c #F6F672726666", "LE c #F7F739392B2B", "ME c #F7F73B3B3A3A", "NE c #F7F740403232", "OE c #F7F75C5C6262", "PE c #F8F835353939", "AF c #F9F949494C4C", "BF c #F9F95A5A5454", "CF c #F9F95C5C5757", "DF c #FBFB4A4A4242", "EF c #FBFB53534646", "FF c #FDFD31312828", "GF c #FDFD50504C4C", "HF c #FDFD53534646", "IF c #FDFD5F5F5454", "JF c #FEFE76768080", "KF c #FFFF22222929", "LF c #FFFF25252A2A", "MF c #FFFF27273434", "NF c #FFFF28282B2B", "OF c #FFFF2B2B2E2E", "PF c #FFFF2F2F3131", "AG c #FFFF30303535", "BG c #FFFF35354242", "CG c #FFFF37372D2D", "DG c #FFFF37373333", "EG c #FFFF38382E2E", "FG c #FFFF46464343", "GG c #FFFF47474949", "HG c #FFFF48483C3C", "IG c #FFFF4A4A3D3D", "JG c #FFFF4B4B4141", "KG c #FFFF4C4C4F4F", "LG c #FFFF4F4F4C4C", "MG c #FFFF53534C4C", "NG c #FFFF61615E5E", "OG c #FFFF81818484", "PG c #FFFF82828A8A", "AH c #FFFF83837E7E", "BH c #FFFF83838484", "CH c #FFFF85858080", "DH c #FFFF8A8A7E7E", "EH c #FFFF8C8C8585", "FH c #FFFF8F8F7C7C", "GH c #FFFF8F8F7D7D", "HH c #FFFF92929D9D", /* pixels */ "KCKCKCKCKCKCKCKCKCKCKCKCKCKCKCKC", "KCKCKCKCKCKCKCKCKCKCKCKCKCKCKCKC", "KCKCCCJBHBKBLBMALALAMBOBACOAKCKC", "KCKCABHHPGBHEHGHFHFHDHCHCECAKCKC", "KCKCFCJFOEJECFPDODODBFAEGEAAKCKC", "KCKCBCOGNGGFMGEFHFHFLGKGADHAKCKC", "KCKCNBAHIFDFJGIGHGHGFGGGMCIBKCKC", "KCKCECKEDFMDNEIELELEDGMEMCGAKCKC", "KCKCECKEDFMDNEIELELEDGMEMCGAKCKC", "KCKCPBFEJDEEEGCGFFFFPFPEGDBAKCKC", "KCKCHCAFAGKFLFOFNFNFMFBGFDIAKCKC", "KCKCICIDNDBEHEDELDLDKDHDJCEAKCKC", "KCKCGBNCCDDDEDBDOCOCPCLCGCJAKCKC", "KCKCDCKABBDBEBPANANAFBCBFADAKCKC", "KCKCKCKCKCKCKCKCKCKCKCKCKCKCKCKC", "KCKCKCKCKCKCKCKCKCKCKCKCKCKCKCKC", }; ������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/allstates_down.xpm�����������������������������������������������������0000644�0001750�0001750�00000001067�12536111364�016654� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *allstates_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 4 1", /* colors */ "A c #000000004040", "B c #494969699F9F", "C c #606060606464", "D c #8C8C9696A6A6", /* pixels */ "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DAAAADAAAADAAAAD", "DACCADADDADABBAD", "DACCADADDADABBAD", "DAAAADAAAADAAAAD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DAAAADAAAADAAAAD", "DADDADADDADADDAD", "DADDADADDADADDAD", "DAAAADAAAADAAAAD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD"}; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/pick_curs.xpm����������������������������������������������������������0000644�0001750�0001750�00000001051�12536111364�015604� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *pick_curs_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 4 1", /* colors */ "A c #FFFFFFFFFFFF", "B c None", "C c #0000FFFFFFFF", "D c #000000000000", /* pixels */ "BBBBBBBBBBBBDDDB", "BBBBBBBBBBBDADDD", "BBBBBBBBBBDDDDDD", "BBBBBBBBDDDDDDDD", "BBBBBBBBBDDDDDDB", "BBBBBBBBDADDDDBB", "BBBBBBBDAAADDBBB", "BBBBBBDAAADBDBBB", "BBBBBDAAADBBBBBB", "BBBBDAAADBBBBBBB", "BBBDCCADBBBBBBBB", "BBDCCCDBBBBBBBBB", "BDCCCDBBBBBBBBBB", "DCCCDBBBBBBBBBBB", "DCCDBBBBBBBBBBBB", "DDDBBBBBBBBBBBBB"}; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/save.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001255�12536111364�014566� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *save_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 10 1", /* colors */ "A c #000000008080", "B c #1C1C38386666", "C c #2D2D5959A3A3", "D c #34346767BCBC", "E c #55558484D1D1", "F c #9F9FB9B9E5E5", "G c #A5A5BEBEE7E7", "H c None", "I c #CBCBD9D9F1F1", "J c #DCDCE6E6F6F6", /* pixels */ "HHHHHHHHHHHHHHHH", "HAAAAAAAAAAAAAAH", "HADAJJJJJJJJADAH", "HAEAJDDDDDDJAEAH", "HAEAJJJJJJJJAEAH", "HAEAJDDDDDDJAEAH", "HAEAJJJJJJJJAEAH", "HAEDAAAAAAAADEAH", "HAEEEEEEEEEEEEAH", "HAEEDAAAAAADEEAH", "HAEEAGGGFIJAEEAH", "HAEEAGBCCIJAEEAH", "HAEEAGBCCIJAEEAH", "HAEEAGGIJJJAEEAH", "HHAAAAAAAAAAAAHH", "HHHHHHHHHHHHHHHH", }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/backwards.xpm����������������������������������������������������������0000644�0001750�0001750�00000001023�12536111364�015562� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *backwards_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000008080", "B c #34346767BCBC", "C c None", /* pixels */ "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC", "CCCCCCCCCBAACCCC", "CCCCCCCBAAAACCCC", "CCCCCBAAAAAACCCC", "CCCBAAAAAAAACCCC", "CCAAAAAAAAAACCCC", "CCAAAAAAAAAACCCC", "CCCBAAAAAAAACCCC", "CCCCCBAAAAAACCCC", "CCCCCCCBAAAACCCC", "CCCCCCCCCBAACCCC", "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC"}; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/draw_down.xpm����������������������������������������������������������0000644�0001750�0001750�00000001066�12536111364�015614� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *draw_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 4 1", /* colors */ "A c #000000004040", "B c #494969699F9F", "C c #606060606464", "D c #8C8C9696A6A6", /* pixels */ "DDDDDDDDDDDDDDDD", "DDDDDDDDDAAADDDD", "DDDDDDDDADDDADDD", "DDDDDDDBAADBADDD", "DDDDDDDABDAAADDD", "DDDDDDABDDDACDDD", "DDDDDBADDDBADDDD", "DDDDDABDDDADDDDD", "DDDDBADDDABDDDDD", "DDDDABDDBADDDDDD", "DDDDADDDACDDDDDD", "DDDDAADAADDDDDDD", "DDDDAAAADDDDDDDD", "DDDDAACDDDDDDDDD", "DDDCADDDDDDDDDDD", "DDDDDDDDDDDDDDDD", }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/redo.xpm���������������������������������������������������������������0000644�0001750�0001750�00000000770�12536111364�014562� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *redo_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000008080", "B c None", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBABBBBBBB", "BBBBBBBBAABBBBBB", "BBBBBBBBAAABBBBB", "BBAAAAAAAAAABBBB", "BBAAAAAAAAAAABBB", "BBAAAAAAAAAAAABB", "BBAAAAAAAAAAAABB", "BBAAAAAAAAAAABBB", "BBAAAAAAAAAABBBB", "BBBBBBBBAAABBBBB", "BBBBBBBBAABBBBBB", "BBBBBBBBABBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB"}; ��������golly-2.7-src/gui-wx/bitmaps/select.xpm�������������������������������������������������������������0000644�0001750�0001750�00000001024�12536111364�015101� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *select_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000008080", "B c None", "C c #DCDCE6E6F6F6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BAACAACAACAACAAB", "BCCCCCCCCCCCCCCB", "BACCCCCCCCCCCCAB", "BACCCCCCCCCCCCAB", "BCCCCCCCCCCCCCCB", "BACCCCCCCCCCCCAB", "BACCCCCCCCCCCCAB", "BCCCCCCCCCCCCCCB", "BACCCCCCCCCCCCAB", "BACCCCCCCCCCCCAB", "BCCCCCCCCCCCCCCB", "BAACAACAACAACAAB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/pick.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001044�12536111364�014552� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *pick_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 4 1", /* colors */ "A c #000000008080", "B c #8989A9A9DFDF", "C c None", "D c #E2E2EAEAF8F8", /* pixels */ "CCCCCCCCCCCCAAAC", "CCCCCCCCCCCADAAA", "CCCCCCCCCCAAAAAA", "CCCCCCCCAAAAAAAA", "CCCCCCCCCAAAAAAC", "CCCCCCCCADAAAACC", "CCCCCCCADDDAACCC", "CCCCCCADDDACACCC", "CCCCCADDDACCCCCC", "CCCCADDDACCCCCCC", "CCCABBDACCCCCCCC", "CCABBBACCCCCCCCC", "CABBBACCCCCCCCCC", "ABBBACCCCCCCCCCC", "ABBACCCCCCCCCCCC", "AAACCCCCCCCCCCCC"}; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/deltime.xpm������������������������������������������������������������0000644�0001750�0001750�00000000773�12536111364�015257� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *deltime_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c None", "B c #EAEA07071212", /* pixels */ "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "AAAABAAAAAABAAAA", "AAABBBAAAABBBAAA", "AABBBBBAABBBBBAA", "AAABBBBBBBBBBAAA", "AAAABBBBBBBBAAAA", "AAAAABBBBBBAAAAA", "AAAAABBBBBBAAAAA", "AAAABBBBBBBBAAAA", "AAABBBBBBBBBBAAA", "AABBBBBAABBBBBAA", "AAABBBAAAABBBAAA", "AAAABAAAAAABAAAA", "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA"}; �����golly-2.7-src/gui-wx/bitmaps/undo.xpm���������������������������������������������������������������0000644�0001750�0001750�00000000770�12536111364�014576� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *undo_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000008080", "B c None", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBABBBBBBBB", "BBBBBBAABBBBBBBB", "BBBBBAAABBBBBBBB", "BBBBAAAAAAAAAABB", "BBBAAAAAAAAAAABB", "BBAAAAAAAAAAAABB", "BBAAAAAAAAAAAABB", "BBBAAAAAAAAAAABB", "BBBBAAAAAAAAAABB", "BBBBBAAABBBBBBBB", "BBBBBBAABBBBBBBB", "BBBBBBBABBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB"}; ��������golly-2.7-src/gui-wx/bitmaps/hand_curs.xpm����������������������������������������������������������0000644�0001750�0001750�00000001027�12536111364�015573� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *hand_curs_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #FFFFFFFFFFFF", "B c None", "C c #000000000000", /* pixels */ "BBBBBBBCCBBBBBBB", "BBBCCBCAACCCBBBB", "BBCAACCAACAACBBB", "BBCAACCAACAACBCB", "BBBCAACAACAACCAC", "BBBCAACAACAACAAC", "BCCBCAAAAAAACAAC", "CAACCAAAAAAAAAAC", "CAAACAAAAAAAAACB", "BCAAAAAAAAAAAACB", "BBCAAAAAAAAAAACB", "BBCAAAAAAAAAACBB", "BBBCAAAAAAAAACBB", "BBBBCAAAAAAACBBB", "BBBBBCAAAAAACBBB", "BBBBBCAAAAAACBBB", }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/duplicate.xpm����������������������������������������������������������0000644�0001750�0001750�00000000776�12536111364�015611� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *duplicate_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 2 1", /* colors */ "A c #000000008080", "B c None", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBAABBAABBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB"}; ��golly-2.7-src/gui-wx/bitmaps/hyper_down.xpm���������������������������������������������������������0000644�0001750�0001750�00000001035�12536111364�016002� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *hyper_down_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000004040", "B c #606060606464", "C c #8C8C9696A6A6", /* pixels */ "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCAC", "CCCCCCCCCCCCCAAC", "CCCCCCCCCCCCAABC", "CCCCCCACCCCAAACC", "CCCCCAAACCAAABCC", "CCCCBAAAAAAAACCC", "CCCCAAAAAAAABCCC", "CCCBAAAAAAAACCCC", "CCCAAAAAAAABCCCC", "CCBAAACCAAACCCCC", "CCAAACCCCACCCCCC", "CBAACCCCCCCCCCCC", "CAACCCCCCCCCCCCC", "CACCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC"}; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/tile.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001022�12536111364�014555� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *tile_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000008080", "B c None", "C c #DCDCE6E6F6F6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBAAAAAAAAAABBB", "BBBACCACCACCABBB", "BBBACCACCACCABBB", "BBBAAAAAAAAAABBB", "BBBACCACCACCABBB", "BBBACCACCACCABBB", "BBBAAAAAAAAAABBB", "BBBACCACCACCABBB", "BBBACCACCACCABBB", "BBBAAAAAAAAAABBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", }; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/algo.xpm���������������������������������������������������������������0000644�0001750�0001750�00000001120�12536111364�014541� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *algo_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 6 1", /* colors */ "A c #000000008080", "B c #9A9AB6B6E4E4", "C c None", "D c #C4C4D5D5F0F0", "E c #DCDCE6E6F6F6", "F c #E2E2EAEAF8F8", /* pixels */ "CCCCCCCCCCCCCCCC", "CCCAAACCCCCCCCCC", "CBADEDABCCCCCCCC", "CABEEEBACCCCCCCC", "BAEEEEEABCCCCCCC", "ABEEAEEBACCCCCCC", "ADEEAEEDACCCCCCC", "AEEEAEEEACCAAAAA", "AEEEEEEEACCCAAAC", "AEEEEEEEACCCCACC", "AEEEAEEEACCCCCCC", "AEEEAEEEACCCCCCC", "AEEEAEEEACCCCCCC", "AEEFAEEEACCCCCCC", "AAAAAAAAACCCCCCC", "CCCCCCCCCCCCCCCC"}; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/record.xpm�������������������������������������������������������������0000644�0001750�0001750�00000001046�12536111364�015104� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *record_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 4 1", /* colors */ "A c #0808B5B50000", "B c #101073731010", "C c #7373BDBD7B7B", "D c None", /* pixels */ "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "DDDDDCBBBBCDDDDD", "DDDCBBAAAABBCDDD", "DDDBAAAAAAAABDDD", "DDCBAAAAAAAABCDD", "DDBAAAAAAAAAABDD", "DDBAAAAAAAAAABDD", "DDBAAAAAAAAAABDD", "DDBAAAAAAAAAABDD", "DDCBAAAAAAAABCDD", "DDDBAAAAAAAABDDD", "DDDCBBAAAABBCDDD", "DDDDDCBBBBCDDDDD", "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD"}; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/hyper.xpm��������������������������������������������������������������0000644�0001750�0001750�00000001017�12536111364�014753� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *hyper_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000008080", "B c #8989A9A9DFDF", "C c None", /* pixels */ "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCAC", "CCCCCCCCCCCCCAAC", "CCCCCCCCCCCCAABC", "CCCCCCACCCCAAACC", "CCCCCAAACCAAABCC", "CCCCBAAAAAAAACCC", "CCCCAAAAAAAABCCC", "CCCBAAAAAAAACCCC", "CCCAAAAAAAABCCCC", "CCBAAACCAAACCCCC", "CCAAACCCCACCCCCC", "CBAACCCCCCCCCCCC", "CAACCCCCCCCCCCCC", "CACCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC"}; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/bitmaps/stack.xpm��������������������������������������������������������������0000644�0001750�0001750�00000001023�12536111364�014726� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *stack_xpm[] = { /* width height ncolors chars_per_pixel */ "16 16 3 1", /* colors */ "A c #000000008080", "B c None", "C c #DCDCE6E6F6F6", /* pixels */ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBAAAAAAAABBBBB", "BBBACCCCCCABBBBB", "BBBACAAAAAAAABBB", "BBBACACCCCACABBB", "BBBACACCCCACABBB", "BBBACACCCCACABBB", "BBBACACCCCACABBB", "BBBAAAAAAAACABBB", "BBBBBACCCCCCABBB", "BBBBBAAAAAAAABBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/wxperl.h�����������������������������������������������������������������������0000644�0001750�0001750�00000002236�12536111364�013135� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXPERL_H_ #define _WXPERL_H_ void RunPerlScript(const wxString& filepath); // Run the given .pl file. void AbortPerlScript(); // Abort the currently running Perl script. void FinishPerlScripting(); // Called when app is quitting. #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/wxlayer.h����������������������������������������������������������������������0000644�0001750�0001750�00000025304�12536111364�013310� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WXLAYER_H_ #define _WXLAYER_H_ #include "bigint.h" // for bigint class #include "viewport.h" // for viewport class #include "wxselect.h" // for Selection class #include "wxundo.h" // for UndoRedo class #include "wxalgos.h" // for algo_type // Golly supports multiple layers. Each layer is a separate universe // (unless cloned) with its own algorithm, rule, viewport, window title, // selection, undo/redo history, etc. class Layer { public: Layer(); ~Layer(); // if this is a cloned layer then cloneid is > 0 and all the other clones // have the same cloneid int cloneid; lifealgo* algo; // this layer's universe (shared by clones) algo_type algtype; // type of universe (index into algoinfo) bool hyperspeed; // use acceleration while generating? bool showhashinfo; // show hashing info? bool autofit; // auto fit pattern while generating? bool dirty; // user has modified pattern? bool savedirty; // state of dirty flag before drawing/script change bool stayclean; // script has reset dirty flag? int currbase; // current base step int currexpo; // current step exponent int drawingstate; // current drawing state wxCursor* curs; // current cursor UndoRedo* undoredo; // undo/redo history (shared by clones) // each layer (cloned or not) has its own viewport for displaying patterns; // note that we use a pointer to the viewport to allow temporary switching // in wxrender.cpp (eg. in DrawStackedLayers) viewport* view; // WARNING: this string is used to remember the current rule when // switching to another layer; to determine the current rule at any // time, use currlayer->algo->getrule() wxString rule; Selection currsel; // current selection Selection savesel; // for saving/restoring selection bigint originx; // X origin offset bigint originy; // Y origin offset wxString currfile; // full path of current pattern file wxString currname; // name seen in window title and Layer menu // for saving and restoring starting pattern algo_type startalgo; // starting algorithm bool savestart; // need to save starting pattern? bool startdirty; // starting state of dirty flag wxString startfile; // file for saving starting pattern wxString startname; // starting currname wxString startrule; // starting rule bigint startgen; // starting generation (>= 0) bigint startx, starty; // starting location int startbase; // starting base step int startexpo; // starting step exponent int startmag; // starting scale Selection startsel; // starting selection // temporary file used to restore starting pattern or to show comments; // each non-cloned layer uses a different temporary file wxString tempstart; // used when tilelayers is true PatternView* tilewin; // tile window wxRect tilerect; // tile window's size and position // color scheme for this layer wxColor fromrgb; // start of gradient wxColor torgb; // end of gradient unsigned char cellr[256]; // red components for states 0..255 unsigned char cellg[256]; // green components for states 0..255 unsigned char cellb[256]; // blue components for states 0..255 wxBrush* deadbrush; // brush for drawing dead cells wxPen* gridpen; // pen for drawing plain grid wxPen* boldpen; // pen for drawing bold grid // icons for this layer wxBitmap** icons7x7; // icons for scale 1:8 wxBitmap** icons15x15; // icons for scale 1:16 wxBitmap** icons31x31; // icons for scale 1:32 bool multicoloricons; // are icons multi-colored? (grayscale if not) // used if the layer has a timeline (see wxtimeline.cpp) int currframe; // current frame in timeline int autoplay; // +ve = play forwards, -ve = play backwards, 0 = stop int tlspeed; // controls speed at which frames are played long lastframe; // time (in msecs) when last frame was displayed }; const int MAX_LAYERS = 10; // maximum number of layers extern int numlayers; // number of existing layers extern int numclones; // number of cloned layers extern int currindex; // index of current layer (0..numlayers-1) extern Layer* currlayer; // pointer to current layer void AddLayer(); // Add a new layer (with an empty universe) and make it the current layer. // The first call creates the initial layer. Later calls insert the // new layer immediately after the old current layer. The new layer // inherits the same type of universe, the same rule, the same scale // and location, and the same cursor. void CloneLayer(); // Like AddLayer but shares the same universe and undo/redo history // as the current layer. All the current layer's settings are duplicated // and most will be kept synchronized; ie. changing one clone changes all // the others, but each cloned layer has a separate viewport so the same // pattern can be viewed at different scales and locations. void SyncClones(); // If the current layer is a clone then this call ensures the universe // and settings in its other clones are correctly synchronized. void DuplicateLayer(); // Like AddLayer but makes a copy of the current layer's pattern. // Also duplicates all the current settings but, unlike a cloned layer, // the settings are not kept synchronized. void DeleteLayer(); // Delete the current layer. The current layer changes to the previous // index, unless layer 0 was deleted, in which case the current layer // is the new layer at index 0. void DeleteOtherLayers(); // Delete all layers except the current layer. void SetLayer(int index); // Set the current layer using the given index (0..numlayers-1). void MoveLayer(int fromindex, int toindex); // Move the layer at fromindex to toindex and make it the current layer. // This is called by MoveLayerDialog and the movelayer script command. void MoveLayerDialog(); // Bring up a dialog that allows the user to move the current layer // to a new index (which becomes the current layer). void NameLayerDialog(); // Bring up a dialog that allows the user to change the name of the // current layer. void MarkLayerDirty(); // Set dirty flag in current layer and any of its clones. // Also prefix window title and layer name(s) with an asterisk. void MarkLayerClean(const wxString& title); // Reset dirty flag in current layer and any of its clones. // Also set window title, removing asterisk from it and layer name(s). void ToggleSyncViews(); // Toggle the syncviews flag. When true, every layer uses the same // scale and location as the current layer. void ToggleSyncCursors(); // Toggle the synccursors flag. When true, every layer uses the same // cursor as the current layer. void ToggleStackLayers(); // Toggle the stacklayers flag. When true, the rendering code displays // all layers using the same scale and location as the current layer. // Layer 0 is drawn first (100% opaque), then all the other layers // are drawn as overlays using an opacity set by the user. The colors // for the live cells in each layer can be set via the Prefs dialog. void ToggleTileLayers(); // Toggle the tilelayers flag. When true, the rendering code displays // all layers in tiled sub-windows. bool CanSwitchLayer(int index); // Return true if the user can switch to the given layer. void SwitchToClickedTile(int index); // If allowed, change current layer to clicked tile. void ResizeLayers(int wd, int ht); // Resize the viewport in all layers. Layer* GetLayer(int index); // Return a pointer to the layer specified by the given index. bool RestoreRule(const wxString& rule); // Try to set the current layer's rule to a previously known rule. // If this succeeds return true, but if it fails then warn the user, // switch to the current algorithm's default rule, and return false. // The latter can happen if the given rule's table/tree file was // deleted or was edited and some sort of error introduced. // Layer bar routines: void CreateLayerBar(wxWindow* parent); // Create layer bar window at top of given parent window. int LayerBarHeight(); // Return height of layer bar. void ResizeLayerBar(int wd); // Change width of layer bar. void UpdateLayerBar(); // Update state of buttons in layer bar. void UpdateLayerButton(int index, const wxString& name); // Update the name in the specified layer button. void RedrawLayerBar(); // Redraw layer bar. This is needed because UpdateLayerBar doesn't // refresh the layer bar (to avoid unwanted flashing). void ToggleLayerBar(); // Show/hide the layer bar. // move this color stuff into wxcolors.*??? void CreateColorGradient(); // Create a color gradient for the current layer using // currlayer->fromrgb and currlayer->torgb. void UpdateCloneColors(); // If current layer has clones then update their colors. void UpdateLayerColors(); // Update the cell colors and icons for the current layer (and its clones) // according to the current algo and rule. Must be called very soon // after any algo/rule change, and before the viewport is updated. void InvertCellColors(); // Invert the cell colors in all layers, including the dead cell color, // grid lines, and the colors in all icon bitmaps. void SetLayerColors(); // Open a dialog to change the current layer's colors. #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/gui-wx/wxrender.cpp�������������������������������������������������������������������0000644�0001750�0001750�00000202051�12536111364�014002� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /* -------------------- Some notes on Golly's display code --------------------- The rectangular area used to display patterns is called the viewport. It's represented by a window of class PatternView defined in wxview.h. The global viewptr points to a PatternView window which is created in MainFrame::MainFrame() in wxmain.cpp. Nearly all drawing in the viewport is done in this module. The only other place is in wxview.cpp where PatternView::DrawOneCell() is used to draw cells with the pencil cursor. This is done for performance reasons -- using Refresh + Update to do the drawing is too slow. The main rendering routine is DrawView() -- see the end of this module. DrawView() is called from PatternView::OnPaint(), the update event handler for the viewport window. Update events are created automatically by the wxWidgets event dispatcher, or they can be created manually by calling Refresh() and Update(). DrawView() does the following tasks: - Calls currlayer->algo->draw() to draw the current pattern. It passes in renderer, an instance of wx_render (derived from liferender) which has these methods: - killrect() draws a rectangular area of dead cells. - pixblit() draws a pixmap containing at least one live cell. - getcolors() provides access to the current layer's color arrays. Note that currlayer->algo->draw() does all the hard work of figuring out which parts of the viewport are dead and building all the pixmaps for the live parts. The pixmaps contain suitably shrunken images when the scale is < 1:1 (ie. mag < 0). Each lifealgo needs to implement its own draw() method; for example, hlifealgo::draw() in hlifedraw.cpp. - Calls DrawGridLines() to overlay grid lines if they are visible. - Calls DrawGridBorder() to draw border around a bounded universe. - Calls DrawSelection() to overlay a translucent selection rectangle if a selection exists and any part of it is visible. - Calls DrawStackedLayers() to overlay multiple layers using the current layer's scale and location. - If the user is doing a paste, CheckPasteImage() creates a temporary viewport (tempview) and draws the paste pattern (stored in pastealgo) into a masked pixmap which is then used by DrawPasteImage(). - Calls DrawControls() if the translucent controls need to be drawn. Other points of interest: - The decision to use buffered drawing is made in PatternView::OnPaint(). It's never used on Mac OS X or GTK+ 2.0 because windows on those systems are automatically buffered. To avoid flicker on Windows, buffering is always used if any of these conditions are true: - the user is doing a paste; - the grid lines are visible; - the selection is visible; - the translucent controls are visible; - multiple layers are being displayed. - Change the "#if 0" to "#if 1" in wx_render::killrect() to see randomly colored rects. This gives an insight into how lifealgo::draw() works. - The viewport window is actually the right-hand pane of a wxSplitWindow. The left-hand pane is a directory control (wxGenericDirCtrl) that displays the user's preferred pattern or script folder. This is all handled in wxmain.cpp. ----------------------------------------------------------------------------- */ #include "wx/wxprec.h" // for compilers that support precompilation #ifndef WX_PRECOMP #include "wx/wx.h" // for all others include the necessary headers #endif #include "wx/rawbmp.h" // for wxAlphaPixelData #include "bigint.h" #include "lifealgo.h" #include "viewport.h" #include "wxgolly.h" // for viewptr, bigview, statusptr #include "wxutils.h" // for Warning, Fatal, FillRect #include "wxprefs.h" // for showgridlines, mingridmag, swapcolors, etc #include "wxstatus.h" // for statusptr->... #include "wxview.h" // for viewptr->... #include "wxlayer.h" // currlayer, GetLayer, etc #include "wxrender.h" // ----------------------------------------------------------------------------- // globals used in wx_render routines wxDC* currdc; // current device context for viewport int currwd, currht; // current width and height of viewport wxBitmap* pixmap = NULL; // 32-bit deep bitmap used in pixblit calls int pixmapwd = -1; // width of pixmap int pixmapht = -1; // height of pixmap wxBitmap** iconmaps; // array of icon bitmaps // for drawing translucent selection (initialized in InitDrawingData) int selwd; // width of selection bitmap int selht; // height of selection bitmap wxBitmap* selbitmap = NULL; // selection bitmap (if NULL then inversion is used) wxBitmap* graybitmap = NULL; // for inactive selections when drawing multiple layers // for drawing paste pattern (initialized in CreatePasteImage) wxBitmap* pastebitmap; // paste bitmap int pimagewd; // width of paste image int pimageht; // height of paste image int prectwd; // must match viewptr->pasterect.width int prectht; // must match viewptr->pasterect.height int pastemag; // must match current viewport's scale int cvwd, cvht; // must match current viewport's width and height paste_location pasteloc; // must match plocation bool pasteicons; // must match showicons bool pastecolors; // must match swapcolors lifealgo* pastealgo; // universe containing paste pattern wxRect pastebbox; // bounding box in cell coords (not necessarily minimal) // for drawing multiple layers int layerwd = -1; // width of layer bitmap int layerht = -1; // height of layer bitmap wxBitmap* layerbitmap = NULL; // layer bitmap // for drawing translucent controls wxBitmap* ctrlsbitmap = NULL; // controls bitmap wxBitmap* darkctrls = NULL; // for showing clicked control int controlswd; // width of ctrlsbitmap int controlsht; // height of ctrlsbitmap // include controls_xpm (XPM data for controls bitmap) #include "bitmaps/controls.xpm" // these constants must match image dimensions in bitmaps/controls.xpm const int buttborder = 6; // size of outer border const int buttsize = 22; // size of each button const int buttsperrow = 3; // # of buttons in each row const int numbutts = 15; // # of buttons const int rowgap = 4; // vertical gap after first 2 rows // currently clicked control control_id currcontrol = NO_CONTROL; // ----------------------------------------------------------------------------- void CreateTranslucentControls() { wxImage image(controls_xpm); controlswd = image.GetWidth(); controlsht = image.GetHeight(); // use depth 32 so bitmap has an alpha channel ctrlsbitmap = new wxBitmap(controlswd, controlsht, 32); if (ctrlsbitmap == NULL) { Warning(_("Not enough memory for controls bitmap!")); } else { // set ctrlsbitmap pixels and their alpha values based on pixels in image wxAlphaPixelData data(*ctrlsbitmap, wxPoint(0,0), wxSize(controlswd,controlsht)); if (data) { int alpha = 192; // 75% opaque #if !wxCHECK_VERSION(2,9,0) data.UseAlpha(); #endif wxAlphaPixelData::Iterator p(data); for ( int y = 0; y < controlsht; y++ ) { wxAlphaPixelData::Iterator rowstart = p; for ( int x = 0; x < controlswd; x++ ) { int r = image.GetRed(x,y); int g = image.GetGreen(x,y); int b = image.GetBlue(x,y); if (r == 0 && g == 0 && b == 0) { // make black pixel fully transparent p.Red() = 0; p.Green() = 0; p.Blue() = 0; p.Alpha() = 0; } else { // make all non-black pixels translucent #if defined(__WXMSW__) || (defined(__WXMAC__) && wxCHECK_VERSION(2,8,8)) // premultiply the RGB values p.Red() = r * alpha / 255; p.Green() = g * alpha / 255; p.Blue() = b * alpha / 255; #else p.Red() = r; p.Green() = g; p.Blue() = b; #endif p.Alpha() = alpha; } p++; } p = rowstart; p.OffsetY(data, 1); } } } // create bitmap for showing clicked control darkctrls = new wxBitmap(controlswd, controlsht, 32); if (darkctrls == NULL) { Warning(_("Not enough memory for dark controls bitmap!")); } else { // set darkctrls pixels and their alpha values based on pixels in image wxAlphaPixelData data(*darkctrls, wxPoint(0,0), wxSize(controlswd,controlsht)); if (data) { int alpha = 128; // 50% opaque int gray = 20; // very dark gray #if !wxCHECK_VERSION(2,9,0) data.UseAlpha(); #endif wxAlphaPixelData::Iterator p(data); for ( int y = 0; y < controlsht; y++ ) { wxAlphaPixelData::Iterator rowstart = p; for ( int x = 0; x < controlswd; x++ ) { int r = image.GetRed(x,y); int g = image.GetGreen(x,y); int b = image.GetBlue(x,y); if (r == 0 && g == 0 && b == 0) { // make black pixel fully transparent p.Red() = 0; p.Green() = 0; p.Blue() = 0; p.Alpha() = 0; } else { // make all non-black pixels translucent gray #if defined(__WXMSW__) || (defined(__WXMAC__) && wxCHECK_VERSION(2,8,8)) // premultiply the RGB values p.Red() = gray * alpha / 255; p.Green() = gray * alpha / 255; p.Blue() = gray * alpha / 255; #else p.Red() = gray; p.Green() = gray; p.Blue() = gray; #endif p.Alpha() = alpha; } p++; } p = rowstart; p.OffsetY(data, 1); } } } } // ----------------------------------------------------------------------------- control_id WhichControl(int x, int y) { // determine which button is at x,y in controls bitmap int col, row; x -= buttborder; y -= buttborder; if (x < 0 || y < 0) return NO_CONTROL; // allow for vertical gap after first 2 rows if (y < (buttsize + rowgap)) { if (y > buttsize) return NO_CONTROL; // in 1st gap row = 1; } else if (y < 2*(buttsize + rowgap)) { if (y > 2*buttsize + rowgap) return NO_CONTROL; // in 2nd gap row = 2; } else { row = 3 + (y - 2*(buttsize + rowgap)) / buttsize; } col = 1 + x / buttsize; if (col < 1 || col > buttsperrow) return NO_CONTROL; if (row < 1 || row > numbutts/buttsperrow) return NO_CONTROL; int control = (row - 1) * buttsperrow + col; return (control_id) control; } // ----------------------------------------------------------------------------- void DrawControls(wxDC& dc, wxRect& rect) { if (ctrlsbitmap) { #ifdef __WXGTK__ // wxGTK Blit doesn't support alpha channel dc.DrawBitmap(*ctrlsbitmap, rect.x, rect.y, true); #else // Blit is about 10% faster than DrawBitmap (on Mac at least) wxMemoryDC memdc; memdc.SelectObject(*ctrlsbitmap); dc.Blit(rect.x, rect.y, rect.width, rect.height, &memdc, 0, 0, wxCOPY, true); memdc.SelectObject(wxNullBitmap); #endif if (currcontrol > NO_CONTROL && darkctrls) { // show clicked control int i = (int)currcontrol - 1; int x = buttborder + (i % buttsperrow) * buttsize; int y = buttborder + (i / buttsperrow) * buttsize; // allow for vertical gap after first 2 rows if (i < buttsperrow) { // y is correct } else if (i < 2*buttsperrow) { y += rowgap; } else { y += 2*rowgap; } #ifdef __WXGTK__ // wxGTK Blit doesn't support alpha channel wxRect r(x, y, buttsize, buttsize); dc.DrawBitmap(darkctrls->GetSubBitmap(r), rect.x + x, rect.y + y, true); #else wxMemoryDC memdc; memdc.SelectObject(*darkctrls); dc.Blit(rect.x + x, rect.y + y, buttsize, buttsize, &memdc, x, y, wxCOPY, true); memdc.SelectObject(wxNullBitmap); #endif } } } // ----------------------------------------------------------------------------- void SetSelectionPixels(wxBitmap* bitmap, const wxColor* color) { // set color and alpha of pixels in given bitmap wxAlphaPixelData data(*bitmap, wxPoint(0,0), wxSize(selwd,selht)); if (data) { int alpha = 128; // 50% opaque #if defined(__WXMSW__) || (defined(__WXMAC__) && wxCHECK_VERSION(2,8,8)) // premultiply the RGB values int r = color->Red() * alpha / 255; int g = color->Green() * alpha / 255; int b = color->Blue() * alpha / 255; #else int r = color->Red(); int g = color->Green(); int b = color->Blue(); #endif #if !wxCHECK_VERSION(2,9,0) data.UseAlpha(); #endif wxAlphaPixelData::Iterator p(data); for ( int y = 0; y < selht; y++ ) { wxAlphaPixelData::Iterator rowstart = p; for ( int x = 0; x < selwd; x++ ) { p.Red() = r; p.Green() = g; p.Blue() = b; p.Alpha() = alpha; p++; } p = rowstart; p.OffsetY(data, 1); } } } // ----------------------------------------------------------------------------- void InitDrawingData() { // create translucent selection bitmap viewptr->GetClientSize(&selwd, &selht); // selwd or selht might be < 1 on Windows if (selwd < 1) selwd = 1; if (selht < 1) selht = 1; // use depth 32 so bitmap has an alpha channel selbitmap = new wxBitmap(selwd, selht, 32); if (selbitmap == NULL) { Warning(_("Not enough memory for selection bitmap!")); } else { SetSelectionPixels(selbitmap, selectrgb); } // create translucent gray bitmap for inactive selections graybitmap = new wxBitmap(selwd, selht, 32); if (graybitmap == NULL) { Warning(_("Not enough memory for gray bitmap!")); } else { SetSelectionPixels(graybitmap, wxLIGHT_GREY); } } // ----------------------------------------------------------------------------- void DestroyDrawingData() { delete layerbitmap; delete selbitmap; delete graybitmap; delete ctrlsbitmap; delete darkctrls; delete pixmap; } // ----------------------------------------------------------------------------- // called from wx_render::pixblit to draw a bitmap at 1:1 scale void DrawPixmap(unsigned char* byteptr, int x, int y, int w, int h, int stride) { wxAlphaPixelData pxldata(*pixmap); if (pxldata) { #if defined(__WXGTK__) && !wxCHECK_VERSION(2,9,0) pxldata.UseAlpha(); #endif wxAlphaPixelData::Iterator p(pxldata); for ( int row = 0; row < h; row++ ) { wxAlphaPixelData::Iterator rowstart = p; for ( int col = 0; col < w; col++ ) { p.Red() = byteptr[(row*stride + col)*3 + 0]; p.Green() = byteptr[(row*stride + col)*3 + 1]; p.Blue() = byteptr[(row*stride + col)*3 + 2]; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif p++; } p = rowstart; p.OffsetY(pxldata, 1); } } currdc->DrawBitmap(*pixmap, x, y); } // ----------------------------------------------------------------------------- // called from wx_render::pixblit to magnify given pixmap by pmscale (2, 4, ... 2^MAX_MAG) void DrawStretchedPixmap(unsigned char* byteptr, int x, int y, int w, int h, int pmscale, int stride) { int cellsize = pmscale > 2 ? pmscale - 1 : pmscale; bool drawgap = (pmscale > 2 && pmscale < (1 << mingridmag)) || #ifdef __WXMAC__ // wxMac seems to draw lines with semi-transparent pixels at the // top/left ends, so we have to draw gaps even if showing grid lines // otherwise we see annoying dots at the top/left edge of the viewport (pmscale >= (1 << mingridmag)); #else (pmscale >= (1 << mingridmag) && !showgridlines); #endif unsigned char deadr = currlayer->cellr[0]; unsigned char deadg = currlayer->cellg[0]; unsigned char deadb = currlayer->cellb[0]; // might be faster to draw rectangles above certain scales??? wxAlphaPixelData pxldata(*pixmap); if (pxldata) { #if defined(__WXGTK__) && !wxCHECK_VERSION(2,9,0) pxldata.UseAlpha(); #endif wxAlphaPixelData::Iterator p(pxldata); for ( int row = 0; row < h; row++ ) { wxAlphaPixelData::Iterator rowstart = p; for ( int col = 0; col < w; col++ ) { unsigned char state = byteptr[row*stride + col]; unsigned char r = currlayer->cellr[state]; unsigned char g = currlayer->cellg[state]; unsigned char b = currlayer->cellb[state]; // expand byte into cellsize*cellsize pixels wxAlphaPixelData::Iterator topleft = p; for (int i = 0; i < cellsize; i++) { wxAlphaPixelData::Iterator colstart = p; for (int j = 0; j < cellsize; j++) { p.Red() = r; p.Green() = g; p.Blue() = b; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif p++; } if (drawgap) { // draw dead pixels at right edge of cell p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif } p = colstart; p.OffsetY(pxldata, 1); } if (drawgap) { // draw dead pixels at bottom edge of cell for (int j = 0; j <= cellsize; j++) { p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif p++; } } p = topleft; p.OffsetX(pxldata, pmscale); } p = rowstart; p.OffsetY(pxldata, pmscale); } } currdc->DrawBitmap(*pixmap, x, y); } // ----------------------------------------------------------------------------- void DrawIcons(unsigned char* byteptr, int x, int y, int w, int h, int pmscale, int stride) { // called from wx_render::pixblit to draw icons for each live cell; // assume pmscale > 2 (should be 8 or 16 or 32) int cellsize = pmscale - 1; bool drawgap = (pmscale < (1 << mingridmag)) || #ifdef __WXMAC__ // wxMac seems to draw lines with semi-transparent pixels at the // top/left ends, so we have to draw gaps even if showing grid lines // otherwise we see annoying dots at the top/left edge of the viewport (pmscale >= (1 << mingridmag)); #else (pmscale >= (1 << mingridmag) && !showgridlines); #endif unsigned char deadr = currlayer->cellr[0]; unsigned char deadg = currlayer->cellg[0]; unsigned char deadb = currlayer->cellb[0]; bool multicolor = currlayer->multicoloricons; wxAlphaPixelData pxldata(*pixmap); if (pxldata) { #if defined(__WXGTK__) && !wxCHECK_VERSION(2,9,0) pxldata.UseAlpha(); #endif wxAlphaPixelData::Iterator p(pxldata); for ( int row = 0; row < h; row++ ) { wxAlphaPixelData::Iterator rowstart = p; for ( int col = 0; col < w; col++ ) { unsigned char state = byteptr[row*stride + col]; unsigned char liver = currlayer->cellr[state]; unsigned char liveg = currlayer->cellg[state]; unsigned char liveb = currlayer->cellb[state]; wxAlphaPixelData::Iterator topleft = p; if (state && iconmaps[state]) { wxAlphaPixelData icondata(*iconmaps[state]); if (icondata) { wxAlphaPixelData::Iterator iconpxl(icondata); for (int i = 0; i < cellsize; i++) { wxAlphaPixelData::Iterator colstart = p; wxAlphaPixelData::Iterator iconrow = iconpxl; for (int j = 0; j < cellsize; j++) { if (iconpxl.Red() || iconpxl.Green() || iconpxl.Blue()) { if (multicolor) { // use non-black pixel in multi-colored icon if (swapcolors) { p.Red() = 255 - iconpxl.Red(); p.Green() = 255 - iconpxl.Green(); p.Blue() = 255 - iconpxl.Blue(); } else { p.Red() = iconpxl.Red(); p.Green() = iconpxl.Green(); p.Blue() = iconpxl.Blue(); } } else { // grayscale icon if (iconpxl.Red() == 255) { // replace white pixel with live cell color p.Red() = liver; p.Green() = liveg; p.Blue() = liveb; } else { // replace gray pixel with appropriate shade between // live and dead cell colors float frac = (float)(iconpxl.Red()) / 255.0; p.Red() = (int)(deadr + frac * (liver - deadr) + 0.5); p.Green() = (int)(deadg + frac * (liveg - deadg) + 0.5); p.Blue() = (int)(deadb + frac * (liveb - deadb) + 0.5); } } } else { // replace black pixel with dead cell color p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; } #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif p++; iconpxl++; } if (drawgap) { // draw dead pixels at right edge of cell p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif } p = colstart; p.OffsetY(pxldata, 1); // move to next row of icon bitmap iconpxl = iconrow; iconpxl.OffsetY(icondata, 1); } if (drawgap) { // draw dead pixels at bottom edge of cell for (int j = 0; j <= cellsize; j++) { p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif p++; } } } } else { // draw dead cell for (int i = 0; i < cellsize; i++) { wxAlphaPixelData::Iterator colstart = p; for (int j = 0; j < cellsize; j++) { p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif p++; } if (drawgap) { // draw dead pixels at right edge of cell p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif } p = colstart; p.OffsetY(pxldata, 1); } if (drawgap) { // draw dead pixels at bottom edge of cell for (int j = 0; j <= cellsize; j++) { p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif p++; } } } p = topleft; p.OffsetX(pxldata, pmscale); } p = rowstart; p.OffsetY(pxldata, pmscale); } } currdc->DrawBitmap(*pixmap, x, y); } // ----------------------------------------------------------------------------- void DrawOneIcon(wxDC& dc, int x, int y, wxBitmap* icon, unsigned char deadr, unsigned char deadg, unsigned char deadb, unsigned char liver, unsigned char liveg, unsigned char liveb, bool multicolor) { // draw a single icon (either multi-color or grayscale) int wd = icon->GetWidth(); int ht = icon->GetHeight(); wxBitmap pixmap(wd, ht, 32); wxAlphaPixelData pxldata(pixmap); if (pxldata) { #if defined(__WXGTK__) && !wxCHECK_VERSION(2,9,0) pxldata.UseAlpha(); #endif wxAlphaPixelData::Iterator p(pxldata); wxAlphaPixelData icondata(*icon); if (icondata) { wxAlphaPixelData::Iterator iconpxl(icondata); for (int i = 0; i < ht; i++) { wxAlphaPixelData::Iterator pixmaprow = p; wxAlphaPixelData::Iterator iconrow = iconpxl; for (int j = 0; j < wd; j++) { if (iconpxl.Red() || iconpxl.Green() || iconpxl.Blue()) { if (multicolor) { // use non-black pixel in multi-colored icon if (swapcolors) { p.Red() = 255 - iconpxl.Red(); p.Green() = 255 - iconpxl.Green(); p.Blue() = 255 - iconpxl.Blue(); } else { p.Red() = iconpxl.Red(); p.Green() = iconpxl.Green(); p.Blue() = iconpxl.Blue(); } } else { // grayscale icon if (iconpxl.Red() == 255) { // replace white pixel with live cell color p.Red() = liver; p.Green() = liveg; p.Blue() = liveb; } else { // replace gray pixel with appropriate shade between // live and dead cell colors float frac = (float)(iconpxl.Red()) / 255.0; p.Red() = (int)(deadr + frac * (liver - deadr) + 0.5); p.Green() = (int)(deadg + frac * (liveg - deadg) + 0.5); p.Blue() = (int)(deadb + frac * (liveb - deadb) + 0.5); } } } else { // replace black pixel with dead cell color p.Red() = deadr; p.Green() = deadg; p.Blue() = deadb; } #if defined(__WXGTK__) || wxCHECK_VERSION(2,9,0) p.Alpha() = 255; #endif p++; iconpxl++; } // move to next row of pixmap p = pixmaprow; p.OffsetY(pxldata, 1); // move to next row of icon bitmap iconpxl = iconrow; iconpxl.OffsetY(icondata, 1); } } } dc.DrawBitmap(pixmap, x, y); } // ----------------------------------------------------------------------------- class wx_render : public liferender { public: wx_render() {} virtual ~wx_render() {} virtual void killrect(int x, int y, int w, int h); virtual void pixblit(int x, int y, int w, int h, char* pm, int pmscale); virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b); }; wx_render renderer; // create instance // ----------------------------------------------------------------------------- void wx_render::killrect(int x, int y, int w, int h) { // is Tom's hashdraw code doing unnecessary work??? if (x >= currwd || y >= currht) return; if (x + w <= 0 || y + h <= 0) return; if (w <= 0 || h <= 0) return; // clip given rect so it's within viewport int clipx = x < 0 ? 0 : x; int clipy = y < 0 ? 0 : y; int clipr = x + w; int clipb = y + h; if (clipr > currwd) clipr = currwd; if (clipb > currht) clipb = currht; int clipwd = clipr - clipx; int clipht = clipb - clipy; wxRect rect(clipx, clipy, clipwd, clipht); #if 0 // use a different pale color each time to see any probs wxBrush randbrush(wxColor((rand()&127)+128, (rand()&127)+128, (rand()&127)+128)); FillRect(*currdc, rect, randbrush); #else FillRect(*currdc, rect, *currlayer->deadbrush); #endif } // ----------------------------------------------------------------------------- void wx_render::pixblit(int x, int y, int w, int h, char* pmdata, int pmscale) { // is Tom's hashdraw code doing unnecessary work??? if (x >= currwd || y >= currht) return; if (x + w <= 0 || y + h <= 0) return; // stride is the horizontal pixel width of the image data int stride = (pmscale == 1) ? w : w/pmscale; // clip pixmap to be drawn against viewport: if (pmscale == 1) { // pmdata contains 3 bytes per pixel if (x < 0) { pmdata -= 3*x; w += x; x = 0; } if (y < 0) { pmdata -= 3*y*stride; h += y; y = 0; } if (w > currwd) w = currwd; if (h > currht) h = currht; } else { // pmdata contains 1 byte per `pmscale' pixels, so we must be careful // and adjust x, y, w and h by multiples of `pmscale' only. if (x < 0) { int dx = -x/pmscale*pmscale; pmdata += dx/pmscale; w -= dx; x += dx; } if (y < 0) { int dy = -y/pmscale*pmscale; pmdata += dy/pmscale*stride; h -= dy; y += dy; } if (x + w >= currwd + pmscale) w = (currwd - x + pmscale - 1)/pmscale*pmscale; if (y + h >= currht + pmscale) h = (currht - y + pmscale - 1)/pmscale*pmscale; } // faster to create new pixmap only when size changes if (pixmapwd != w || pixmapht != h) { delete pixmap; pixmap = new wxBitmap(w, h, 32); pixmapwd = w; pixmapht = h; } if (pmscale == 1) { // draw rgb pixel data DrawPixmap((unsigned char*) pmdata, x, y, w, h, stride); } else if (showicons && pmscale > 4 && iconmaps) { // draw icons only at scales 1:8 or 1:16 or 1:32 DrawIcons((unsigned char*) pmdata, x, y, w/pmscale, h/pmscale, pmscale, stride); } else { // stretch pixmap by pmscale, assuming pmdata contains (w/pmscale)*(h/pmscale) bytes // where each byte contains a cell state DrawStretchedPixmap((unsigned char*) pmdata, x, y, w/pmscale, h/pmscale, pmscale, stride); } } // ----------------------------------------------------------------------------- void wx_render::getcolors(unsigned char** r, unsigned char** g, unsigned char** b) { *r = currlayer->cellr; *g = currlayer->cellg; *b = currlayer->cellb; } // ----------------------------------------------------------------------------- void CheckSelectionSize(int viewwd, int viewht) { if (viewwd != selwd || viewht != selht) { // resize selbitmap and graybitmap selwd = viewwd; selht = viewht; delete selbitmap; delete graybitmap; // use depth 32 so bitmaps have an alpha channel selbitmap = new wxBitmap(selwd, selht, 32); graybitmap = new wxBitmap(selwd, selht, 32); if (selbitmap) SetSelectionPixels(selbitmap, selectrgb); if (graybitmap) SetSelectionPixels(graybitmap, wxLIGHT_GREY); } } // ----------------------------------------------------------------------------- void SetSelectionColor() { // selectrgb has changed if (selbitmap) SetSelectionPixels(selbitmap, selectrgb); } // ----------------------------------------------------------------------------- void DrawSelection(wxDC& dc, wxRect& rect) { if (selbitmap) { #ifdef __WXGTK__ // wxGTK Blit doesn't support alpha channel if (selectrgb->Red() == 255 && selectrgb->Green() == 255 && selectrgb->Blue() == 255) { // use inversion for speed dc.Blit(rect.x, rect.y, rect.width, rect.height, &dc, rect.x, rect.y, wxINVERT); } else { dc.DrawBitmap(selbitmap->GetSubBitmap(rect), rect.x, rect.y, true); } #else // Blit seems to be about 10% faster (on Mac at least) wxMemoryDC memdc; memdc.SelectObject(*selbitmap); dc.Blit(rect.x, rect.y, rect.width, rect.height, &memdc, 0, 0, wxCOPY, true); memdc.SelectObject(wxNullBitmap); #endif } else { // no alpha channel so just invert rect dc.Blit(rect.x, rect.y, rect.width, rect.height, &dc, rect.x, rect.y, wxINVERT); } } // ----------------------------------------------------------------------------- void DrawInactiveSelection(wxDC& dc, wxRect& rect) { if (graybitmap) { #ifdef __WXGTK__ // wxGTK Blit doesn't support alpha channel if (selectrgb->Red() == 255 && selectrgb->Green() == 255 && selectrgb->Blue() == 255) { // use inversion for speed dc.Blit(rect.x, rect.y, rect.width, rect.height, &dc, rect.x, rect.y, wxINVERT); } else { dc.DrawBitmap(graybitmap->GetSubBitmap(rect), rect.x, rect.y, true); } #else // Blit seems to be about 10% faster (on Mac at least) wxMemoryDC memdc; memdc.SelectObject(*graybitmap); dc.Blit(rect.x, rect.y, rect.width, rect.height, &memdc, 0, 0, wxCOPY, true); memdc.SelectObject(wxNullBitmap); #endif } else { // no alpha channel so just invert rect dc.Blit(rect.x, rect.y, rect.width, rect.height, &dc, rect.x, rect.y, wxINVERT); } } // ----------------------------------------------------------------------------- void CreatePasteImage(lifealgo* palgo, wxRect& bbox) { pastealgo = palgo; // save for use in CheckPasteImage pastebbox = bbox; // ditto pastebitmap = NULL; prectwd = -1; // force CheckPasteImage to update paste image prectht = -1; pimagewd = -1; // force CheckPasteImage to rescale paste image pimageht = -1; pastemag = currlayer->view->getmag(); pasteicons = showicons; pastecolors = swapcolors; } // ----------------------------------------------------------------------------- void DestroyPasteImage() { if (pastebitmap) { delete pastebitmap; pastebitmap = NULL; } } // ----------------------------------------------------------------------------- void MaskDeadPixels(wxBitmap* bitmap, int wd, int ht, int livealpha) { // access pixels in given bitmap and make all dead pixels 100% transparent // and use given alpha value for all live pixels wxAlphaPixelData data(*bitmap, wxPoint(0,0), wxSize(wd,ht)); if (data) { int deadr = currlayer->cellr[0]; int deadg = currlayer->cellg[0]; int deadb = currlayer->cellb[0]; #if !wxCHECK_VERSION(2,9,0) data.UseAlpha(); #endif wxAlphaPixelData::Iterator p(data); for ( int y = 0; y < ht; y++ ) { wxAlphaPixelData::Iterator rowstart = p; for ( int x = 0; x < wd; x++ ) { // get pixel color int r = p.Red(); int g = p.Green(); int b = p.Blue(); // set alpha value depending on whether pixel is live or dead if (r == deadr && g == deadg && b == deadb) { // make dead pixel 100% transparent p.Red() = 0; p.Green() = 0; p.Blue() = 0; p.Alpha() = 0; } else { // live pixel #if defined(__WXMSW__) || (defined(__WXMAC__) && wxCHECK_VERSION(2,8,8)) // premultiply the RGB values p.Red() = r * livealpha / 255; p.Green() = g * livealpha / 255; p.Blue() = b * livealpha / 255; #else // no change needed // p.Red() = r; // p.Green() = g; // p.Blue() = b; #endif p.Alpha() = livealpha; } p++; } p = rowstart; p.OffsetY(data, 1); } } } // ----------------------------------------------------------------------------- int PixelsToCells(int pixels) { // convert given # of screen pixels to corresponding # of cells if (pastemag >= 0) { int cellsize = 1 << pastemag; return (pixels + cellsize - 1) / cellsize; } else { // pastemag < 0; no need to worry about overflow return pixels << -pastemag; } } // ----------------------------------------------------------------------------- void CheckPasteImage() { // paste image needs to be updated if any of these changed: // pasterect size, viewport size, plocation, showicons, swapcolors if ( prectwd != viewptr->pasterect.width || prectht != viewptr->pasterect.height || cvwd != currlayer->view->getwidth() || cvht != currlayer->view->getheight() || pasteloc != plocation || pasteicons != showicons || pastecolors != swapcolors ) { prectwd = viewptr->pasterect.width; prectht = viewptr->pasterect.height; pastemag = currlayer->view->getmag(); cvwd = currlayer->view->getwidth(); cvht = currlayer->view->getheight(); pasteloc = plocation; pasteicons = showicons; pastecolors = swapcolors; // calculate size of paste image; we could just set it to pasterect size // but that would be slow and wasteful for large pasterects, so we use // the following code (the only tricky bit is when plocation = Middle) int pastewd = prectwd; int pasteht = prectht; if (pastewd <= 2 || pasteht <= 2) { // no need to draw paste image because border lines will cover it delete pastebitmap; pastebitmap = NULL; if (pimagewd != 1 || pimageht != 1) { pimagewd = 1; pimageht = 1; } return; } wxRect cellbox = pastebbox; if (pastewd > currlayer->view->getwidth() || pasteht > currlayer->view->getheight()) { if (plocation == Middle) { // temporary viewport may need to be TWICE size of current viewport if (pastewd > 2 * currlayer->view->getwidth()) pastewd = 2 * currlayer->view->getwidth(); if (pasteht > 2 * currlayer->view->getheight()) pasteht = 2 * currlayer->view->getheight(); if (pastemag > 0) { // make sure pastewd/ht don't have partial cells int cellsize = 1 << pastemag; if ((pastewd + 1) % cellsize > 0) pastewd += cellsize - ((pastewd + 1) % cellsize); if ((pasteht + 1) % cellsize != 0) pasteht += cellsize - ((pasteht + 1) % cellsize); } if (prectwd > pastewd) { // make sure prectwd - pastewd is an even number of *cells* // to simplify shifting in DrawPasteImage if (pastemag > 0) { int cellsize = 1 << pastemag; int celldiff = (prectwd - pastewd) / cellsize; if (celldiff & 1) pastewd += cellsize; } else { if ((prectwd - pastewd) & 1) pastewd++; } } if (prectht > pasteht) { // make sure prectht - pasteht is an even number of *cells* // to simplify shifting in DrawPasteImage if (pastemag > 0) { int cellsize = 1 << pastemag; int celldiff = (prectht - pasteht) / cellsize; if (celldiff & 1) pasteht += cellsize; } else { if ((prectht - pasteht) & 1) pasteht++; } } } else { // plocation is at a corner of pasterect so temporary viewport // may need to be size of current viewport if (pastewd > currlayer->view->getwidth()) pastewd = currlayer->view->getwidth(); if (pasteht > currlayer->view->getheight()) pasteht = currlayer->view->getheight(); if (pastemag > 0) { // make sure pastewd/ht don't have partial cells int cellsize = 1 << pastemag; int gap = 1; // gap between cells if (pastemag == 1) gap = 0; // no gap at scale 1:2 if ((pastewd + gap) % cellsize > 0) pastewd += cellsize - ((pastewd + gap) % cellsize); if ((pasteht + gap) % cellsize != 0) pasteht += cellsize - ((pasteht + gap) % cellsize); } cellbox.width = PixelsToCells(pastewd); cellbox.height = PixelsToCells(pasteht); if (plocation == TopLeft) { // show top left corner of pasterect cellbox.x = pastebbox.x; cellbox.y = pastebbox.y; } else if (plocation == TopRight) { // show top right corner of pasterect cellbox.x = pastebbox.x + pastebbox.width - cellbox.width; cellbox.y = pastebbox.y; } else if (plocation == BottomRight) { // show bottom right corner of pasterect cellbox.x = pastebbox.x + pastebbox.width - cellbox.width; cellbox.y = pastebbox.y + pastebbox.height - cellbox.height; } else { // plocation == BottomLeft // show bottom left corner of pasterect cellbox.x = pastebbox.x; cellbox.y = pastebbox.y + pastebbox.height - cellbox.height; } } } // delete old bitmap even if size hasn't changed delete pastebitmap; pimagewd = pastewd; pimageht = pasteht; // create a bitmap with depth 32 so it has an alpha channel pastebitmap = new wxBitmap(pimagewd, pimageht, 32); if (pastebitmap) { // create temporary viewport and draw pattern into pastebitmap // for later use in DrawPasteImage viewport tempview(pimagewd, pimageht); int midx, midy; if (pastemag > 1) { // allow for gap between cells midx = cellbox.x + (cellbox.width - 1) / 2; midy = cellbox.y + (cellbox.height - 1) / 2; } else { midx = cellbox.x + cellbox.width / 2; midy = cellbox.y + cellbox.height / 2; } tempview.setpositionmag(midx, midy, pastemag); // temporarily turn off grid lines bool saveshow = showgridlines; showgridlines = false; wxMemoryDC pattdc; pattdc.SelectObject(*pastebitmap); currdc = &pattdc; currwd = tempview.getwidth(); currht = tempview.getheight(); pastealgo->draw(tempview, renderer); pattdc.SelectObject(wxNullBitmap); showgridlines = saveshow; // make dead pixels 100% transparent and live pixels 100% opaque MaskDeadPixels(pastebitmap, pimagewd, pimageht, 255); } } } // ----------------------------------------------------------------------------- void DrawPasteImage(wxDC& dc) { if (pastebitmap) { // draw paste image wxRect r = viewptr->pasterect; if (r.width > pimagewd || r.height > pimageht) { // paste image is smaller than pasterect (which can't fit in viewport) // so shift image depending on plocation switch (plocation) { case TopLeft: // no need to do any shifting break; case TopRight: // shift image to top right corner of pasterect r.x += r.width - pimagewd; break; case BottomRight: // shift image to bottom right corner of pasterect r.x += r.width - pimagewd; r.y += r.height - pimageht; break; case BottomLeft: // shift image to bottom left corner of pasterect r.y += r.height - pimageht; break; case Middle: // shift image to middle of pasterect; note that CheckPasteImage // has ensured (r.width - pimagewd) and (r.height - pimageht) // are an even number of *cells* if pastemag > 0 r.x += (r.width - pimagewd) / 2; r.y += (r.height - pimageht) / 2; break; } } #ifdef __WXGTK__ // wxGTK Blit doesn't support alpha channel dc.DrawBitmap(*pastebitmap, r.x, r.y, true); #else wxMemoryDC memdc; memdc.SelectObject(*pastebitmap); dc.Blit(r.x, r.y, pimagewd, pimageht, &memdc, 0, 0, wxCOPY, true); memdc.SelectObject(wxNullBitmap); #endif } // now overlay border rectangle dc.SetPen(*pastepen); dc.SetBrush(*wxTRANSPARENT_BRUSH); // if large rect then we need to avoid overflow because DrawRectangle // has problems on Mac if given a size that exceeds 32K wxRect r = viewptr->pasterect; if (r.x < 0) { int diff = -1 - r.x; r.x = -1; r.width -= diff; } if (r.y < 0) { int diff = -1 - r.y; r.y = -1; r.height -= diff; } if (r.width > currlayer->view->getwidth()) r.width = currlayer->view->getwidth() + 2; if (r.height > currlayer->view->getheight()) r.height = currlayer->view->getheight() + 2; dc.DrawRectangle(r); if (r.y > 0) { dc.SetFont(*statusptr->GetStatusFont()); //dc.SetBackgroundMode(wxSOLID); //dc.SetTextBackground(*wxWHITE); dc.SetBackgroundMode(wxTRANSPARENT); // better in case pastergb is white dc.SetTextForeground(*pastergb); wxString pmodestr = wxString(GetPasteMode(),wxConvLocal); int pmodex = r.x + 2; int pmodey = r.y - 4; dc.DrawText(pmodestr, pmodex, pmodey - statusptr->GetTextAscent()); } dc.SetBrush(wxNullBrush); dc.SetPen(wxNullPen); } // ----------------------------------------------------------------------------- void DrawGridLines(wxDC& dc) { int cellsize = 1 << currlayer->view->getmag(); int h, v, i, topbold, leftbold; if (showboldlines) { // ensure that origin cell stays next to bold lines; // ie. bold lines scroll when pattern is scrolled pair<bigint, bigint> lefttop = currlayer->view->at(0, 0); leftbold = lefttop.first.mod_smallint(boldspacing); topbold = lefttop.second.mod_smallint(boldspacing); if (currlayer->originx != bigint::zero) { leftbold -= currlayer->originx.mod_smallint(boldspacing); } if (currlayer->originy != bigint::zero) { topbold -= currlayer->originy.mod_smallint(boldspacing); } if (mathcoords) topbold--; // show origin cell above bold line } else { // avoid gcc warning topbold = leftbold = 0; } // draw all plain lines first dc.SetPen(*currlayer->gridpen); i = showboldlines ? topbold : 1; v = -1; while (true) { v += cellsize; if (v >= currht) break; if (showboldlines) i++; if (i % boldspacing != 0 && v >= 0 && v < currht) dc.DrawLine(0, v, currwd, v); } i = showboldlines ? leftbold : 1; h = -1; while (true) { h += cellsize; if (h >= currwd) break; if (showboldlines) i++; if (i % boldspacing != 0 && h >= 0 && h < currwd) dc.DrawLine(h, 0, h, currht); } if (showboldlines) { // overlay bold lines dc.SetPen(*currlayer->boldpen); i = topbold; v = -1; while (true) { v += cellsize; if (v >= currht) break; i++; if (i % boldspacing == 0 && v >= 0 && v < currht) dc.DrawLine(0, v, currwd, v); } i = leftbold; h = -1; while (true) { h += cellsize; if (h >= currwd) break; i++; if (i % boldspacing == 0 && h >= 0 && h < currwd) dc.DrawLine(h, 0, h, currht); } } dc.SetPen(wxNullPen); } // ----------------------------------------------------------------------------- void DrawGridBorder(wxDC& dc) { // universe is bounded so draw any visible border regions pair<int,int> ltpxl = currlayer->view->screenPosOf(currlayer->algo->gridleft, currlayer->algo->gridtop, currlayer->algo); pair<int,int> rbpxl = currlayer->view->screenPosOf(currlayer->algo->gridright, currlayer->algo->gridbottom, currlayer->algo); int left = ltpxl.first; int top = ltpxl.second; int right = rbpxl.first; int bottom = rbpxl.second; if (currlayer->algo->gridwd == 0) { left = 0; right = currwd-1; } if (currlayer->algo->gridht == 0) { top = 0; bottom = currht-1; } // note that right and/or bottom might be INT_MAX so avoid adding to cause overflow if (currlayer->view->getmag() > 0) { // move to bottom right pixel of cell at gridright,gridbottom if (right < currwd) right += (1 << currlayer->view->getmag()) - 1; if (bottom < currht) bottom += (1 << currlayer->view->getmag()) - 1; if (currlayer->view->getmag() == 1) { // there are no gaps at scale 1:2 if (right < currwd) right++; if (bottom < currht) bottom++; } } else { if (right < currwd) right++; if (bottom < currht) bottom++; } if (left < 0 && right >= currwd && top < 0 && bottom >= currht) { // border isn't visible (ie. grid fills viewport) return; } if (left >= currwd || right < 0 || top >= currht || bottom < 0) { // no part of grid is visible so fill viewport with border wxRect r(0, 0, currwd, currht); FillRect(dc, r, *borderbrush); return; } // avoid drawing overlapping rects below int rtop = 0; int rheight = currht; if (currlayer->algo->gridht > 0) { if (top > 0) { // top border is visible wxRect r(0, 0, currwd, top); FillRect(dc, r, *borderbrush); // reduce size of rect below rtop = top; rheight -= top; } if (bottom < currht) { // bottom border is visible wxRect r(0, bottom, currwd, currht - bottom); FillRect(dc, r, *borderbrush); // reduce size of rect below rheight -= currht - bottom; } } if (currlayer->algo->gridwd > 0) { if (left > 0) { // left border is visible wxRect r(0, rtop, left, rheight); FillRect(dc, r, *borderbrush); } if (right < currwd) { // right border is visible wxRect r(right, rtop, currwd - right, rheight); FillRect(dc, r, *borderbrush); } } } // ----------------------------------------------------------------------------- void DrawOneLayer(wxDC& dc) { wxMemoryDC layerdc; layerdc.SelectObject(*layerbitmap); // only show icons at scales 1:8 or 1:16 or 1:32 if (showicons && currlayer->view->getmag() > 2) { if (currlayer->view->getmag() == 3) { iconmaps = currlayer->icons7x7; } else if (currlayer->view->getmag() == 4) { iconmaps = currlayer->icons15x15; } else { iconmaps = currlayer->icons31x31; } } currdc = &layerdc; currlayer->algo->draw(*currlayer->view, renderer); layerdc.SelectObject(wxNullBitmap); // make dead pixels 100% transparent; live pixels use opacity setting MaskDeadPixels(layerbitmap, layerwd, layerht, int(2.55 * opacity)); // draw result dc.DrawBitmap(*layerbitmap, 0, 0, true); } // ----------------------------------------------------------------------------- void DrawStackedLayers(wxDC& dc) { // check if layerbitmap needs to be created or resized if ( layerwd != currlayer->view->getwidth() || layerht != currlayer->view->getheight() ) { layerwd = currlayer->view->getwidth(); layerht = currlayer->view->getheight(); delete layerbitmap; // create a bitmap with depth 32 so it has an alpha channel layerbitmap = new wxBitmap(layerwd, layerht, 32); if (!layerbitmap) { Fatal(_("Not enough memory for layer bitmap!")); return; } } // temporarily turn off grid lines bool saveshow = showgridlines; showgridlines = false; // draw patterns in layers 1..numlayers-1 for ( int i = 1; i < numlayers; i++ ) { Layer* savelayer = currlayer; currlayer = GetLayer(i); // use real current layer's viewport viewport* saveview = currlayer->view; currlayer->view = savelayer->view; // avoid drawing a cloned layer more than once??? draw first or last clone??? if ( !currlayer->algo->isEmpty() ) { DrawOneLayer(dc); } // draw this layer's selection if necessary wxRect r; if ( currlayer->currsel.Visible(&r) ) { CheckSelectionSize(layerwd, layerht); if (i == currindex) DrawSelection(dc, r); else DrawInactiveSelection(dc, r); } // restore viewport and currlayer currlayer->view = saveview; currlayer = savelayer; } showgridlines = saveshow; } // ----------------------------------------------------------------------------- void DrawTileFrame(wxDC& dc, wxRect& trect, wxBrush& brush, int wd) { trect.Inflate(wd); wxRect r = trect; r.height = wd; FillRect(dc, r, brush); // top edge r.y += trect.height - wd; FillRect(dc, r, brush); // bottom edge r = trect; r.width = wd; FillRect(dc, r, brush); // left edge r.x += trect.width - wd; FillRect(dc, r, brush); // right edge } // ----------------------------------------------------------------------------- void DrawTileBorders(wxDC& dc) { if (tileborder <= 0) return; // no borders // draw tile borders in bigview window int wd, ht; bigview->GetClientSize(&wd, &ht); if (wd < 1 || ht < 1) return; // most people will choose either a very light or very dark color for dead cells, // so draw mid gray border around non-current tiles wxBrush brush; brush.SetColour(144, 144, 144); wxRect trect; for ( int i = 0; i < numlayers; i++ ) { if (i != currindex) { trect = GetLayer(i)->tilerect; DrawTileFrame(dc, trect, brush, tileborder); } } // draw green border around current tile trect = GetLayer(currindex)->tilerect; brush.SetColour(0, 255, 0); DrawTileFrame(dc, trect, brush, tileborder); } // ----------------------------------------------------------------------------- void DrawView(wxDC& dc, int tileindex) { wxRect r; Layer* savelayer = NULL; viewport* saveview0 = NULL; int colorindex; // if grid is bounded then ensure viewport's central cell is not outside grid edges if ( currlayer->algo->gridwd > 0) { if ( currlayer->view->x < currlayer->algo->gridleft ) currlayer->view->setpositionmag(currlayer->algo->gridleft, currlayer->view->y, currlayer->view->getmag()); else if ( currlayer->view->x > currlayer->algo->gridright ) currlayer->view->setpositionmag(currlayer->algo->gridright, currlayer->view->y, currlayer->view->getmag()); } if ( currlayer->algo->gridht > 0) { if ( currlayer->view->y < currlayer->algo->gridtop ) currlayer->view->setpositionmag(currlayer->view->x, currlayer->algo->gridtop, currlayer->view->getmag()); else if ( currlayer->view->y > currlayer->algo->gridbottom ) currlayer->view->setpositionmag(currlayer->view->x, currlayer->algo->gridbottom, currlayer->view->getmag()); } if ( viewptr->nopattupdate ) { // don't draw incomplete pattern, just fill background currwd = currlayer->view->getwidth(); currht = currlayer->view->getheight(); r = wxRect(0, 0, currwd, currht); FillRect(dc, r, *currlayer->deadbrush); // might as well draw grid lines and border if ( viewptr->GridVisible() ) DrawGridLines(dc); // uses currwd and currht if ( currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0 ) DrawGridBorder(dc); // uses currwd and currht return; } if ( numlayers > 1 && tilelayers ) { if ( tileindex < 0 ) { DrawTileBorders(dc); return; } // tileindex >= 0 so temporarily change some globals to draw this tile if ( syncviews && tileindex != currindex ) { // make sure this layer uses same location and scale as current layer GetLayer(tileindex)->view->setpositionmag(currlayer->view->x, currlayer->view->y, currlayer->view->getmag()); } savelayer = currlayer; currlayer = GetLayer(tileindex); viewptr = currlayer->tilewin; colorindex = tileindex; } else if ( numlayers > 1 && stacklayers ) { // draw all layers starting with layer 0 but using current layer's viewport savelayer = currlayer; if ( currindex != 0 ) { // change currlayer to layer 0 currlayer = GetLayer(0); saveview0 = currlayer->view; currlayer->view = savelayer->view; } colorindex = 0; } else { // just draw the current layer colorindex = currindex; } // only show icons at scales 1:8 or 1:16 or 1:32 if (showicons && currlayer->view->getmag() > 2) { if (currlayer->view->getmag() == 3) { iconmaps = currlayer->icons7x7; } else if (currlayer->view->getmag() == 4) { iconmaps = currlayer->icons15x15; } else { iconmaps = currlayer->icons31x31; } } // draw pattern using a sequence of pixblit and killrect calls currdc = &dc; currwd = currlayer->view->getwidth(); currht = currlayer->view->getheight(); currlayer->algo->draw(*currlayer->view, renderer); if ( viewptr->GridVisible() ) { DrawGridLines(dc); // uses currwd and currht } // if universe is bounded then draw border regions (if visible) if ( currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0 ) { DrawGridBorder(dc); // uses currwd and currht } if ( currlayer->currsel.Visible(&r) ) { CheckSelectionSize(currwd, currht); if (colorindex == currindex) DrawSelection(dc, r); else DrawInactiveSelection(dc, r); } if ( numlayers > 1 && stacklayers ) { // must restore currlayer before we call DrawStackedLayers currlayer = savelayer; if ( saveview0 ) { // restore layer 0's viewport GetLayer(0)->view = saveview0; } // draw layers 1, 2, ... numlayers-1 DrawStackedLayers(dc); } if ( viewptr->waitingforclick && viewptr->pasterect.width > 0 ) { // this test is not really necessary, but it avoids unnecessary // drawing of the paste image when user changes scale if ( pastemag != currlayer->view->getmag() && prectwd == viewptr->pasterect.width && prectwd > 1 && prectht == viewptr->pasterect.height && prectht > 1 ) { // don't draw old paste image, a new one is coming very soon } else { CheckPasteImage(); DrawPasteImage(dc); } } if (viewptr->showcontrols) DrawControls(dc, viewptr->controlsrect); if ( numlayers > 1 && tilelayers ) { // restore globals changed above currlayer = savelayer; viewptr = currlayer->tilewin; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/��������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�12536111546�011374� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Banks-II.rule�������������������������������������������������������������������0000644�0001750�0001750�00000000656�12536111364�013547� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Banks-II Edwin Roger Banks, PhD Thesis 1971 Three-state, five-neighbor CA for a universal computer (Appendix II) http://www.bottomlayer.com/bottom/banks/banks_commentary.htm @TABLE # Format: C,N,E,S,W,C' n_states:3 neighborhood:vonNeumann symmetries:rotate4reflect 010002 011122 011202 012002 012022 012222 022201 022222 021012 110002 112220 122200 122000 200001 211120 211221 212221 @COLORS 1 255 0 0 2 200 200 200 ����������������������������������������������������������������������������������golly-2.7-src/Rules/TriTurmite_120010.rule����������������������������������������������������������0000644�0001750�0001750�00000074717�12536111364�015136� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE TriTurmite_120010 @TREE num_states=64 num_neighbors=4 num_nodes=31 1 0 1 1 17 1 0 0 16 8 9 9 41 9 8 8 40 8 9 9 41 9 8 8 40 10 13 13 45 13 10 10 42 8 9 9 41 9 8 8 40 0 1 1 17 1 0 0 16 0 1 1 17 1 0 0 16 2 5 5 21 5 2 2 18 1 3 6 6 22 6 3 3 19 11 14 14 46 14 11 11 43 11 14 14 46 14 11 11 43 8 9 9 41 9 8 8 40 11 14 14 46 14 11 11 43 3 6 6 22 6 3 3 19 3 6 6 22 6 3 3 19 0 1 1 17 1 0 0 16 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 32 33 33 1 33 32 32 0 56 57 57 9 57 56 56 8 56 57 57 9 57 56 56 8 58 61 61 13 61 58 58 10 56 57 57 9 57 56 56 8 32 33 33 1 33 32 32 0 32 33 33 1 33 32 32 0 34 37 37 5 37 34 34 2 1 35 38 38 6 38 35 35 3 59 62 62 14 62 59 59 11 59 62 62 14 62 59 59 11 56 57 57 9 57 56 56 8 59 62 62 14 62 59 59 11 35 38 38 6 38 35 35 3 35 38 38 6 38 35 35 3 32 33 33 1 33 32 32 0 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 2 2 5 2 1 4 7 7 23 7 4 4 20 12 15 15 47 15 12 12 44 12 15 15 47 15 12 12 44 8 9 9 41 9 8 8 40 12 15 15 47 15 12 12 44 4 7 7 23 7 4 4 20 4 7 7 23 7 4 4 20 0 1 1 17 1 0 0 16 1 0 1 1 17 1 0 0 16 8 9 9 41 9 8 8 40 8 9 9 41 9 8 8 40 8 9 9 41 9 8 8 40 8 9 9 41 9 8 8 40 0 1 1 17 1 0 0 16 0 1 1 17 1 0 0 16 0 1 1 17 1 0 0 16 2 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 1 36 39 39 7 39 36 36 4 60 63 63 15 63 60 60 12 60 63 63 15 63 60 60 12 56 57 57 9 57 56 56 8 60 63 63 15 63 60 60 12 36 39 39 7 39 36 36 4 36 39 39 7 39 36 36 4 32 33 33 1 33 32 32 0 1 32 33 33 1 33 32 32 0 56 57 57 9 57 56 56 8 56 57 57 9 57 56 56 8 56 57 57 9 57 56 56 8 56 57 57 9 57 56 56 8 32 33 33 1 33 32 32 0 32 33 33 1 33 32 32 0 32 33 33 1 33 32 32 0 2 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 3 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 9 9 12 9 4 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 13 13 13 13 13 13 13 13 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 13 13 13 13 13 13 13 13 6 6 6 6 6 6 6 6 1 24 25 25 1 25 24 24 0 48 49 49 9 49 48 48 8 48 49 49 9 49 48 48 8 50 53 53 13 53 50 50 10 48 49 49 9 49 48 48 8 24 25 25 1 25 24 24 0 24 25 25 1 25 24 24 0 26 29 29 5 29 26 26 2 1 27 30 30 6 30 27 27 3 51 54 54 14 54 51 51 11 51 54 54 14 54 51 51 11 48 49 49 9 49 48 48 8 51 54 54 14 54 51 51 11 27 30 30 6 30 27 27 3 27 30 30 6 30 27 27 3 24 25 25 1 25 24 24 0 2 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 16 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 1 0 1 1 1 1 0 0 0 8 9 9 9 9 8 8 8 8 9 9 9 9 8 8 8 10 13 13 13 13 10 10 10 8 9 9 9 9 8 8 8 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 2 5 5 5 5 2 2 2 1 3 6 6 6 6 3 3 3 11 14 14 14 14 11 11 11 11 14 14 14 14 11 11 11 8 9 9 9 9 8 8 8 11 14 14 14 14 11 11 11 3 6 6 6 6 3 3 3 3 6 6 6 6 3 3 3 0 1 1 1 1 0 0 0 2 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 19 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 3 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 17 17 20 17 1 28 31 31 7 31 28 28 4 52 55 55 15 55 52 52 12 52 55 55 15 55 52 52 12 48 49 49 9 49 48 48 8 52 55 55 15 55 52 52 12 28 31 31 7 31 28 28 4 28 31 31 7 31 28 28 4 24 25 25 1 25 24 24 0 1 24 25 25 1 25 24 24 0 48 49 49 9 49 48 48 8 48 49 49 9 49 48 48 8 48 49 49 9 49 48 48 8 48 49 49 9 49 48 48 8 24 25 25 1 25 24 24 0 24 25 25 1 25 24 24 0 24 25 25 1 25 24 24 0 2 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 23 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22 1 4 7 7 7 7 4 4 4 12 15 15 15 15 12 12 12 12 15 15 15 15 12 12 12 8 9 9 9 9 8 8 8 12 15 15 15 15 12 12 12 4 7 7 7 7 4 4 4 4 7 7 7 7 4 4 4 0 1 1 1 1 0 0 0 1 0 1 1 1 1 0 0 0 8 9 9 9 9 8 8 8 8 9 9 9 9 8 8 8 8 9 9 9 9 8 8 8 8 9 9 9 9 8 8 8 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 2 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 26 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 3 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 24 24 27 24 4 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 28 28 28 28 28 28 28 28 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 21 28 28 28 28 28 28 28 28 21 21 21 21 21 21 21 21 5 14 14 14 14 29 29 14 14 14 14 14 14 29 29 14 14 14 14 14 14 29 29 14 14 14 14 14 14 29 29 14 14 14 14 14 14 29 29 14 14 14 14 14 14 29 29 14 14 14 14 14 14 29 29 14 14 14 14 14 14 29 29 14 14 @COLORS 0 0 0 0 1 0 155 67 2 127 0 255 3 127 0 255 4 127 0 255 5 13 138 86 6 18 132 93 7 18 132 93 8 0 155 67 9 0 155 67 10 12 140 84 11 15 135 90 12 15 135 90 13 6 146 76 14 9 143 80 15 9 143 80 16 127 0 255 17 12 140 84 18 127 0 255 19 127 0 255 20 127 0 255 21 24 125 102 22 28 120 109 23 28 120 109 24 127 0 255 25 15 135 90 26 127 0 255 27 127 0 255 28 127 0 255 29 27 121 107 30 31 116 114 31 31 116 114 32 127 0 255 33 15 135 90 34 127 0 255 35 127 0 255 36 127 0 255 37 27 121 107 38 31 116 114 39 31 116 114 40 13 138 86 41 6 146 76 42 24 125 102 43 27 121 107 44 27 121 107 45 13 138 86 46 15 135 90 47 15 135 90 48 18 132 93 49 9 143 80 50 28 120 109 51 31 116 114 52 31 116 114 53 15 135 90 54 18 132 93 55 18 132 93 56 18 132 93 57 9 143 80 58 28 120 109 59 31 116 114 60 31 116 114 61 15 135 90 62 18 132 93 63 18 132 93 @ICONS XPM /* width height num_colors chars_per_pixel */ "15 960 3 1" /* colors */ ". c #000000" "B c #009B43" "C c #7F00FF" /* icon for state 1 */ "..............." "B.............." "BB............." "BBB............" "BBBB..........." "BBBBB.........." "BBBBBB........." "BBBBBBB........" "BBBBBBBB......." "BBBBBBBBB......" "BBBBBBBBBB....." "BBBBBBBBBBB...." "BBBBBBBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 2 */ "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "......C........" "..C..C........." "..C.C.........." "..CC..........." "..CCCC........." "..............." "..............." /* icon for state 3 */ "..............." "..............." "..............." "..............." "..............." "..C............" "..CC..........." "..CCC.........." "..CC..........." "..C.C.........." "....C.........." ".....C........." ".....C........." "......C........" "......C........" /* icon for state 4 */ "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "CC............." "..CC..........." "....CC.C......." "......CCC......" ".....CCCCC....." "..............." "..............." /* icon for state 5 */ "..............." "B.............." "BB............." "BBB............" "BBBB..........." "BBBBB.........." "BBBBBB........." "BBBBBBB........" "BBBBBBCB......." "BBCBBCBBB......" "BBCBCBBBBB....." "BBCCBBBBBBB...." "BBCCCCBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 6 */ "..............." "B.............." "BB............." "BBB............" "BBBB..........." "BBCBB.........." "BBCCBB........." "BBCCCBB........" "BBCCBBBB......." "BBCBCBBBB......" "BBBBCBBBBB....." "BBBBBCBBBBB...." "BBBBBCBBBBBB..." "BBBBBBCBBBBBB.." "BBBBBBCBBBBBBB." /* icon for state 7 */ "..............." "B.............." "BB............." "BBB............" "BBBB..........." "BBBBB.........." "BBBBBB........." "BBBBBBB........" "CCBBBBBB......." "BBCCBBBBB......" "BBBBCCBCBB....." "BBBBBBCCCBB...." "BBBBBCCCCCBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 8 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBBBBBBB" "....BBBBBBBBBBB" ".....BBBBBBBBBB" "......BBBBBBBBB" ".......BBBBBBBB" "........BBBBBBB" ".........BBBBBB" "..........BBBBB" "...........BBBB" "............BBB" ".............BB" "..............B" "..............." /* icon for state 9 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBBBBBBB" "BBB.BBBBBBBBBBB" "BBBB.BBBBBBBBBB" "BBBBB.BBBBBBBBB" "BBBBBB.BBBBBBBB" "BBBBBBB.BBBBBBB" "BBBBBBBB.BBBBBB" "BBBBBBBBB.BBBBB" "BBBBBBBBBB.BBBB" "BBBBBBBBBBB.BBB" "BBBBBBBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 10 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBBBBBBB" "....BBBBBBBBBBB" ".....BBBBBBBBBB" "......BBBBBBBBB" ".......BBBBBBBB" "........BBBBBBB" "......C..BBBBBB" "..C..C....BBBBB" "..C.C......BBBB" "..CC........BBB" "..CCCC.......BB" "..............B" "..............." /* icon for state 11 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBBBBBBB" "....BBBBBBBBBBB" ".....BBBBBBBBBB" "..C...BBBBBBBBB" "..CC...BBBBBBBB" "..CCC...BBBBBBB" "..CC.....BBBBBB" "..C.C.....BBBBB" "....C......BBBB" ".....C......BBB" ".....C.......BB" "......C.......B" "......C........" /* icon for state 12 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBBBBBBB" "....BBBBBBBBBBB" ".....BBBBBBBBBB" "......BBBBBBBBB" ".......BBBBBBBB" "........BBBBBBB" "CC.......BBBBBB" "..CC......BBBBB" "....CC.C...BBBB" "......CCC...BBB" ".....CCCCC...BB" "..............B" "..............." /* icon for state 13 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBBBBBBB" "BBB.BBBBBBBBBBB" "BBBB.BBBBBBBBBB" "BBBBB.BBBBBBBBB" "BBBBBB.BBBBBBBB" "BBBBBBB.BBBBBBB" "BBBBBBCB.BBBBBB" "BBCBBCBBB.BBBBB" "BBCBCBBBBB.BBBB" "BBCCBBBBBBB.BBB" "BBCCCCBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 14 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBBBBBBB" "BBB.BBBBBBBBBBB" "BBBB.BBBBBBBBBB" "BBCBB.BBBBBBBBB" "BBCCBB.BBBBBBBB" "BBCCCBB.BBBBBBB" "BBCCBBBB.BBBBBB" "BBCBCBBBB.BBBBB" "BBBBCBBBBB.BBBB" "BBBBBCBBBBB.BBB" "BBBBBCBBBBBB.BB" "BBBBBBCBBBBBB.B" "BBBBBBCBBBBBBB." /* icon for state 15 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBBBBBBB" "BBB.BBBBBBBBBBB" "BBBB.BBBBBBBBBB" "BBBBB.BBBBBBBBB" "BBBBBB.BBBBBBBB" "BBBBBBB.BBBBBBB" "CCBBBBBB.BBBBBB" "BBCCBBBBB.BBBBB" "BBBBCCBCBB.BBBB" "BBBBBBCCCBB.BBB" "BBBBBCCCCCBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 16 */ "..............." "..............." ".........CCCC.." "...........CC.." "..........C.C.." ".........C..C.." "........C......" "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." /* icon for state 17 */ "..............." "B.............." "BB.......CCCC.." "BBB........CC.." "BBBB......C.C.." "BBBBB....C..C.." "BBBBBB..C......" "BBBBBBB........" "BBBBBBBB......." "BBBBBBBBB......" "BBBBBBBBBB....." "BBBBBBBBBBB...." "BBBBBBBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 18 */ "..............." "..............." ".........CCCC.." "...........CC.." "..........C.C.." ".........C..C.." "........C......" "..............." "......C........" "..C..C........." "..C.C.........." "..CC..........." "..CCCC........." "..............." "..............." /* icon for state 19 */ "..............." "..............." ".........CCCC.." "...........CC.." "..........C.C.." "..C......C..C.." "..CC....C......" "..CCC.........." "..CC..........." "..C.C.........." "....C.........." ".....C........." ".....C........." "......C........" "......C........" /* icon for state 20 */ "..............." "..............." ".........CCCC.." "...........CC.." "..........C.C.." ".........C..C.." "........C......" "..............." "CC............." "..CC..........." "....CC.C......." "......CCC......" ".....CCCCC....." "..............." "..............." /* icon for state 21 */ "..............." "B.............." "BB.......CCCC.." "BBB........CC.." "BBBB......C.C.." "BBBBB....C..C.." "BBBBBB..C......" "BBBBBBB........" "BBBBBBCB......." "BBCBBCBBB......" "BBCBCBBBBB....." "BBCCBBBBBBB...." "BBCCCCBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 22 */ "..............." "B.............." "BB.......CCCC.." "BBB........CC.." "BBBB......C.C.." "BBCBB....C..C.." "BBCCBB..C......" "BBCCCBB........" "BBCCBBBB......." "BBCBCBBBB......" "BBBBCBBBBB....." "BBBBBCBBBBB...." "BBBBBCBBBBBB..." "BBBBBBCBBBBBB.." "BBBBBBCBBBBBBB." /* icon for state 23 */ "..............." "B.............." "BB.......CCCC.." "BBB........CC.." "BBBB......C.C.." "BBBBB....C..C.." "BBBBBB..C......" "BBBBBBB........" "CCBBBBBB......." "BBCCBBBBB......" "BBBBCCBCBB....." "BBBBBBCCCBB...." "BBBBBCCCCCBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 24 */ "........C......" "........C......" ".........C....." ".........C....." "..........C...." "..........C.C.." "...........CC.." "..........CCC.." "...........CC.." "............C.." "..............." "..............." "..............." "..............." "..............." /* icon for state 25 */ "........C......" "B.......C......" "BB.......C....." "BBB......C....." "BBBB......C...." "BBBBB.....C.C.." "BBBBBB.....CC.." "BBBBBBB...CCC.." "BBBBBBBB...CC.." "BBBBBBBBB...C.." "BBBBBBBBBB....." "BBBBBBBBBBB...." "BBBBBBBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 26 */ "........C......" "........C......" ".........C....." ".........C....." "..........C...." "..........C.C.." "...........CC.." "..........CCC.." "......C....CC.." "..C..C......C.." "..C.C.........." "..CC..........." "..CCCC........." "..............." "..............." /* icon for state 27 */ "........C......" "........C......" ".........C....." ".........C....." "..........C...." "..C.......C.C.." "..CC.......CC.." "..CCC.....CCC.." "..CC.......CC.." "..C.C.......C.." "....C.........." ".....C........." ".....C........." "......C........" "......C........" /* icon for state 28 */ "........C......" "........C......" ".........C....." ".........C....." "..........C...." "..........C.C.." "...........CC.." "..........CCC.." "CC.........CC.." "..CC........C.." "....CC.C......." "......CCC......" ".....CCCCC....." "..............." "..............." /* icon for state 29 */ "........C......" "B.......C......" "BB.......C....." "BBB......C....." "BBBB......C...." "BBBBB.....C.C.." "BBBBBB.....CC.." "BBBBBBB...CCC.." "BBBBBBCB...CC.." "BBCBBCBBB...C.." "BBCBCBBBBB....." "BBCCBBBBBBB...." "BBCCCCBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 30 */ "........C......" "B.......C......" "BB.......C....." "BBB......C....." "BBBB......C...." "BBCBB.....C.C.." "BBCCBB.....CC.." "BBCCCBB...CCC.." "BBCCBBBB...CC.." "BBCBCBBBB...C.." "BBBBCBBBBB....." "BBBBBCBBBBB...." "BBBBBCBBBBBB..." "BBBBBBCBBBBBB.." "BBBBBBCBBBBBBB." /* icon for state 31 */ "........C......" "B.......C......" "BB.......C....." "BBB......C....." "BBBB......C...." "BBBBB.....C.C.." "BBBBBB.....CC.." "BBBBBBB...CCC.." "CCBBBBBB...CC.." "BBCCBBBBB...C.." "BBBBCCBCBB....." "BBBBBBCCCBB...." "BBBBBCCCCCBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 32 */ "..............." "..............." ".....CCCCC....." "......CCC......" ".......C.CC...." "...........CC.." ".............CC" "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." /* icon for state 33 */ "..............." "B.............." "BB...CCCCC....." "BBB...CCC......" "BBBB...C.CC...." "BBBBB......CC.." "BBBBBB.......CC" "BBBBBBB........" "BBBBBBBB......." "BBBBBBBBB......" "BBBBBBBBBB....." "BBBBBBBBBBB...." "BBBBBBBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 34 */ "..............." "..............." ".....CCCCC....." "......CCC......" ".......C.CC...." "...........CC.." ".............CC" "..............." "......C........" "..C..C........." "..C.C.........." "..CC..........." "..CCCC........." "..............." "..............." /* icon for state 35 */ "..............." "..............." ".....CCCCC....." "......CCC......" ".......C.CC...." "..C........CC.." "..CC.........CC" "..CCC.........." "..CC..........." "..C.C.........." "....C.........." ".....C........." ".....C........." "......C........" "......C........" /* icon for state 36 */ "..............." "..............." ".....CCCCC....." "......CCC......" ".......C.CC...." "...........CC.." ".............CC" "..............." "CC............." "..CC..........." "....CC.C......." "......CCC......" ".....CCCCC....." "..............." "..............." /* icon for state 37 */ "..............." "B.............." "BB...CCCCC....." "BBB...CCC......" "BBBB...C.CC...." "BBBBB......CC.." "BBBBBB.......CC" "BBBBBBB........" "BBBBBBCB......." "BBCBBCBBB......" "BBCBCBBBBB....." "BBCCBBBBBBB...." "BBCCCCBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 38 */ "..............." "B.............." "BB...CCCCC....." "BBB...CCC......" "BBBB...C.CC...." "BBCBB......CC.." "BBCCBB.......CC" "BBCCCBB........" "BBCCBBBB......." "BBCBCBBBB......" "BBBBCBBBBB....." "BBBBBCBBBBB...." "BBBBBCBBBBBB..." "BBBBBBCBBBBBB.." "BBBBBBCBBBBBBB." /* icon for state 39 */ "..............." "B.............." "BB...CCCCC....." "BBB...CCC......" "BBBB...C.CC...." "BBBBB......CC.." "BBBBBB.......CC" "BBBBBBB........" "CCBBBBBB......." "BBCCBBBBB......" "BBBBCCBCBB....." "BBBBBBCCCBB...." "BBBBBCCCCCBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 40 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBCCCCBB" "....BBBBBBBCCBB" ".....BBBBBCBCBB" "......BBBCBBCBB" ".......BCBBBBBB" "........BBBBBBB" ".........BBBBBB" "..........BBBBB" "...........BBBB" "............BBB" ".............BB" "..............B" "..............." /* icon for state 41 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBCCCCBB" "BBB.BBBBBBBCCBB" "BBBB.BBBBBCBCBB" "BBBBB.BBBCBBCBB" "BBBBBB.BCBBBBBB" "BBBBBBB.BBBBBBB" "BBBBBBBB.BBBBBB" "BBBBBBBBB.BBBBB" "BBBBBBBBBB.BBBB" "BBBBBBBBBBB.BBB" "BBBBBBBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 42 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBCCCCBB" "....BBBBBBBCCBB" ".....BBBBBCBCBB" "......BBBCBBCBB" ".......BCBBBBBB" "........BBBBBBB" "......C..BBBBBB" "..C..C....BBBBB" "..C.C......BBBB" "..CC........BBB" "..CCCC.......BB" "..............B" "..............." /* icon for state 43 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBCCCCBB" "....BBBBBBBCCBB" ".....BBBBBCBCBB" "..C...BBBCBBCBB" "..CC...BCBBBBBB" "..CCC...BBBBBBB" "..CC.....BBBBBB" "..C.C.....BBBBB" "....C......BBBB" ".....C......BBB" ".....C.......BB" "......C.......B" "......C........" /* icon for state 44 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBCCCCBB" "....BBBBBBBCCBB" ".....BBBBBCBCBB" "......BBBCBBCBB" ".......BCBBBBBB" "........BBBBBBB" "CC.......BBBBBB" "..CC......BBBBB" "....CC.C...BBBB" "......CCC...BBB" ".....CCCCC...BB" "..............B" "..............." /* icon for state 45 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBCCCCBB" "BBB.BBBBBBBCCBB" "BBBB.BBBBBCBCBB" "BBBBB.BBBCBBCBB" "BBBBBB.BCBBBBBB" "BBBBBBB.BBBBBBB" "BBBBBBCB.BBBBBB" "BBCBBCBBB.BBBBB" "BBCBCBBBBB.BBBB" "BBCCBBBBBBB.BBB" "BBCCCCBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 46 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBCCCCBB" "BBB.BBBBBBBCCBB" "BBBB.BBBBBCBCBB" "BBCBB.BBBCBBCBB" "BBCCBB.BCBBBBBB" "BBCCCBB.BBBBBBB" "BBCCBBBB.BBBBBB" "BBCBCBBBB.BBBBB" "BBBBCBBBBB.BBBB" "BBBBBCBBBBB.BBB" "BBBBBCBBBBBB.BB" "BBBBBBCBBBBBB.B" "BBBBBBCBBBBBBB." /* icon for state 47 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBCCCCBB" "BBB.BBBBBBBCCBB" "BBBB.BBBBBCBCBB" "BBBBB.BBBCBBCBB" "BBBBBB.BCBBBBBB" "BBBBBBB.BBBBBBB" "CCBBBBBB.BBBBBB" "BBCCBBBBB.BBBBB" "BBBBCCBCBB.BBBB" "BBBBBBCCCBB.BBB" "BBBBBCCCCCBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 48 */ ".BBBBBBBCBBBBBB" "..BBBBBBCBBBBBB" "...BBBBBBCBBBBB" "....BBBBBCBBBBB" ".....BBBBBCBBBB" "......BBBBCBCBB" ".......BBBBCCBB" "........BBCCCBB" ".........BBCCBB" "..........BBCBB" "...........BBBB" "............BBB" ".............BB" "..............B" "..............." /* icon for state 49 */ ".BBBBBBBCBBBBBB" "B.BBBBBBCBBBBBB" "BB.BBBBBBCBBBBB" "BBB.BBBBBCBBBBB" "BBBB.BBBBBCBBBB" "BBBBB.BBBBCBCBB" "BBBBBB.BBBBCCBB" "BBBBBBB.BBCCCBB" "BBBBBBBB.BBCCBB" "BBBBBBBBB.BBCBB" "BBBBBBBBBB.BBBB" "BBBBBBBBBBB.BBB" "BBBBBBBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 50 */ ".BBBBBBBCBBBBBB" "..BBBBBBCBBBBBB" "...BBBBBBCBBBBB" "....BBBBBCBBBBB" ".....BBBBBCBBBB" "......BBBBCBCBB" ".......BBBBCCBB" "........BBCCCBB" "......C..BBCCBB" "..C..C....BBCBB" "..C.C......BBBB" "..CC........BBB" "..CCCC.......BB" "..............B" "..............." /* icon for state 51 */ ".BBBBBBBCBBBBBB" "..BBBBBBCBBBBBB" "...BBBBBBCBBBBB" "....BBBBBCBBBBB" ".....BBBBBCBBBB" "..C...BBBBCBCBB" "..CC...BBBBCCBB" "..CCC...BBCCCBB" "..CC.....BBCCBB" "..C.C.....BBCBB" "....C......BBBB" ".....C......BBB" ".....C.......BB" "......C.......B" "......C........" /* icon for state 52 */ ".BBBBBBBCBBBBBB" "..BBBBBBCBBBBBB" "...BBBBBBCBBBBB" "....BBBBBCBBBBB" ".....BBBBBCBBBB" "......BBBBCBCBB" ".......BBBBCCBB" "........BBCCCBB" "CC.......BBCCBB" "..CC......BBCBB" "....CC.C...BBBB" "......CCC...BBB" ".....CCCCC...BB" "..............B" "..............." /* icon for state 53 */ ".BBBBBBBCBBBBBB" "B.BBBBBBCBBBBBB" "BB.BBBBBBCBBBBB" "BBB.BBBBBCBBBBB" "BBBB.BBBBBCBBBB" "BBBBB.BBBBCBCBB" "BBBBBB.BBBBCCBB" "BBBBBBB.BBCCCBB" "BBBBBBCB.BBCCBB" "BBCBBCBBB.BBCBB" "BBCBCBBBBB.BBBB" "BBCCBBBBBBB.BBB" "BBCCCCBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 54 */ ".BBBBBBBCBBBBBB" "B.BBBBBBCBBBBBB" "BB.BBBBBBCBBBBB" "BBB.BBBBBCBBBBB" "BBBB.BBBBBCBBBB" "BBCBB.BBBBCBCBB" "BBCCBB.BBBBCCBB" "BBCCCBB.BBCCCBB" "BBCCBBBB.BBCCBB" "BBCBCBBBB.BBCBB" "BBBBCBBBBB.BBBB" "BBBBBCBBBBB.BBB" "BBBBBCBBBBBB.BB" "BBBBBBCBBBBBB.B" "BBBBBBCBBBBBBB." /* icon for state 55 */ ".BBBBBBBCBBBBBB" "B.BBBBBBCBBBBBB" "BB.BBBBBBCBBBBB" "BBB.BBBBBCBBBBB" "BBBB.BBBBBCBBBB" "BBBBB.BBBBCBCBB" "BBBBBB.BBBBCCBB" "BBBBBBB.BBCCCBB" "CCBBBBBB.BBCCBB" "BBCCBBBBB.BBCBB" "BBBBCCBCBB.BBBB" "BBBBBBCCCBB.BBB" "BBBBBCCCCCBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 56 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBCCCCCBBBBB" "....BBCCCBBBBBB" ".....BBCBCCBBBB" "......BBBBBCCBB" ".......BBBBBBCC" "........BBBBBBB" ".........BBBBBB" "..........BBBBB" "...........BBBB" "............BBB" ".............BB" "..............B" "..............." /* icon for state 57 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBCCCCCBBBBB" "BBB.BBCCCBBBBBB" "BBBB.BBCBCCBBBB" "BBBBB.BBBBBCCBB" "BBBBBB.BBBBBBCC" "BBBBBBB.BBBBBBB" "BBBBBBBB.BBBBBB" "BBBBBBBBB.BBBBB" "BBBBBBBBBB.BBBB" "BBBBBBBBBBB.BBB" "BBBBBBBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 58 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBCCCCCBBBBB" "....BBCCCBBBBBB" ".....BBCBCCBBBB" "......BBBBBCCBB" ".......BBBBBBCC" "........BBBBBBB" "......C..BBBBBB" "..C..C....BBBBB" "..C.C......BBBB" "..CC........BBB" "..CCCC.......BB" "..............B" "..............." /* icon for state 59 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBCCCCCBBBBB" "....BBCCCBBBBBB" ".....BBCBCCBBBB" "..C...BBBBBCCBB" "..CC...BBBBBBCC" "..CCC...BBBBBBB" "..CC.....BBBBBB" "..C.C.....BBBBB" "....C......BBBB" ".....C......BBB" ".....C.......BB" "......C.......B" "......C........" /* icon for state 60 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBCCCCCBBBBB" "....BBCCCBBBBBB" ".....BBCBCCBBBB" "......BBBBBCCBB" ".......BBBBBBCC" "........BBBBBBB" "CC.......BBBBBB" "..CC......BBBBB" "....CC.C...BBBB" "......CCC...BBB" ".....CCCCC...BB" "..............B" "..............." /* icon for state 61 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBCCCCCBBBBB" "BBB.BBCCCBBBBBB" "BBBB.BBCBCCBBBB" "BBBBB.BBBBBCCBB" "BBBBBB.BBBBBBCC" "BBBBBBB.BBBBBBB" "BBBBBBCB.BBBBBB" "BBCBBCBBB.BBBBB" "BBCBCBBBBB.BBBB" "BBCCBBBBBBB.BBB" "BBCCCCBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 62 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBCCCCCBBBBB" "BBB.BBCCCBBBBBB" "BBBB.BBCBCCBBBB" "BBCBB.BBBBBCCBB" "BBCCBB.BBBBBBCC" "BBCCCBB.BBBBBBB" "BBCCBBBB.BBBBBB" "BBCBCBBBB.BBBBB" "BBBBCBBBBB.BBBB" "BBBBBCBBBBB.BBB" "BBBBBCBBBBBB.BB" "BBBBBBCBBBBBB.B" "BBBBBBCBBBBBBB." /* icon for state 63 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBCCCCCBBBBB" "BBB.BBCCCBBBBBB" "BBBB.BBCBCCBBBB" "BBBBB.BBBBBCCBB" "BBBBBB.BBBBBBCC" "BBBBBBB.BBBBBBB" "CCBBBBBB.BBBBBB" "BBCCBBBBB.BBBBB" "BBBBCCBCBB.BBBB" "BBBBBBCCCBB.BBB" "BBBBBCCCCCBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." /* icon for state 64 */ "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." XPM /* width height num_colors chars_per_pixel */ "7 448 3 1" /* colors */ ". c #000000" "B c #009B43" "C c #7F00FF" /* icon for state 1 */ "......." "B......" "BB....." "BBB...." "BBBB..." "BBBBB.." "BBBBBB." /* icon for state 2 */ "......." "......." "......." ".C....." ".C....." ".CCC..." "......." /* icon for state 3 */ "......." "......." "......." ".C....." ".CC...." ".C....." "......." /* icon for state 4 */ "......." "......." "......." "......." "..C...." ".CCC..." "......." /* icon for state 5 */ "......." "B......" "BB....." "BCB...." "BCBB..." "BCCCB.." "BBBBBB." /* icon for state 6 */ "......." "B......" "BB....." "BCB...." "BCCB..." "BCBBB.." "BBBBBB." /* icon for state 7 */ "......." "B......" "BB....." "BBB...." "BBCB..." "BCCCB.." "BBBBBB." /* icon for state 8 */ ".BBBBBB" "..BBBBB" "...BBBB" "....BBB" ".....BB" "......B" "......." /* icon for state 9 */ ".BBBBBB" "B.BBBBB" "BB.BBBB" "BBB.BBB" "BBBB.BB" "BBBBB.B" "BBBBBB." /* icon for state 10 */ ".BBBBBB" "..BBBBB" "...BBBB" ".C..BBB" ".C...BB" ".CCC..B" "......." /* icon for state 11 */ ".BBBBBB" "..BBBBB" "...BBBB" ".C..BBB" ".CC..BB" ".C....B" "......." /* icon for state 12 */ ".BBBBBB" "..BBBBB" "...BBBB" "....BBB" "..C..BB" ".CCC..B" "......." /* icon for state 13 */ ".BBBBBB" "B.BBBBB" "BB.BBBB" "BCB.BBB" "BCBB.BB" "BCCCB.B" "BBBBBB." /* icon for state 14 */ ".BBBBBB" "B.BBBBB" "BB.BBBB" "BCB.BBB" "BCCB.BB" "BCBBB.B" "BBBBBB." /* icon for state 15 */ ".BBBBBB" "B.BBBBB" "BB.BBBB" "BBB.BBB" "BBCB.BB" "BCCCB.B" "BBBBBB." /* icon for state 16 */ "......." "...CCC." ".....C." ".....C." "......." "......." "......." /* icon for state 17 */ "......." "B..CCC." "BB...C." "BBB..C." "BBBB..." "BBBBB.." "BBBBBB." /* icon for state 18 */ "......." "...CCC." ".....C." ".C...C." ".C....." ".CCC..." "......." /* icon for state 19 */ "......." "...CCC." ".....C." ".C...C." ".CC...." ".C....." "......." /* icon for state 20 */ "......." "...CCC." ".....C." ".....C." "..C...." ".CCC..." "......." /* icon for state 21 */ "......." "B..CCC." "BB...C." "BCB..C." "BCBB..." "BCCCB.." "BBBBBB." /* icon for state 22 */ "......." "B..CCC." "BB...C." "BCB..C." "BCCB..." "BCBBB.." "BBBBBB." /* icon for state 23 */ "......." "B..CCC." "BB...C." "BBB..C." "BBCB..." "BCCCB.." "BBBBBB." /* icon for state 24 */ "......." ".....C." "....CC." ".....C." "......." "......." "......." /* icon for state 25 */ "......." "B....C." "BB..CC." "BBB..C." "BBBB..." "BBBBB.." "BBBBBB." /* icon for state 26 */ "......." ".....C." "....CC." ".C...C." ".C....." ".CCC..." "......." /* icon for state 27 */ "......." ".....C." "....CC." ".C...C." ".CC...." ".C....." "......." /* icon for state 28 */ "......." ".....C." "....CC." ".....C." "..C...." ".CCC..." "......." /* icon for state 29 */ "......." "B....C." "BB..CC." "BCB..C." "BCBB..." "BCCCB.." "BBBBBB." /* icon for state 30 */ "......." "B....C." "BB..CC." "BCB..C." "BCCB..." "BCBBB.." "BBBBBB." /* icon for state 31 */ "......." "B....C." "BB..CC." "BBB..C." "BBCB..." "BCCCB.." "BBBBBB." /* icon for state 32 */ "......." "...CCC." "....C.." "......." "......." "......." "......." /* icon for state 33 */ "......." "B..CCC." "BB..C.." "BBB...." "BBBB..." "BBBBB.." "BBBBBB." /* icon for state 34 */ "......." "...CCC." "....C.." ".C....." ".C....." ".CCC..." "......." /* icon for state 35 */ "......." "...CCC." "....C.." ".C....." ".CC...." ".C....." "......." /* icon for state 36 */ "......." "...CCC." "....C.." "......." "..C...." ".CCC..." "......." /* icon for state 37 */ "......." "B..CCC." "BB..C.." "BCB...." "BCBB..." "BCCCB.." "BBBBBB." /* icon for state 38 */ "......." "B..CCC." "BB..C.." "BCB...." "BCCB..." "BCBBB.." "BBBBBB." /* icon for state 39 */ "......." "B..CCC." "BB..C.." "BBB...." "BBCB..." "BCCCB.." "BBBBBB." /* icon for state 40 */ ".BBBBBB" "..BCCCB" "...BBCB" "....BCB" ".....BB" "......B" "......." /* icon for state 41 */ ".BBBBBB" "B.BCCCB" "BB.BBCB" "BBB.BCB" "BBBB.BB" "BBBBB.B" "BBBBBB." /* icon for state 42 */ ".BBBBBB" "..BCCCB" "...BBCB" ".C..BCB" ".C...BB" ".CCC..B" "......." /* icon for state 43 */ ".BBBBBB" "..BCCCB" "...BBCB" ".C..BCB" ".CC..BB" ".C....B" "......." /* icon for state 44 */ ".BBBBBB" "..BCCCB" "...BBCB" "....BCB" "..C..BB" ".CCC..B" "......." /* icon for state 45 */ ".BBBBBB" "B.BCCCB" "BB.BBCB" "BCB.BCB" "BCBB.BB" "BCCCB.B" "BBBBBB." /* icon for state 46 */ ".BBBBBB" "B.BCCCB" "BB.BBCB" "BCB.BCB" "BCCB.BB" "BCBBB.B" "BBBBBB." /* icon for state 47 */ ".BBBBBB" "B.BCCCB" "BB.BBCB" "BBB.BCB" "BBCB.BB" "BCCCB.B" "BBBBBB." /* icon for state 48 */ ".BBBBBB" "..BBBCB" "...BCCB" "....BCB" ".....BB" "......B" "......." /* icon for state 49 */ ".BBBBBB" "B.BBBCB" "BB.BCCB" "BBB.BCB" "BBBB.BB" "BBBBB.B" "BBBBBB." /* icon for state 50 */ ".BBBBBB" "..BBBCB" "...BCCB" ".C..BCB" ".C...BB" ".CCC..B" "......." /* icon for state 51 */ ".BBBBBB" "..BBBCB" "...BCCB" ".C..BCB" ".CC..BB" ".C....B" "......." /* icon for state 52 */ ".BBBBBB" "..BBBCB" "...BCCB" "....BCB" "..C..BB" ".CCC..B" "......." /* icon for state 53 */ ".BBBBBB" "B.BBBCB" "BB.BCCB" "BCB.BCB" "BCBB.BB" "BCCCB.B" "BBBBBB." /* icon for state 54 */ ".BBBBBB" "B.BBBCB" "BB.BCCB" "BCB.BCB" "BCCB.BB" "BCBBB.B" "BBBBBB." /* icon for state 55 */ ".BBBBBB" "B.BBBCB" "BB.BCCB" "BBB.BCB" "BBCB.BB" "BCCCB.B" "BBBBBB." /* icon for state 56 */ ".BBBBBB" "..BCCCB" "...BCBB" "....BBB" ".....BB" "......B" "......." /* icon for state 57 */ ".BBBBBB" "B.BCCCB" "BB.BCBB" "BBB.BBB" "BBBB.BB" "BBBBB.B" "BBBBBB." /* icon for state 58 */ ".BBBBBB" "..BCCCB" "...BCBB" ".C..BBB" ".C...BB" ".CCC..B" "......." /* icon for state 59 */ ".BBBBBB" "..BCCCB" "...BCBB" ".C..BBB" ".CC..BB" ".C....B" "......." /* icon for state 60 */ ".BBBBBB" "..BCCCB" "...BCBB" "....BBB" "..C..BB" ".CCC..B" "......." /* icon for state 61 */ ".BBBBBB" "B.BCCCB" "BB.BCBB" "BCB.BBB" "BCBB.BB" "BCCCB.B" "BBBBBB." /* icon for state 62 */ ".BBBBBB" "B.BCCCB" "BB.BCBB" "BCB.BBB" "BCCB.BB" "BCBBB.B" "BBBBBB." /* icon for state 63 */ ".BBBBBB" "B.BCCCB" "BB.BCBB" "BBB.BBB" "BBCB.BB" "BCCCB.B" "BBBBBB." /* icon for state 64 */ "......." "......." "......." "......." "......." "......." "......." �������������������������������������������������golly-2.7-src/Rules/Chou-Reggia-1.rule��������������������������������������������������������������0000644�0001750�0001750�00000014252�12536111364�014437� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Chou-Reggia-1 J. A. Reggia, S.L.Armentrout, H.-H. Chou, and Y. Peng. ``Simple systems that exhibit self-directed replication.'' Science, Vol. 259, pages 1282-1287, February 1993. Transition rules from: http://necsi.org/postdocs/sayama/sdsr/java/loops.java Credits: "Self-Replicating Loops & Ant, Programmed by Eli Bachmutsky, Copyleft Feb.1999" @TABLE # rules: 174 # format: CNESWC' n_states:8 neighborhood:vonNeumann symmetries:rotate4 000000 000200 000110 004420 006301 001447 003030 046000 060400 062102 051060 010420 010360 012152 032000 401033 410011 431206 640406 660630 616600 636000 000440 000260 000330 004512 005103 001540 003100 045002 060600 061110 051710 010506 010320 030400 076010 460313 410633 600000 640106 610006 616100 636100 000420 000231 000705 006030 002020 001210 040000 045600 060100 050006 020320 010140 016000 036000 400035 466633 410100 606100 660060 610106 613001 676600 000600 000100 004040 006440 001010 001110 040160 041040 060166 050306 024200 010154 016100 036606 400313 423106 411033 606313 660460 614004 630160 500000 000540 000152 004010 006110 001030 003000 044400 060066 062030 054040 023010 010340 012000 036300 405033 410061 431033 640006 660615 616000 630360 500044 500011 230000 100111 101044 146004 143321 166611 121121 117044 300111 340066 366611 374017 200100 100044 104414 101601 141403 160414 161101 112244 130414 304011 340611 314001 703010 203010 100011 104674 101301 141424 160111 161301 111044 133001 301471 340261 314676 703330 240400 100441 106101 103011 141141 164104 120414 113011 133011 301303 340211 313023 733630 210102 100414 105011 103103 141121 166644 124104 113601 300101 307141 344011 331001 @TREE num_states=8 num_neighbors=4 num_nodes=195 1 0 1 2 3 4 0 0 7 1 0 1 0 1 4 1 6 7 1 0 1 2 3 4 5 6 7 1 0 1 0 3 5 5 6 7 1 0 4 2 3 4 4 6 7 1 6 1 2 3 4 5 6 7 1 5 1 2 3 4 5 6 7 2 0 1 2 3 4 5 2 6 1 0 1 2 1 1 5 6 7 1 0 1 2 3 4 5 1 7 1 0 1 2 1 4 5 4 7 1 2 1 2 3 4 5 6 7 1 0 1 2 3 4 5 0 7 2 1 8 2 9 10 11 12 2 1 1 1 2 3 4 5 6 7 2 2 2 2 14 2 2 2 2 1 0 3 2 1 3 5 6 7 2 3 16 2 2 2 2 12 2 1 0 4 2 3 4 5 6 7 2 4 18 2 2 2 11 18 2 1 3 1 2 3 4 5 6 7 2 5 20 2 2 2 2 2 2 1 0 1 2 3 1 5 0 7 1 0 1 2 6 4 5 6 7 1 6 1 2 3 4 5 0 7 2 2 22 2 14 23 2 24 2 2 6 2 2 2 2 2 2 2 3 7 13 15 17 19 21 25 26 2 1 8 2 16 18 20 22 2 1 0 1 2 3 0 5 6 7 1 4 1 2 3 4 5 6 7 2 29 2 2 2 2 30 12 2 1 0 1 2 3 6 5 6 7 2 2 2 2 32 18 2 2 2 1 0 1 0 3 3 5 6 0 1 0 1 2 3 3 5 6 7 2 34 35 2 35 2 2 12 2 1 0 4 2 1 4 5 6 7 2 37 18 2 2 18 11 2 2 2 5 2 2 2 2 2 2 2 1 0 1 2 3 3 5 3 7 2 2 2 11 40 18 2 2 2 2 2 2 2 2 2 2 2 2 3 28 31 33 36 38 39 41 42 2 2 32 2 2 2 2 2 2 2 2 18 2 2 2 2 2 2 3 42 42 42 44 45 42 42 42 2 3 9 14 2 2 2 14 2 2 34 2 2 2 2 2 12 2 1 0 1 2 3 4 5 6 0 2 2 2 2 49 2 2 12 2 1 6 1 2 3 3 5 6 7 2 51 2 2 2 2 2 2 2 3 47 48 42 50 45 52 42 42 2 4 10 2 2 2 2 23 2 1 7 1 2 1 4 5 6 7 1 0 1 2 7 4 5 6 7 2 37 2 2 2 55 2 2 56 1 0 1 2 1 4 5 6 7 2 2 58 2 2 2 2 58 2 1 0 1 0 3 4 5 6 7 1 0 3 2 3 4 5 6 7 2 60 61 2 2 2 2 2 2 2 2 58 2 2 2 2 2 2 3 54 57 59 42 62 42 63 63 2 5 11 2 2 11 2 2 2 3 65 39 42 52 42 42 42 42 2 2 12 2 12 18 2 24 2 2 2 2 2 2 2 2 24 2 2 2 35 2 2 2 2 5 2 2 2 18 2 2 2 2 12 2 1 0 1 2 3 4 5 5 7 2 2 71 2 12 2 2 2 2 2 2 2 2 2 2 2 12 2 3 67 68 42 69 70 42 72 73 2 2 2 2 2 58 2 2 2 2 2 18 2 2 2 2 18 2 3 26 75 42 42 76 42 42 42 4 27 43 46 53 64 66 74 77 2 1 29 2 34 37 5 2 2 2 8 2 2 2 2 2 2 2 2 9 2 2 2 2 2 2 2 2 10 2 2 2 55 2 2 58 2 11 30 2 2 2 2 2 2 2 12 12 2 12 2 2 24 2 2 2 2 2 2 56 2 2 2 3 79 80 42 81 82 83 84 85 2 8 2 2 35 18 2 2 2 3 87 42 42 42 42 42 42 42 2 2 2 2 2 2 2 11 2 2 58 2 2 2 2 2 2 2 2 2 11 2 2 2 2 2 2 3 89 42 42 42 90 91 42 42 2 16 2 32 35 2 2 40 2 2 35 2 2 2 2 2 2 2 2 32 2 2 2 2 2 2 2 3 93 94 95 42 42 42 94 42 2 18 2 18 2 18 2 18 2 2 18 2 2 2 2 2 2 2 2 18 2 18 2 2 2 2 2 2 61 2 18 2 2 2 2 2 3 97 98 99 98 100 42 98 98 2 20 30 2 2 11 2 2 2 3 102 42 91 42 42 42 42 42 2 22 12 2 12 2 2 2 2 2 71 2 2 2 2 2 58 2 3 104 42 42 42 90 42 105 42 2 58 2 2 2 2 2 23 2 3 42 42 42 42 107 42 42 42 4 86 88 92 96 101 103 106 108 2 14 32 2 2 2 2 2 2 3 42 75 42 110 45 42 75 42 2 2 2 2 2 2 11 2 2 2 2 2 2 2 18 2 2 2 3 33 112 113 42 42 42 42 42 3 42 42 42 42 45 42 42 42 3 42 42 42 42 42 42 42 42 2 11 2 2 2 2 2 2 2 3 42 117 42 42 42 42 42 42 4 111 114 115 116 115 116 118 116 2 3 34 2 2 2 51 2 2 2 16 35 32 2 2 2 35 2 2 2 35 2 49 2 2 2 2 2 12 12 2 12 2 2 5 2 3 120 121 42 122 42 42 123 42 2 9 2 2 2 18 2 2 2 3 125 42 42 42 42 42 42 42 2 14 2 2 2 2 2 2 2 3 127 95 42 42 42 42 42 42 2 2 2 2 49 2 2 2 2 2 49 2 2 2 2 2 49 2 3 129 94 42 130 42 42 129 42 2 14 12 2 12 2 2 2 2 2 40 2 2 2 2 2 2 2 2 12 2 2 2 2 2 35 2 3 132 133 42 129 42 42 134 42 4 124 126 128 131 116 116 135 116 2 4 37 2 2 60 2 2 2 2 18 18 18 18 61 2 18 18 2 11 11 2 2 2 2 2 2 2 18 2 2 2 2 2 12 18 3 137 138 42 42 45 139 140 42 2 10 2 58 2 61 2 58 58 2 55 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 23 3 142 42 113 42 143 42 144 90 2 18 2 18 2 18 2 2 2 3 42 146 42 42 42 42 42 42 2 2 55 2 2 2 2 2 2 3 148 98 42 42 42 42 42 42 2 23 2 58 2 2 2 2 2 2 2 2 2 2 2 2 18 2 3 150 98 42 42 42 42 151 42 2 2 56 2 2 2 2 2 2 3 153 42 42 42 42 42 42 42 4 141 145 147 116 149 116 152 154 2 5 5 2 51 2 2 2 2 2 20 2 2 2 2 2 2 2 3 156 157 42 42 42 42 42 42 2 30 2 11 2 2 2 2 2 3 117 159 42 42 42 42 42 42 3 117 117 42 42 42 42 42 42 4 158 160 116 116 161 116 116 116 2 22 2 2 2 58 2 71 2 2 14 40 2 2 2 2 12 2 2 23 18 2 2 2 2 2 2 2 24 2 2 2 2 2 2 2 3 42 163 91 164 165 42 166 42 2 12 2 2 35 18 2 71 2 2 12 2 2 2 2 2 2 2 2 24 2 2 2 2 2 58 2 3 168 169 42 169 42 42 170 42 3 42 42 42 42 90 42 42 42 2 12 2 2 2 2 2 12 2 2 12 2 2 49 2 2 2 2 2 5 2 2 2 2 2 35 2 3 173 169 42 174 42 42 175 42 2 12 2 2 2 2 2 18 2 2 18 23 2 2 2 2 2 2 3 98 42 42 42 42 42 177 178 2 24 24 2 5 12 2 2 12 2 2 2 2 2 2 2 58 2 2 2 2 2 2 2 2 35 2 2 2 58 2 35 18 2 2 2 3 180 181 42 182 151 42 183 42 3 42 42 42 42 42 42 169 42 4 167 171 172 176 179 116 184 185 3 26 75 42 42 42 42 73 42 2 56 2 2 2 2 2 2 2 3 113 42 42 42 188 42 42 42 3 63 42 42 42 42 42 42 42 2 2 2 2 2 23 2 2 2 3 113 191 42 42 42 42 42 42 4 187 189 116 116 190 116 192 116 5 78 109 119 136 155 162 186 193 @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Banks-III.rule������������������������������������������������������������������0000644�0001750�0001750�00000001533�12536111364�013653� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Banks-III Edwin Roger Banks, PhD Thesis 1971 Two-state, nine-neighbor CA for a universal computer (Appendix III) NOTE: The rules listed in the thesis start at the corner, not at N,S,E or W. We have converted them to Golly's format. http://www.bottomlayer.com/bottom/banks/banks_commentary.htm @TABLE # Format: C,N,NE,E,SE,S,SW,W,NW,C' n_states:2 neighborhood:Moore symmetries:rotate4reflect # transitions for signal propagation: 1111111010 1011000010 0111010111 0101000111 # transitions for echo: 0010000011 0111010011 0111110011 1101010100 1011000010 1010000010 0101010111 1100000010 0111110001 1110100010 0101000001 0101010001 1011010010 0101010011 # transitions for junction properties: 0111111111 0111111101 1010011010 1011001010 0101010111 1110110010 1111101011 0101010111 1100011010 1101101010 1010100010 0110110111 0111011011 0110111011 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Banks-I.rule��������������������������������������������������������������������0000644�0001750�0001750�00000000446�12536111364�013433� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Banks-I Edwin Roger Banks, PhD Thesis 1971 Two-state, five-neighbor CA for a universal computer (Appendix I) http://www.bottomlayer.com/bottom/banks/banks_commentary.htm @TABLE # Format: C,N,E,S,W,C' n_states:2 neighborhood:vonNeumann symmetries:rotate4reflect 111000 011101 011111 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Byl-Loop.rule�������������������������������������������������������������������0000644�0001750�0001750�00000010432�12536111364�013640� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Byl-Loop J. Byl. "Self-Reproduction in small cellular automata." Physica D, Vol. 34, pages 295-299, 1989. Transition rules from: http://necsi.org/postdocs/sayama/sdsr/java/loops.java Credits: "Self-Replicating Loops & Ant, Programmed by Eli Bachmutsky, Copyleft Feb.1999" @TABLE # rules: 145 # format: CNESWC' n_states:6 neighborhood:vonNeumann symmetries:rotate4 000000 000010 000031 000420 000110 000120 000311 000330 000320 000200 000242 000233 004330 005120 001400 001120 001305 001310 001320 003020 003400 003420 003120 002040 002050 002010 002020 002420 002500 002520 002200 002250 002220 040000 050000 050500 010052 010022 010400 010100 020055 400233 405235 401233 442024 452020 415233 411233 412024 412533 432024 421433 422313 501302 502230 540022 542002 512024 530025 520025 520442 523242 522020 100000 100010 100033 100330 101233 103401 103244 111244 113244 112404 133244 121351 123444 123543 122414 122434 300100 300300 300211 300233 304233 301100 301211 303211 303233 302233 344233 343233 351202 353215 314233 311233 313251 313211 312211 335223 333211 320533 324433 325415 321433 321511 321321 323411 200000 200042 200032 200022 200442 200515 200112 200122 200342 200332 200242 200212 201502 203202 202302 244022 245022 242042 242022 254202 255042 252025 210042 214022 215022 #212052 this line appears to be inserted through an error - correct transition is the one below 212055 212022 230052 234022 235002 235022 232042 232022 220042 220020 220533 221552 @TREE num_states=6 num_neighbors=4 num_nodes=152 1 0 0 0 3 4 5 1 0 0 2 0 4 5 1 0 1 2 3 4 5 1 1 3 2 0 4 5 2 0 1 2 3 2 2 1 0 1 2 0 4 5 1 5 1 2 3 4 2 2 1 5 2 6 2 2 1 2 1 2 1 4 5 1 0 1 0 3 4 5 1 3 1 2 3 3 5 1 2 1 2 3 4 2 2 2 8 9 10 11 2 1 1 1 2 3 4 5 1 0 0 2 3 4 5 2 3 13 2 14 2 2 1 0 1 2 3 4 2 2 2 2 16 2 2 2 1 2 1 5 3 4 5 1 5 1 2 3 4 5 2 2 18 19 2 2 2 3 4 7 12 15 17 20 2 1 5 8 13 2 18 1 0 1 2 1 4 5 2 2 2 23 2 2 2 2 2 2 2 2 2 2 3 22 24 25 24 25 25 2 2 2 9 2 16 19 1 0 1 2 3 4 4 1 0 1 2 3 4 0 1 0 1 5 3 0 5 2 2 28 29 2 2 30 2 2 2 2 2 16 2 1 0 1 5 2 4 5 1 0 1 3 3 4 5 2 2 33 2 34 2 2 3 27 25 31 25 32 35 2 3 6 10 14 2 2 1 0 3 2 3 3 5 2 2 2 38 2 2 2 2 2 2 29 2 2 2 1 0 1 2 3 5 5 2 2 2 41 2 2 2 3 37 39 40 25 25 42 2 2 2 11 2 2 2 1 0 4 2 3 4 5 2 2 2 45 2 2 2 3 44 46 25 46 25 25 3 25 25 25 25 25 25 4 21 26 36 43 47 48 2 1 2 2 2 2 2 2 5 2 2 2 2 2 2 2 23 2 38 45 2 2 6 2 2 2 2 2 3 50 51 52 53 25 25 1 0 1 2 3 3 5 2 2 2 23 55 45 2 3 51 25 56 24 25 25 2 8 23 2 23 2 2 2 2 2 23 23 2 2 2 28 2 2 2 2 2 2 2 2 2 55 2 2 1 0 1 2 5 4 5 2 2 23 2 62 2 2 3 58 59 60 59 61 63 2 13 2 2 2 2 2 2 2 2 55 2 2 2 2 2 2 55 2 2 55 3 65 66 67 25 25 66 2 2 2 45 23 2 62 3 25 46 69 46 25 25 2 18 2 2 2 2 2 2 33 23 2 2 2 2 3 71 25 72 24 25 25 4 54 57 64 68 70 73 2 8 2 28 2 2 2 2 9 2 29 29 2 2 2 10 2 2 2 2 2 2 11 2 2 2 2 2 2 2 2 30 2 2 2 3 25 75 76 77 78 79 2 2 2 28 2 2 33 2 23 2 2 2 2 23 2 2 23 2 55 45 2 2 38 55 2 2 23 2 2 45 45 2 2 2 2 2 2 2 2 55 62 2 3 81 82 83 84 85 86 2 9 2 29 2 2 2 2 2 23 2 23 2 2 2 29 2 2 2 2 2 2 29 55 2 2 2 2 2 2 45 2 45 2 2 3 88 89 90 91 92 25 2 2 2 2 2 2 34 2 23 23 2 23 55 62 2 2 23 2 2 45 2 2 45 45 16 45 2 2 2 2 23 2 2 2 2 3 94 95 96 25 97 98 2 16 2 2 2 16 2 1 0 3 2 3 4 5 2 2 2 16 2 45 101 3 100 25 25 102 25 25 2 19 2 30 2 2 2 2 41 55 2 2 2 2 3 104 25 25 105 25 25 4 80 87 93 99 103 106 2 3 2 2 2 2 2 2 14 2 2 2 2 2 3 108 65 96 109 25 25 2 2 23 23 2 45 23 3 53 25 111 24 25 25 2 10 38 29 2 2 41 2 2 55 55 2 2 55 2 2 2 2 2 101 2 3 113 114 32 25 96 115 3 109 25 96 25 25 25 2 2 55 45 2 2 2 3 25 25 118 46 25 25 2 34 62 2 2 2 2 3 25 66 120 25 25 25 4 110 112 116 117 119 121 2 16 2 2 2 2 2 3 25 25 123 25 17 25 3 25 25 25 66 25 25 2 11 45 2 45 2 2 2 2 45 45 45 2 2 2 2 2 2 16 2 2 2 2 2 45 45 2 2 3 126 127 128 129 25 25 3 25 24 25 25 46 25 2 16 2 2 45 2 2 3 25 25 132 25 25 25 2 2 2 62 2 2 2 2 2 2 2 101 2 2 3 25 134 135 25 25 25 4 124 125 130 131 133 136 2 18 2 33 2 2 2 2 19 2 2 41 2 2 2 2 2 34 2 2 2 3 25 138 139 140 25 25 3 25 24 61 134 25 25 2 2 2 2 23 2 2 2 30 2 2 2 2 2 2 2 55 2 2 2 2 2 2 62 2 2 2 2 3 25 143 144 145 146 25 2 2 2 101 2 2 2 3 25 25 25 25 148 25 4 141 142 147 149 48 48 5 49 74 107 122 137 150 @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Turmite_121181121020.rule�������������������������������������������������������0000644�0001750�0001750�00000065016�12536111364�015127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Turmite_121181121020 @TREE num_states=18 num_neighbors=4 num_nodes=27 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 6 14 14 14 14 14 14 14 14 14 14 14 14 14 6 6 6 6 1 2 10 10 10 10 10 10 10 10 10 10 10 10 10 2 2 2 2 2 0 0 0 0 0 1 0 0 0 1 0 1 0 0 0 0 0 2 1 9 17 17 17 17 17 17 17 17 17 17 17 17 17 9 9 9 9 2 4 4 4 4 4 0 4 4 4 0 4 0 4 4 4 4 4 0 1 5 13 13 13 13 13 13 13 13 13 13 13 13 13 5 5 5 5 2 6 6 6 6 6 0 6 6 6 0 6 0 6 6 6 6 6 0 3 3 3 3 3 5 3 3 3 5 3 5 3 3 3 3 3 7 3 1 7 15 15 15 15 15 15 15 15 15 15 15 15 15 7 7 7 7 2 9 9 9 9 9 0 9 9 9 0 9 0 9 9 9 9 9 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 10 10 10 10 11 10 10 10 11 10 11 10 10 10 10 10 11 10 1 3 11 11 11 11 11 11 11 11 11 11 11 11 11 3 3 3 3 2 13 13 13 13 13 0 13 13 13 0 13 0 13 13 13 13 13 0 3 14 14 14 14 11 14 14 14 11 14 11 14 14 14 14 14 11 14 4 8 8 12 8 8 8 12 8 8 8 8 8 12 8 15 8 8 8 1 8 16 16 16 16 16 16 16 16 16 16 16 16 16 8 8 8 8 2 17 17 17 17 17 0 17 17 17 0 17 0 17 17 17 17 17 0 3 18 18 18 18 11 18 18 18 11 18 11 18 18 18 18 18 11 18 3 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 4 19 19 20 19 19 19 20 19 19 19 19 19 20 19 20 19 19 19 1 4 12 12 12 12 12 12 12 12 12 12 12 12 12 4 4 4 4 2 22 22 22 22 22 0 22 22 22 0 22 0 22 22 22 22 22 0 3 23 23 23 23 11 23 23 23 11 23 11 23 23 23 23 23 11 23 4 24 24 20 24 24 24 20 24 24 24 24 24 20 24 20 24 24 24 5 16 16 16 21 16 16 16 21 16 16 16 16 16 21 16 25 16 16 @COLORS 0 0 0 0 1 0 155 67 2 131 12 251 3 131 12 251 4 131 12 251 5 131 12 251 6 132 132 132 7 132 132 132 8 132 132 132 9 132 132 132 10 23 130 99 11 23 130 99 12 23 130 99 13 23 130 99 14 23 151 78 15 23 151 78 16 23 151 78 17 23 151 78 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 527 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ "..............................." ".......C...............C......." ".......C...............C......." "........C.............C........" "........C.............C........" ".........CCCIICCCIICCC........." "............IICCCII............" ".............CCCCC............." "........CC....CCC....CC........" ".........CC...CCC...CC........." "..........CC..CCC..CC.........." "...........CCCCCCCCC..........." "............CCCCCCC............" "..............CCC.............." "..............CCC.............." "...........CCCCCCCCC..........." "..........CCCCCCCCCCC.........." ".........CC...CCC...CC........." "........CC....CCC....CC........" ".............CCCCC............." "............CCCCCCC............" "...........CC.CCC.CC..........." "..........CC..CCC..CC.........." ".........CC...CCC...CC........." "........CC...ECCCE...CC........" ".............CCCCC............." ".............CCCCC............." ".............ECCCE............." "..............CCC.............." "..............................." "..............................." /* icon for state 3 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................CC." "......C.....C.........C...CC..." "......CC....CC.......CC..C....." ".......CC....CC.....CC...C....." "........CC....CC...CC....C....." ".........CC...CC..CC....II....." "...ECCE...CC..CC..CC...CII....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "...ECCE...CC..CC..CC...CII....." ".........CC...CC..CC....II....." "........CC....CC...CC....C....." ".......CC....CC.....CC...C....." "......CC....CC.......CC..C....." "......C.....C.........C...CC..." "............................CC." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." "..............CCC.............." ".............ECCCE............." ".............CCCCC............." ".............CCCCC............." "........CC...ECCCE...CC........" ".........CC...CCC...CC........." "..........CC..CCC..CC.........." "...........CC.CCC.CC..........." "............CCCCCCC............" ".............CCCCC............." "........CC....CCC....CC........" ".........CC...CCC...CC........." "..........CCCCCCCCCCC.........." "...........CCCCCCCCC..........." "..............CCC.............." "..............CCC.............." "............CCCCCCC............" "...........CCCCCCCCC..........." "..........CC..CCC..CC.........." ".........CC...CCC...CC........." "........CC....CCC....CC........" ".............CCCCC............." "............IICCCII............" ".........CCCIICCCIICCC........." "........C.............C........" "........C.............C........" ".......C...............C......." ".......C...............C......." "..............................." /* icon for state 5 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".CC............................" "...CC...C.........C.....C......" ".....C..CC.......CC....CC......" ".....C...CC.....CC....CC......." ".....C....CC...CC....CC........" ".....II....CC..CC...CC........." ".....IIC...CC..CC..CC...ECCE..." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....IIC...CC..CC..CC...ECCE..." ".....II....CC..CC...CC........." ".....C....CC...CC....CC........" ".....C...CC.....CC....CC......." ".....C..CC.......CC....CC......" "...CC...C.........C.....C......" ".CC............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 6 */ "..............................." ".......D...............D......." ".......D...............D......." "........D.............D........" "........D.............D........" ".........DDDIIDDDIIDDD........." "............IIDDDII............" ".............DDDDD............." "........DD....DDD....DD........" ".........DD...DDD...DD........." "..........DD..DDD..DD.........." "...........DDDDDDDDD..........." "............DDDDDDD............" "..............DDD.............." "..............DDD.............." "...........DDDDDDDDD..........." "..........DDDDDDDDDDD.........." ".........DD...DDD...DD........." "........DD....DDD....DD........" ".............DDDDD............." "............DDDDDDD............" "...........DD.DDD.DD..........." "..........DD..DDD..DD.........." ".........DD...DDD...DD........." "........DD...FDDDF...DD........" ".............DDDDD............." ".............DDDDD............." ".............FDDDF............." "..............DDD.............." "..............................." "..............................." /* icon for state 7 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................DD." "......D.....D.........D...DD..." "......DD....DD.......DD..D....." ".......DD....DD.....DD...D....." "........DD....DD...DD....D....." ".........DD...DD..DD....II....." "...FDDF...DD..DD..DD...DII....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "...FDDF...DD..DD..DD...DII....." ".........DD...DD..DD....II....." "........DD....DD...DD....D....." ".......DD....DD.....DD...D....." "......DD....DD.......DD..D....." "......D.....D.........D...DD..." "............................DD." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 8 */ "..............................." "..............................." "..............DDD.............." ".............FDDDF............." ".............DDDDD............." ".............DDDDD............." "........DD...FDDDF...DD........" ".........DD...DDD...DD........." "..........DD..DDD..DD.........." "...........DD.DDD.DD..........." "............DDDDDDD............" ".............DDDDD............." "........DD....DDD....DD........" ".........DD...DDD...DD........." "..........DDDDDDDDDDD.........." "...........DDDDDDDDD..........." "..............DDD.............." "..............DDD.............." "............DDDDDDD............" "...........DDDDDDDDD..........." "..........DD..DDD..DD.........." ".........DD...DDD...DD........." "........DD....DDD....DD........" ".............DDDDD............." "............IIDDDII............" ".........DDDIIDDDIIDDD........." "........D.............D........" "........D.............D........" ".......D...............D......." ".......D...............D......." "..............................." /* icon for state 9 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".DD............................" "...DD...D.........D.....D......" ".....D..DD.......DD....DD......" ".....D...DD.....DD....DD......." ".....D....DD...DD....DD........" ".....II....DD..DD...DD........." ".....IID...DD..DD..DD...FDDF..." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....IID...DD..DD..DD...FDDF..." ".....II....DD..DD...DD........." ".....D....DD...DD....DD........" ".....D...DD.....DD....DD......." ".....D..DD.......DD....DD......" "...DD...D.........D.....D......" ".DD............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 10 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAAACCCIICCCIICCCAAAAAAAAA" "AAAAAAAAAAAAIICCCIIAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAACCCCCCCCCCCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAACCACCCACCAAAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAGCCCGAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAAGCCCGAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 11 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAACCA" "AAAAAACAAAAACAAAAAAAAACAAACCAAA" "AAAAAACCAAAACCAAAAAAACCAACAAAAA" "AAAAAAACCAAAACCAAAAACCAAACAAAAA" "AAAAAAAACCAAAACCAAACCAAAACAAAAA" "AAAAAAAAACCAAACCAACCAAAAIIAAAAA" "AAAGCCGAAACCAACCAACCAAACIIAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AAAGCCGAAACCAACCAACCAAACIIAAAAA" "AAAAAAAAACCAAACCAACCAAAAIIAAAAA" "AAAAAAAACCAAAACCAAACCAAAACAAAAA" "AAAAAAACCAAAACCAAAAACCAAACAAAAA" "AAAAAACCAAAACCAAAAAAACCAACAAAAA" "AAAAAACAAAAACAAAAAAAAACAAACCAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAACCA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 12 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAGCCCGAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAGCCCGAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAAAACCACCCACCAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCCCCCCCCCCAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAIICCCIIAAAAAAAAAAAA" "AAAAAAAAACCCIICCCIICCCAAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 13 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "ACCAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAACCAAACAAAAAAAAACAAAAACAAAAAA" "AAAAACAACCAAAAAAACCAAAACCAAAAAA" "AAAAACAAACCAAAAACCAAAACCAAAAAAA" "AAAAACAAAACCAAACCAAAACCAAAAAAAA" "AAAAAIIAAAACCAACCAAACCAAAAAAAAA" "AAAAAIICAAACCAACCAACCAAAGCCGAAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAAIICAAACCAACCAACCAAAGCCGAAA" "AAAAAIIAAAACCAACCAAACCAAAAAAAAA" "AAAAACAAAACCAAACCAAAACCAAAAAAAA" "AAAAACAAACCAAAAACCAAAACCAAAAAAA" "AAAAACAACCAAAAAAACCAAAACCAAAAAA" "AAACCAAACAAAAAAAAACAAAAACAAAAAA" "ACCAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 14 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAAADDDIIDDDIIDDDAAAAAAAAA" "AAAAAAAAAAAAIIDDDIIAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAADDDDDDDDDDDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAADDADDDADDAAAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAHDDDHAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAAHDDDHAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 15 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAADDA" "AAAAAADAAAAADAAAAAAAAADAAADDAAA" "AAAAAADDAAAADDAAAAAAADDAADAAAAA" "AAAAAAADDAAAADDAAAAADDAAADAAAAA" "AAAAAAAADDAAAADDAAADDAAAADAAAAA" "AAAAAAAAADDAAADDAADDAAAAIIAAAAA" "AAAHDDHAAADDAADDAADDAAADIIAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AAAHDDHAAADDAADDAADDAAADIIAAAAA" "AAAAAAAAADDAAADDAADDAAAAIIAAAAA" "AAAAAAAADDAAAADDAAADDAAAADAAAAA" "AAAAAAADDAAAADDAAAAADDAAADAAAAA" "AAAAAADDAAAADDAAAAAAADDAADAAAAA" "AAAAAADAAAAADAAAAAAAAADAAADDAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAADDA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 16 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAHDDDHAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAHDDDHAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAAAADDADDDADDAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDDDDDDDDDDAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAIIDDDIIAAAAAAAAAAAA" "AAAAAAAAADDDIIDDDIIDDDAAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 17 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "ADDAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAADDAAADAAAAAAAAADAAAAADAAAAAA" "AAAAADAADDAAAAAAADDAAAADDAAAAAA" "AAAAADAAADDAAAAADDAAAADDAAAAAAA" "AAAAADAAAADDAAADDAAAADDAAAAAAAA" "AAAAAIIAAAADDAADDAAADDAAAAAAAAA" "AAAAAIIDAAADDAADDAADDAAAHDDHAAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAAIIDAAADDAADDAADDAAAHDDHAAA" "AAAAAIIAAAADDAADDAAADDAAAAAAAAA" "AAAAADAAAADDAAADDAAAADDAAAAAAAA" "AAAAADAAADDAAAAADDAAAADDAAAAAAA" "AAAAADAADDAAAAAAADDAAAADDAAAAAA" "AAADDAAADAAAAAAAAADAAAAADAAAAAA" "ADDAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "15 255 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "....C.....C...." ".....C...C....." "......ICI......" "...C..CCC..C..." "....C..C..C...." ".....CCCCC....." ".......C......." "....CCCCCCC...." "...C...C...C..." ".....CCCCC....." "....C..C..C...." "...C..ECE..C..." "......CCC......" "......ECE......" "..............." /* icon for state 3 */ "..............." "..............." "..............." "...C..C....C..." "....C..C..C...C" ".....C.C.C...C." ".ECE.C.C.C.CI.." ".CCCCCCCCCCCC.." ".ECE.C.C.C.CI.." ".....C.C.C...C." "....C..C..C...C" "...C..C....C..." "..............." "..............." "..............." /* icon for state 4 */ "..............." "......ECE......" "......CCC......" "...C..ECE..C..." "....C..C..C...." ".....CCCCC....." "...C...C...C..." "....CCCCCCC...." ".......C......." ".....CCCCC....." "....C..C..C...." "...C..CCC..C..." "......ICI......" ".....C...C....." "....C.....C...." /* icon for state 5 */ "..............." "..............." "..............." "...C....C..C..." "C...C..C..C...." ".C...C.C.C....." "..IC.C.C.C.ECE." "..CCCCCCCCCCCC." "..IC.C.C.C.ECE." ".C...C.C.C....." "C...C..C..C...." "...C....C..C..." "..............." "..............." "..............." /* icon for state 6 */ "....D.....D...." ".....D...D....." "......IDI......" "...D..DDD..D..." "....D..D..D...." ".....DDDDD....." ".......D......." "....DDDDDDD...." "...D...D...D..." ".....DDDDD....." "....D..D..D...." "...D..FDF..D..." "......DDD......" "......FDF......" "..............." /* icon for state 7 */ "..............." "..............." "..............." "...D..D....D..." "....D..D..D...D" ".....D.D.D...D." ".FDF.D.D.D.DI.." ".DDDDDDDDDDDD.." ".FDF.D.D.D.DI.." ".....D.D.D...D." "....D..D..D...D" "...D..D....D..." "..............." "..............." "..............." /* icon for state 8 */ "..............." "......FDF......" "......DDD......" "...D..FDF..D..." "....D..D..D...." ".....DDDDD....." "...D...D...D..." "....DDDDDDD...." ".......D......." ".....DDDDD....." "....D..D..D...." "...D..DDD..D..." "......IDI......" ".....D...D....." "....D.....D...." /* icon for state 9 */ "..............." "..............." "..............." "...D....D..D..." "D...D..D..D...." ".D...D.D.D....." "..ID.D.D.D.FDF." "..DDDDDDDDDDDD." "..ID.D.D.D.FDF." ".D...D.D.D....." "D...D..D..D...." "...D....D..D..." "..............." "..............." "..............." /* icon for state 10 */ "AAAACAAAAACAAAA" "AAAAACAAACAAAAA" "AAAAAAICIAAAAAA" "AAACAACCCAACAAA" "AAAACAACAACAAAA" "AAAAACCCCCAAAAA" "AAAAAAACAAAAAAA" "AAAACCCCCCCAAAA" "AAACAAACAAACAAA" "AAAAACCCCCAAAAA" "AAAACAACAACAAAA" "AAACAAGCGAACAAA" "AAAAAACCCAAAAAA" "AAAAAAGCGAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 11 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAACAACAAAACAAA" "AAAACAACAACAAAC" "AAAAACACACAAACA" "AGCGACACACACIAA" "ACCCCCCCCCCCCAA" "AGCGACACACACIAA" "AAAAACACACAAACA" "AAAACAACAACAAAC" "AAACAACAAAACAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 12 */ "AAAAAAAAAAAAAAA" "AAAAAAGCGAAAAAA" "AAAAAACCCAAAAAA" "AAACAAGCGAACAAA" "AAAACAACAACAAAA" "AAAAACCCCCAAAAA" "AAACAAACAAACAAA" "AAAACCCCCCCAAAA" "AAAAAAACAAAAAAA" "AAAAACCCCCAAAAA" "AAAACAACAACAAAA" "AAACAACCCAACAAA" "AAAAAAICIAAAAAA" "AAAAACAAACAAAAA" "AAAACAAAAACAAAA" /* icon for state 13 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAACAAAACAACAAA" "CAAACAACAACAAAA" "ACAAACACACAAAAA" "AAICACACACAGCGA" "AACCCCCCCCCCCCA" "AAICACACACAGCGA" "ACAAACACACAAAAA" "CAAACAACAACAAAA" "AAACAAAACAACAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 14 */ "AAAADAAAAADAAAA" "AAAAADAAADAAAAA" "AAAAAAIDIAAAAAA" "AAADAADDDAADAAA" "AAAADAADAADAAAA" "AAAAADDDDDAAAAA" "AAAAAAADAAAAAAA" "AAAADDDDDDDAAAA" "AAADAAADAAADAAA" "AAAAADDDDDAAAAA" "AAAADAADAADAAAA" "AAADAAHDHAADAAA" "AAAAAADDDAAAAAA" "AAAAAAHDHAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 15 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAADAADAAAADAAA" "AAAADAADAADAAAD" "AAAAADADADAAADA" "AHDHADADADADIAA" "ADDDDDDDDDDDDAA" "AHDHADADADADIAA" "AAAAADADADAAADA" "AAAADAADAADAAAD" "AAADAADAAAADAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 16 */ "AAAAAAAAAAAAAAA" "AAAAAAHDHAAAAAA" "AAAAAADDDAAAAAA" "AAADAAHDHAADAAA" "AAAADAADAADAAAA" "AAAAADDDDDAAAAA" "AAADAAADAAADAAA" "AAAADDDDDDDAAAA" "AAAAAAADAAAAAAA" "AAAAADDDDDAAAAA" "AAAADAADAADAAAA" "AAADAADDDAADAAA" "AAAAAAIDIAAAAAA" "AAAAADAAADAAAAA" "AAAADAAAAADAAAA" /* icon for state 17 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAADAAAADAADAAA" "DAAADAADAADAAAA" "ADAAADADADAAAAA" "AAIDADADADAHDHA" "AADDDDDDDDDDDDA" "AAIDADADADAHDHA" "ADAAADADADAAAAA" "DAAADAADAADAAAA" "AAADAAAADAADAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "7 119 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ ".C...C." "..ICI.." "...C..." ".CCCCC." "...C..." ".CCCCC." "...C..." /* icon for state 3 */ "......." ".C.C..C" ".C.C.I." "CCCCCC." ".C.C.I." ".C.C..C" "......." /* icon for state 4 */ "...C..." ".CCCCC." "...C..." ".CCCCC." "...C..." "..ICI.." ".C...C." /* icon for state 5 */ "......." "C..C.C." ".I.C.C." ".CCCCCC" ".I.C.C." "C..C.C." "......." /* icon for state 6 */ ".D...D." "..IDI.." "...D..." ".DDDDD." "...D..." ".DDDDD." "...D..." /* icon for state 7 */ "......." ".D.D..D" ".D.D.I." "DDDDDD." ".D.D.I." ".D.D..D" "......." /* icon for state 8 */ "...D..." ".DDDDD." "...D..." ".DDDDD." "...D..." "..IDI.." ".D...D." /* icon for state 9 */ "......." "D..D.D." ".I.D.D." ".DDDDDD" ".I.D.D." "D..D.D." "......." /* icon for state 10 */ "ACAAACA" "AAICIAA" "AAACAAA" "ACCCCCA" "AAACAAA" "ACCCCCA" "AAACAAA" /* icon for state 11 */ "AAAAAAA" "ACACAAC" "ACACAIA" "CCCCCCA" "ACACAIA" "ACACAAC" "AAAAAAA" /* icon for state 12 */ "AAACAAA" "ACCCCCA" "AAACAAA" "ACCCCCA" "AAACAAA" "AAICIAA" "ACAAACA" /* icon for state 13 */ "AAAAAAA" "CAACACA" "AIACACA" "ACCCCCC" "AIACACA" "CAACACA" "AAAAAAA" /* icon for state 14 */ "ADAAADA" "AAIDIAA" "AAADAAA" "ADDDDDA" "AAADAAA" "ADDDDDA" "AAADAAA" /* icon for state 15 */ "AAAAAAA" "ADADAAD" "ADADAIA" "DDDDDDA" "ADADAIA" "ADADAAD" "AAAAAAA" /* icon for state 16 */ "AAADAAA" "ADDDDDA" "AAADAAA" "ADDDDDA" "AAADAAA" "AAIDIAA" "ADAAADA" /* icon for state 17 */ "AAAAAAA" "DAADADA" "AIADADA" "ADDDDDD" "AIADADA" "DAADADA" "AAAAAAA" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Devore.rule���������������������������������������������������������������������0000644�0001750�0001750�00000014426�12536111364�013436� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Devore Devore's cellular automaton (a variation on Codd's CA). See patterns in Patterns/Devore/. Devore,J. and Hightower,R. (1992) The Devore variation of the Codd self-replicating computer, Third Workshop on Artificial Life, Santa Fe, New Mexico, Original work carried out in the 1970s though apparently never published. Reported by John R. Koza, "Artificial life: spontaneous emergence of self-replicating and evolutionary self-improving computer programs," in Christopher G. Langton, Artificial Life III, Proc. Volume XVII Santa Fe Institute Studies in the Sciences of Complexity, Addison-Wesley Publishing Company, New York, 1994, p. 260. @TABLE n_states:8 neighborhood:vonNeumann symmetries:rotate4 var a={4,5} 0,0,0,0,4,0 # j 0,0,0,0,5,0 0,0,0,0,6,2 0,0,0,1,4,0 0,0,0,1,6,2 0,0,0,2,5,2 0,0,0,2,6,2 0,0,0,3,5,0 0,0,0,4,1,0 0,0,0,4,2,2 0,0,0,6,1,2 0,0,0,6,2,2 0,0,0,6,6,2 0,0,1,0,4,0 0,0,1,0,5,0 0,0,1,0,6,2 0,0,1,0,7,3 0,0,1,1,6,2 0,0,1,6,2,2 0,0,1,6,6,2 0,0,2,0,6,2 0,0,2,1,3,1 0,0,2,2,6,2 0,0,2,6,1,2 0,0,2,6,2,2 0,0,2,6,6,2 0,0,2,7,2,1 0,0,2,7,3,0 0,0,3,0,7,0 0,0,3,1,2,1 0,0,3,6,3,1 0,0,3,7,2,0 0,0,6,2,2,2 0,0,6,6,1,2 0,0,6,6,2,2 0,1,1,1,6,2 0,1,1,2,4,1 0,1,1,2,5,1 0,1,1,2,6,1 0,1,1,2,7,1 0,1,1,4,2,1 0,1,1,5,2,1 0,1,1,6,2,1 0,1,1,6,6,3 0,1,1,7,2,1 0,1,1,7,3,1 0,1,2,1,2,1 0,1,2,1,3,1 0,1,2,1,4,1 0,1,2,1,5,1 0,1,2,1,6,1 0,1,2,1,7,1 0,1,2,2,2,7 0,1,2,2,3,1 0,1,2,2,4,1 0,1,2,2,5,1 0,1,2,2,6,1 0,1,2,2,7,1 0,1,2,3,2,6 0,1,2,3,5,1 0,1,2,4,2,1 0,1,2,4,3,1 0,1,2,4,4,1 0,1,2,5,2,1 0,1,2,5,3,1 0,1,2,5,5,1 0,1,2,6,2,1 0,1,2,6,6,1 0,1,2,7,2,1 0,1,2,7,3,1 0,1,2,7,7,1 0,1,3,2,2,1 0,1,3,2,4,1 0,1,3,4,2,1 0,1,3,4,3,1 0,1,3,4,4,1 0,1,3,5,2,1 0,1,3,6,2,1 0,1,3,7,2,1 0,1,3,7,3,1 0,1,4,2,2,1 0,1,4,2,3,1 0,1,4,2,4,1 0,1,4,3,2,1 0,1,4,3,3,1 0,1,4,4,2,1 0,1,5,2,2,1 0,1,5,2,3,1 0,1,5,2,5,1 0,1,5,3,2,1 0,1,5,5,2,1 0,1,6,2,2,1 0,1,6,2,3,1 0,1,6,2,6,1 0,1,6,6,2,1 0,1,6,6,6,3 0,1,7,2,2,1 0,1,7,2,3,1 0,1,7,2,7,1 0,1,7,7,2,1 0,2,2,2,6,2 0,2,2,6,6,2 0,2,3,2,6,1 0,2,6,6,6,2 1,0,0,0,4,0 1,0,0,0,5,0 1,0,0,0,6,6 1,0,0,0,7,3 1,0,0,1,4,0 1,0,0,1,5,3 1,0,0,1,6,6 1,0,0,1,7,2 1,0,0,2,4,4 1,0,0,2,6,6 1,0,0,3,6,2 1,0,0,5,1,3 1,0,0,5,2,5 1,0,0,6,1,6 1,0,0,6,2,6 1,0,0,6,3,2 1,0,0,6,6,6 1,0,0,7,1,2 1,0,1,0,4,0 1,0,1,0,5,0 1,0,1,0,6,6 1,0,1,0,7,2 1,0,1,1,6,6 1,0,1,2,6,6 1,0,1,6,1,6 1,0,1,6,2,6 1,0,1,6,6,6 1,0,2,2,6,6 1,0,2,5,2,5 1,0,2,6,1,6 1,0,2,6,2,6 1,0,2,6,6,6 1,0,2,7,2,7 1,0,3,5,2,5 1,0,6,0,6,6 1,0,6,1,1,6 1,0,6,1,6,6 1,0,6,2,1,6 1,0,6,2,2,6 1,0,6,2,6,6 1,0,6,6,1,6 1,0,6,6,6,6 1,1,1,1,4,0 1,1,1,1,5,6 1,1,1,1,6,6 1,1,1,2,4,4 1,1,1,2,5,5 1,1,1,2,6,6 1,1,1,2,7,7 1,1,1,4,2,4 1,1,1,5,2,5 1,1,1,6,2,6 1,1,1,6,6,6 1,1,1,7,2,7 1,1,2,1,4,4 1,1,2,1,5,5 1,1,2,1,6,6 1,1,2,1,7,7 1,1,2,2,4,4 1,1,2,2,5,5 1,1,2,2,6,6 1,1,2,2,7,7 1,1,2,3,5,5 1,1,2,4,2,4 1,1,2,4,3,1 1,1,2,4,4,3 1,1,2,5,2,5 1,1,2,5,3,1 1,1,2,5,5,3 1,1,2,6,2,6 1,1,2,6,3,1 1,1,2,6,6,3 1,1,2,7,2,7 1,1,2,7,3,1 1,1,2,7,7,3 1,1,3,4,2,1 1,1,3,4,3,7 1,1,3,5,2,1 1,1,3,5,3,7 1,1,3,6,2,1 1,1,3,6,3,7 1,1,3,7,2,1 1,1,3,7,3,7 1,1,3,7,6,7 1,1,3,7,7,1 1,1,4,2,2,4 1,1,4,2,4,5 1,1,4,3,2,4 1,1,4,4,2,4 1,1,5,2,2,5 1,1,5,2,5,6 1,1,5,5,2,5 1,1,6,2,2,6 1,1,6,6,2,6 1,1,6,7,2,1 1,1,7,2,2,7 1,1,7,2,7,4 1,1,7,7,2,7 1,2,2,2,3,3 1,2,2,2,4,4 1,2,2,2,5,5 1,2,2,2,6,6 1,2,2,2,7,7 1,2,2,3,5,5 1,2,2,3,6,6 1,2,2,4,3,4 1,2,2,4,4,1 1,2,2,5,3,5 1,2,2,5,5,1 1,2,2,6,3,6 1,2,2,6,6,1 1,2,2,7,7,1 1,2,3,2,4,4 1,2,3,2,5,5 1,2,3,2,6,6 1,2,3,2,7,7 1,2,3,6,3,6 1,2,3,7,3,7 1,2,5,3,3,5 1,2,6,2,6,6 1,3,3,3,6,6 2,0,0,0,4,2 2,0,0,0,5,2 2,0,0,0,6,0 2,0,0,0,7,1 2,0,0,1,4,2 2,0,0,1,5,2 2,0,0,1,6,2 2,0,0,1,7,1 2,0,0,2,4,2 2,0,0,2,5,3 2,0,0,2,6,2 2,0,0,2,7,2 2,0,0,3,4,2 2,0,0,3,5,2 2,0,0,3,6,2 2,0,0,3,7,2 2,0,0,4,1,2 2,0,0,4,2,3 2,0,0,5,1,2 2,0,0,5,2,2 2,0,0,5,3,2 2,0,0,6,1,2 2,0,0,6,2,2 2,0,0,6,3,2 2,0,0,7,1,1 2,0,0,7,2,2 2,0,0,7,3,2 2,0,1,0,4,2 2,0,1,0,5,2 2,0,1,0,6,0 2,0,1,0,7,1 2,0,1,1,4,2 2,0,1,1,5,2 2,0,1,1,6,2 2,0,1,1,7,1 2,0,1,4,1,2 2,0,1,4,2,3 2,0,1,5,1,2 2,0,1,5,2,2 2,0,1,5,3,2 2,0,1,6,1,2 2,0,1,6,2,2 2,0,1,7,1,1 2,0,1,7,2,2 2,0,2,0,6,2 2,0,2,0,7,3 2,0,2,1,4,2 2,0,2,1,5,2 2,0,2,1,6,2 2,0,2,1,7,2 2,0,2,2,4,2 2,0,2,2,5,2 2,0,2,2,6,2 2,0,2,2,7,2 2,0,2,4,1,2 2,0,2,4,2,2 2,0,2,4,3,2 2,0,2,5,1,3 2,0,2,5,2,2 2,0,2,5,3,2 2,0,2,6,1,2 2,0,2,6,2,2 2,0,2,6,3,2 2,0,2,6,6,2 2,0,2,7,1,2 2,0,2,7,2,2 2,0,2,7,3,2 2,0,2,7,7,2 2,0,3,0,6,3 2,0,3,0,7,3 2,0,3,1,6,2 2,0,3,1,7,2 2,0,3,4,1,2 2,0,3,4,2,2 2,0,3,4,3,2 2,0,3,5,2,2 2,0,3,5,3,2 2,0,3,6,2,2 2,0,3,7,1,2 2,0,3,7,2,2 2,0,3,7,3,2 2,0,4,1,2,2 2,0,4,2,2,2 2,0,5,1,2,2 2,0,5,2,2,2 2,0,6,1,2,2 2,0,6,1,3,2 2,0,6,2,2,2 2,0,6,6,2,2 2,0,7,1,2,2 2,0,7,2,2,2 2,0,7,3,2,2 2,0,7,7,2,2 2,1,1,1,4,2 2,1,1,1,5,2 2,1,1,1,6,5 2,1,1,1,7,1 2,1,1,6,2,2 2,1,2,2,4,2 2,1,2,2,5,2 2,1,2,2,6,2 2,1,2,2,7,2 2,1,2,3,2,3 2,1,2,3,4,2 2,1,2,3,5,2 2,1,2,3,6,2 2,1,2,3,7,2 2,1,3,2,6,2 2,1,3,2,7,2 2,1,4,2,2,2 2,1,5,2,2,2 2,1,5,3,2,2 2,1,5,3,3,2 2,1,6,2,2,2 2,1,6,2,3,2 2,1,6,3,2,2 2,1,7,2,2,2 2,1,7,2,3,2 2,1,7,3,2,2 2,1,7,7,2,2 2,2,2,2,4,2 2,2,2,2,5,2 2,2,2,2,6,2 2,2,2,2,7,2 2,2,2,3,4,2 2,2,2,4,3,2 2,2,2,4,4,2 2,2,2,5,3,2 2,2,2,5,5,2 2,2,2,6,3,2 2,2,2,6,6,2 2,2,2,6,7,2 2,2,2,7,3,2 2,2,2,7,6,2 2,2,2,7,7,2 2,2,3,7,6,2 2,2,3,7,7,2 2,2,6,7,3,2 2,2,7,7,3,2 3,0,0,0,2,2 3,0,0,0,4,3 3,0,0,0,5,3 3,0,0,0,6,1 3,0,0,1,1,1 3,0,0,2,5,1 3,0,0,2,6,0 3,0,0,2,7,0 3,0,0,4,2,1 3,0,0,5,2,3 3,0,0,6,2,0 3,0,0,7,2,0 3,0,1,0,2,2 3,0,1,0,3,2 3,0,1,0,4,3 3,0,1,0,5,3 3,0,1,0,6,4 3,0,1,0,7,7 3,0,1,1,1,1 3,0,1,5,2,3 3,0,1,6,2,0 3,0,1,7,2,0 3,0,2,6,1,0 3,0,2,7,1,0 3,1,1,1,1,1 3,1,1,1,2,1 3,1,1,1,3,1 3,1,1,7,2,7 3,1,2,3,2,2 3,2,2,2,7,3 4,0,0,0,1,0 4,0,0,0,2,1 4,0,0,2,1,0 4,0,1,0,2,0 4,0,1,1,2,0 4,0,1,2,1,0 4,0,1,2,2,0 4,0,2,1,1,0 4,0,2,1,2,0 4,0,2,2,1,0 4,0,2,2,2,1 4,0,2,3,2,1 4,0,3,2,2,1 5,0,0,0,2,1 5,0,0,2,1,0 5,0,1,0,2,0 5,0,1,1,1,0 5,0,1,1,2,0 5,0,1,2,1,0 5,0,1,2,2,0 5,0,2,0,2,1 5,0,2,1,1,0 5,0,2,1,2,0 5,0,2,2,1,0 5,0,2,2,2,1 5,0,2,2,3,1 5,0,3,2,2,1 5,0,3,3,2,1 6,0,0,0,0,1 6,0,0,0,1,0 6,0,0,0,2,1 6,0,0,1,1,0 6,0,0,1,2,0 6,0,0,2,1,0 6,0,0,2,2,1 6,0,1,0,1,0 6,0,1,0,2,0 6,0,1,1,1,0 6,0,1,1,2,0 6,0,1,2,1,0 6,0,1,2,2,0 6,0,2,0,2,1 6,0,2,1,1,0 6,0,2,1,2,0 6,0,2,2,1,0 6,0,2,2,2,1 6,0,2,2,3,0 6,0,2,3,2,0 6,0,3,2,2,0 6,0,3,2,3,0 6,0,3,3,3,0 6,1,2,3,2,0 7,0,0,0,1,0 7,0,0,1,3,0 7,0,0,2,1,0 7,0,1,1,2,0 7,0,1,2,1,0 7,0,1,2,2,0 7,0,2,0,2,1 7,0,2,1,1,0 7,0,2,1,2,0 7,0,2,2,1,0 7,0,2,2,2,1 7,0,2,3,2,0 7,0,3,1,3,0 7,0,3,2,3,0 7,1,2,2,2,0 # End of ruleset @COLORS 1 0 0 255 2 0 220 0 3 255 255 0 4 0 255 255 5 255 0 255 6 255 0 0 7 255 255 255 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TreeGenerators/�����������������������������������������������������������������0000755�0001750�0001750�00000000000�12536111546�014325� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TreeGenerators/RuleTreeGen.pl���������������������������������������������������0000644�0001750�0001750�00000002027�12536111364�016762� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Set the states, neighbors, and function here. my $numStates = 2 ; my $numNeighbors = 8 ; # order for nine neighbors is nw, ne, sw, se, n, w, e, s, c # order for five neighbors is n, w, e, s, c sub f { my ($nw, $ne, $sw, $se, $n, $w, $e, $s, $c) = @_ ; my $sum = $nw + $ne + $sw + $se + $n + $w + $e + $s ; return ($sum == 3 || ($sum == 2 && $c)) ? 1 : 0 ; } my $numParams = $numNeighbors + 1 ; my %world ; my $nodeseq = 0 ; my @r ; my @params = (0) x $numParams ; sub getNode { my $n = shift ; return $world{$n} if defined($world{$n}) ; $world{$n} = $nodeseq ; push @r, $n ; return $nodeseq++ ; } sub recur { my $at = shift ; if ($at == 0) { return f(@params) ; } else { my $n = $at ; for (my $i=0; $i<$numStates; $i++) { $params[$numParams-$at] = $i ; $n .= " " . recur($at-1) ; } return getNode($n) ; } } recur($numParams) ; print "num_states=$numStates\n" ; print "num_neighbors=$numNeighbors\n" ; print "num_nodes=", scalar @r, "\n" ; print "$_\n" for @r ; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TreeGenerators/LifeOnTheSlope.cpp�����������������������������������������������0000644�0001750�0001750�00000003146�12536111364�017573� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <vector> #include <map> #include <string> #include <cstdio> using namespace std ; /** * Set the state count, neighbor count, and put your function here. */ const int numStates = 3 ; const int numNeighbors = 8 ; /** 0: (nothing set) 1: \ 2: / */ /* order for nine neighbors is nw, ne, sw, se, n, w, e, s, c */ int f(int *a) { int on1 = (a[0] & 1) + (a[3] & 1) + (a[4] >> 1) + (a[5] >> 1) + (a[6] >> 1) + (a[7] >> 1) + (a[8] & 1) ; int on2 = (a[1] >> 1) + (a[2] >> 1) + (a[4] & 1) + (a[5] & 1) + (a[6] & 1) + (a[7] & 1) + (a[8] >> 1) ; if (on1 == 2) if (on2 == 2) return 0 ; else return 1 ; else if (on2 == 2) return 2 ; else return 0 ; } const int numParams = numNeighbors + 1 ; map<string,int> world ; vector<string> r ; int nodeSeq, params[9] ; int getNode(const string &n) { map<string,int>::iterator it = world.find(n) ; if (it != world.end()) return it->second ; world[n] = nodeSeq ; r.push_back(n) ; return nodeSeq++ ; } int recur(int at) { if (at == 0) { return f(params) ; } else { char buf[256*10] ; sprintf(buf, "%d", at) ; for (int i=0; i<numStates; i++) { params[numParams-at] = i ; sprintf(buf+strlen(buf), " %d", recur(at-1)) ; } return getNode(buf) ; } } void writestring() { printf("num_states=%d\n", numStates) ; printf("num_neighbors=%d\n", numNeighbors) ; printf("num_nodes=%d\n", r.size()) ; for (unsigned int i=0; i<r.size(); i++) printf("%s\n", r[i].c_str()) ; } int main(int argc, char *argv[]) { recur(numParams) ; writestring() ; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TreeGenerators/LifeOnTheEdge.cpp������������������������������������������������0000644�0001750�0001750�00000003034�12536111364�017351� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <vector> #include <map> #include <string> #include <cstdio> using namespace std ; /** * Set the state count, neighbor count, and put your function here. */ const int numStates = 4 ; const int numNeighbors = 8 ; /** 0: (nothing set) 1: | 2: - 3: |- */ /* order for nine neighbors is nw, ne, sw, se, n, w, e, s, c */ int f(int *a) { int on0 = a[8] - (a[8] >> 1) ; // # bits set int on1 = (a[2] >> 1) + (a[4] & 1) + (a[5] >> 1) + (a[7] & 1) + (a[7] >> 1) + on0 ; int on2 = (a[1] & 1) + (a[4] & 1) + (a[5] >> 1) + (a[6] & 1) + (a[6] >> 1) + on0 ; return (on1 == 2) + 2 * (on2 == 2) ; } const int numParams = numNeighbors + 1 ; map<string,int> world ; vector<string> r ; int nodeSeq, params[9] ; int getNode(const string &n) { map<string,int>::iterator it = world.find(n) ; if (it != world.end()) return it->second ; world[n] = nodeSeq ; r.push_back(n) ; return nodeSeq++ ; } int recur(int at) { if (at == 0) { return f(params) ; } else { char buf[256*10] ; sprintf(buf, "%d", at) ; for (int i=0; i<numStates; i++) { params[numParams-at] = i ; sprintf(buf+strlen(buf), " %d", recur(at-1)) ; } return getNode(buf) ; } } void writestring() { printf("num_states=%d\n", numStates) ; printf("num_neighbors=%d\n", numNeighbors) ; printf("num_nodes=%d\n", r.size()) ; for (unsigned int i=0; i<r.size(); i++) printf("%s\n", r[i].c_str()) ; } int main(int argc, char *argv[]) { recur(numParams) ; writestring() ; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TreeGenerators/RuleTreeGen.java�������������������������������������������������0000644�0001750�0001750�00000003140�12536111364�017265� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������import java.util.* ; public class RuleTreeGen { /* Put your state count, neighbor count, and function here */ final static int numStates = 2 ; final static int numNeighbors = 8 ; /* order for nine neighbors is nw, ne, sw, se, n, w, e, s, c */ /* order for five neighbors is n, w, e, s, c */ int f(int[] a) { int n = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] ; if (n == 2 && a[8] != 0) return 1 ; if (n == 3) return 1 ; return 0 ; } final static int numParams = numNeighbors + 1 ; HashMap<String, Integer> world = new HashMap<String, Integer>() ; ArrayList<String> r = new ArrayList<String>() ; int[] params = new int[numParams] ; int nodeSeq = 0 ; int getNode(String n) { Integer found = world.get(n) ; if (found == null) { found = nodeSeq++ ; r.add(n) ; world.put(n, found) ; } return found ; } int recur(int at) { if (at == 0) return f(params) ; String n = "" + at ; for (int i=0; i<numStates; i++) { params[numParams-at] = i ; n += " " + recur(at-1) ; } return getNode(n) ; } void writeRuleTree() { System.out.println("num_states=" + numStates) ; System.out.println("num_neighbors=" + numNeighbors) ; System.out.println("num_nodes=" + r.size()) ; for (int i=0; i<r.size(); i++) System.out.println(r.get(i)) ; } public static void main(String[] args) throws Exception { RuleTreeGen rtg = new RuleTreeGen() ; rtg.recur(numParams) ; rtg.writeRuleTree() ; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TreeGenerators/RuleTreeGen.cpp��������������������������������������������������0000644�0001750�0001750�00000002700�12536111364�017127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string.h> // for strlen #include <vector> #include <map> #include <string> #include <cstdio> using namespace std ; /** * Set the state count, neighbor count, and put your function here. */ const int numStates = 2 ; const int numNeighbors = 8 ; /* order for nine neighbors is nw, ne, sw, se, n, w, e, s, c */ /* order for five neighbors is n, w, e, s, c */ int f(int *a) { int n = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] ; if (n == 2 && a[8]) return 1 ; if (n == 3) return 1 ; return 0 ; } const int numParams = numNeighbors + 1 ; map<string,int> world ; vector<string> r ; int nodeSeq, params[9] ; int getNode(const string &n) { map<string,int>::iterator it = world.find(n) ; if (it != world.end()) return it->second ; world[n] = nodeSeq ; r.push_back(n) ; return nodeSeq++ ; } int recur(int at) { if (at == 0) { return f(params) ; } else { char buf[256*10] ; sprintf(buf, "%d", at) ; for (int i=0; i<numStates; i++) { params[numParams-at] = i ; sprintf(buf+strlen(buf), " %d", recur(at-1)) ; } return getNode(buf) ; } } void writestring() { printf("num_states=%d\n", numStates) ; printf("num_neighbors=%d\n", numNeighbors) ; printf("num_nodes=%d\n", r.size()) ; for (unsigned int i=0; i<r.size(); i++) printf("%s\n", r[i].c_str()) ; } int main(int argc, char *argv[]) { recur(numParams) ; writestring() ; } ����������������������������������������������������������������golly-2.7-src/Rules/TreeGenerators/RuleTreeGen.py���������������������������������������������������0000644�0001750�0001750�00000003024�12536111364�016775� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������class GenerateRuleTree: def __init__(self,numStates,numNeighbors,f): self.numParams = numNeighbors + 1 ; self.world = {} self.r = [] self.params = [0]*self.numParams self.nodeSeq = 0 self.numStates = numStates self.numNeighbors = numNeighbors self.f = f self.recur(self.numParams) self.writeRuleTree() def getNode(self,n): if n in self.world: return self.world[n] else: new_node = self.nodeSeq self.nodeSeq += 1 self.r.append(n) self.world[n] = new_node return new_node def recur(self,at): if at == 0: return self.f(self.params) n = str(at) for i in range(self.numStates): self.params[self.numParams-at] = i n += " " + str(self.recur(at-1)) return self.getNode(n) def writeRuleTree(self): print "num_states=" + str(self.numStates) print "num_neighbors=" + str(self.numNeighbors) print "num_nodes=" + str(len(self.r)) for rule in self.r: print rule # define your own transition function here: def my_transition_function(a): # B3/S23 n = a[0] + a[1] + a[2] + a[3] + a[4] + a[5] + a[6] + a[7] if n == 2 and not a[8] == 0: return 1 if n == 3: return 1 return 0 # call the rule tree generator with your chosen parameters n_states = 2 n_neighbors = 8 GenerateRuleTree(n_states,n_neighbors,my_transition_function) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TableGenerators/����������������������������������������������������������������0000755�0001750�0001750�00000000000�12536111546�014455� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TableGenerators/make-ruletable.cpp����������������������������������������������0000644�0001750�0001750�00000056474�12536111364�020011� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2008 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include <math.h> #include <time.h> #include <iostream> #include <set> #include <fstream> #include <vector> #include <map> #include <sstream> #include <algorithm> using namespace std; /* Makes a rule-table for your transition function. To compile: g++ -O5 -o make-ruletable make-ruletable.cpp or in Microsoft Visual Studio, add to an empty CLR project. To use: 1) fill slowcalc with your own transition function. 2) set the parameters in main() at the bottom. 3) execute the program from the command line (no options taken) For a 32-state 5-neighbourhood rule it took 16mins on a 2.2GHz machine. For a 4-state 9-neighbourhood rule it took 4s. The merging is very simple - if a transition is compatible with the first rule, then merge the transition into the rule. If not, try the next rule. If there are no more rules, add a new rule containing just the transition. === Worked example: === Transitions: 1,0,0->3 1,2,0->3 2,0,0->3 2,2,0->1 Start. First transition taken as first rule: rule 1: 1,0,0->3 Next transition - is it compatible with rule 1? i.e. is 1,[0,2],0->3 valid for all permutations? Yes. rule 1 now: 1,[0,2],0->3 Next transition - is it compatible with rule 1? i.e. is [1,2],[0,2],0->3 valid for all permutations? no - because 2,2,0 ->1, not ->3. so add the transition as a new rule: rule 1 still: 1,[0,2],0 -> 3 rule 2 now : 2,0,0->3 Next transition - is it compatible with rule 1? no - output is different. Is it compatible with rule 2? no - output is different. Final output: 1,[0,2],0 -> 3 2,0,0 -> 3 2,2,0 -> 1 Written with variables: var a={0,2} 1,a,0,3 2,0,0,3 2,2,0,1 =============== In the function produce_rule_table, the state space is exhaustively traversed. If your transition function consists of transition rules already then you can optimise by running through the transitions instead. You might also want to turn off the optimisation in rule::can_merge, to see if it gives you better compression. Also note: I feel sure there are better ways to compress rule tables than this... Contact: Tim Hutton <tim.hutton@gmail.com> */ // some typedefs and compile-time constants typedef unsigned short state; enum TSymm { none, rotate4, rotate8, reflect, rotate4reflect, rotate8reflect }; static const string symmetry_strings[] = {"none","rotate4","rotate8","reflect","rotate4reflect","rotate8reflect"}; // fill in this function with your desired transition rules // (for von Neumann neighbourhoods, just ignore the nw,se,sw,ne inputs) state slowcalc(state nw,state n,state ne,state w,state c,state e,state sw,state s,state se) { // wireworld: switch (c) { case 0: return 0 ; case 1: return 2 ; case 2: return 3 ; case 3: if ((((1+(nw==1)+(n==1)+(ne==1)+(w==1)+(e==1)+(sw==1)+ (s==1)+(se==1))) | 1) == 3) return 1 ; else return 3 ; default: return 0 ; // should throw an error here } } vector<state> rotate_inputs(const vector<state>& inputs,int rot) { vector<state> rotinp(inputs); rotate_copy(inputs.begin()+1,inputs.begin()+1+rot,inputs.end(),rotinp.begin()+1); return rotinp; } vector<state> reflect_inputs(const vector<state>& inputs,int neighbourhood_size) { vector<state> refinp(inputs); if(neighbourhood_size==5) // CNESW { refinp[2]=inputs[4]; // swap E and W refinp[4]=inputs[2]; } else // neighbourhood_size==9 (C,N,NE,E,SE,S,SW,W,NW) { refinp[2]=inputs[8]; refinp[8]=inputs[2]; refinp[3]=inputs[7]; refinp[7]=inputs[3]; refinp[4]=inputs[6]; refinp[6]=inputs[4]; // swap all E and W } return refinp; } // simple rule structure, e.g. 1,2,[4,5],8,2 -> 0 class rule { public: set<state> inputs[9]; // c,n,ne,e,se,s,sw,w,nw or c,n,e,s,w state ns; // new state int n_inputs; // 5: von Neumann; 9: Moore TSymm symm; public: // constructors rule(const rule& r) : ns(r.ns),n_inputs(r.n_inputs),symm(r.symm) { for(int i=0;i<n_inputs;i++) inputs[i]=r.inputs[i]; } rule& operator=(const rule& r) { n_inputs=r.n_inputs; symm = r.symm; ns = r.ns; for(int i=0;i<n_inputs;i++) inputs[i]=r.inputs[i]; return *this; } rule(const vector<state>& inputs,int n_inputs,state ns1,TSymm symm1) : ns(ns1),n_inputs(n_inputs),symm(symm1) { merge(inputs); } // if we merge the rule and the supplied transition, will the rule remain true for all cases? bool can_merge(const vector<state>& test_inputs,state ns1) const { if(ns1!=ns) return false; // can't merge if the outputs are different // If you are running through your own transitions, or for small state spaces, // you might want to turn off this optimisation, to get better compression. // On JvN29 it doesn't make any difference but on Nobili32 it does. const bool forbid_multiple_input_differences = true; if(forbid_multiple_input_differences) { // optimisation: we skip this rule if more than 2 entries are different, we // assume we will have considered the relevant one-change rules before this. int n_different=0; for(int i=0;i<n_inputs;i++) if(inputs[i].find(test_inputs[i])==inputs[i].end()) if(++n_different>1) return false; // just check the new permutations for(int i=0;i<n_inputs;i++) { if(inputs[i].find(test_inputs[i])==inputs[i].end()) { rule r1(*this); r1.inputs[i].clear(); // (since we don't need to re-test all the other permutations) r1.inputs[i].insert(test_inputs[i]); if(!r1.all_true()) return false; } } } else { // need to check all combinations - this can be very slow for large state spaces for(int i=0;i<n_inputs;i++) { if(inputs[i].find(test_inputs[i])==inputs[i].end()) { rule r1(*this); r1.merge(test_inputs); // this is what makes it slow, we may introduce many new permutations r1.inputs[i].clear(); // (since we don't need to re-test all the old permutations) r1.inputs[i].insert(test_inputs[i]); if(!r1.all_true()) return false; } } } return true; } // merge the inputs with this rule void merge(const vector<state>& new_inputs) { for(int i=0;i<n_inputs;i++) inputs[i].insert(new_inputs[i]); // may already exist, set ignores if so } // is this set of inputs a match for the rule, for the given symmetry? bool matches(const vector<state>& test_inputs) const { int n_rotations,rotation_skip; bool do_reflect; switch(symm) { default: case none: n_rotations=1; rotation_skip=1; do_reflect=false; break; case rotate4: if(n_inputs==5) { n_rotations=4; rotation_skip=1; do_reflect=false; } else { n_rotations=4; rotation_skip=2; do_reflect=false; } break; case rotate8: n_rotations=8; rotation_skip=1; do_reflect=false; break; case reflect: n_rotations=1; rotation_skip=1; do_reflect=true; break; case rotate4reflect: if(n_inputs==5) { n_rotations=4; rotation_skip=1; do_reflect=true; } else { n_rotations=4; rotation_skip=2; do_reflect=true; } break; case rotate8reflect: n_rotations=8; rotation_skip=1; do_reflect=true; break; } for(int iRot=0;iRot<n_rotations;iRot++) { if(nosymm_matches(rotate_inputs(test_inputs,iRot*rotation_skip))) return true; if(do_reflect && nosymm_matches(reflect_inputs(rotate_inputs(test_inputs,iRot*rotation_skip),n_inputs))) return true; } return false; // no match found } protected: // ignoring symmetry, does this set of inputs match the rule? bool nosymm_matches(const vector<state>& test_inputs) const { for(int i=0;i<n_inputs;i++) if(inputs[i].find(test_inputs[i])==inputs[i].end()) return false; return true; } // is the rule true in all permutations? bool all_true() const { set<state>::const_iterator c_it,n_it,ne_it,e_it,se_it,s_it,sw_it,w_it,nw_it; if(n_inputs==9) { for(c_it = inputs[0].begin();c_it!=inputs[0].end();c_it++) for(n_it = inputs[1].begin();n_it!=inputs[1].end();n_it++) for(ne_it = inputs[2].begin();ne_it!=inputs[2].end();ne_it++) for(e_it = inputs[3].begin();e_it!=inputs[3].end();e_it++) for(se_it = inputs[4].begin();se_it!=inputs[4].end();se_it++) for(s_it = inputs[5].begin();s_it!=inputs[5].end();s_it++) for(sw_it = inputs[6].begin();sw_it!=inputs[6].end();sw_it++) for(w_it = inputs[7].begin();w_it!=inputs[7].end();w_it++) for(nw_it = inputs[8].begin();nw_it!=inputs[8].end();nw_it++) if(slowcalc(*nw_it,*n_it,*ne_it,*w_it,*c_it,*e_it,*sw_it,*s_it,*se_it)!=ns) return false; } else { for(c_it = inputs[0].begin();c_it!=inputs[0].end();c_it++) for(n_it = inputs[1].begin();n_it!=inputs[1].end();n_it++) for(e_it = inputs[2].begin();e_it!=inputs[2].end();e_it++) for(s_it = inputs[3].begin();s_it!=inputs[3].end();s_it++) for(w_it = inputs[4].begin();w_it!=inputs[4].end();w_it++) if(slowcalc(0,*n_it,0,*w_it,*c_it,*e_it,0,*s_it,0)!=ns) return false; } return true; } }; // makes a unique variable name for a given value string get_variable_name(unsigned int iVar) { const char VARS[52]={'a','b','c','d','e','f','g','h','i','j', 'k','l','m','n','o','p','q','r','s','t','u','v','w','x', 'y','z','A','B','C','D','E','F','G','H','I','J','K','L', 'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; ostringstream oss; if(iVar<52) oss << VARS[iVar]; else if(iVar<52*52) oss << VARS[(iVar-(iVar%52))/52 - 1] << VARS[iVar%52]; else oss << "!"; // we have a 52*52 limit ("should be enough for anyone") return oss.str(); } void print_rules(const vector<rule>& rules,ostream& out) { // first collect all variables (makes reading easier) map< string , set<state> > vars; ostringstream rules_out; for(vector<rule>::const_iterator r_it=rules.begin();r_it!=rules.end();r_it++) { vector<string> variables_used; for(int i=0;i<r_it->n_inputs;i++) { // if more than one state for this input, we need a variable if(r_it->inputs[i].size()>1) { string var; // is there a variable that matches these inputs, and that we haven't used? bool found_unused_var=false; for(map<string, set<state> >::const_iterator v_it=vars.begin();v_it!=vars.end();v_it++) { if(v_it->second==r_it->inputs[i] && find(variables_used.begin(),variables_used.end(),v_it->first)==variables_used.end()) { found_unused_var = true; var = v_it->first; break; } } if(!found_unused_var) { // we need to make a new one for this set of inputs var = get_variable_name(vars.size()); // add it to the list of made variables vars[var] = r_it->inputs[i]; // print it out << "var " << var << "={"; set<state>::const_iterator it=r_it->inputs[i].begin(); while(true) { out << (int)*it; it++; if(it!=r_it->inputs[i].end()) out << ","; else break; } out << "}\n"; } // add the variable to the list of used ones variables_used.push_back(var); rules_out << var << ","; } else { // just a state, output it rules_out << (int)*r_it->inputs[i].begin() << ","; } } rules_out << (int)r_it->ns << endl; } out << rules_out.str(); } void produce_rule_table(vector<rule>& rules,int N,int nhood_size,TSymm symm,bool remove_stasis) { int n_rotations,rotation_skip; bool do_reflect; switch(symm) { default: case none: n_rotations=1; rotation_skip=1; do_reflect=false; break; case rotate4: if(nhood_size==5) { n_rotations=4; rotation_skip=1; do_reflect=false; } else { n_rotations=4; rotation_skip=2; do_reflect=false; } break; case rotate8: n_rotations=8; rotation_skip=1; do_reflect=false; break; case reflect: n_rotations=1; rotation_skip=1; do_reflect=true; break; case rotate4reflect: if(nhood_size==5) { n_rotations=4; rotation_skip=1; do_reflect=true; } else { n_rotations=4; rotation_skip=2; do_reflect=true; } break; case rotate8reflect: n_rotations=8; rotation_skip=1; do_reflect=true; break; } state c,n,ne,nw,sw,s,se,e,w,ns; vector<rule>::iterator it; bool merged; for(c=0;c<N;c++) { cout << "\nProcessing for c=" << (int)c << ", " << rules.size() << " rules so far." << endl; if(nhood_size==9) { vector<state> inputs(9); inputs[0]=c; for(n=0;n<N;n++) { cout << "."; cout.flush(); inputs[1]=n; for(ne=0;ne<N;ne++) { inputs[2]=ne; for(e=0;e<N;e++) { inputs[3]=e; for(se=0;se<N;se++) { inputs[4]=se; for(s=0;s<N;s++) { inputs[5]=s; for(sw=0;sw<N;sw++) { inputs[6]=sw; for(w=0;w<N;w++) { inputs[7]=w; for(nw=0;nw<N;nw++) { ns = slowcalc(nw,n,ne,w,c,e,sw,s,se); if(remove_stasis && ns == c) continue; // we can ignore stasis transitions // can we merge this transition with any existing rule? inputs[8]=nw; merged = false; for(it=rules.begin();!merged && it!=rules.end();it++) { rule &r = *it; for(int iRot=0;!merged && iRot<n_rotations;iRot++) { if(r.can_merge(rotate_inputs(inputs,iRot*rotation_skip),ns)) { r.merge(rotate_inputs(inputs,iRot*rotation_skip)); merged = true; } else if(do_reflect && r.can_merge(reflect_inputs(rotate_inputs(inputs,iRot*rotation_skip),nhood_size),ns)) { r.merge(reflect_inputs(rotate_inputs(inputs,iRot*rotation_skip),nhood_size)); merged = true; } } } if(!merged) { // need to make a new rule starting with this transition rule r(inputs,nhood_size,ns,symm); rules.push_back(r); } } } } } } } } } } else // nhood_size==5 { vector<state> inputs(5); inputs[0]=c; for(n=0;n<N;n++) { cout << "."; cout.flush(); inputs[1]=n; for(e=0;e<N;e++) { inputs[2]=e; for(s=0;s<N;s++) { inputs[3]=s; for(w=0;w<N;w++) { ns = slowcalc(0,n,0,w,c,e,0,s,0); if(remove_stasis && ns == c) continue; // we can ignore stasis transitions // can we merge this transition with any existing rule? inputs[4]=w; merged = false; for(it=rules.begin();!merged && it!=rules.end();it++) { rule &r = *it; for(int iRot=0;!merged && iRot<n_rotations;iRot++) { if(r.can_merge(rotate_inputs(inputs,iRot*rotation_skip),ns)) { r.merge(rotate_inputs(inputs,iRot*rotation_skip)); merged = true; } else if(do_reflect && r.can_merge(reflect_inputs(rotate_inputs(inputs,iRot*rotation_skip),nhood_size),ns)) { r.merge(reflect_inputs(rotate_inputs(inputs,iRot*rotation_skip),nhood_size)); merged = true; } } } if(!merged) { // need to make a new rule starting with this transition rule r(inputs,nhood_size,ns,symm); rules.push_back(r); } } } } } } } } // here we use the computed rule table as a replacement slowcalc, for checking correctness state new_slowcalc(const vector<rule>& rules,const vector<state>& inputs) { for(vector<rule>::const_iterator it=rules.begin();it!=rules.end();it++) if(it->matches(inputs)) return it->ns; return inputs[0]; // default: no change } bool is_correct(const vector<rule>&rules,int N,int neighbourhood_size) { // exhaustive check state c,n,ne,nw,sw,s,se,e,w; if(neighbourhood_size==9) { vector<state> inputs(9); for(c=0;c<N;c++) { inputs[0]=c; for(n=0;n<N;n++) { inputs[1]=n; for(ne=0;ne<N;ne++) { inputs[2]=ne; for(e=0;e<N;e++) { inputs[3]=e; for(se=0;se<N;se++) { inputs[4]=se; for(s=0;s<N;s++) { inputs[5]=s; for(sw=0;sw<N;sw++) { inputs[6]=sw; for(w=0;w<N;w++) { inputs[7]=w; for(nw=0;nw<N;nw++) { inputs[8]=nw; if(new_slowcalc(rules,inputs) != slowcalc(nw,n,ne,w,c,e,sw,s,se)) return false; } } } } } } } } } } else { vector<state> inputs(5); for(c=0;c<N;c++) { inputs[0]=c; for(n=0;n<N;n++) { inputs[1]=n; for(e=0;e<N;e++) { inputs[2]=e; for(s=0;s<N;s++) { inputs[3]=s; for(w=0;w<N;w++) { inputs[4]=w; if(new_slowcalc(rules,inputs) != slowcalc(0,n,0,w,c,e,0,s,0)) return false; } } } } } } return true; } int main() { // parameters for use: const int N_STATES = 4; const TSymm symmetry = rotate8; const int nhood_size = 9; const string output_filename = "wireworld.table"; const bool remove_stasis_transitions = true; vector<rule> rules; time_t t1,t2; time(&t1); produce_rule_table(rules,N_STATES,nhood_size,symmetry,remove_stasis_transitions); time(&t2); int n_secs = (int)difftime(t2,t1); cout << "\nProcessing took: " << n_secs << " seconds." << endl; { ofstream out(output_filename.c_str()); out << "# rules: " << rules.size() << "\n#"; out << "\n# Golly rule-table format.\n# Each rule: C,"; if(nhood_size==5) out << "N,E,S,W"; else out << "N,NE,E,SE,S,SW,W,NW"; out << ",C'"; out << "\n# N.B. Where the same variable appears multiple times in a transition,\n# it takes the same value each time.\n#"; if(remove_stasis_transitions) out << "\n# Default for transitions not listed: no change\n#"; else out << "\n# All transitions should be included below, including no-change ones.\n#"; out << "\nn_states:" << N_STATES; out << "\nneighborhood:" << ((nhood_size==5)?("vonNeumann"):("Moore")); out << "\nsymmetries:" << symmetry_strings[symmetry] << "\n"; print_rules(rules,out); } cout << rules.size() << " rules written." << endl; // optional: run through the entire state space, checking that new_slowcalc matches slowcalc cout << "Verifying is correct (can abort if you're confident)..."; cout.flush(); if(is_correct(rules,N_STATES,nhood_size)) cout << "yes." << endl; else cout << "no! Either there's a bug in the code, or the transition function does not have the symmetry you selected." << endl; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Turmite_1202822111121111812a0281282.rule����������������������������������������0000644�0001750�0001750�00000167545�12536111364�016613� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Turmite_1202822111121111812a0281282 @TREE num_states=39 num_neighbors=4 num_nodes=37 1 0 1 2 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 1 1 1 1 2 2 2 2 2 2 2 2 1 1 1 1 2 2 2 2 1 3 15 27 15 15 15 15 15 15 15 15 27 27 27 27 27 27 27 27 15 15 15 15 27 27 27 27 27 27 27 27 15 15 15 15 27 27 27 27 1 11 23 35 23 23 23 23 23 23 23 23 35 35 35 35 35 35 35 35 23 23 23 23 35 35 35 35 35 35 35 35 23 23 23 23 35 35 35 35 1 7 19 31 19 19 19 19 19 19 19 19 31 31 31 31 31 31 31 31 19 19 19 19 31 31 31 31 31 31 31 31 19 19 19 19 31 31 31 31 2 0 0 0 0 0 0 1 2 0 0 0 0 1 0 1 0 2 0 0 3 0 0 0 0 3 0 0 3 0 0 0 0 3 0 0 0 2 0 0 1 6 18 30 18 18 18 18 18 18 18 18 30 30 30 30 30 30 30 30 18 18 18 18 30 30 30 30 30 30 30 30 18 18 18 18 30 30 30 30 2 5 5 5 5 5 5 0 0 5 5 5 5 0 5 0 5 0 5 5 0 5 5 5 5 0 5 5 0 5 5 5 5 0 5 5 5 0 5 5 1 14 26 38 26 26 26 26 26 26 26 26 38 38 38 38 38 38 38 38 26 26 26 26 38 38 38 38 38 38 38 38 26 26 26 26 38 38 38 38 2 7 7 7 7 7 7 0 0 7 7 7 7 0 7 0 7 0 7 7 0 7 7 7 7 0 7 7 0 7 7 7 7 0 7 7 7 0 7 7 1 10 22 34 22 22 22 22 22 22 22 22 34 34 34 34 34 34 34 34 22 22 22 22 34 34 34 34 34 34 34 34 22 22 22 22 34 34 34 34 2 9 9 9 9 9 9 0 0 9 9 9 9 0 9 0 9 0 9 9 0 9 9 9 9 0 9 9 0 9 9 9 9 0 9 9 9 0 9 9 3 4 4 4 4 4 6 4 4 4 4 8 6 4 6 4 8 4 4 4 4 4 4 10 10 4 4 4 4 4 4 10 10 4 4 4 8 4 4 4 1 4 16 28 16 16 16 16 16 16 16 16 28 28 28 28 28 28 28 28 16 16 16 16 28 28 28 28 28 28 28 28 16 16 16 16 28 28 28 28 2 12 12 12 12 12 12 0 0 12 12 12 12 0 12 0 12 0 12 12 0 12 12 12 12 0 12 12 0 12 12 12 12 0 12 12 12 0 12 12 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 13 13 13 13 13 14 13 13 13 13 14 14 13 14 13 14 13 13 13 13 13 13 14 14 13 13 13 13 13 13 14 14 13 13 13 14 13 13 13 1 12 24 36 24 24 24 24 24 24 24 24 36 36 36 36 36 36 36 36 24 24 24 24 36 36 36 36 36 36 36 36 24 24 24 24 36 36 36 36 2 16 16 16 16 16 16 0 0 16 16 16 16 0 16 0 16 0 16 16 0 16 16 16 16 0 16 16 0 16 16 16 16 0 16 16 16 0 16 16 3 17 17 17 17 17 14 17 17 17 17 14 14 17 14 17 14 17 17 17 17 17 17 14 14 17 17 17 17 17 17 14 14 17 17 17 14 17 17 17 1 8 20 32 20 20 20 20 20 20 20 20 32 32 32 32 32 32 32 32 20 20 20 20 32 32 32 32 32 32 32 32 20 20 20 20 32 32 32 32 2 19 19 19 19 19 19 0 0 19 19 19 19 0 19 0 19 0 19 19 0 19 19 19 19 0 19 19 0 19 19 19 19 0 19 19 19 0 19 19 3 20 20 20 20 20 14 20 20 20 20 14 14 20 14 20 14 20 20 20 20 20 20 14 14 20 20 20 20 20 20 14 14 20 20 20 14 20 20 20 4 11 11 11 15 11 11 11 11 18 11 11 15 11 15 11 11 11 18 11 11 21 11 11 11 11 21 11 11 21 11 11 11 11 21 11 11 11 18 11 1 5 17 29 17 17 17 17 17 17 17 17 29 29 29 29 29 29 29 29 17 17 17 17 29 29 29 29 29 29 29 29 17 17 17 17 29 29 29 29 2 23 23 23 23 23 23 0 0 23 23 23 23 0 23 0 23 0 23 23 0 23 23 23 23 0 23 23 0 23 23 23 23 0 23 23 23 0 23 23 3 24 24 24 24 24 14 24 24 24 24 14 14 24 14 24 14 24 24 24 24 24 24 14 14 24 24 24 24 24 24 14 14 24 24 24 14 24 24 24 3 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 4 25 25 25 26 25 25 25 25 26 25 25 26 25 26 25 25 25 26 25 25 26 25 25 25 25 26 25 25 26 25 25 25 25 26 25 25 25 26 25 1 13 25 37 25 25 25 25 25 25 25 25 37 37 37 37 37 37 37 37 25 25 25 25 37 37 37 37 37 37 37 37 25 25 25 25 37 37 37 37 2 28 28 28 28 28 28 0 0 28 28 28 28 0 28 0 28 0 28 28 0 28 28 28 28 0 28 28 0 28 28 28 28 0 28 28 28 0 28 28 3 29 29 29 29 29 14 29 29 29 29 14 14 29 14 29 14 29 29 29 29 29 29 14 14 29 29 29 29 29 29 14 14 29 29 29 14 29 29 29 4 30 30 30 26 30 30 30 30 26 30 30 26 30 26 30 30 30 26 30 30 26 30 30 30 30 26 30 30 26 30 30 30 30 26 30 30 30 26 30 1 9 21 33 21 21 21 21 21 21 21 21 33 33 33 33 33 33 33 33 21 21 21 21 33 33 33 33 33 33 33 33 21 21 21 21 33 33 33 33 2 32 32 32 32 32 32 0 0 32 32 32 32 0 32 0 32 0 32 32 0 32 32 32 32 0 32 32 0 32 32 32 32 0 32 32 32 0 32 32 3 33 33 33 33 33 14 33 33 33 33 14 14 33 14 33 14 33 33 33 33 33 33 14 14 33 33 33 33 33 33 14 14 33 33 33 14 33 33 33 4 34 34 34 26 34 34 34 34 26 34 34 26 34 26 34 34 34 26 34 34 26 34 34 34 34 26 34 34 26 34 34 34 34 26 34 34 34 26 34 5 22 22 22 22 27 22 22 22 22 31 22 22 27 22 27 22 22 22 31 22 22 35 22 22 22 22 35 22 22 35 22 22 22 22 35 22 22 22 31 @COLORS 0 0 0 0 1 0 155 67 2 127 0 255 3 132 132 132 4 132 132 132 5 132 132 132 6 132 132 132 7 186 185 102 8 186 185 102 9 186 185 102 10 186 185 102 11 12 106 251 12 12 106 251 13 12 106 251 14 12 106 251 15 23 151 78 16 23 151 78 17 23 151 78 18 23 151 78 19 32 160 73 20 32 160 73 21 32 160 73 22 32 160 73 23 2 146 99 24 2 146 99 25 2 146 99 26 2 146 99 27 128 23 233 28 128 23 233 29 128 23 233 30 128 23 233 31 137 32 228 32 137 32 228 33 137 32 228 34 137 32 228 35 106 18 255 36 106 18 255 37 106 18 255 38 106 18 255 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 1178 16 1" /* colors */ "A c #009B43" "B c #7F00FF" ". c #000000" "D c #808080" "E c #B9B860" "F c #0064FF" "G c #404040" "H c #5C5C30" "I c #00327F" "J c #408D61" "K c #5CA951" "L c #007FA1" "M c #7F40BF" "N c #9C5CAF" "O c #3F32FF" "P c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 3 */ "..............................." ".......D...............D......." ".......D...............D......." "........D.............D........" "........D.............D........" ".........DDDPPDDDPPDDD........." "............PPDDDPP............" ".............DDDDD............." "........DD....DDD....DD........" ".........DD...DDD...DD........." "..........DD..DDD..DD.........." "...........DDDDDDDDD..........." "............DDDDDDD............" "..............DDD.............." "..............DDD.............." "...........DDDDDDDDD..........." "..........DDDDDDDDDDD.........." ".........DD...DDD...DD........." "........DD....DDD....DD........" ".............DDDDD............." "............DDDDDDD............" "...........DD.DDD.DD..........." "..........DD..DDD..DD.........." ".........DD...DDD...DD........." "........DD...GDDDG...DD........" ".............DDDDD............." ".............DDDDD............." ".............GDDDG............." "..............DDD.............." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................DD." "......D.....D.........D...DD..." "......DD....DD.......DD..D....." ".......DD....DD.....DD...D....." "........DD....DD...DD....D....." ".........DD...DD..DD....PP....." "...GDDG...DD..DD..DD...DPP....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "...GDDG...DD..DD..DD...DPP....." ".........DD...DD..DD....PP....." "........DD....DD...DD....D....." ".......DD....DD.....DD...D....." "......DD....DD.......DD..D....." "......D.....D.........D...DD..." "............................DD." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 5 */ "..............................." "..............................." "..............DDD.............." ".............GDDDG............." ".............DDDDD............." ".............DDDDD............." "........DD...GDDDG...DD........" ".........DD...DDD...DD........." "..........DD..DDD..DD.........." "...........DD.DDD.DD..........." "............DDDDDDD............" ".............DDDDD............." "........DD....DDD....DD........" ".........DD...DDD...DD........." "..........DDDDDDDDDDD.........." "...........DDDDDDDDD..........." "..............DDD.............." "..............DDD.............." "............DDDDDDD............" "...........DDDDDDDDD..........." "..........DD..DDD..DD.........." ".........DD...DDD...DD........." "........DD....DDD....DD........" ".............DDDDD............." "............PPDDDPP............" ".........DDDPPDDDPPDDD........." "........D.............D........" "........D.............D........" ".......D...............D......." ".......D...............D......." "..............................." /* icon for state 6 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".DD............................" "...DD...D.........D.....D......" ".....D..DD.......DD....DD......" ".....D...DD.....DD....DD......." ".....D....DD...DD....DD........" ".....PP....DD..DD...DD........." ".....PPD...DD..DD..DD...GDDG..." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....PPD...DD..DD..DD...GDDG..." ".....PP....DD..DD...DD........." ".....D....DD...DD....DD........" ".....D...DD.....DD....DD......." ".....D..DD.......DD....DD......" "...DD...D.........D.....D......" ".DD............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 7 */ "..............................." ".......E...............E......." ".......E...............E......." "........E.............E........" "........E.............E........" ".........EEEPPEEEPPEEE........." "............PPEEEPP............" ".............EEEEE............." "........EE....EEE....EE........" ".........EE...EEE...EE........." "..........EE..EEE..EE.........." "...........EEEEEEEEE..........." "............EEEEEEE............" "..............EEE.............." "..............EEE.............." "...........EEEEEEEEE..........." "..........EEEEEEEEEEE.........." ".........EE...EEE...EE........." "........EE....EEE....EE........" ".............EEEEE............." "............EEEEEEE............" "...........EE.EEE.EE..........." "..........EE..EEE..EE.........." ".........EE...EEE...EE........." "........EE...HEEEH...EE........" ".............EEEEE............." ".............EEEEE............." ".............HEEEH............." "..............EEE.............." "..............................." "..............................." /* icon for state 8 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................EE." "......E.....E.........E...EE..." "......EE....EE.......EE..E....." ".......EE....EE.....EE...E....." "........EE....EE...EE....E....." ".........EE...EE..EE....PP....." "...HEEH...EE..EE..EE...EPP....." "..EEEEEEEEEEEEEEEEEEEEEEEE....." "..EEEEEEEEEEEEEEEEEEEEEEEE....." "..EEEEEEEEEEEEEEEEEEEEEEEE....." "...HEEH...EE..EE..EE...EPP....." ".........EE...EE..EE....PP....." "........EE....EE...EE....E....." ".......EE....EE.....EE...E....." "......EE....EE.......EE..E....." "......E.....E.........E...EE..." "............................EE." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 9 */ "..............................." "..............................." "..............EEE.............." ".............HEEEH............." ".............EEEEE............." ".............EEEEE............." "........EE...HEEEH...EE........" ".........EE...EEE...EE........." "..........EE..EEE..EE.........." "...........EE.EEE.EE..........." "............EEEEEEE............" ".............EEEEE............." "........EE....EEE....EE........" ".........EE...EEE...EE........." "..........EEEEEEEEEEE.........." "...........EEEEEEEEE..........." "..............EEE.............." "..............EEE.............." "............EEEEEEE............" "...........EEEEEEEEE..........." "..........EE..EEE..EE.........." ".........EE...EEE...EE........." "........EE....EEE....EE........" ".............EEEEE............." "............PPEEEPP............" ".........EEEPPEEEPPEEE........." "........E.............E........" "........E.............E........" ".......E...............E......." ".......E...............E......." "..............................." /* icon for state 10 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".EE............................" "...EE...E.........E.....E......" ".....E..EE.......EE....EE......" ".....E...EE.....EE....EE......." ".....E....EE...EE....EE........" ".....PP....EE..EE...EE........." ".....PPE...EE..EE..EE...HEEH..." ".....EEEEEEEEEEEEEEEEEEEEEEEE.." ".....EEEEEEEEEEEEEEEEEEEEEEEE.." ".....EEEEEEEEEEEEEEEEEEEEEEEE.." ".....PPE...EE..EE..EE...HEEH..." ".....PP....EE..EE...EE........." ".....E....EE...EE....EE........" ".....E...EE.....EE....EE......." ".....E..EE.......EE....EE......" "...EE...E.........E.....E......" ".EE............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 11 */ "..............................." ".......F...............F......." ".......F...............F......." "........F.............F........" "........F.............F........" ".........FFFPPFFFPPFFF........." "............PPFFFPP............" ".............FFFFF............." "........FF....FFF....FF........" ".........FF...FFF...FF........." "..........FF..FFF..FF.........." "...........FFFFFFFFF..........." "............FFFFFFF............" "..............FFF.............." "..............FFF.............." "...........FFFFFFFFF..........." "..........FFFFFFFFFFF.........." ".........FF...FFF...FF........." "........FF....FFF....FF........" ".............FFFFF............." "............FFFFFFF............" "...........FF.FFF.FF..........." "..........FF..FFF..FF.........." ".........FF...FFF...FF........." "........FF...IFFFI...FF........" ".............FFFFF............." ".............FFFFF............." ".............IFFFI............." "..............FFF.............." "..............................." "..............................." /* icon for state 12 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................FF." "......F.....F.........F...FF..." "......FF....FF.......FF..F....." ".......FF....FF.....FF...F....." "........FF....FF...FF....F....." ".........FF...FF..FF....PP....." "...IFFI...FF..FF..FF...FPP....." "..FFFFFFFFFFFFFFFFFFFFFFFF....." "..FFFFFFFFFFFFFFFFFFFFFFFF....." "..FFFFFFFFFFFFFFFFFFFFFFFF....." "...IFFI...FF..FF..FF...FPP....." ".........FF...FF..FF....PP....." "........FF....FF...FF....F....." ".......FF....FF.....FF...F....." "......FF....FF.......FF..F....." "......F.....F.........F...FF..." "............................FF." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 13 */ "..............................." "..............................." "..............FFF.............." ".............IFFFI............." ".............FFFFF............." ".............FFFFF............." "........FF...IFFFI...FF........" ".........FF...FFF...FF........." "..........FF..FFF..FF.........." "...........FF.FFF.FF..........." "............FFFFFFF............" ".............FFFFF............." "........FF....FFF....FF........" ".........FF...FFF...FF........." "..........FFFFFFFFFFF.........." "...........FFFFFFFFF..........." "..............FFF.............." "..............FFF.............." "............FFFFFFF............" "...........FFFFFFFFF..........." "..........FF..FFF..FF.........." ".........FF...FFF...FF........." "........FF....FFF....FF........" ".............FFFFF............." "............PPFFFPP............" ".........FFFPPFFFPPFFF........." "........F.............F........" "........F.............F........" ".......F...............F......." ".......F...............F......." "..............................." /* icon for state 14 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".FF............................" "...FF...F.........F.....F......" ".....F..FF.......FF....FF......" ".....F...FF.....FF....FF......." ".....F....FF...FF....FF........" ".....PP....FF..FF...FF........." ".....PPF...FF..FF..FF...IFFI..." ".....FFFFFFFFFFFFFFFFFFFFFFFF.." ".....FFFFFFFFFFFFFFFFFFFFFFFF.." ".....FFFFFFFFFFFFFFFFFFFFFFFF.." ".....PPF...FF..FF..FF...IFFI..." ".....PP....FF..FF...FF........." ".....F....FF...FF....FF........" ".....F...FF.....FF....FF......." ".....F..FF.......FF....FF......" "...FF...F.........F.....F......" ".FF............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 15 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAAADDDPPDDDPPDDDAAAAAAAAA" "AAAAAAAAAAAAPPDDDPPAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAADDDDDDDDDDDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAADDADDDADDAAAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAJDDDJAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAAJDDDJAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 16 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAADDA" "AAAAAADAAAAADAAAAAAAAADAAADDAAA" "AAAAAADDAAAADDAAAAAAADDAADAAAAA" "AAAAAAADDAAAADDAAAAADDAAADAAAAA" "AAAAAAAADDAAAADDAAADDAAAADAAAAA" "AAAAAAAAADDAAADDAADDAAAAPPAAAAA" "AAAJDDJAAADDAADDAADDAAADPPAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AAAJDDJAAADDAADDAADDAAADPPAAAAA" "AAAAAAAAADDAAADDAADDAAAAPPAAAAA" "AAAAAAAADDAAAADDAAADDAAAADAAAAA" "AAAAAAADDAAAADDAAAAADDAAADAAAAA" "AAAAAADDAAAADDAAAAAAADDAADAAAAA" "AAAAAADAAAAADAAAAAAAAADAAADDAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAADDA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 17 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAJDDDJAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAJDDDJAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAAAADDADDDADDAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDDDDDDDDDDAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAPPDDDPPAAAAAAAAAAAA" "AAAAAAAAADDDPPDDDPPDDDAAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 18 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "ADDAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAADDAAADAAAAAAAAADAAAAADAAAAAA" "AAAAADAADDAAAAAAADDAAAADDAAAAAA" "AAAAADAAADDAAAAADDAAAADDAAAAAAA" "AAAAADAAAADDAAADDAAAADDAAAAAAAA" "AAAAAPPAAAADDAADDAAADDAAAAAAAAA" "AAAAAPPDAAADDAADDAADDAAAJDDJAAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAAPPDAAADDAADDAADDAAAJDDJAAA" "AAAAAPPAAAADDAADDAAADDAAAAAAAAA" "AAAAADAAAADDAAADDAAAADDAAAAAAAA" "AAAAADAAADDAAAAADDAAAADDAAAAAAA" "AAAAADAADDAAAAAAADDAAAADDAAAAAA" "AAADDAAADAAAAAAAAADAAAAADAAAAAA" "ADDAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 19 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAEAAAAAAAAAAAAAAAEAAAAAAA" "AAAAAAAEAAAAAAAAAAAAAAAEAAAAAAA" "AAAAAAAAEAAAAAAAAAAAAAEAAAAAAAA" "AAAAAAAAEAAAAAAAAAAAAAEAAAAAAAA" "AAAAAAAAAEEEPPEEEPPEEEAAAAAAAAA" "AAAAAAAAAAAAPPEEEPPAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAEEAAAAEEEAAAAEEAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAAAEEAAEEEAAEEAAAAAAAAAA" "AAAAAAAAAAAEEEEEEEEEAAAAAAAAAAA" "AAAAAAAAAAAAEEEEEEEAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAEEEEEEEEEAAAAAAAAAAA" "AAAAAAAAAAEEEEEEEEEEEAAAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAEEAAAAEEEAAAAEEAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAEEEEEEEAAAAAAAAAAAA" "AAAAAAAAAAAEEAEEEAEEAAAAAAAAAAA" "AAAAAAAAAAEEAAEEEAAEEAAAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAEEAAAKEEEKAAAEEAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAAKEEEKAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 20 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAEEA" "AAAAAAEAAAAAEAAAAAAAAAEAAAEEAAA" "AAAAAAEEAAAAEEAAAAAAAEEAAEAAAAA" "AAAAAAAEEAAAAEEAAAAAEEAAAEAAAAA" "AAAAAAAAEEAAAAEEAAAEEAAAAEAAAAA" "AAAAAAAAAEEAAAEEAAEEAAAAPPAAAAA" "AAAKEEKAAAEEAAEEAAEEAAAEPPAAAAA" "AAEEEEEEEEEEEEEEEEEEEEEEEEAAAAA" "AAEEEEEEEEEEEEEEEEEEEEEEEEAAAAA" "AAEEEEEEEEEEEEEEEEEEEEEEEEAAAAA" "AAAKEEKAAAEEAAEEAAEEAAAEPPAAAAA" "AAAAAAAAAEEAAAEEAAEEAAAAPPAAAAA" "AAAAAAAAEEAAAAEEAAAEEAAAAEAAAAA" "AAAAAAAEEAAAAEEAAAAAEEAAAEAAAAA" "AAAAAAEEAAAAEEAAAAAAAEEAAEAAAAA" "AAAAAAEAAAAAEAAAAAAAAAEAAAEEAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAEEA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 21 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAAKEEEKAAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAEEAAAKEEEKAAAEEAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAAAEEAAEEEAAEEAAAAAAAAAA" "AAAAAAAAAAAEEAEEEAEEAAAAAAAAAAA" "AAAAAAAAAAAAEEEEEEEAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAEEAAAAEEEAAAAEEAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAAAEEEEEEEEEEEAAAAAAAAAA" "AAAAAAAAAAAEEEEEEEEEAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAEEEEEEEAAAAAAAAAAAA" "AAAAAAAAAAAEEEEEEEEEAAAAAAAAAAA" "AAAAAAAAAAEEAAEEEAAEEAAAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAEEAAAAEEEAAAAEEAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAPPEEEPPAAAAAAAAAAAA" "AAAAAAAAAEEEPPEEEPPEEEAAAAAAAAA" "AAAAAAAAEAAAAAAAAAAAAAEAAAAAAAA" "AAAAAAAAEAAAAAAAAAAAAAEAAAAAAAA" "AAAAAAAEAAAAAAAAAAAAAAAEAAAAAAA" "AAAAAAAEAAAAAAAAAAAAAAAEAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 22 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AEEAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAEEAAAEAAAAAAAAAEAAAAAEAAAAAA" "AAAAAEAAEEAAAAAAAEEAAAAEEAAAAAA" "AAAAAEAAAEEAAAAAEEAAAAEEAAAAAAA" "AAAAAEAAAAEEAAAEEAAAAEEAAAAAAAA" "AAAAAPPAAAAEEAAEEAAAEEAAAAAAAAA" "AAAAAPPEAAAEEAAEEAAEEAAAKEEKAAA" "AAAAAEEEEEEEEEEEEEEEEEEEEEEEEAA" "AAAAAEEEEEEEEEEEEEEEEEEEEEEEEAA" "AAAAAEEEEEEEEEEEEEEEEEEEEEEEEAA" "AAAAAPPEAAAEEAAEEAAEEAAAKEEKAAA" "AAAAAPPAAAAEEAAEEAAAEEAAAAAAAAA" "AAAAAEAAAAEEAAAEEAAAAEEAAAAAAAA" "AAAAAEAAAEEAAAAAEEAAAAEEAAAAAAA" "AAAAAEAAEEAAAAAAAEEAAAAEEAAAAAA" "AAAEEAAAEAAAAAAAAAEAAAAAEAAAAAA" "AEEAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 23 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAFAAAAAAAAAAAAAAAFAAAAAAA" "AAAAAAAFAAAAAAAAAAAAAAAFAAAAAAA" "AAAAAAAAFAAAAAAAAAAAAAFAAAAAAAA" "AAAAAAAAFAAAAAAAAAAAAAFAAAAAAAA" "AAAAAAAAAFFFPPFFFPPFFFAAAAAAAAA" "AAAAAAAAAAAAPPFFFPPAAAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAFFAAAAFFFAAAAFFAAAAAAAA" "AAAAAAAAAFFAAAFFFAAAFFAAAAAAAAA" "AAAAAAAAAAFFAAFFFAAFFAAAAAAAAAA" "AAAAAAAAAAAFFFFFFFFFAAAAAAAAAAA" "AAAAAAAAAAAAFFFFFFFAAAAAAAAAAAA" "AAAAAAAAAAAAAAFFFAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAFFFAAAAAAAAAAAAAA" "AAAAAAAAAAAFFFFFFFFFAAAAAAAAAAA" "AAAAAAAAAAFFFFFFFFFFFAAAAAAAAAA" "AAAAAAAAAFFAAAFFFAAAFFAAAAAAAAA" "AAAAAAAAFFAAAAFFFAAAAFFAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAAAFFFFFFFAAAAAAAAAAAA" "AAAAAAAAAAAFFAFFFAFFAAAAAAAAAAA" "AAAAAAAAAAFFAAFFFAAFFAAAAAAAAAA" "AAAAAAAAAFFAAAFFFAAAFFAAAAAAAAA" "AAAAAAAAFFAAALFFFLAAAFFAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAAAALFFFLAAAAAAAAAAAAA" "AAAAAAAAAAAAAAFFFAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 24 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAFFA" "AAAAAAFAAAAAFAAAAAAAAAFAAAFFAAA" "AAAAAAFFAAAAFFAAAAAAAFFAAFAAAAA" "AAAAAAAFFAAAAFFAAAAAFFAAAFAAAAA" "AAAAAAAAFFAAAAFFAAAFFAAAAFAAAAA" "AAAAAAAAAFFAAAFFAAFFAAAAPPAAAAA" "AAALFFLAAAFFAAFFAAFFAAAFPPAAAAA" "AAFFFFFFFFFFFFFFFFFFFFFFFFAAAAA" "AAFFFFFFFFFFFFFFFFFFFFFFFFAAAAA" "AAFFFFFFFFFFFFFFFFFFFFFFFFAAAAA" "AAALFFLAAAFFAAFFAAFFAAAFPPAAAAA" "AAAAAAAAAFFAAAFFAAFFAAAAPPAAAAA" "AAAAAAAAFFAAAAFFAAAFFAAAAFAAAAA" "AAAAAAAFFAAAAFFAAAAAFFAAAFAAAAA" "AAAAAAFFAAAAFFAAAAAAAFFAAFAAAAA" "AAAAAAFAAAAAFAAAAAAAAAFAAAFFAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAFFA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 25 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAFFFAAAAAAAAAAAAAA" "AAAAAAAAAAAAALFFFLAAAAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAFFAAALFFFLAAAFFAAAAAAAA" "AAAAAAAAAFFAAAFFFAAAFFAAAAAAAAA" "AAAAAAAAAAFFAAFFFAAFFAAAAAAAAAA" "AAAAAAAAAAAFFAFFFAFFAAAAAAAAAAA" "AAAAAAAAAAAAFFFFFFFAAAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAFFAAAAFFFAAAAFFAAAAAAAA" "AAAAAAAAAFFAAAFFFAAAFFAAAAAAAAA" "AAAAAAAAAAFFFFFFFFFFFAAAAAAAAAA" "AAAAAAAAAAAFFFFFFFFFAAAAAAAAAAA" "AAAAAAAAAAAAAAFFFAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAFFFAAAAAAAAAAAAAA" "AAAAAAAAAAAAFFFFFFFAAAAAAAAAAAA" "AAAAAAAAAAAFFFFFFFFFAAAAAAAAAAA" "AAAAAAAAAAFFAAFFFAAFFAAAAAAAAAA" "AAAAAAAAAFFAAAFFFAAAFFAAAAAAAAA" "AAAAAAAAFFAAAAFFFAAAAFFAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAAAPPFFFPPAAAAAAAAAAAA" "AAAAAAAAAFFFPPFFFPPFFFAAAAAAAAA" "AAAAAAAAFAAAAAAAAAAAAAFAAAAAAAA" "AAAAAAAAFAAAAAAAAAAAAAFAAAAAAAA" "AAAAAAAFAAAAAAAAAAAAAAAFAAAAAAA" "AAAAAAAFAAAAAAAAAAAAAAAFAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 26 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AFFAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAFFAAAFAAAAAAAAAFAAAAAFAAAAAA" "AAAAAFAAFFAAAAAAAFFAAAAFFAAAAAA" "AAAAAFAAAFFAAAAAFFAAAAFFAAAAAAA" "AAAAAFAAAAFFAAAFFAAAAFFAAAAAAAA" "AAAAAPPAAAAFFAAFFAAAFFAAAAAAAAA" "AAAAAPPFAAAFFAAFFAAFFAAALFFLAAA" "AAAAAFFFFFFFFFFFFFFFFFFFFFFFFAA" "AAAAAFFFFFFFFFFFFFFFFFFFFFFFFAA" "AAAAAFFFFFFFFFFFFFFFFFFFFFFFFAA" "AAAAAPPFAAAFFAAFFAAFFAAALFFLAAA" "AAAAAPPAAAAFFAAFFAAAFFAAAAAAAAA" "AAAAAFAAAAFFAAAFFAAAAFFAAAAAAAA" "AAAAAFAAAFFAAAAAFFAAAAFFAAAAAAA" "AAAAAFAAFFAAAAAAAFFAAAAFFAAAAAA" "AAAFFAAAFAAAAAAAAAFAAAAAFAAAAAA" "AFFAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 27 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBDBBBBBBBBBBBBBBBDBBBBBBB" "BBBBBBBDBBBBBBBBBBBBBBBDBBBBBBB" "BBBBBBBBDBBBBBBBBBBBBBDBBBBBBBB" "BBBBBBBBDBBBBBBBBBBBBBDBBBBBBBB" "BBBBBBBBBDDDPPDDDPPDDDBBBBBBBBB" "BBBBBBBBBBBBPPDDDPPBBBBBBBBBBBB" "BBBBBBBBBBBBBDDDDDBBBBBBBBBBBBB" "BBBBBBBBDDBBBBDDDBBBBDDBBBBBBBB" "BBBBBBBBBDDBBBDDDBBBDDBBBBBBBBB" "BBBBBBBBBBDDBBDDDBBDDBBBBBBBBBB" "BBBBBBBBBBBDDDDDDDDDBBBBBBBBBBB" "BBBBBBBBBBBBDDDDDDDBBBBBBBBBBBB" "BBBBBBBBBBBBBBDDDBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBDDDBBBBBBBBBBBBBB" "BBBBBBBBBBBDDDDDDDDDBBBBBBBBBBB" "BBBBBBBBBBDDDDDDDDDDDBBBBBBBBBB" "BBBBBBBBBDDBBBDDDBBBDDBBBBBBBBB" "BBBBBBBBDDBBBBDDDBBBBDDBBBBBBBB" "BBBBBBBBBBBBBDDDDDBBBBBBBBBBBBB" "BBBBBBBBBBBBDDDDDDDBBBBBBBBBBBB" "BBBBBBBBBBBDDBDDDBDDBBBBBBBBBBB" "BBBBBBBBBBDDBBDDDBBDDBBBBBBBBBB" "BBBBBBBBBDDBBBDDDBBBDDBBBBBBBBB" "BBBBBBBBDDBBBMDDDMBBBDDBBBBBBBB" "BBBBBBBBBBBBBDDDDDBBBBBBBBBBBBB" "BBBBBBBBBBBBBDDDDDBBBBBBBBBBBBB" "BBBBBBBBBBBBBMDDDMBBBBBBBBBBBBB" "BBBBBBBBBBBBBBDDDBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 28 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBDDB" "BBBBBBDBBBBBDBBBBBBBBBDBBBDDBBB" "BBBBBBDDBBBBDDBBBBBBBDDBBDBBBBB" "BBBBBBBDDBBBBDDBBBBBDDBBBDBBBBB" "BBBBBBBBDDBBBBDDBBBDDBBBBDBBBBB" "BBBBBBBBBDDBBBDDBBDDBBBBPPBBBBB" "BBBMDDMBBBDDBBDDBBDDBBBDPPBBBBB" "BBDDDDDDDDDDDDDDDDDDDDDDDDBBBBB" "BBDDDDDDDDDDDDDDDDDDDDDDDDBBBBB" "BBDDDDDDDDDDDDDDDDDDDDDDDDBBBBB" "BBBMDDMBBBDDBBDDBBDDBBBDPPBBBBB" "BBBBBBBBBDDBBBDDBBDDBBBBPPBBBBB" "BBBBBBBBDDBBBBDDBBBDDBBBBDBBBBB" "BBBBBBBDDBBBBDDBBBBBDDBBBDBBBBB" "BBBBBBDDBBBBDDBBBBBBBDDBBDBBBBB" "BBBBBBDBBBBBDBBBBBBBBBDBBBDDBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBDDB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 29 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBDDDBBBBBBBBBBBBBB" "BBBBBBBBBBBBBMDDDMBBBBBBBBBBBBB" "BBBBBBBBBBBBBDDDDDBBBBBBBBBBBBB" "BBBBBBBBBBBBBDDDDDBBBBBBBBBBBBB" "BBBBBBBBDDBBBMDDDMBBBDDBBBBBBBB" "BBBBBBBBBDDBBBDDDBBBDDBBBBBBBBB" "BBBBBBBBBBDDBBDDDBBDDBBBBBBBBBB" "BBBBBBBBBBBDDBDDDBDDBBBBBBBBBBB" "BBBBBBBBBBBBDDDDDDDBBBBBBBBBBBB" "BBBBBBBBBBBBBDDDDDBBBBBBBBBBBBB" "BBBBBBBBDDBBBBDDDBBBBDDBBBBBBBB" "BBBBBBBBBDDBBBDDDBBBDDBBBBBBBBB" "BBBBBBBBBBDDDDDDDDDDDBBBBBBBBBB" "BBBBBBBBBBBDDDDDDDDDBBBBBBBBBBB" "BBBBBBBBBBBBBBDDDBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBDDDBBBBBBBBBBBBBB" "BBBBBBBBBBBBDDDDDDDBBBBBBBBBBBB" "BBBBBBBBBBBDDDDDDDDDBBBBBBBBBBB" "BBBBBBBBBBDDBBDDDBBDDBBBBBBBBBB" "BBBBBBBBBDDBBBDDDBBBDDBBBBBBBBB" "BBBBBBBBDDBBBBDDDBBBBDDBBBBBBBB" "BBBBBBBBBBBBBDDDDDBBBBBBBBBBBBB" "BBBBBBBBBBBBPPDDDPPBBBBBBBBBBBB" "BBBBBBBBBDDDPPDDDPPDDDBBBBBBBBB" "BBBBBBBBDBBBBBBBBBBBBBDBBBBBBBB" "BBBBBBBBDBBBBBBBBBBBBBDBBBBBBBB" "BBBBBBBDBBBBBBBBBBBBBBBDBBBBBBB" "BBBBBBBDBBBBBBBBBBBBBBBDBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 30 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BDDBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBDDBBBDBBBBBBBBBDBBBBBDBBBBBB" "BBBBBDBBDDBBBBBBBDDBBBBDDBBBBBB" "BBBBBDBBBDDBBBBBDDBBBBDDBBBBBBB" "BBBBBDBBBBDDBBBDDBBBBDDBBBBBBBB" "BBBBBPPBBBBDDBBDDBBBDDBBBBBBBBB" "BBBBBPPDBBBDDBBDDBBDDBBBMDDMBBB" "BBBBBDDDDDDDDDDDDDDDDDDDDDDDDBB" "BBBBBDDDDDDDDDDDDDDDDDDDDDDDDBB" "BBBBBDDDDDDDDDDDDDDDDDDDDDDDDBB" "BBBBBPPDBBBDDBBDDBBDDBBBMDDMBBB" "BBBBBPPBBBBDDBBDDBBBDDBBBBBBBBB" "BBBBBDBBBBDDBBBDDBBBBDDBBBBBBBB" "BBBBBDBBBDDBBBBBDDBBBBDDBBBBBBB" "BBBBBDBBDDBBBBBBBDDBBBBDDBBBBBB" "BBBDDBBBDBBBBBBBBBDBBBBBDBBBBBB" "BDDBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 31 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBEBBBBBBBBBBBBBBBEBBBBBBB" "BBBBBBBEBBBBBBBBBBBBBBBEBBBBBBB" "BBBBBBBBEBBBBBBBBBBBBBEBBBBBBBB" "BBBBBBBBEBBBBBBBBBBBBBEBBBBBBBB" "BBBBBBBBBEEEPPEEEPPEEEBBBBBBBBB" "BBBBBBBBBBBBPPEEEPPBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBEEBBBBEEEBBBBEEBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBBBEEBBEEEBBEEBBBBBBBBBB" "BBBBBBBBBBBEEEEEEEEEBBBBBBBBBBB" "BBBBBBBBBBBBEEEEEEEBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBEEEEEEEEEBBBBBBBBBBB" "BBBBBBBBBBEEEEEEEEEEEBBBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBEEBBBBEEEBBBBEEBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBEEEEEEEBBBBBBBBBBBB" "BBBBBBBBBBBEEBEEEBEEBBBBBBBBBBB" "BBBBBBBBBBEEBBEEEBBEEBBBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBEEBBBNEEENBBBEEBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBBNEEENBBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 32 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBEEB" "BBBBBBEBBBBBEBBBBBBBBBEBBBEEBBB" "BBBBBBEEBBBBEEBBBBBBBEEBBEBBBBB" "BBBBBBBEEBBBBEEBBBBBEEBBBEBBBBB" "BBBBBBBBEEBBBBEEBBBEEBBBBEBBBBB" "BBBBBBBBBEEBBBEEBBEEBBBBPPBBBBB" "BBBNEENBBBEEBBEEBBEEBBBEPPBBBBB" "BBEEEEEEEEEEEEEEEEEEEEEEEEBBBBB" "BBEEEEEEEEEEEEEEEEEEEEEEEEBBBBB" "BBEEEEEEEEEEEEEEEEEEEEEEEEBBBBB" "BBBNEENBBBEEBBEEBBEEBBBEPPBBBBB" "BBBBBBBBBEEBBBEEBBEEBBBBPPBBBBB" "BBBBBBBBEEBBBBEEBBBEEBBBBEBBBBB" "BBBBBBBEEBBBBEEBBBBBEEBBBEBBBBB" "BBBBBBEEBBBBEEBBBBBBBEEBBEBBBBB" "BBBBBBEBBBBBEBBBBBBBBBEBBBEEBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBEEB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 33 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBBNEEENBBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBEEBBBNEEENBBBEEBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBBBEEBBEEEBBEEBBBBBBBBBB" "BBBBBBBBBBBEEBEEEBEEBBBBBBBBBBB" "BBBBBBBBBBBBEEEEEEEBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBEEBBBBEEEBBBBEEBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBBBEEEEEEEEEEEBBBBBBBBBB" "BBBBBBBBBBBEEEEEEEEEBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBEEEEEEEBBBBBBBBBBBB" "BBBBBBBBBBBEEEEEEEEEBBBBBBBBBBB" "BBBBBBBBBBEEBBEEEBBEEBBBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBEEBBBBEEEBBBBEEBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBPPEEEPPBBBBBBBBBBBB" "BBBBBBBBBEEEPPEEEPPEEEBBBBBBBBB" "BBBBBBBBEBBBBBBBBBBBBBEBBBBBBBB" "BBBBBBBBEBBBBBBBBBBBBBEBBBBBBBB" "BBBBBBBEBBBBBBBBBBBBBBBEBBBBBBB" "BBBBBBBEBBBBBBBBBBBBBBBEBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 34 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BEEBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBEEBBBEBBBBBBBBBEBBBBBEBBBBBB" "BBBBBEBBEEBBBBBBBEEBBBBEEBBBBBB" "BBBBBEBBBEEBBBBBEEBBBBEEBBBBBBB" "BBBBBEBBBBEEBBBEEBBBBEEBBBBBBBB" "BBBBBPPBBBBEEBBEEBBBEEBBBBBBBBB" "BBBBBPPEBBBEEBBEEBBEEBBBNEENBBB" "BBBBBEEEEEEEEEEEEEEEEEEEEEEEEBB" "BBBBBEEEEEEEEEEEEEEEEEEEEEEEEBB" "BBBBBEEEEEEEEEEEEEEEEEEEEEEEEBB" "BBBBBPPEBBBEEBBEEBBEEBBBNEENBBB" "BBBBBPPBBBBEEBBEEBBBEEBBBBBBBBB" "BBBBBEBBBBEEBBBEEBBBBEEBBBBBBBB" "BBBBBEBBBEEBBBBBEEBBBBEEBBBBBBB" "BBBBBEBBEEBBBBBBBEEBBBBEEBBBBBB" "BBBEEBBBEBBBBBBBBBEBBBBBEBBBBBB" "BEEBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 35 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBFBBBBBBBBBBBBBBBFBBBBBBB" "BBBBBBBFBBBBBBBBBBBBBBBFBBBBBBB" "BBBBBBBBFBBBBBBBBBBBBBFBBBBBBBB" "BBBBBBBBFBBBBBBBBBBBBBFBBBBBBBB" "BBBBBBBBBFFFPPFFFPPFFFBBBBBBBBB" "BBBBBBBBBBBBPPFFFPPBBBBBBBBBBBB" "BBBBBBBBBBBBBFFFFFBBBBBBBBBBBBB" "BBBBBBBBFFBBBBFFFBBBBFFBBBBBBBB" "BBBBBBBBBFFBBBFFFBBBFFBBBBBBBBB" "BBBBBBBBBBFFBBFFFBBFFBBBBBBBBBB" "BBBBBBBBBBBFFFFFFFFFBBBBBBBBBBB" "BBBBBBBBBBBBFFFFFFFBBBBBBBBBBBB" "BBBBBBBBBBBBBBFFFBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBFFFBBBBBBBBBBBBBB" "BBBBBBBBBBBFFFFFFFFFBBBBBBBBBBB" "BBBBBBBBBBFFFFFFFFFFFBBBBBBBBBB" "BBBBBBBBBFFBBBFFFBBBFFBBBBBBBBB" "BBBBBBBBFFBBBBFFFBBBBFFBBBBBBBB" "BBBBBBBBBBBBBFFFFFBBBBBBBBBBBBB" "BBBBBBBBBBBBFFFFFFFBBBBBBBBBBBB" "BBBBBBBBBBBFFBFFFBFFBBBBBBBBBBB" "BBBBBBBBBBFFBBFFFBBFFBBBBBBBBBB" "BBBBBBBBBFFBBBFFFBBBFFBBBBBBBBB" "BBBBBBBBFFBBBOFFFOBBBFFBBBBBBBB" "BBBBBBBBBBBBBFFFFFBBBBBBBBBBBBB" "BBBBBBBBBBBBBFFFFFBBBBBBBBBBBBB" "BBBBBBBBBBBBBOFFFOBBBBBBBBBBBBB" "BBBBBBBBBBBBBBFFFBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 36 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBFFB" "BBBBBBFBBBBBFBBBBBBBBBFBBBFFBBB" "BBBBBBFFBBBBFFBBBBBBBFFBBFBBBBB" "BBBBBBBFFBBBBFFBBBBBFFBBBFBBBBB" "BBBBBBBBFFBBBBFFBBBFFBBBBFBBBBB" "BBBBBBBBBFFBBBFFBBFFBBBBPPBBBBB" "BBBOFFOBBBFFBBFFBBFFBBBFPPBBBBB" "BBFFFFFFFFFFFFFFFFFFFFFFFFBBBBB" "BBFFFFFFFFFFFFFFFFFFFFFFFFBBBBB" "BBFFFFFFFFFFFFFFFFFFFFFFFFBBBBB" "BBBOFFOBBBFFBBFFBBFFBBBFPPBBBBB" "BBBBBBBBBFFBBBFFBBFFBBBBPPBBBBB" "BBBBBBBBFFBBBBFFBBBFFBBBBFBBBBB" "BBBBBBBFFBBBBFFBBBBBFFBBBFBBBBB" "BBBBBBFFBBBBFFBBBBBBBFFBBFBBBBB" "BBBBBBFBBBBBFBBBBBBBBBFBBBFFBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBFFB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 37 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBFFFBBBBBBBBBBBBBB" "BBBBBBBBBBBBBOFFFOBBBBBBBBBBBBB" "BBBBBBBBBBBBBFFFFFBBBBBBBBBBBBB" "BBBBBBBBBBBBBFFFFFBBBBBBBBBBBBB" "BBBBBBBBFFBBBOFFFOBBBFFBBBBBBBB" "BBBBBBBBBFFBBBFFFBBBFFBBBBBBBBB" "BBBBBBBBBBFFBBFFFBBFFBBBBBBBBBB" "BBBBBBBBBBBFFBFFFBFFBBBBBBBBBBB" "BBBBBBBBBBBBFFFFFFFBBBBBBBBBBBB" "BBBBBBBBBBBBBFFFFFBBBBBBBBBBBBB" "BBBBBBBBFFBBBBFFFBBBBFFBBBBBBBB" "BBBBBBBBBFFBBBFFFBBBFFBBBBBBBBB" "BBBBBBBBBBFFFFFFFFFFFBBBBBBBBBB" "BBBBBBBBBBBFFFFFFFFFBBBBBBBBBBB" "BBBBBBBBBBBBBBFFFBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBFFFBBBBBBBBBBBBBB" "BBBBBBBBBBBBFFFFFFFBBBBBBBBBBBB" "BBBBBBBBBBBFFFFFFFFFBBBBBBBBBBB" "BBBBBBBBBBFFBBFFFBBFFBBBBBBBBBB" "BBBBBBBBBFFBBBFFFBBBFFBBBBBBBBB" "BBBBBBBBFFBBBBFFFBBBBFFBBBBBBBB" "BBBBBBBBBBBBBFFFFFBBBBBBBBBBBBB" "BBBBBBBBBBBBPPFFFPPBBBBBBBBBBBB" "BBBBBBBBBFFFPPFFFPPFFFBBBBBBBBB" "BBBBBBBBFBBBBBBBBBBBBBFBBBBBBBB" "BBBBBBBBFBBBBBBBBBBBBBFBBBBBBBB" "BBBBBBBFBBBBBBBBBBBBBBBFBBBBBBB" "BBBBBBBFBBBBBBBBBBBBBBBFBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 38 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BFFBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBFFBBBFBBBBBBBBBFBBBBBFBBBBBB" "BBBBBFBBFFBBBBBBBFFBBBBFFBBBBBB" "BBBBBFBBBFFBBBBBFFBBBBFFBBBBBBB" "BBBBBFBBBBFFBBBFFBBBBFFBBBBBBBB" "BBBBBPPBBBBFFBBFFBBBFFBBBBBBBBB" "BBBBBPPFBBBFFBBFFBBFFBBBOFFOBBB" "BBBBBFFFFFFFFFFFFFFFFFFFFFFFFBB" "BBBBBFFFFFFFFFFFFFFFFFFFFFFFFBB" "BBBBBFFFFFFFFFFFFFFFFFFFFFFFFBB" "BBBBBPPFBBBFFBBFFBBFFBBBOFFOBBB" "BBBBBPPBBBBFFBBFFBBBFFBBBBBBBBB" "BBBBBFBBBBFFBBBFFBBBBFFBBBBBBBB" "BBBBBFBBBFFBBBBBFFBBBBFFBBBBBBB" "BBBBBFBBFFBBBBBBBFFBBBBFFBBBBBB" "BBBFFBBBFBBBBBBBBBFBBBBBFBBBBBB" "BFFBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" XPM /* width height num_colors chars_per_pixel */ "15 570 16 1" /* colors */ "A c #009B43" "B c #7F00FF" ". c #000000" "D c #808080" "E c #B9B860" "F c #0064FF" "G c #404040" "H c #5C5C30" "I c #00327F" "J c #408D61" "K c #5CA951" "L c #007FA1" "M c #7F40BF" "N c #9C5CAF" "O c #3F32FF" "P c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 3 */ "....D.....D...." ".....D...D....." "......PDP......" "...D..DDD..D..." "....D..D..D...." ".....DDDDD....." ".......D......." "....DDDDDDD...." "...D...D...D..." ".....DDDDD....." "....D..D..D...." "...D..GDG..D..." "......DDD......" "......GDG......" "..............." /* icon for state 4 */ "..............." "..............." "..............." "...D..D....D..." "....D..D..D...D" ".....D.D.D...D." ".GDG.D.D.D.DP.." ".DDDDDDDDDDDD.." ".GDG.D.D.D.DP.." ".....D.D.D...D." "....D..D..D...D" "...D..D....D..." "..............." "..............." "..............." /* icon for state 5 */ "..............." "......GDG......" "......DDD......" "...D..GDG..D..." "....D..D..D...." ".....DDDDD....." "...D...D...D..." "....DDDDDDD...." ".......D......." ".....DDDDD....." "....D..D..D...." "...D..DDD..D..." "......PDP......" ".....D...D....." "....D.....D...." /* icon for state 6 */ "..............." "..............." "..............." "...D....D..D..." "D...D..D..D...." ".D...D.D.D....." "..PD.D.D.D.GDG." "..DDDDDDDDDDDD." "..PD.D.D.D.GDG." ".D...D.D.D....." "D...D..D..D...." "...D....D..D..." "..............." "..............." "..............." /* icon for state 7 */ "....E.....E...." ".....E...E....." "......PEP......" "...E..EEE..E..." "....E..E..E...." ".....EEEEE....." ".......E......." "....EEEEEEE...." "...E...E...E..." ".....EEEEE....." "....E..E..E...." "...E..HEH..E..." "......EEE......" "......HEH......" "..............." /* icon for state 8 */ "..............." "..............." "..............." "...E..E....E..." "....E..E..E...E" ".....E.E.E...E." ".HEH.E.E.E.EP.." ".EEEEEEEEEEEE.." ".HEH.E.E.E.EP.." ".....E.E.E...E." "....E..E..E...E" "...E..E....E..." "..............." "..............." "..............." /* icon for state 9 */ "..............." "......HEH......" "......EEE......" "...E..HEH..E..." "....E..E..E...." ".....EEEEE....." "...E...E...E..." "....EEEEEEE...." ".......E......." ".....EEEEE....." "....E..E..E...." "...E..EEE..E..." "......PEP......" ".....E...E....." "....E.....E...." /* icon for state 10 */ "..............." "..............." "..............." "...E....E..E..." "E...E..E..E...." ".E...E.E.E....." "..PE.E.E.E.HEH." "..EEEEEEEEEEEE." "..PE.E.E.E.HEH." ".E...E.E.E....." "E...E..E..E...." "...E....E..E..." "..............." "..............." "..............." /* icon for state 11 */ "....F.....F...." ".....F...F....." "......PFP......" "...F..FFF..F..." "....F..F..F...." ".....FFFFF....." ".......F......." "....FFFFFFF...." "...F...F...F..." ".....FFFFF....." "....F..F..F...." "...F..IFI..F..." "......FFF......" "......IFI......" "..............." /* icon for state 12 */ "..............." "..............." "..............." "...F..F....F..." "....F..F..F...F" ".....F.F.F...F." ".IFI.F.F.F.FP.." ".FFFFFFFFFFFF.." ".IFI.F.F.F.FP.." ".....F.F.F...F." "....F..F..F...F" "...F..F....F..." "..............." "..............." "..............." /* icon for state 13 */ "..............." "......IFI......" "......FFF......" "...F..IFI..F..." "....F..F..F...." ".....FFFFF....." "...F...F...F..." "....FFFFFFF...." ".......F......." ".....FFFFF....." "....F..F..F...." "...F..FFF..F..." "......PFP......" ".....F...F....." "....F.....F...." /* icon for state 14 */ "..............." "..............." "..............." "...F....F..F..." "F...F..F..F...." ".F...F.F.F....." "..PF.F.F.F.IFI." "..FFFFFFFFFFFF." "..PF.F.F.F.IFI." ".F...F.F.F....." "F...F..F..F...." "...F....F..F..." "..............." "..............." "..............." /* icon for state 15 */ "AAAADAAAAADAAAA" "AAAAADAAADAAAAA" "AAAAAAPDPAAAAAA" "AAADAADDDAADAAA" "AAAADAADAADAAAA" "AAAAADDDDDAAAAA" "AAAAAAADAAAAAAA" "AAAADDDDDDDAAAA" "AAADAAADAAADAAA" "AAAAADDDDDAAAAA" "AAAADAADAADAAAA" "AAADAAJDJAADAAA" "AAAAAADDDAAAAAA" "AAAAAAJDJAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 16 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAADAADAAAADAAA" "AAAADAADAADAAAD" "AAAAADADADAAADA" "AJDJADADADADPAA" "ADDDDDDDDDDDDAA" "AJDJADADADADPAA" "AAAAADADADAAADA" "AAAADAADAADAAAD" "AAADAADAAAADAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 17 */ "AAAAAAAAAAAAAAA" "AAAAAAJDJAAAAAA" "AAAAAADDDAAAAAA" "AAADAAJDJAADAAA" "AAAADAADAADAAAA" "AAAAADDDDDAAAAA" "AAADAAADAAADAAA" "AAAADDDDDDDAAAA" "AAAAAAADAAAAAAA" "AAAAADDDDDAAAAA" "AAAADAADAADAAAA" "AAADAADDDAADAAA" "AAAAAAPDPAAAAAA" "AAAAADAAADAAAAA" "AAAADAAAAADAAAA" /* icon for state 18 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAADAAAADAADAAA" "DAAADAADAADAAAA" "ADAAADADADAAAAA" "AAPDADADADAJDJA" "AADDDDDDDDDDDDA" "AAPDADADADAJDJA" "ADAAADADADAAAAA" "DAAADAADAADAAAA" "AAADAAAADAADAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 19 */ "AAAAEAAAAAEAAAA" "AAAAAEAAAEAAAAA" "AAAAAAPEPAAAAAA" "AAAEAAEEEAAEAAA" "AAAAEAAEAAEAAAA" "AAAAAEEEEEAAAAA" "AAAAAAAEAAAAAAA" "AAAAEEEEEEEAAAA" "AAAEAAAEAAAEAAA" "AAAAAEEEEEAAAAA" "AAAAEAAEAAEAAAA" "AAAEAAKEKAAEAAA" "AAAAAAEEEAAAAAA" "AAAAAAKEKAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 20 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAEAAEAAAAEAAA" "AAAAEAAEAAEAAAE" "AAAAAEAEAEAAAEA" "AKEKAEAEAEAEPAA" "AEEEEEEEEEEEEAA" "AKEKAEAEAEAEPAA" "AAAAAEAEAEAAAEA" "AAAAEAAEAAEAAAE" "AAAEAAEAAAAEAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 21 */ "AAAAAAAAAAAAAAA" "AAAAAAKEKAAAAAA" "AAAAAAEEEAAAAAA" "AAAEAAKEKAAEAAA" "AAAAEAAEAAEAAAA" "AAAAAEEEEEAAAAA" "AAAEAAAEAAAEAAA" "AAAAEEEEEEEAAAA" "AAAAAAAEAAAAAAA" "AAAAAEEEEEAAAAA" "AAAAEAAEAAEAAAA" "AAAEAAEEEAAEAAA" "AAAAAAPEPAAAAAA" "AAAAAEAAAEAAAAA" "AAAAEAAAAAEAAAA" /* icon for state 22 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAEAAAAEAAEAAA" "EAAAEAAEAAEAAAA" "AEAAAEAEAEAAAAA" "AAPEAEAEAEAKEKA" "AAEEEEEEEEEEEEA" "AAPEAEAEAEAKEKA" "AEAAAEAEAEAAAAA" "EAAAEAAEAAEAAAA" "AAAEAAAAEAAEAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 23 */ "AAAAFAAAAAFAAAA" "AAAAAFAAAFAAAAA" "AAAAAAPFPAAAAAA" "AAAFAAFFFAAFAAA" "AAAAFAAFAAFAAAA" "AAAAAFFFFFAAAAA" "AAAAAAAFAAAAAAA" "AAAAFFFFFFFAAAA" "AAAFAAAFAAAFAAA" "AAAAAFFFFFAAAAA" "AAAAFAAFAAFAAAA" "AAAFAALFLAAFAAA" "AAAAAAFFFAAAAAA" "AAAAAALFLAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 24 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAFAAFAAAAFAAA" "AAAAFAAFAAFAAAF" "AAAAAFAFAFAAAFA" "ALFLAFAFAFAFPAA" "AFFFFFFFFFFFFAA" "ALFLAFAFAFAFPAA" "AAAAAFAFAFAAAFA" "AAAAFAAFAAFAAAF" "AAAFAAFAAAAFAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 25 */ "AAAAAAAAAAAAAAA" "AAAAAALFLAAAAAA" "AAAAAAFFFAAAAAA" "AAAFAALFLAAFAAA" "AAAAFAAFAAFAAAA" "AAAAAFFFFFAAAAA" "AAAFAAAFAAAFAAA" "AAAAFFFFFFFAAAA" "AAAAAAAFAAAAAAA" "AAAAAFFFFFAAAAA" "AAAAFAAFAAFAAAA" "AAAFAAFFFAAFAAA" "AAAAAAPFPAAAAAA" "AAAAAFAAAFAAAAA" "AAAAFAAAAAFAAAA" /* icon for state 26 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAFAAAAFAAFAAA" "FAAAFAAFAAFAAAA" "AFAAAFAFAFAAAAA" "AAPFAFAFAFALFLA" "AAFFFFFFFFFFFFA" "AAPFAFAFAFALFLA" "AFAAAFAFAFAAAAA" "FAAAFAAFAAFAAAA" "AAAFAAAAFAAFAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 27 */ "BBBBDBBBBBDBBBB" "BBBBBDBBBDBBBBB" "BBBBBBPDPBBBBBB" "BBBDBBDDDBBDBBB" "BBBBDBBDBBDBBBB" "BBBBBDDDDDBBBBB" "BBBBBBBDBBBBBBB" "BBBBDDDDDDDBBBB" "BBBDBBBDBBBDBBB" "BBBBBDDDDDBBBBB" "BBBBDBBDBBDBBBB" "BBBDBBMDMBBDBBB" "BBBBBBDDDBBBBBB" "BBBBBBMDMBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 28 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBDBBDBBBBDBBB" "BBBBDBBDBBDBBBD" "BBBBBDBDBDBBBDB" "BMDMBDBDBDBDPBB" "BDDDDDDDDDDDDBB" "BMDMBDBDBDBDPBB" "BBBBBDBDBDBBBDB" "BBBBDBBDBBDBBBD" "BBBDBBDBBBBDBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 29 */ "BBBBBBBBBBBBBBB" "BBBBBBMDMBBBBBB" "BBBBBBDDDBBBBBB" "BBBDBBMDMBBDBBB" "BBBBDBBDBBDBBBB" "BBBBBDDDDDBBBBB" "BBBDBBBDBBBDBBB" "BBBBDDDDDDDBBBB" "BBBBBBBDBBBBBBB" "BBBBBDDDDDBBBBB" "BBBBDBBDBBDBBBB" "BBBDBBDDDBBDBBB" "BBBBBBPDPBBBBBB" "BBBBBDBBBDBBBBB" "BBBBDBBBBBDBBBB" /* icon for state 30 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBDBBBBDBBDBBB" "DBBBDBBDBBDBBBB" "BDBBBDBDBDBBBBB" "BBPDBDBDBDBMDMB" "BBDDDDDDDDDDDDB" "BBPDBDBDBDBMDMB" "BDBBBDBDBDBBBBB" "DBBBDBBDBBDBBBB" "BBBDBBBBDBBDBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 31 */ "BBBBEBBBBBEBBBB" "BBBBBEBBBEBBBBB" "BBBBBBPEPBBBBBB" "BBBEBBEEEBBEBBB" "BBBBEBBEBBEBBBB" "BBBBBEEEEEBBBBB" "BBBBBBBEBBBBBBB" "BBBBEEEEEEEBBBB" "BBBEBBBEBBBEBBB" "BBBBBEEEEEBBBBB" "BBBBEBBEBBEBBBB" "BBBEBBNENBBEBBB" "BBBBBBEEEBBBBBB" "BBBBBBNENBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 32 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBEBBEBBBBEBBB" "BBBBEBBEBBEBBBE" "BBBBBEBEBEBBBEB" "BNENBEBEBEBEPBB" "BEEEEEEEEEEEEBB" "BNENBEBEBEBEPBB" "BBBBBEBEBEBBBEB" "BBBBEBBEBBEBBBE" "BBBEBBEBBBBEBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 33 */ "BBBBBBBBBBBBBBB" "BBBBBBNENBBBBBB" "BBBBBBEEEBBBBBB" "BBBEBBNENBBEBBB" "BBBBEBBEBBEBBBB" "BBBBBEEEEEBBBBB" "BBBEBBBEBBBEBBB" "BBBBEEEEEEEBBBB" "BBBBBBBEBBBBBBB" "BBBBBEEEEEBBBBB" "BBBBEBBEBBEBBBB" "BBBEBBEEEBBEBBB" "BBBBBBPEPBBBBBB" "BBBBBEBBBEBBBBB" "BBBBEBBBBBEBBBB" /* icon for state 34 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBEBBBBEBBEBBB" "EBBBEBBEBBEBBBB" "BEBBBEBEBEBBBBB" "BBPEBEBEBEBNENB" "BBEEEEEEEEEEEEB" "BBPEBEBEBEBNENB" "BEBBBEBEBEBBBBB" "EBBBEBBEBBEBBBB" "BBBEBBBBEBBEBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 35 */ "BBBBFBBBBBFBBBB" "BBBBBFBBBFBBBBB" "BBBBBBPFPBBBBBB" "BBBFBBFFFBBFBBB" "BBBBFBBFBBFBBBB" "BBBBBFFFFFBBBBB" "BBBBBBBFBBBBBBB" "BBBBFFFFFFFBBBB" "BBBFBBBFBBBFBBB" "BBBBBFFFFFBBBBB" "BBBBFBBFBBFBBBB" "BBBFBBOFOBBFBBB" "BBBBBBFFFBBBBBB" "BBBBBBOFOBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 36 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBFBBFBBBBFBBB" "BBBBFBBFBBFBBBF" "BBBBBFBFBFBBBFB" "BOFOBFBFBFBFPBB" "BFFFFFFFFFFFFBB" "BOFOBFBFBFBFPBB" "BBBBBFBFBFBBBFB" "BBBBFBBFBBFBBBF" "BBBFBBFBBBBFBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 37 */ "BBBBBBBBBBBBBBB" "BBBBBBOFOBBBBBB" "BBBBBBFFFBBBBBB" "BBBFBBOFOBBFBBB" "BBBBFBBFBBFBBBB" "BBBBBFFFFFBBBBB" "BBBFBBBFBBBFBBB" "BBBBFFFFFFFBBBB" "BBBBBBBFBBBBBBB" "BBBBBFFFFFBBBBB" "BBBBFBBFBBFBBBB" "BBBFBBFFFBBFBBB" "BBBBBBPFPBBBBBB" "BBBBBFBBBFBBBBB" "BBBBFBBBBBFBBBB" /* icon for state 38 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBFBBBBFBBFBBB" "FBBBFBBFBBFBBBB" "BFBBBFBFBFBBBBB" "BBPFBFBFBFBOFOB" "BBFFFFFFFFFFFFB" "BBPFBFBFBFBOFOB" "BFBBBFBFBFBBBBB" "FBBBFBBFBBFBBBB" "BBBFBBBBFBBFBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" XPM /* width height num_colors chars_per_pixel */ "7 266 16 1" /* colors */ "A c #009B43" "B c #7F00FF" ". c #000000" "D c #808080" "E c #B9B860" "F c #0064FF" "G c #404040" "H c #5C5C30" "I c #00327F" "J c #408D61" "K c #5CA951" "L c #007FA1" "M c #7F40BF" "N c #9C5CAF" "O c #3F32FF" "P c #FFFFFF" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" /* icon for state 3 */ ".D...D." "..PDP.." "...D..." ".DDDDD." "...D..." ".DDDDD." "...D..." /* icon for state 4 */ "......." ".D.D..D" ".D.D.P." "DDDDDD." ".D.D.P." ".D.D..D" "......." /* icon for state 5 */ "...D..." ".DDDDD." "...D..." ".DDDDD." "...D..." "..PDP.." ".D...D." /* icon for state 6 */ "......." "D..D.D." ".P.D.D." ".DDDDDD" ".P.D.D." "D..D.D." "......." /* icon for state 7 */ ".E...E." "..PEP.." "...E..." ".EEEEE." "...E..." ".EEEEE." "...E..." /* icon for state 8 */ "......." ".E.E..E" ".E.E.P." "EEEEEE." ".E.E.P." ".E.E..E" "......." /* icon for state 9 */ "...E..." ".EEEEE." "...E..." ".EEEEE." "...E..." "..PEP.." ".E...E." /* icon for state 10 */ "......." "E..E.E." ".P.E.E." ".EEEEEE" ".P.E.E." "E..E.E." "......." /* icon for state 11 */ ".F...F." "..PFP.." "...F..." ".FFFFF." "...F..." ".FFFFF." "...F..." /* icon for state 12 */ "......." ".F.F..F" ".F.F.P." "FFFFFF." ".F.F.P." ".F.F..F" "......." /* icon for state 13 */ "...F..." ".FFFFF." "...F..." ".FFFFF." "...F..." "..PFP.." ".F...F." /* icon for state 14 */ "......." "F..F.F." ".P.F.F." ".FFFFFF" ".P.F.F." "F..F.F." "......." /* icon for state 15 */ "ADAAADA" "AAPDPAA" "AAADAAA" "ADDDDDA" "AAADAAA" "ADDDDDA" "AAADAAA" /* icon for state 16 */ "AAAAAAA" "ADADAAD" "ADADAPA" "DDDDDDA" "ADADAPA" "ADADAAD" "AAAAAAA" /* icon for state 17 */ "AAADAAA" "ADDDDDA" "AAADAAA" "ADDDDDA" "AAADAAA" "AAPDPAA" "ADAAADA" /* icon for state 18 */ "AAAAAAA" "DAADADA" "APADADA" "ADDDDDD" "APADADA" "DAADADA" "AAAAAAA" /* icon for state 19 */ "AEAAAEA" "AAPEPAA" "AAAEAAA" "AEEEEEA" "AAAEAAA" "AEEEEEA" "AAAEAAA" /* icon for state 20 */ "AAAAAAA" "AEAEAAE" "AEAEAPA" "EEEEEEA" "AEAEAPA" "AEAEAAE" "AAAAAAA" /* icon for state 21 */ "AAAEAAA" "AEEEEEA" "AAAEAAA" "AEEEEEA" "AAAEAAA" "AAPEPAA" "AEAAAEA" /* icon for state 22 */ "AAAAAAA" "EAAEAEA" "APAEAEA" "AEEEEEE" "APAEAEA" "EAAEAEA" "AAAAAAA" /* icon for state 23 */ "AFAAAFA" "AAPFPAA" "AAAFAAA" "AFFFFFA" "AAAFAAA" "AFFFFFA" "AAAFAAA" /* icon for state 24 */ "AAAAAAA" "AFAFAAF" "AFAFAPA" "FFFFFFA" "AFAFAPA" "AFAFAAF" "AAAAAAA" /* icon for state 25 */ "AAAFAAA" "AFFFFFA" "AAAFAAA" "AFFFFFA" "AAAFAAA" "AAPFPAA" "AFAAAFA" /* icon for state 26 */ "AAAAAAA" "FAAFAFA" "APAFAFA" "AFFFFFF" "APAFAFA" "FAAFAFA" "AAAAAAA" /* icon for state 27 */ "BDBBBDB" "BBPDPBB" "BBBDBBB" "BDDDDDB" "BBBDBBB" "BDDDDDB" "BBBDBBB" /* icon for state 28 */ "BBBBBBB" "BDBDBBD" "BDBDBPB" "DDDDDDB" "BDBDBPB" "BDBDBBD" "BBBBBBB" /* icon for state 29 */ "BBBDBBB" "BDDDDDB" "BBBDBBB" "BDDDDDB" "BBBDBBB" "BBPDPBB" "BDBBBDB" /* icon for state 30 */ "BBBBBBB" "DBBDBDB" "BPBDBDB" "BDDDDDD" "BPBDBDB" "DBBDBDB" "BBBBBBB" /* icon for state 31 */ "BEBBBEB" "BBPEPBB" "BBBEBBB" "BEEEEEB" "BBBEBBB" "BEEEEEB" "BBBEBBB" /* icon for state 32 */ "BBBBBBB" "BEBEBBE" "BEBEBPB" "EEEEEEB" "BEBEBPB" "BEBEBBE" "BBBBBBB" /* icon for state 33 */ "BBBEBBB" "BEEEEEB" "BBBEBBB" "BEEEEEB" "BBBEBBB" "BBPEPBB" "BEBBBEB" /* icon for state 34 */ "BBBBBBB" "EBBEBEB" "BPBEBEB" "BEEEEEE" "BPBEBEB" "EBBEBEB" "BBBBBBB" /* icon for state 35 */ "BFBBBFB" "BBPFPBB" "BBBFBBB" "BFFFFFB" "BBBFBBB" "BFFFFFB" "BBBFBBB" /* icon for state 36 */ "BBBBBBB" "BFBFBBF" "BFBFBPB" "FFFFFFB" "BFBFBPB" "BFBFBBF" "BBBBBBB" /* icon for state 37 */ "BBBFBBB" "BFFFFFB" "BBBFBBB" "BFFFFFB" "BBBFBBB" "BBPFPBB" "BFBBBFB" /* icon for state 38 */ "BBBBBBB" "FBBFBFB" "BPBFBFB" "BFFFFFF" "BPBFBFB" "FBBFBFB" "BBBBBBB" �����������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Worm-1040512.rule���������������������������������������������������������������0000644�0001750�0001750�00000011251�12536111364�013741� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Worm-1040512 Paterson's worms (by Dean Hickerson, 11/19/2008) Pattern #055 Sven Kahrkling's notation 1040512 Gardner's notation 1a2c3cbaa4b Finishes after 569804 steps, almost filling a regular hexagon. Points and lines of hexagonal grid are mapped to points of square grid as below. "*" is a point of the hex grid, "-", "/", and "\" are lines of the hex grid. +--+--+--+--+ |- |* |- |* | +--+--+--+--+ | /| \| /| \| +--+--+--+--+ |* |- |* |- | +--+--+--+--+ Each step of the worm is simulated by 2 gens in the rule. In even gens, there's an arrow at one point of the hex grid showing which way the worm will move next. In odd gens, there's an arrow on one line of the hex grid. The transitions from even to odd gens are the same for all worms. Those from odd to even depend on the specific type of worm: If a point (state 0 or 1) has a line with an arrow pointing at it, it becomes a 'point with arrow'; the direction depends on the 6 neighboring lines, which are the NW, N, E, S, SW, and W neighbors in the square grid. Gen 0 consists of a single point in state 1, a 'point with arrow' pointing east. (Starting with a point in state 2, 3, 4, 5, or 6 would also work, rotating the whole pattern.) States are: 0 empty (unvisited point or line) 1-6 'point with arrow', showing direction of next movement (1=E; 2=SE; 3=SW; 4=W; 5=NW; 6=NE) 7 point that's been visited 8,9,10 edge - (8=line; 9=E arrow; 10=W arrow) 11,12,13 edge / (11=line; 12=NE arrow; 13=SW arrow) 14,15,16 edge \ (14=line; 15=SE arrow; 16=NW arrow) @TABLE n_states:17 neighborhood:Moore symmetries:none var point={1,2,3,4,5,6} var a0={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a1={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a2={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a3={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a4={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a5={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a6={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a7={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var n={8,11,14} var o={8,11,14} var p={8,11,14} var q={8,11,14} var b={0,7} # point with arrow becomes point that's been visited point,a0,a1,a2,a3,a4,a5,a6,a7,7 # line with arrow becomes line without arrow 9,a0,a1,a2,a3,a4,a5,a6,a7,8 10,a0,a1,a2,a3,a4,a5,a6,a7,8 12,a0,a1,a2,a3,a4,a5,a6,a7,11 13,a0,a1,a2,a3,a4,a5,a6,a7,11 15,a0,a1,a2,a3,a4,a5,a6,a7,14 16,a0,a1,a2,a3,a4,a5,a6,a7,14 # point with arrow creates line with arrow next to it 0,a0,a1,a2,a3,a4,a5,1,a6,9 0,2,a0,a1,a2,a3,a4,a5,a6,15 0,a0,3,a1,a2,a3,a4,a5,a6,13 0,a0,a1,4,a2,a3,a4,a5,a6,10 0,a0,a1,a2,5,a3,a4,a5,a6,16 0,a0,a1,a2,a3,6,a4,a5,a6,12 # 4 eaten: use only remaining direction # 0 (straight): b,0,a0,n,a1,o,12,p,q,6 b,n,a0,0,a1,o,p,9,q,1 b,n,a0,o,a1,0,p,q,15,2 b,13,a0,n,a1,o,0,p,q,3 b,n,a0,10,a1,o,p,0,q,4 b,n,a0,o,a1,16,p,q,0,5 # 1 (gentle right): b,n,a0,0,a1,o,12,p,q,1 b,n,a0,o,a1,0,p,9,q,2 b,n,a0,o,a1,p,0,q,15,3 b,13,a0,n,a1,o,p,0,q,4 b,n,a0,10,a1,o,p,q,0,5 b,0,a0,n,a1,16,o,p,q,6 # 2 (sharp right): b,n,a0,o,a1,0,12,p,q,2 b,n,a0,o,a1,p,0,9,q,3 b,n,a0,o,a1,p,q,0,15,4 b,13,a0,n,a1,o,p,q,0,5 b,0,a0,10,a1,n,o,p,q,6 b,n,a0,0,a1,16,o,p,q,1 # 4 (sharp left): b,n,a0,o,a1,p,12,0,q,4 b,n,a0,o,a1,p,q,9,0,5 b,0,a0,n,a1,o,p,q,15,6 b,13,a0,0,a1,n,o,p,q,1 b,n,a0,10,a1,0,o,p,q,2 b,n,a0,o,a1,16,0,p,q,3 # 5 (gentle left): b,n,a0,o,a1,p,12,q,0,5 b,0,a0,n,a1,o,p,9,q,6 b,n,a0,0,a1,o,p,q,15,1 b,13,a0,n,a1,0,o,p,q,2 b,n,a0,10,a1,o,0,p,q,3 b,n,a0,o,a1,16,p,0,q,4 # rule-specific transitions at point with arrow coming in # rule 1040512 # none eaten: 1 = gentle right b,0,a0,0,a1,0,12,0,0,1 b,0,a0,0,a1,0,0,9,0,2 b,0,a0,0,a1,0,0,0,15,3 b,13,a0,0,a1,0,0,0,0,4 b,0,a0,10,a1,0,0,0,0,5 b,0,a0,0,a1,16,0,0,0,6 # 1 eaten(1): 0 = straight b,0,a0,n,a1,0,12,0,0,6 b,0,a0,0,a1,n,0,9,0,1 b,0,a0,0,a1,0,n,0,15,2 b,13,a0,0,a1,0,0,n,0,3 b,0,a0,10,a1,0,0,0,n,4 b,n,a0,0,a1,16,0,0,0,5 # 2 eaten(02): 4 = sharp left b,n,a0,0,a1,o,12,0,0,4 b,0,a0,n,a1,0,o,9,0,5 b,0,a0,0,a1,n,0,o,15,6 b,13,a0,0,a1,0,n,0,o,1 b,o,a0,10,a1,0,0,n,0,2 b,0,a0,o,a1,16,0,0,n,3 # 2 eaten(15): 0 = straight b,0,a0,o,a1,0,12,0,n,6 b,n,a0,0,a1,o,0,9,0,1 b,0,a0,n,a1,0,o,0,15,2 b,13,a0,0,a1,n,0,o,0,3 b,0,a0,10,a1,0,n,0,o,4 b,o,a0,0,a1,16,0,n,0,5 # 2 eaten(24): 5 = gentle left b,0,a0,0,a1,n,12,o,0,5 b,0,a0,0,a1,0,n,9,o,6 b,o,a0,0,a1,0,0,n,15,1 b,13,a0,o,a1,0,0,0,n,2 b,n,a0,10,a1,o,0,0,0,3 b,0,a0,n,a1,16,o,0,0,4 # 2 eaten(04): 1 = gentle right b,n,a0,0,a1,0,12,o,0,1 b,0,a0,n,a1,0,0,9,o,2 b,o,a0,0,a1,n,0,0,15,3 b,13,a0,o,a1,0,n,0,0,4 b,0,a0,10,a1,o,0,n,0,5 b,0,a0,0,a1,16,o,0,n,6 # 3 eaten(145): 2 = sharp right b,0,a0,n,a1,0,12,o,p,2 b,p,a0,0,a1,n,0,9,o,3 b,o,a0,p,a1,0,n,0,15,4 b,13,a0,o,a1,p,0,n,0,5 b,0,a0,10,a1,o,p,0,n,6 b,n,a0,0,a1,16,o,p,0,1 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Sand-Margolus-emulated.rule�����������������������������������������������������0000644�0001750�0001750�00000006226�12536111364�016463� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Sand-Margolus-emulated @TREE num_states=9 num_neighbors=8 num_nodes=113 1 0 2 2 4 4 6 6 8 8 1 0 1 2 3 4 5 6 7 8 2 0 1 0 1 0 1 0 1 0 2 1 1 1 1 1 1 1 1 1 1 0 2 1 4 3 6 5 8 7 2 0 1 4 1 4 1 4 1 4 3 2 3 5 3 5 3 5 3 5 3 3 3 3 3 3 3 3 3 3 3 5 3 5 3 5 3 5 3 5 4 6 7 8 7 8 7 8 7 8 4 7 7 7 7 7 7 7 7 7 2 4 1 4 1 4 1 4 1 4 3 2 3 11 3 11 3 11 3 11 3 11 3 11 3 11 3 11 3 11 4 12 7 13 7 13 7 13 7 13 5 9 10 14 10 14 10 14 10 14 1 0 1 1 3 3 5 5 7 7 2 16 1 16 1 16 1 16 1 16 3 17 3 17 3 17 3 17 3 17 4 18 7 18 7 18 7 18 7 18 5 19 10 19 10 19 10 19 10 19 1 0 2 2 2 4 6 6 8 8 2 0 1 21 1 21 1 21 1 21 2 0 1 21 1 0 1 0 1 0 3 2 3 22 3 23 3 23 3 23 4 24 7 24 7 24 7 24 7 24 5 25 10 25 10 25 10 25 10 25 3 2 3 23 3 23 3 23 3 23 4 27 7 27 7 27 7 27 7 27 5 28 10 28 10 28 10 28 10 28 6 15 20 26 20 29 20 29 20 29 5 10 10 10 10 10 10 10 10 10 6 20 20 31 20 31 20 31 20 31 3 2 3 2 3 2 3 2 3 2 1 0 1 2 3 2 5 6 7 8 2 1 1 34 1 34 1 34 1 34 3 35 35 3 35 3 35 3 35 3 2 1 1 34 1 1 1 1 1 1 3 37 37 3 37 3 37 3 37 3 4 33 36 33 38 33 38 33 38 33 5 39 10 39 10 39 10 39 10 39 4 24 36 24 38 24 38 24 38 24 5 41 10 41 10 41 10 41 10 41 4 27 36 27 38 27 38 27 38 27 5 43 10 43 10 43 10 43 10 43 6 40 31 42 31 44 31 44 31 44 4 33 38 33 38 33 38 33 38 33 5 46 10 46 10 46 10 46 10 46 4 24 38 24 38 24 38 24 38 24 5 48 10 48 10 48 10 48 10 48 4 27 38 27 38 27 38 27 38 27 5 50 10 50 10 50 10 50 10 50 6 47 31 49 31 51 31 51 31 51 7 30 32 45 32 52 32 52 32 52 6 31 31 31 31 31 31 31 31 31 7 32 32 54 32 54 32 54 32 54 4 33 7 33 7 33 7 33 7 33 1 0 1 4 3 4 5 6 7 8 2 57 57 1 57 1 57 1 57 1 3 3 3 58 3 58 3 58 3 58 4 59 7 59 7 59 7 59 7 59 5 56 10 56 60 56 10 56 60 56 5 25 10 25 60 25 10 25 60 25 5 28 10 28 60 28 10 28 60 28 6 61 31 62 31 63 31 63 31 63 5 39 10 39 60 39 10 39 60 39 5 41 10 41 60 41 10 41 60 41 5 43 10 43 60 43 10 43 60 43 6 65 31 66 31 67 31 67 31 67 5 46 10 46 60 46 10 46 60 46 5 48 10 48 60 48 10 48 60 48 5 50 10 50 60 50 10 50 60 50 6 69 31 70 31 71 31 71 31 71 7 64 54 68 54 72 54 72 54 72 3 3 3 3 3 58 3 58 3 58 4 74 7 74 7 74 7 74 7 74 5 56 75 56 60 56 10 56 75 56 5 25 75 25 60 25 10 25 75 25 5 28 75 28 60 28 10 28 75 28 6 76 31 77 31 78 31 78 31 78 5 39 75 39 60 39 10 39 75 39 5 41 75 41 60 41 10 41 75 41 5 43 75 43 60 43 10 43 75 43 6 80 31 81 31 82 31 82 31 82 5 46 75 46 60 46 10 46 75 46 5 48 75 48 60 48 10 48 75 48 5 50 75 50 60 50 10 50 75 50 6 84 31 85 31 86 31 86 31 86 7 79 54 83 54 87 54 87 54 87 8 53 55 73 55 88 55 73 55 73 1 0 1 3 3 3 5 5 7 7 2 90 1 90 1 90 1 90 1 90 3 91 3 91 3 91 3 91 3 91 4 18 7 92 7 92 7 92 7 92 5 19 10 19 10 93 10 19 10 93 6 94 94 31 94 31 94 31 94 31 7 95 95 54 95 54 95 54 95 54 7 54 54 54 54 54 54 54 54 54 8 96 96 97 96 97 96 97 96 97 5 56 10 56 10 56 10 56 10 56 6 99 31 26 31 29 31 29 31 29 7 100 54 45 54 52 54 52 54 52 8 101 97 73 97 88 97 73 97 73 4 18 7 18 7 92 7 92 7 92 5 19 10 103 10 93 10 19 10 103 6 104 104 31 104 31 104 31 104 31 7 105 105 54 105 54 105 54 105 54 8 106 106 97 106 97 106 97 106 97 5 19 10 19 10 93 10 19 10 103 6 108 108 31 108 31 108 31 108 31 7 109 109 54 109 54 109 54 109 54 8 110 110 97 110 97 110 97 110 97 9 89 98 102 107 102 98 102 111 102 @COLORS 1 90 90 90 2 62 62 62 3 255 255 0 4 220 220 0 5 120 100 0 6 100 80 0 7 148 148 148 8 103 103 103 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Worm-1525115.rule���������������������������������������������������������������0000644�0001750�0001750�00000011351�12536111364�013751� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Worm-1525115 Paterson's worms (by Dean Hickerson, 11/24/2008) Pattern #322 Sven Kahrkling's notation 1525115 Gardner's notation 1a2b3cbcc4a Final outcome unknown; doesn't finish within 1.4*10^17 steps. Forms almost full regular hexagons at certain times. Points and lines of hexagonal grid are mapped to points of square grid as below. "*" is a point of the hex grid, "-", "/", and "\" are lines of the hex grid. +--+--+--+--+ |- |* |- |* | +--+--+--+--+ | /| \| /| \| +--+--+--+--+ |* |- |* |- | +--+--+--+--+ Each step of the worm is simulated by 2 gens in the rule. In even gens, there's an arrow at one point of the hex grid showing which way the worm will move next. In odd gens, there's an arrow on one line of the hex grid. The transitions from even to odd gens are the same for all worms. Those from odd to even depend on the specific type of worm: If a point (state 0 or 1) has a line with an arrow pointing at it, it becomes a 'point with arrow'; the direction depends on the 6 neighboring lines, which are the NW, N, E, S, SW, and W neighbors in the square grid. Gen 0 consists of a single point in state 1, a 'point with arrow' pointing east. (Starting with a point in state 2, 3, 4, 5, or 6 would also work, rotating the whole pattern.) States are: 0 empty (unvisited point or line) 1-6 'point with arrow', showing direction of next movement (1=E; 2=SE; 3=SW; 4=W; 5=NW; 6=NE) 7 point that's been visited 8,9,10 edge - (8=line; 9=E arrow; 10=W arrow) 11,12,13 edge / (11=line; 12=NE arrow; 13=SW arrow) 14,15,16 edge \ (14=line; 15=SE arrow; 16=NW arrow) @TABLE n_states:17 neighborhood:Moore symmetries:none var point={1,2,3,4,5,6} var a0={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a1={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a2={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a3={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a4={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a5={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a6={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a7={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var n={8,11,14} var o={8,11,14} var p={8,11,14} var q={8,11,14} var b={0,7} # point with arrow becomes point that's been visited point,a0,a1,a2,a3,a4,a5,a6,a7,7 # line with arrow becomes line without arrow 9,a0,a1,a2,a3,a4,a5,a6,a7,8 10,a0,a1,a2,a3,a4,a5,a6,a7,8 12,a0,a1,a2,a3,a4,a5,a6,a7,11 13,a0,a1,a2,a3,a4,a5,a6,a7,11 15,a0,a1,a2,a3,a4,a5,a6,a7,14 16,a0,a1,a2,a3,a4,a5,a6,a7,14 # point with arrow creates line with arrow next to it 0,a0,a1,a2,a3,a4,a5,1,a6,9 0,2,a0,a1,a2,a3,a4,a5,a6,15 0,a0,3,a1,a2,a3,a4,a5,a6,13 0,a0,a1,4,a2,a3,a4,a5,a6,10 0,a0,a1,a2,5,a3,a4,a5,a6,16 0,a0,a1,a2,a3,6,a4,a5,a6,12 # 4 eaten: use only remaining direction # 0 (straight): b,0,a0,n,a1,o,12,p,q,6 b,n,a0,0,a1,o,p,9,q,1 b,n,a0,o,a1,0,p,q,15,2 b,13,a0,n,a1,o,0,p,q,3 b,n,a0,10,a1,o,p,0,q,4 b,n,a0,o,a1,16,p,q,0,5 # 1 (gentle right): b,n,a0,0,a1,o,12,p,q,1 b,n,a0,o,a1,0,p,9,q,2 b,n,a0,o,a1,p,0,q,15,3 b,13,a0,n,a1,o,p,0,q,4 b,n,a0,10,a1,o,p,q,0,5 b,0,a0,n,a1,16,o,p,q,6 # 2 (sharp right): b,n,a0,o,a1,0,12,p,q,2 b,n,a0,o,a1,p,0,9,q,3 b,n,a0,o,a1,p,q,0,15,4 b,13,a0,n,a1,o,p,q,0,5 b,0,a0,10,a1,n,o,p,q,6 b,n,a0,0,a1,16,o,p,q,1 # 4 (sharp left): b,n,a0,o,a1,p,12,0,q,4 b,n,a0,o,a1,p,q,9,0,5 b,0,a0,n,a1,o,p,q,15,6 b,13,a0,0,a1,n,o,p,q,1 b,n,a0,10,a1,0,o,p,q,2 b,n,a0,o,a1,16,0,p,q,3 # 5 (gentle left): b,n,a0,o,a1,p,12,q,0,5 b,0,a0,n,a1,o,p,9,q,6 b,n,a0,0,a1,o,p,q,15,1 b,13,a0,n,a1,0,o,p,q,2 b,n,a0,10,a1,o,0,p,q,3 b,n,a0,o,a1,16,p,0,q,4 # rule-specific transitions at point with arrow coming in # rule 1525115 # none eaten: 1 = gentle right b,0,a0,0,a1,0,12,0,0,1 b,0,a0,0,a1,0,0,9,0,2 b,0,a0,0,a1,0,0,0,15,3 b,13,a0,0,a1,0,0,0,0,4 b,0,a0,10,a1,0,0,0,0,5 b,0,a0,0,a1,16,0,0,0,6 # 1 eaten(1): 5 = gentle left b,0,a0,n,a1,0,12,0,0,5 b,0,a0,0,a1,n,0,9,0,6 b,0,a0,0,a1,0,n,0,15,1 b,13,a0,0,a1,0,0,n,0,2 b,0,a0,10,a1,0,0,0,n,3 b,n,a0,0,a1,16,0,0,0,4 # 2 eaten(15): 2 = sharp right b,0,a0,o,a1,0,12,0,n,2 b,n,a0,0,a1,o,0,9,0,3 b,0,a0,n,a1,0,o,0,15,4 b,13,a0,0,a1,n,0,o,0,5 b,0,a0,10,a1,0,n,0,o,6 b,o,a0,0,a1,16,0,n,0,1 # 2 eaten(24): 5 = gentle left b,0,a0,0,a1,n,12,o,0,5 b,0,a0,0,a1,0,n,9,o,6 b,o,a0,0,a1,0,0,n,15,1 b,13,a0,o,a1,0,0,0,n,2 b,n,a0,10,a1,o,0,0,0,3 b,0,a0,n,a1,16,o,0,0,4 # 2 eaten(02): 1 = gentle right b,n,a0,0,a1,o,12,0,0,1 b,0,a0,n,a1,0,o,9,0,2 b,0,a0,0,a1,n,0,o,15,3 b,13,a0,0,a1,0,n,0,o,4 b,o,a0,10,a1,0,0,n,0,5 b,0,a0,o,a1,16,0,0,n,6 # 2 eaten(04): 1 = gentle right b,n,a0,0,a1,0,12,o,0,1 b,0,a0,n,a1,0,0,9,o,2 b,o,a0,0,a1,n,0,0,15,3 b,13,a0,o,a1,0,n,0,0,4 b,0,a0,10,a1,o,0,n,0,5 b,0,a0,0,a1,16,o,0,n,6 # 3 eaten(024): 5 = gentle left b,n,a0,0,a1,o,12,p,0,5 b,0,a0,n,a1,0,o,9,p,6 b,p,a0,0,a1,n,0,o,15,1 b,13,a0,p,a1,0,n,0,o,2 b,o,a0,10,a1,p,0,n,0,3 b,0,a0,o,a1,16,p,0,n,4 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/SDSR-Loop.rule������������������������������������������������������������������0000644�0001750�0001750�00000035311�12536111364�013670� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE SDSR-Loop Hiroki Sayama. "Introduction of Structural Dissolution into Langton's Self-Reproducing Loop." Artificial Life VI: Proceedings of the Sixth International Conference on Artificial Life, C. Adami, R. K. Belew, H. Kitano, and C. E. Taylor, eds., pp.114-122, Los Angeles, California, 1998, MIT Press. Transition rules from: http://necsi.org/postdocs/sayama/sdsr/java/loops.java Credits: "Self-Replicating Loops & Ant, Programmed by Eli Bachmutsky, Copyleft Feb.1999" Note that the transition table given in the above link is incomplete (it's the original Langton's Loops one), and is patched by the function set_undefined_rule(). The table below has these changes incorporated, and was produced automatically by a bottom-up merging procedure from the full 9^5 rule table. Tim Hutton <tim.hutton@gmail.com> @TABLE # rules: 142 # variables: 123 # format: CNESWC' # # Variables are bound within each transition. # For example, if a={1,2} then 4,a,0->a represents # two transitions: 4,1,0->1 and 4,2,0->2 n_states:9 neighborhood:vonNeumann symmetries:rotate4 var a={0,1,2} var b={0,1} var c={0,1} var d={0,1} var e={2,3} var f={0,1,2,3,4,5,6,7} var g={0,1,2,3,4,6,7} var h={4,6,7} var i={6,7} var j={0,1,2,3,4,5,6,7,8} var k={0,1,2,3,4,5,6,7,8} var l={2,3,4,5,6,7} var m={0,1,2,3,5} var n={0,1,8} var o={1,4,6,7} var p={0,1,3,5} var q={1,2,4,6,7} var r={3,5} var s={2,3,4,5,6} var t={0,3,5} var u={1,3,5} var v={0,5} var w={2,3,5} var x={0,2} var y={1,4,7} var z={0,3,5} var A={0,3,5} var B={0,2,3,4,5} var C={0,2,4,6,7} var D={0,1,2,4,6,7} var E={0,1,2,4,6,7} var F={1,3,4,6,7} var G={0,1,2,3,4,5} var H={0,1,2,3,4} var I={1,2,4} var J={0,3,5,6} var K={0,1,3,4,5,6} var L={1,2,4,6} var M={0,3} var N={0,2,3,5} var O={1,3,4,5,6,7} var P={0,1,3,4} var Q={1,2} var R={2,4,6,7} var S={0,1,2,3,4,5,6} var T={0,1,3,4,5,6,7} var U={1,5} var V={0,1,3,4,5} var W={1,3,5} var X={1,3,5} var Y={0,3,4,5,6} var Z={0,6} var aa={0,6} var ab={1,3} var ac={2,5} var ad={2,3,5} var ae={0,7} var af={2,7} var ag={1,4,6,7,8} var ah={1,3,5} var ai={1,2,3,4,5} var aj={1,4,5,6,7} var ak={1,2,3,5} var al={1,2,3,5} var am={4,7} var an={0,5,6} var ao={0,5,6} var ap={0,5,6} var aq={0,5,6} var ar={0,3} var as={0,3} var at={3,7} var au={2,3,5,8} var av={0,1,2,3,4,5,6,7,8} var aw={0,1,4,5,6,7} var ax={0,1,4,5,6,7} var ay={1,4,6,7} var az={0,1,2,3,4,5,6,7} var aA={2,8} var aB={4,5,6,7} var aC={4,5,6} var aD={0,1,5} var aE={0,1,5} var aF={1,4,5,6,7} var aG={0,1,2,4,5,6,7} var aH={5,6,7} var aI={0,2,3,4,5,6,7} var aJ={0,4,6,7} var aK={2,3,5,7} var aL={1,2,3,4,6,7} var aM={1,2,3,4,5,6,7} var aN={3,4,6,7,8} var aO={1,3,4,5,6,7} var aP={2,4,6,7} var aQ={4,5} var aR={0,1,3,4,6,7} var aS={4,6,7,8} var aT={1,2,4,6,7} var aU={4,6,8} var aV={1,2,3,4,5,6,7} var aW={1,2,3,4,5,6,7} var aX={1,2,3,4,5,6,7} var aY={0,3,7} var aZ={0,1,2,3} var ba={0,3,4,5,6,7} var bb={5,8} var bc={0,1,7} var bd={0,1,3,7} var be={1,2,7} var bf={1,3,6,7} var bg={0,1,2,3,7} var bh={3,6} var bi={5,6} var bj={2,3,4,5,6,7} var bk={2,3,4,5,6,7} var bl={2,3,4,5,6,7} var bm={6,8} var bn={6,7,8} var bo={3,4,6,7} var bp={1,6} var bq={0,1,4,6,7} var br={0,1,2,3,4,5,6,7} var bs={0,1,2,3,4,5,6,7} 0,0,0,a,1,2 0,0,0,0,6,3 0,b,c,d,7,1 0,0,0,1,e,2 0,f,g,1,h,1 0,0,0,2,i,2 b,j,k,l,8,8 0,m,f,h,1,1 0,0,0,5,2,5 0,0,0,i,2,2 b,f,n,8,l,8 0,m,1,f,o,1 0,0,1,0,2,2 0,p,1,q,r,1 0,m,1,s,2,1 b,c,l,d,8,8 0,t,2,1,u,1 0,v,2,1,2,5 0,0,2,w,1,1 0,0,2,3,2,2 0,0,r,1,q,1 0,0,r,2,1,1 0,0,5,2,2,2 x,1,q,3,f,1 0,1,7,2,5,5 0,2,5,2,7,1 y,t,z,A,B,8 1,C,D,E,7,7 F,A,t,f,r,8 1,G,H,I,4,4 1,J,K,L,6,6 1,M,p,N,w,8 O,A,t,3,f,8 1,m,P,4,Q,4 F,0,A,5,R,8 1,S,K,6,L,6 1,f,T,7,q,7 U,M,u,m,w,8 1,p,I,A,4,4 1,A,L,V,6,6 u,A,W,w,X,8 1,p,q,f,7,7 1,p,L,7,Y,7 1,Z,2,aa,2,6 1,A,w,U,W,8 ab,N,w,ac,ad,8 1,0,2,2,6,3 1,ae,af,3,2,7 1,B,2,6,W,6 1,0,2,6,4,4 ag,0,2,7,1,0 O,A,r,v,D,8 1,b,s,L,7,7 1,p,5,I,4,4 1,A,5,4,1,4 1,x,5,4,2,7 1,0,7,r,L,7 O,W,X,u,ah,8 1,1,Q,2,7,7 ab,m,Q,5,x,8 1,ai,2,6,4,6 aj,ak,5,ad,al,8 1,W,5,4,2,4 1,2,ad,2,6,6 1,2,am,2,5,5 1,2,4,2,6,7 ad,an,ao,ap,aq,8 2,M,ar,as,at,1 au,j,k,av,8,0 ad,aw,ax,o,ay,8 2,f,az,O,3,1 aA,x,0,2,5,0 2,aw,x,3,aj,1 2,a,0,3,2,6 2,0,0,4,2,3 ad,aw,ax,aB,aC,8 2,0,0,5,1,7 2,0,b,5,aC,8 2,x,0,5,7,5 ad,aD,aj,aE,aF,8 2,0,O,x,3,1 2,0,2,0,7,3 2,aG,l,2,3,1 af,0,2,3,2,1 2,0,3,2,aB,1 2,0,3,aH,2,1 2,0,5,5,2,1 2,1,1,2,6,1 3,0,0,Z,2,2 3,aI,az,f,r,8 3,x,0,0,4,1 3,0,0,0,7,6 3,D,aJ,aK,aL,8 3,v,1,0,2,1 3,az,aM,F,aL,8 aN,0,1,2,2,0 r,T,O,az,aO,8 3,0,R,0,aP,8 aQ,A,0,v,aR,8 h,av,j,k,8,1 aS,0,aw,q,aT,0 aS,0,ay,A,aT,0 aU,0,aT,q,O,0 aU,0,2,aw,aT,0 aS,0,2,aM,ay,0 4,0,e,2,2,1 4,0,2,3,2,6 aS,0,e,ay,aT,0 aS,0,3,2,ay,0 am,aM,aV,aW,aX,8 5,aY,0,0,2,2 5,aZ,T,F,az,8 5,az,ba,e,aC,8 bb,0,0,5,2,0 5,b,2,bc,2,2 5,0,e,bd,h,8 5,v,e,be,bf,8 5,0,2,1,5,2 bb,b,2,2,2,0 5,0,2,2,4,4 5,0,2,af,5,8 5,bg,2,bh,2,8 5,1,2,4,2,2 bi,l,bj,bk,bl,8 6,0,0,0,aJ,8 6,0,0,0,Q,1 i,0,0,5,1,8 bm,0,2,e,2,0 bn,0,3,2,2,0 6,O,aF,aM,bj,8 6,1,2,Q,2,5 6,1,2,1,3,1 6,1,e,bo,2,8 6,1,3,2,2,8 7,0,0,0,bp,8 7,0,ay,aT,r,0 7,0,2,bq,2,0 7,0,2,ay,r,0 7,0,2,2,ac,1 7,0,2,2,3,0 7,0,2,5,2,5 8,az,f,br,bs,0 @TREE num_states=9 num_neighbors=4 num_nodes=339 1 0 8 8 8 8 8 8 8 0 1 2 1 2 3 8 8 1 8 0 1 0 8 2 2 8 2 1 8 0 1 0 8 1 8 8 8 8 8 0 1 0 8 2 1 8 8 8 8 0 1 3 1 8 8 8 8 8 8 0 1 1 7 1 6 8 8 8 7 0 1 0 1 0 0 1 0 1 1 0 2 0 1 2 3 4 0 5 6 7 1 2 1 8 8 0 8 0 0 0 1 2 1 2 3 0 8 0 0 0 1 2 8 1 8 8 8 8 8 0 1 1 4 8 8 0 8 0 0 0 1 0 8 2 8 8 8 8 8 0 1 1 6 8 8 0 8 0 0 0 1 1 7 8 8 0 8 0 0 0 2 1 9 10 11 12 13 14 15 7 1 2 1 2 8 0 5 0 0 0 1 0 8 2 8 0 5 0 0 0 1 0 8 2 8 8 2 8 8 0 1 0 4 2 8 0 8 0 0 0 1 0 8 0 8 8 8 8 8 0 1 2 6 2 8 0 8 0 0 0 1 2 7 2 8 0 2 0 0 0 1 8 8 0 0 1 0 1 1 0 2 2 17 18 19 20 21 22 23 24 1 0 8 6 8 8 8 8 8 0 2 3 3 26 3 3 3 3 3 24 1 0 4 3 1 0 8 0 0 0 1 0 4 8 8 0 8 0 0 0 1 0 6 8 8 0 8 0 0 0 1 0 7 8 8 0 8 0 0 0 2 4 12 28 3 29 0 30 31 24 1 0 1 7 8 8 8 8 8 0 1 5 8 2 8 8 0 8 8 0 1 0 8 5 8 8 8 8 8 0 2 0 33 34 3 0 0 0 35 24 1 2 6 2 2 0 8 0 0 0 2 5 14 37 3 30 0 30 31 24 1 2 7 2 8 0 8 0 0 0 2 6 15 39 3 31 0 31 31 24 2 7 7 24 24 24 24 24 24 7 3 8 16 25 27 32 36 38 40 41 2 1 9 17 3 12 33 14 15 7 1 1 1 8 8 0 8 0 0 0 1 1 8 2 8 0 8 0 0 0 1 1 8 1 8 0 8 0 0 0 1 1 8 8 8 0 8 0 0 0 2 44 44 45 46 12 47 14 15 7 1 2 8 2 1 0 8 0 0 0 1 1 1 2 8 0 8 0 0 0 1 1 4 2 8 0 8 0 0 0 1 1 8 2 1 0 8 0 0 0 1 1 6 2 8 0 8 0 0 0 1 1 0 2 8 0 8 0 0 0 2 49 45 50 46 51 52 53 54 24 1 1 8 6 8 0 8 0 0 0 1 1 4 1 8 0 8 0 0 0 1 1 6 1 8 0 8 0 0 0 1 1 7 1 8 0 8 0 0 0 2 3 46 56 3 57 3 58 59 24 2 12 12 51 57 12 12 14 15 24 2 0 47 45 3 12 0 14 15 24 2 14 14 53 58 14 14 14 15 24 1 1 7 2 8 0 8 0 0 0 2 15 15 64 59 15 15 15 15 24 3 43 48 55 60 61 62 63 65 41 2 2 10 18 26 28 34 37 39 24 1 0 8 2 8 0 8 0 0 0 1 1 8 2 0 0 8 0 0 0 2 49 68 69 46 51 45 53 64 24 1 0 6 2 8 0 2 0 0 0 1 5 1 2 8 0 2 0 0 0 1 0 8 2 8 1 0 0 1 0 1 2 7 1 8 6 8 0 1 0 1 0 8 0 8 0 8 0 5 0 1 0 6 2 8 0 8 0 0 0 1 0 7 2 8 0 2 0 0 0 2 71 72 73 74 20 75 76 77 24 1 0 8 6 8 1 8 0 0 0 1 0 6 1 8 0 8 0 0 0 1 0 7 1 8 0 8 0 0 0 2 13 45 79 3 20 3 80 81 24 1 0 4 1 8 0 8 0 0 0 1 0 7 2 8 0 8 0 0 0 2 20 51 20 83 20 20 76 84 24 1 2 8 2 8 0 8 0 0 0 1 0 7 5 8 0 8 0 0 0 2 13 45 86 3 84 3 76 87 24 2 76 53 76 80 76 76 76 84 24 1 0 7 3 8 0 8 0 0 0 2 90 64 84 81 84 84 84 84 24 2 24 24 24 24 24 24 24 24 24 3 67 70 78 82 85 88 89 91 92 2 3 11 19 3 3 3 3 3 24 2 3 46 46 3 57 3 58 59 24 1 0 8 1 8 0 8 0 0 0 2 13 46 96 3 83 3 80 81 24 2 3 3 3 3 3 3 3 3 24 2 3 57 83 3 83 3 80 81 24 2 3 58 80 3 80 3 80 81 24 2 3 59 81 3 81 3 81 81 24 3 94 95 97 98 99 98 100 101 92 2 4 12 20 3 29 0 30 31 24 1 0 4 2 8 0 4 0 0 0 2 20 51 104 83 20 20 20 84 24 2 29 12 20 83 29 29 30 31 24 2 0 12 20 3 29 0 30 31 24 2 30 14 76 80 30 30 30 31 24 2 31 15 84 81 31 31 31 31 24 3 103 61 105 99 106 107 108 109 92 2 0 13 21 3 0 0 0 0 24 1 1 8 2 8 0 2 0 0 0 1 0 8 2 8 0 8 0 1 0 2 13 112 113 3 20 13 76 84 24 2 0 0 13 3 0 0 0 0 24 2 0 14 76 3 30 0 30 31 24 2 0 15 84 3 31 0 31 31 24 3 111 62 114 98 107 115 116 117 92 2 5 14 22 3 30 0 30 31 24 1 0 3 2 8 0 8 0 0 0 2 76 53 120 80 76 76 76 84 24 3 119 63 121 100 108 116 108 109 92 2 6 15 23 3 31 35 31 31 24 3 123 65 91 101 109 117 109 109 92 3 41 41 92 92 92 92 92 92 41 4 42 66 93 102 110 118 122 124 125 2 1 44 49 3 12 0 14 15 7 2 9 44 68 46 12 47 14 15 7 2 10 45 69 46 51 45 53 64 24 2 11 46 46 3 57 3 58 59 24 2 13 47 45 3 12 0 14 15 24 3 127 128 129 130 61 131 63 65 41 2 9 44 45 46 12 47 14 15 7 1 1 8 8 8 8 8 8 8 0 1 1 1 2 8 8 8 8 8 0 1 1 8 1 8 8 8 8 8 0 1 1 4 8 8 8 8 8 8 0 1 1 6 8 8 8 8 8 8 0 1 1 7 8 8 8 8 8 8 0 2 44 134 135 136 137 134 138 139 7 1 1 4 2 8 8 8 8 8 0 1 1 1 1 8 8 8 8 8 0 1 1 7 2 8 8 8 8 8 0 2 68 135 135 136 141 135 142 143 24 1 1 4 1 8 8 8 8 8 0 1 1 6 1 8 8 8 8 8 0 1 1 7 1 8 8 8 8 8 0 2 46 136 136 136 145 136 146 147 24 2 12 137 141 145 137 137 138 139 24 1 1 8 2 8 8 8 8 8 0 2 47 134 150 136 137 134 138 139 24 1 1 6 2 8 8 8 8 8 0 2 14 138 152 146 138 138 138 139 24 2 15 139 143 147 139 139 139 139 24 3 133 140 144 148 149 151 153 154 41 2 17 45 50 56 51 45 53 64 24 2 45 135 135 136 141 150 152 143 24 1 1 1 2 8 8 2 5 8 0 1 1 1 2 8 8 0 5 8 0 1 1 4 2 8 8 2 8 8 0 1 5 8 2 8 8 8 8 8 0 1 1 7 2 8 8 2 8 8 0 2 72 158 159 142 160 161 135 162 24 1 1 8 1 8 8 8 1 8 0 2 46 164 142 136 145 136 146 147 24 2 51 141 141 145 141 141 152 143 24 2 112 150 150 136 141 150 152 143 24 2 53 152 152 146 152 152 152 143 24 2 64 143 143 147 143 143 143 143 24 3 156 157 163 165 166 167 168 169 92 2 45 164 136 136 145 136 146 147 24 2 3 136 136 3 145 3 146 147 24 2 57 145 145 145 145 145 146 147 24 2 58 146 146 146 146 146 146 147 24 2 59 147 147 147 147 147 147 147 24 3 95 148 171 172 173 172 174 175 92 3 61 149 166 173 149 149 153 154 92 2 33 47 52 3 12 0 14 15 24 2 47 134 135 136 137 134 138 139 24 2 45 150 135 136 141 150 152 143 24 2 0 134 150 3 137 0 138 139 24 1 5 7 2 8 8 8 8 8 0 2 15 139 182 147 139 139 139 139 24 3 178 179 180 172 149 181 153 183 92 2 14 138 142 146 138 138 138 139 24 3 63 185 168 174 153 153 153 154 92 2 15 15 54 59 15 15 15 15 24 3 187 154 169 175 154 154 154 154 92 4 132 155 170 176 177 184 186 188 125 2 2 49 71 13 20 13 76 90 24 2 17 45 72 46 51 112 53 64 24 2 18 50 73 96 104 113 120 84 24 2 19 46 74 3 83 3 80 81 24 2 21 52 75 3 20 13 76 84 24 2 22 53 76 80 20 76 76 84 24 2 23 54 77 81 84 84 84 84 24 3 190 191 192 193 85 194 195 196 92 2 10 68 72 45 51 45 53 64 24 2 45 135 158 164 141 150 152 143 24 2 69 135 159 136 141 135 152 143 24 2 46 136 142 136 145 136 146 147 24 2 51 141 160 145 141 141 152 143 24 2 45 135 161 136 141 150 152 143 24 2 53 142 135 146 152 152 152 143 24 2 64 143 162 147 143 143 143 143 24 3 198 199 200 201 202 203 204 205 92 2 18 69 73 79 20 86 76 84 24 2 50 135 159 142 141 150 152 143 24 1 0 4 2 8 8 8 8 8 0 1 0 6 2 8 8 8 8 8 0 1 0 7 2 8 8 8 8 8 0 2 73 159 13 3 209 13 210 211 24 1 0 4 1 8 8 8 8 8 0 1 0 6 1 8 8 8 8 8 0 1 0 7 1 8 8 8 8 8 0 2 96 136 3 3 213 3 214 215 24 2 104 141 209 213 209 209 210 211 24 2 113 135 13 3 211 13 210 211 24 2 120 152 210 214 210 210 210 211 24 2 84 143 211 215 211 211 211 211 24 3 207 208 212 216 217 218 219 220 92 2 26 46 74 3 83 3 80 81 24 2 56 136 142 136 145 136 146 147 24 2 79 142 3 3 213 3 214 215 24 2 3 136 3 3 213 3 214 215 24 2 83 145 213 213 213 213 214 215 24 2 80 146 214 214 214 214 214 215 24 2 81 147 215 215 215 215 215 215 24 3 222 223 224 225 226 225 227 228 92 2 28 51 20 20 20 84 76 84 24 2 20 141 209 213 209 211 210 211 24 2 20 141 209 213 209 209 210 211 24 1 0 5 2 8 8 8 8 8 0 2 20 141 233 213 209 209 210 211 24 2 76 152 211 214 210 210 210 211 24 3 230 202 231 226 232 234 235 220 92 2 34 45 75 3 20 3 76 84 24 2 45 150 161 136 141 150 152 143 24 2 86 150 13 3 209 13 210 211 24 2 13 150 13 3 209 13 210 211 24 2 76 152 210 214 210 210 210 211 24 1 1 5 2 8 8 8 8 8 0 2 84 143 242 215 211 211 211 211 24 3 237 238 239 225 234 240 241 243 92 2 37 53 76 80 76 76 76 84 24 2 53 152 135 146 152 152 152 143 24 3 245 246 241 227 235 241 241 220 92 2 39 64 77 81 84 87 84 84 24 2 84 182 242 215 211 211 211 211 24 3 248 205 220 228 220 249 220 220 92 3 92 92 92 92 92 92 92 92 92 4 197 206 221 229 236 244 247 250 251 2 3 3 13 3 3 3 3 3 24 2 3 46 45 3 57 3 58 59 24 2 26 56 79 3 83 3 80 81 24 2 3 57 20 3 83 3 80 81 24 3 253 254 255 98 256 98 100 101 92 2 46 136 164 136 145 136 146 147 24 3 130 258 201 172 173 172 174 175 92 2 19 46 96 3 83 3 80 81 24 2 74 142 3 3 213 3 214 215 24 3 260 148 261 225 226 225 227 228 92 2 3 145 213 3 213 3 214 215 24 2 3 146 214 3 214 3 214 215 24 2 3 147 215 3 215 3 215 215 24 3 98 172 225 98 263 98 264 265 92 3 99 173 226 263 226 263 227 228 92 3 100 174 227 264 227 264 227 228 92 3 101 175 228 265 228 265 228 228 92 4 257 259 262 266 267 266 268 269 251 2 28 51 20 83 20 20 76 84 24 3 103 61 271 99 106 107 108 109 92 2 20 51 104 83 20 20 76 84 24 2 20 160 209 213 209 233 211 211 24 3 273 166 274 226 232 232 241 220 92 2 20 145 213 213 213 213 214 215 24 3 99 173 276 263 226 263 227 228 92 1 0 4 8 8 8 8 8 8 0 1 0 6 8 8 8 8 8 8 0 1 0 7 8 8 8 8 8 8 0 2 29 137 209 213 278 278 279 280 24 2 30 138 210 214 279 279 279 280 24 2 31 139 211 215 280 280 280 280 24 3 106 149 232 226 281 281 282 283 92 2 84 141 211 213 209 209 210 211 24 2 0 137 209 3 278 0 279 280 24 3 107 149 285 263 281 286 282 283 92 2 30 14 20 80 30 30 30 31 24 3 288 153 241 227 282 282 282 283 92 3 109 154 220 228 283 283 283 283 92 4 272 177 275 277 284 287 289 290 251 2 33 47 45 3 12 0 14 15 24 2 34 45 86 3 20 13 76 84 24 2 0 12 84 3 29 0 30 31 24 2 0 0 3 3 0 0 0 0 24 2 35 15 87 3 31 0 31 31 24 3 115 292 293 98 294 295 116 296 92 2 13 47 112 3 12 0 14 15 24 2 45 150 150 136 141 150 152 143 24 3 298 151 299 172 149 181 153 154 92 2 21 45 113 3 20 13 76 84 24 2 52 135 135 136 141 150 152 182 24 2 75 161 13 3 233 13 210 242 24 2 20 141 211 213 209 209 210 211 24 3 301 302 303 225 304 240 241 220 92 3 107 149 232 263 281 286 282 283 92 2 3 150 13 3 209 13 210 211 24 2 0 138 210 3 279 0 279 280 24 2 0 139 211 3 280 0 280 280 24 3 115 181 307 98 286 115 308 309 92 3 116 153 241 264 282 308 282 283 92 3 117 154 220 265 283 309 283 283 92 4 297 300 305 266 306 310 311 312 251 2 5 14 76 3 30 0 30 31 24 3 314 63 245 100 108 116 108 109 92 3 63 153 168 174 153 153 153 154 92 2 22 53 120 80 76 76 76 84 24 2 53 142 152 146 152 152 152 143 24 2 76 135 210 214 211 210 210 211 24 2 20 152 210 214 210 210 210 211 24 3 317 318 319 227 320 241 241 220 92 3 108 153 241 227 282 282 282 283 92 4 315 316 321 268 322 311 322 290 251 2 6 15 90 3 31 0 31 31 24 2 39 64 84 81 84 84 84 84 24 3 324 65 325 101 109 117 109 109 92 2 64 143 143 147 143 182 143 143 24 3 65 154 327 175 154 154 154 154 92 2 23 64 84 81 84 84 84 84 24 2 54 143 143 147 143 143 143 143 24 2 77 162 211 215 211 242 211 211 24 3 329 330 331 228 220 220 220 220 92 2 35 15 84 3 31 0 31 31 24 2 87 143 211 215 211 211 211 211 24 3 333 154 334 265 283 309 283 283 92 4 326 328 332 269 290 335 290 290 251 4 125 125 251 251 251 251 251 251 125 5 126 189 252 270 291 313 323 336 337 @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 8 255 128 0 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Turmite_181181121010.rule�������������������������������������������������������0000644�0001750�0001750�00000065016�12536111364�015134� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Turmite_181181121010 @TREE num_states=18 num_neighbors=4 num_nodes=27 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 6 14 14 14 14 14 14 14 14 14 14 14 14 14 6 6 6 6 1 2 10 10 10 10 10 10 10 10 10 10 10 10 10 2 2 2 2 2 0 0 0 1 0 0 0 0 0 1 0 1 0 0 2 0 0 0 1 9 17 17 17 17 17 17 17 17 17 17 17 17 17 9 9 9 9 2 4 4 4 0 4 4 4 4 4 0 4 0 4 4 0 4 4 4 1 5 13 13 13 13 13 13 13 13 13 13 13 13 13 5 5 5 5 2 6 6 6 0 6 6 6 6 6 0 6 0 6 6 0 6 6 6 3 3 3 5 3 3 3 3 3 5 3 5 3 3 3 3 3 3 7 1 7 15 15 15 15 15 15 15 15 15 15 15 15 15 7 7 7 7 2 9 9 9 0 9 9 9 9 9 0 9 0 9 9 0 9 9 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 10 10 11 10 10 10 10 10 11 10 11 10 10 10 10 10 10 11 1 3 11 11 11 11 11 11 11 11 11 11 11 11 11 3 3 3 3 2 13 13 13 0 13 13 13 13 13 0 13 0 13 13 0 13 13 13 3 14 14 11 14 14 14 14 14 11 14 11 14 14 14 14 14 14 11 4 8 8 8 8 12 8 12 8 8 8 8 8 12 8 8 15 8 8 1 8 16 16 16 16 16 16 16 16 16 16 16 16 16 8 8 8 8 2 17 17 17 0 17 17 17 17 17 0 17 0 17 17 0 17 17 17 3 18 18 11 18 18 18 18 18 11 18 11 18 18 18 18 18 18 11 3 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 4 19 19 19 19 20 19 20 19 19 19 19 19 20 19 19 20 19 19 1 4 12 12 12 12 12 12 12 12 12 12 12 12 12 4 4 4 4 2 22 22 22 0 22 22 22 22 22 0 22 0 22 22 0 22 22 22 3 23 23 11 23 23 23 23 23 11 23 11 23 23 23 23 23 23 11 4 24 24 24 24 20 24 20 24 24 24 24 24 20 24 24 20 24 24 5 16 16 16 16 16 21 16 21 16 16 16 16 16 21 16 16 25 16 @COLORS 0 0 0 0 1 0 155 67 2 131 12 251 3 131 12 251 4 131 12 251 5 131 12 251 6 132 132 132 7 132 132 132 8 132 132 132 9 132 132 132 10 23 130 99 11 23 130 99 12 23 130 99 13 23 130 99 14 23 151 78 15 23 151 78 16 23 151 78 17 23 151 78 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 527 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ "..............................." ".......C...............C......." ".......C...............C......." "........C.............C........" "........C.............C........" ".........CCCIICCCIICCC........." "............IICCCII............" ".............CCCCC............." "........CC....CCC....CC........" ".........CC...CCC...CC........." "..........CC..CCC..CC.........." "...........CCCCCCCCC..........." "............CCCCCCC............" "..............CCC.............." "..............CCC.............." "...........CCCCCCCCC..........." "..........CCCCCCCCCCC.........." ".........CC...CCC...CC........." "........CC....CCC....CC........" ".............CCCCC............." "............CCCCCCC............" "...........CC.CCC.CC..........." "..........CC..CCC..CC.........." ".........CC...CCC...CC........." "........CC...ECCCE...CC........" ".............CCCCC............." ".............CCCCC............." ".............ECCCE............." "..............CCC.............." "..............................." "..............................." /* icon for state 3 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................CC." "......C.....C.........C...CC..." "......CC....CC.......CC..C....." ".......CC....CC.....CC...C....." "........CC....CC...CC....C....." ".........CC...CC..CC....II....." "...ECCE...CC..CC..CC...CII....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "...ECCE...CC..CC..CC...CII....." ".........CC...CC..CC....II....." "........CC....CC...CC....C....." ".......CC....CC.....CC...C....." "......CC....CC.......CC..C....." "......C.....C.........C...CC..." "............................CC." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." "..............CCC.............." ".............ECCCE............." ".............CCCCC............." ".............CCCCC............." "........CC...ECCCE...CC........" ".........CC...CCC...CC........." "..........CC..CCC..CC.........." "...........CC.CCC.CC..........." "............CCCCCCC............" ".............CCCCC............." "........CC....CCC....CC........" ".........CC...CCC...CC........." "..........CCCCCCCCCCC.........." "...........CCCCCCCCC..........." "..............CCC.............." "..............CCC.............." "............CCCCCCC............" "...........CCCCCCCCC..........." "..........CC..CCC..CC.........." ".........CC...CCC...CC........." "........CC....CCC....CC........" ".............CCCCC............." "............IICCCII............" ".........CCCIICCCIICCC........." "........C.............C........" "........C.............C........" ".......C...............C......." ".......C...............C......." "..............................." /* icon for state 5 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".CC............................" "...CC...C.........C.....C......" ".....C..CC.......CC....CC......" ".....C...CC.....CC....CC......." ".....C....CC...CC....CC........" ".....II....CC..CC...CC........." ".....IIC...CC..CC..CC...ECCE..." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....IIC...CC..CC..CC...ECCE..." ".....II....CC..CC...CC........." ".....C....CC...CC....CC........" ".....C...CC.....CC....CC......." ".....C..CC.......CC....CC......" "...CC...C.........C.....C......" ".CC............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 6 */ "..............................." ".......D...............D......." ".......D...............D......." "........D.............D........" "........D.............D........" ".........DDDIIDDDIIDDD........." "............IIDDDII............" ".............DDDDD............." "........DD....DDD....DD........" ".........DD...DDD...DD........." "..........DD..DDD..DD.........." "...........DDDDDDDDD..........." "............DDDDDDD............" "..............DDD.............." "..............DDD.............." "...........DDDDDDDDD..........." "..........DDDDDDDDDDD.........." ".........DD...DDD...DD........." "........DD....DDD....DD........" ".............DDDDD............." "............DDDDDDD............" "...........DD.DDD.DD..........." "..........DD..DDD..DD.........." ".........DD...DDD...DD........." "........DD...FDDDF...DD........" ".............DDDDD............." ".............DDDDD............." ".............FDDDF............." "..............DDD.............." "..............................." "..............................." /* icon for state 7 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................DD." "......D.....D.........D...DD..." "......DD....DD.......DD..D....." ".......DD....DD.....DD...D....." "........DD....DD...DD....D....." ".........DD...DD..DD....II....." "...FDDF...DD..DD..DD...DII....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "...FDDF...DD..DD..DD...DII....." ".........DD...DD..DD....II....." "........DD....DD...DD....D....." ".......DD....DD.....DD...D....." "......DD....DD.......DD..D....." "......D.....D.........D...DD..." "............................DD." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 8 */ "..............................." "..............................." "..............DDD.............." ".............FDDDF............." ".............DDDDD............." ".............DDDDD............." "........DD...FDDDF...DD........" ".........DD...DDD...DD........." "..........DD..DDD..DD.........." "...........DD.DDD.DD..........." "............DDDDDDD............" ".............DDDDD............." "........DD....DDD....DD........" ".........DD...DDD...DD........." "..........DDDDDDDDDDD.........." "...........DDDDDDDDD..........." "..............DDD.............." "..............DDD.............." "............DDDDDDD............" "...........DDDDDDDDD..........." "..........DD..DDD..DD.........." ".........DD...DDD...DD........." "........DD....DDD....DD........" ".............DDDDD............." "............IIDDDII............" ".........DDDIIDDDIIDDD........." "........D.............D........" "........D.............D........" ".......D...............D......." ".......D...............D......." "..............................." /* icon for state 9 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".DD............................" "...DD...D.........D.....D......" ".....D..DD.......DD....DD......" ".....D...DD.....DD....DD......." ".....D....DD...DD....DD........" ".....II....DD..DD...DD........." ".....IID...DD..DD..DD...FDDF..." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....IID...DD..DD..DD...FDDF..." ".....II....DD..DD...DD........." ".....D....DD...DD....DD........" ".....D...DD.....DD....DD......." ".....D..DD.......DD....DD......" "...DD...D.........D.....D......" ".DD............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 10 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAAACCCIICCCIICCCAAAAAAAAA" "AAAAAAAAAAAAIICCCIIAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAACCCCCCCCCCCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAACCACCCACCAAAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAGCCCGAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAAGCCCGAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 11 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAACCA" "AAAAAACAAAAACAAAAAAAAACAAACCAAA" "AAAAAACCAAAACCAAAAAAACCAACAAAAA" "AAAAAAACCAAAACCAAAAACCAAACAAAAA" "AAAAAAAACCAAAACCAAACCAAAACAAAAA" "AAAAAAAAACCAAACCAACCAAAAIIAAAAA" "AAAGCCGAAACCAACCAACCAAACIIAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AAAGCCGAAACCAACCAACCAAACIIAAAAA" "AAAAAAAAACCAAACCAACCAAAAIIAAAAA" "AAAAAAAACCAAAACCAAACCAAAACAAAAA" "AAAAAAACCAAAACCAAAAACCAAACAAAAA" "AAAAAACCAAAACCAAAAAAACCAACAAAAA" "AAAAAACAAAAACAAAAAAAAACAAACCAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAACCA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 12 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAGCCCGAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAGCCCGAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAAAACCACCCACCAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCCCCCCCCCCAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAIICCCIIAAAAAAAAAAAA" "AAAAAAAAACCCIICCCIICCCAAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 13 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "ACCAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAACCAAACAAAAAAAAACAAAAACAAAAAA" "AAAAACAACCAAAAAAACCAAAACCAAAAAA" "AAAAACAAACCAAAAACCAAAACCAAAAAAA" "AAAAACAAAACCAAACCAAAACCAAAAAAAA" "AAAAAIIAAAACCAACCAAACCAAAAAAAAA" "AAAAAIICAAACCAACCAACCAAAGCCGAAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAAIICAAACCAACCAACCAAAGCCGAAA" "AAAAAIIAAAACCAACCAAACCAAAAAAAAA" "AAAAACAAAACCAAACCAAAACCAAAAAAAA" "AAAAACAAACCAAAAACCAAAACCAAAAAAA" "AAAAACAACCAAAAAAACCAAAACCAAAAAA" "AAACCAAACAAAAAAAAACAAAAACAAAAAA" "ACCAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 14 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAAADDDIIDDDIIDDDAAAAAAAAA" "AAAAAAAAAAAAIIDDDIIAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAADDDDDDDDDDDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAADDADDDADDAAAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAHDDDHAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAAHDDDHAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 15 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAADDA" "AAAAAADAAAAADAAAAAAAAADAAADDAAA" "AAAAAADDAAAADDAAAAAAADDAADAAAAA" "AAAAAAADDAAAADDAAAAADDAAADAAAAA" "AAAAAAAADDAAAADDAAADDAAAADAAAAA" "AAAAAAAAADDAAADDAADDAAAAIIAAAAA" "AAAHDDHAAADDAADDAADDAAADIIAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AAAHDDHAAADDAADDAADDAAADIIAAAAA" "AAAAAAAAADDAAADDAADDAAAAIIAAAAA" "AAAAAAAADDAAAADDAAADDAAAADAAAAA" "AAAAAAADDAAAADDAAAAADDAAADAAAAA" "AAAAAADDAAAADDAAAAAAADDAADAAAAA" "AAAAAADAAAAADAAAAAAAAADAAADDAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAADDA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 16 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAHDDDHAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAHDDDHAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAAAADDADDDADDAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDDDDDDDDDDAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAIIDDDIIAAAAAAAAAAAA" "AAAAAAAAADDDIIDDDIIDDDAAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 17 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "ADDAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAADDAAADAAAAAAAAADAAAAADAAAAAA" "AAAAADAADDAAAAAAADDAAAADDAAAAAA" "AAAAADAAADDAAAAADDAAAADDAAAAAAA" "AAAAADAAAADDAAADDAAAADDAAAAAAAA" "AAAAAIIAAAADDAADDAAADDAAAAAAAAA" "AAAAAIIDAAADDAADDAADDAAAHDDHAAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAAIIDAAADDAADDAADDAAAHDDHAAA" "AAAAAIIAAAADDAADDAAADDAAAAAAAAA" "AAAAADAAAADDAAADDAAAADDAAAAAAAA" "AAAAADAAADDAAAAADDAAAADDAAAAAAA" "AAAAADAADDAAAAAAADDAAAADDAAAAAA" "AAADDAAADAAAAAAAAADAAAAADAAAAAA" "ADDAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "15 255 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "....C.....C...." ".....C...C....." "......ICI......" "...C..CCC..C..." "....C..C..C...." ".....CCCCC....." ".......C......." "....CCCCCCC...." "...C...C...C..." ".....CCCCC....." "....C..C..C...." "...C..ECE..C..." "......CCC......" "......ECE......" "..............." /* icon for state 3 */ "..............." "..............." "..............." "...C..C....C..." "....C..C..C...C" ".....C.C.C...C." ".ECE.C.C.C.CI.." ".CCCCCCCCCCCC.." ".ECE.C.C.C.CI.." ".....C.C.C...C." "....C..C..C...C" "...C..C....C..." "..............." "..............." "..............." /* icon for state 4 */ "..............." "......ECE......" "......CCC......" "...C..ECE..C..." "....C..C..C...." ".....CCCCC....." "...C...C...C..." "....CCCCCCC...." ".......C......." ".....CCCCC....." "....C..C..C...." "...C..CCC..C..." "......ICI......" ".....C...C....." "....C.....C...." /* icon for state 5 */ "..............." "..............." "..............." "...C....C..C..." "C...C..C..C...." ".C...C.C.C....." "..IC.C.C.C.ECE." "..CCCCCCCCCCCC." "..IC.C.C.C.ECE." ".C...C.C.C....." "C...C..C..C...." "...C....C..C..." "..............." "..............." "..............." /* icon for state 6 */ "....D.....D...." ".....D...D....." "......IDI......" "...D..DDD..D..." "....D..D..D...." ".....DDDDD....." ".......D......." "....DDDDDDD...." "...D...D...D..." ".....DDDDD....." "....D..D..D...." "...D..FDF..D..." "......DDD......" "......FDF......" "..............." /* icon for state 7 */ "..............." "..............." "..............." "...D..D....D..." "....D..D..D...D" ".....D.D.D...D." ".FDF.D.D.D.DI.." ".DDDDDDDDDDDD.." ".FDF.D.D.D.DI.." ".....D.D.D...D." "....D..D..D...D" "...D..D....D..." "..............." "..............." "..............." /* icon for state 8 */ "..............." "......FDF......" "......DDD......" "...D..FDF..D..." "....D..D..D...." ".....DDDDD....." "...D...D...D..." "....DDDDDDD...." ".......D......." ".....DDDDD....." "....D..D..D...." "...D..DDD..D..." "......IDI......" ".....D...D....." "....D.....D...." /* icon for state 9 */ "..............." "..............." "..............." "...D....D..D..." "D...D..D..D...." ".D...D.D.D....." "..ID.D.D.D.FDF." "..DDDDDDDDDDDD." "..ID.D.D.D.FDF." ".D...D.D.D....." "D...D..D..D...." "...D....D..D..." "..............." "..............." "..............." /* icon for state 10 */ "AAAACAAAAACAAAA" "AAAAACAAACAAAAA" "AAAAAAICIAAAAAA" "AAACAACCCAACAAA" "AAAACAACAACAAAA" "AAAAACCCCCAAAAA" "AAAAAAACAAAAAAA" "AAAACCCCCCCAAAA" "AAACAAACAAACAAA" "AAAAACCCCCAAAAA" "AAAACAACAACAAAA" "AAACAAGCGAACAAA" "AAAAAACCCAAAAAA" "AAAAAAGCGAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 11 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAACAACAAAACAAA" "AAAACAACAACAAAC" "AAAAACACACAAACA" "AGCGACACACACIAA" "ACCCCCCCCCCCCAA" "AGCGACACACACIAA" "AAAAACACACAAACA" "AAAACAACAACAAAC" "AAACAACAAAACAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 12 */ "AAAAAAAAAAAAAAA" "AAAAAAGCGAAAAAA" "AAAAAACCCAAAAAA" "AAACAAGCGAACAAA" "AAAACAACAACAAAA" "AAAAACCCCCAAAAA" "AAACAAACAAACAAA" "AAAACCCCCCCAAAA" "AAAAAAACAAAAAAA" "AAAAACCCCCAAAAA" "AAAACAACAACAAAA" "AAACAACCCAACAAA" "AAAAAAICIAAAAAA" "AAAAACAAACAAAAA" "AAAACAAAAACAAAA" /* icon for state 13 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAACAAAACAACAAA" "CAAACAACAACAAAA" "ACAAACACACAAAAA" "AAICACACACAGCGA" "AACCCCCCCCCCCCA" "AAICACACACAGCGA" "ACAAACACACAAAAA" "CAAACAACAACAAAA" "AAACAAAACAACAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 14 */ "AAAADAAAAADAAAA" "AAAAADAAADAAAAA" "AAAAAAIDIAAAAAA" "AAADAADDDAADAAA" "AAAADAADAADAAAA" "AAAAADDDDDAAAAA" "AAAAAAADAAAAAAA" "AAAADDDDDDDAAAA" "AAADAAADAAADAAA" "AAAAADDDDDAAAAA" "AAAADAADAADAAAA" "AAADAAHDHAADAAA" "AAAAAADDDAAAAAA" "AAAAAAHDHAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 15 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAADAADAAAADAAA" "AAAADAADAADAAAD" "AAAAADADADAAADA" "AHDHADADADADIAA" "ADDDDDDDDDDDDAA" "AHDHADADADADIAA" "AAAAADADADAAADA" "AAAADAADAADAAAD" "AAADAADAAAADAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 16 */ "AAAAAAAAAAAAAAA" "AAAAAAHDHAAAAAA" "AAAAAADDDAAAAAA" "AAADAAHDHAADAAA" "AAAADAADAADAAAA" "AAAAADDDDDAAAAA" "AAADAAADAAADAAA" "AAAADDDDDDDAAAA" "AAAAAAADAAAAAAA" "AAAAADDDDDAAAAA" "AAAADAADAADAAAA" "AAADAADDDAADAAA" "AAAAAAIDIAAAAAA" "AAAAADAAADAAAAA" "AAAADAAAAADAAAA" /* icon for state 17 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAADAAAADAADAAA" "DAAADAADAADAAAA" "ADAAADADADAAAAA" "AAIDADADADAHDHA" "AADDDDDDDDDDDDA" "AAIDADADADAHDHA" "ADAAADADADAAAAA" "DAAADAADAADAAAA" "AAADAAAADAADAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "7 119 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ ".C...C." "..ICI.." "...C..." ".CCCCC." "...C..." ".CCCCC." "...C..." /* icon for state 3 */ "......." ".C.C..C" ".C.C.I." "CCCCCC." ".C.C.I." ".C.C..C" "......." /* icon for state 4 */ "...C..." ".CCCCC." "...C..." ".CCCCC." "...C..." "..ICI.." ".C...C." /* icon for state 5 */ "......." "C..C.C." ".I.C.C." ".CCCCCC" ".I.C.C." "C..C.C." "......." /* icon for state 6 */ ".D...D." "..IDI.." "...D..." ".DDDDD." "...D..." ".DDDDD." "...D..." /* icon for state 7 */ "......." ".D.D..D" ".D.D.I." "DDDDDD." ".D.D.I." ".D.D..D" "......." /* icon for state 8 */ "...D..." ".DDDDD." "...D..." ".DDDDD." "...D..." "..IDI.." ".D...D." /* icon for state 9 */ "......." "D..D.D." ".I.D.D." ".DDDDDD" ".I.D.D." "D..D.D." "......." /* icon for state 10 */ "ACAAACA" "AAICIAA" "AAACAAA" "ACCCCCA" "AAACAAA" "ACCCCCA" "AAACAAA" /* icon for state 11 */ "AAAAAAA" "ACACAAC" "ACACAIA" "CCCCCCA" "ACACAIA" "ACACAAC" "AAAAAAA" /* icon for state 12 */ "AAACAAA" "ACCCCCA" "AAACAAA" "ACCCCCA" "AAACAAA" "AAICIAA" "ACAAACA" /* icon for state 13 */ "AAAAAAA" "CAACACA" "AIACACA" "ACCCCCC" "AIACACA" "CAACACA" "AAAAAAA" /* icon for state 14 */ "ADAAADA" "AAIDIAA" "AAADAAA" "ADDDDDA" "AAADAAA" "ADDDDDA" "AAADAAA" /* icon for state 15 */ "AAAAAAA" "ADADAAD" "ADADAIA" "DDDDDDA" "ADADAIA" "ADADAAD" "AAAAAAA" /* icon for state 16 */ "AAADAAA" "ADDDDDA" "AAADAAA" "ADDDDDA" "AAADAAA" "AAIDIAA" "ADAAADA" /* icon for state 17 */ "AAAAAAA" "DAADADA" "AIADADA" "ADDDDDD" "AIADADA" "DAADADA" "AAAAAAA" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Codd2.rule����������������������������������������������������������������������0000644�0001750�0001750�00000021545�12536111364�013145� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Codd2 Codd, E.F., _Cellular_Automata_, Academic Press 1968 (ACM Monograph #3). Originally distributed with XLife as codd.r. Several corrections have been made from the XLife version, to match Codd's printed transition table. Stasis transitions have been taken out. More importantly, some extra transitions have been added, to deal with sheathing- signal collision cases that Codd hadn't considered. These additions are at the bottom of the file and clearly marked. Hopefully these changes can be considered to be the intent of Codd's work, if not his exact specification. Just to be clear, these changes change nothing about the way the examples in Codd's book work, and only affect rarely-encountered situations. Contact: Tim Hutton <tim.hutton@gmail.com> @TABLE n_states:8 neighborhood:vonNeumann symmetries:rotate4 var a={4,5} var b={2,3} var c={2,3} var d={4,5,6,7} var e={4,5,6} var f={0,1} var g={1,2} var h={0,1,2} var i={1,2,6} var j={1,6} var k={4,5} var l={4,6,7} var m={1,2,3} var n={6,7} var o={1,2,7} var p={0,2,3} # Almost all configurations with neighborhoods in [0-3] are stable # These are the exceptions (Codd's `short table', page 66) 0,1,2,1,2,1 # Path self-repair 3,0,0,0,2,2 # Path self-repair 3,0,1,0,2,2 # Gate control 3,0,1,0,3,0 # Gate control 2,1,2,3,2,3 # Gate control 3,1,2,3,2,2 # Gate control 0,0,2,1,3,1 # Path end self-repair 0,1,2,3,2,6 # Echo generation 0,1,2,2,2,7 # Echo generation # The long table 0,0,2,7,2,1 # j 0,0,3,6,3,1 # i 0,1,1,2,d,1 # fi = fan-in 0,1,1,e,2,1 # fi 0,1,2,1,d,1 # fi 0,1,2,2,d,1 # p = signal propagation 0,1,2,3,5,1 # p 0,1,2,4,2,1 # p 0,1,2,4,4,1 # fo = fan-out 0,1,2,5,b,1 # p (was fi) 0,1,2,5,5,1 # fo 0,1,2,6,2,1 # p 0,1,2,6,6,1 # fo 0,1,2,7,b,1 # p 0,1,2,7,7,1 # fo 0,1,3,2,4,1 # p 0,1,3,d,2,1 # pg - propagation at gate (subordinate path) 0,1,3,7,3,1 # t7 = transforming to 07 0,1,4,2,2,1 # p 0,1,4,2,4,1 # fo 0,1,4,3,2,1 # p 0,1,4,4,2,1 # fo 0,1,5,2,b,1 # p 0,1,5,2,5,1 # fo 0,1,5,3,2,1 # p 0,1,5,5,2,1 # fo 0,1,6,2,2,1 # p 0,1,6,2,6,1 # fo 0,1,6,6,2,1 # fo 0,1,7,2,2,1 # p 0,1,7,2,7,1 # fo 0,1,7,7,2,1 # fo 0,0,0,f,6,2 # k 0,0,0,2,5,2 # xl = extend left 0,0,0,2,6,2 # sh = sheathing 0,0,0,4,2,2 # xr = extend right 0,0,0,6,1,2 # k 0,0,0,6,2,2 # sh 0,0,0,6,6,2 # sh 0,0,1,0,6,2 # sh 0,0,1,1,6,2 # k 0,0,1,2,6,2 # sh 0,0,1,6,1,2 # k 0,0,1,6,2,2 # sh 0,0,1,6,6,2 # sh 0,0,2,0,6,2 # g = gate control 0,0,2,2,6,2 # sh 0,0,2,6,g,2 # sh 0,0,6,1,1,2 # k 0,0,6,2,1,2 # sh 0,0,6,2,2,2 # sh 0,0,6,2,6,2 # sh 0,0,6,6,1,2 # sh 0,1,1,1,6,2 # k 0,1,1,6,6,2 # sh 0,2,2,2,6,2 # sh 0,2,2,6,6,2 # sh 0,0,0,0,7,3 # k 0,0,0,1,5,3 # i 0,0,0,5,1,3 # i 0,0,1,0,7,3 # e 0,0,2,0,7,3 # g 1,0,0,0,4,0 # e 1,0,0,1,4,0 # e 1,0,0,4,1,0 # e 1,0,1,0,4,0 # e 1,0,1,1,4,0 # e 1,0,1,4,1,0 # e 1,0,4,1,1,0 # e 1,1,1,1,4,0 # e 1,0,0,3,6,2 # i 1,0,0,6,3,2 # i # error in codd.r: 10107[23] # s = sense 1,0,1,0,7,2 # s = sense 1,0,0,0,7,3 # s 1,0,0,2,4,4 # xr 1,0,b,4,c,4 # pe = path end 1,1,1,2,4,4 # fo 1,1,g,4,2,4 # fo,p 1,1,2,g,4,4 # fo,p 1,1,2,4,3,4 # pg 1,1,2,7,7,4 # fi 1,1,4,2,2,4 # p 1,1,7,2,7,4 # fi 1,1,7,7,2,4 # fi 1,2,b,2,4,4 # pe 1,2,b,4,3,4 # pe 1,2,2,4,4,4 # c = collision 1,2,3,2,4,4 # pe 1,b,3,3,4,4 # pe 1,2,4,2,2,4 # c 1,2,4,3,3,4 # pe 1,0,0,5,2,5 # xl 1,0,1,0,5,5 # i 1,0,b,5,c,5 # pe 1,1,1,2,5,5 # fo 1,1,g,5,2,5 # fo,p 1,1,2,g,5,5 # fo,p 1,1,2,4,4,5 # fi 1,1,2,5,3,5 # pg 1,1,4,2,4,5 # fi 1,1,4,4,2,5 # fi 1,1,5,2,2,5 # p 1,2,2,b,5,5 # pe 1,2,2,5,3,5 # pe 1,2,2,5,5,5 # c 1,2,3,b,5,5 # pe 1,2,3,5,3,5 # pe 1,2,5,2,5,5 # c 1,2,5,3,3,5 # pe 1,3,3,3,5,5 # pe 1,0,0,h,6,6 # sh 1,0,0,6,i,6 # sh 1,0,1,h,6,6 # sh 1,0,1,6,i,6 # sh 1,0,2,2,6,6 # pe 1,0,2,6,1,6 # sh 1,0,b,6,c,6 # pe 1,0,6,0,6,6 # sh 1,0,6,1,j,6 # sh 1,0,6,2,g,6 # sh,pe 1,0,6,2,6,6 # c 1,0,6,0,6,6 # sh 1,0,6,1,j,6 # sh 1,0,6,2,i,6 # sh,pe,c 1,0,6,6,1,6 # sh 1,1,1,1,5,6 # i 1,1,1,2,6,6 # fo 1,1,1,6,2,6 # fo 1,1,2,1,6,6 # fo 1,1,2,2,6,6 # p 1,1,2,5,5,6 # fi 1,1,2,6,2,6 # p 1,1,2,6,3,6 # pg 1,1,2,6,6,6 # fi 1,1,5,2,5,6 # fi 1,1,5,5,2,6 # fi 1,1,6,2,2,6 # p 1,1,6,2,6,6 # fi 1,1,6,6,2,6 # fi 1,2,2,b,6,6 # pe 1,2,2,6,3,6 # pe 1,2,2,6,6,6 # c 1,2,3,b,6,6 # pe 1,2,3,6,3,6 # pe 1,2,6,2,6,6 # c 1,2,6,3,3,6 # pe 1,3,3,3,6,6 # pe 1,0,2,7,b,7 # pe 1,0,3,7,b,7 # pe 1,1,1,2,7,7 # fo 1,1,1,7,2,7 # fo 1,1,2,g,7,7 # fo,p 1,1,2,7,b,7 # p,pg 1,1,3,e,3,7 # t7 1,1,3,7,3,7 # t7 1,1,7,2,2,7 # p 1,2,2,b,7,7 # pe 1,2,2,7,3,7 # pe 1,2,2,7,7,7 # c 1,2,3,b,7,7 # pe 1,2,3,7,3,7 # pe 1,2,7,2,7,7 # c 1,2,7,3,3,7 # pe 1,3,3,3,7,7 # pe 2,0,h,0,6,0 # k,k,g 2,0,0,f,7,1 # s,x 2,0,0,7,1,1 # x = extend 2,0,1,0,7,1 # s 2,0,1,1,7,1 # x 2,0,1,7,1,1 # x 2,0,7,1,1,1 # x 2,1,1,1,7,1 # x 2,0,0,2,5,3 # qm = cell q change of state 2,0,0,4,2,3 # pm = cell p change of state 2,0,1,4,2,3 # pm (was missing in codd.r) 2,0,2,0,7,3 # g 2,0,2,5,1,3 # qm 2,0,3,0,n,3 # g 2,2,3,2,d,3 # g (was missing in codd.r) 3,0,0,2,n,0 # r,m 3,0,0,6,2,0 # r 3,0,0,7,2,0 # m 3,0,1,6,2,0 # pm 3,0,1,7,2,0 # m 3,0,2,6,1,0 # qm 3,0,2,7,1,0 # m 3,0,0,0,6,1 # s 3,0,0,2,5,1 # qm 3,0,0,4,2,1 # pm 3,2,3,2,d,2 # g 3,0,1,0,6,4 # e 3,0,1,0,7,7 # j 4,0,0,0,1,0 # e 4,0,0,1,2,0 # fi 4,0,0,2,1,0 # fi 4,0,1,0,2,0 # fi 4,0,1,1,2,0 # fo 4,0,1,2,1,0 # fo 4,0,1,2,2,0 # p 4,0,2,1,1,0 # fo 4,0,2,1,2,0 # p 4,0,2,2,1,0 # p 4,0,3,1,2,0 # pg 4,0,0,0,2,1 # xr 4,0,0,2,2,1 # c 4,0,2,0,2,1 # pe 4,0,2,2,2,1 # pe 4,0,2,2,3,1 # pe 4,0,2,3,2,1 # pe 4,0,2,3,3,1 # pe 4,0,3,2,2,1 # pe 4,0,3,2,3,1 # pe 4,0,3,3,2,1 # pe 4,0,3,3,3,1 # pe 5,0,0,0,1,0 # i 5,0,0,1,2,0 # fi 5,0,0,2,1,0 # fi 5,0,1,0,2,0 # fi 5,0,1,1,2,0 # fo 5,0,1,2,1,0 # fo 5,0,1,2,2,0 # p 5,0,2,1,1,0 # fo 5,0,2,1,2,0 # p 5,0,2,2,1,0 # p 5,0,3,1,2,0 # pg 5,0,0,0,2,1 # xl 5,0,0,2,2,1 # c 5,0,2,p,b,1 # pe 5,0,3,b,c,1 # pe (was missing in codd.r) 6,0,0,0,1,0 # sh 6,0,0,1,1,0 # sh 6,0,0,1,2,0 # fi 6,0,0,2,1,0 # fi 6,0,1,0,1,0 # sh 6,0,1,0,2,0 # fi 6,0,1,1,1,0 # i 6,0,1,1,2,0 # fo 6,0,1,2,1,0 # fo 6,0,1,2,2,0 # p 6,0,2,1,1,0 # fo 6,0,2,1,2,0 # p 6,0,2,2,1,0 # p 6,0,2,2,3,0 # pe 6,0,2,3,2,0 # pe 6,0,2,3,3,0 # pe 6,0,3,1,2,0 # pg 6,0,3,2,2,0 # pe 6,0,3,2,3,0 # pe 6,0,3,3,2,0 # pe 6,0,3,3,3,0 # pe 6,1,2,3,2,0 # s 6,0,0,0,0,1 # sh 6,0,0,0,2,1 # sh 6,0,0,2,2,1 # c 6,0,2,0,2,1 # pe 6,0,2,2,2,1 # sh 7,0,0,0,1,0 # j 7,0,1,1,2,0 # fo 7,0,1,2,1,0 # fo 7,0,1,2,2,0 # p 7,0,2,1,1,0 # fo 7,0,2,1,2,0 # p 7,0,2,2,1,0 # p 7,0,2,2,3,0 # pe 7,0,2,3,2,0 # pe 7,0,2,3,3,0 # pe 7,0,3,1,2,0 # pg 7,0,3,1,3,0 # pe 7,0,3,2,2,0 # pe 7,0,3,2,3,0 # pe 7,0,3,3,2,0 # pe 7,0,3,3,3,0 # pe 7,1,2,2,2,0 # s 7,0,0,0,2,1 # pe 7,0,0,2,2,1 # c 7,0,2,0,2,1 # pe 7,0,2,2,2,1 # x # End of Codd's original ruleset # TJH added some extra cases for collisions between sheathing-signals: # (see top of file) # for 2-way collisions: 0,0,6,6,2,2 # sh 0,6,6,0,2,2 # sh (reflected form of above) # for 3-way collisions: 1,6,6,6,0,6 # sh @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 �����������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/LifeHistory.rule����������������������������������������������������������������0000644�0001750�0001750�00000026222�12536111364�014450� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE LifeHistory A variant of HistoricalLife with two extra ON states and two extra OFF states, for annotation purposes: state 0: OFF state 1: ON state 2: history/envelope (state=2 if cell was ever ON) state 3: marked ON (may change to OFF but will always remain marked) state 4: marked OFF (may change to ON but will always remain marked) state 5: start ON (becomes a normal marked OFF cell when it dies) state 6: boundary OFF (can never turn on -- can keep subpatterns in a stamp collection from interfering with each other) @TABLE n_states:7 neighborhood:Moore symmetries:rotate8 var a={0,2,4,6} var b={0,2,4,6} var c={0,2,4,6} var d={0,2,4,6} var e={0,2,4,6} var f={0,2,4,6} var g={3,5} var h={0,1,2} var i={0,1,2,3,4,5,6} var j={0,1,2,3,4,5,6} var k={0,1,2,3,4,5,6} var l={0,1,2,3,4,5,6} var m={0,1,2,3,4,5,6} var n={0,1,2,3,4,5,6} var o={0,1,2,3,4,5,6} var p={0,1,2,3,4,5,6} var q={1,3,5} var R={1,3,5} var S={1,3,5} var T={1,3,5} var u={3,4,5} # boundary cell always stays a boundary cell 6,i,j,k,l,m,n,o,p,6 # anything else that touches a boundary cell dies # (using 'u' instead of 'g' below lets gliders survive as blocks) g,6,i,j,k,l,m,n,o,4 1,6,i,j,k,l,m,n,o,2 # marked 3-neighbour birth # (has to be separate from the next section # only to handle the extra 'start' state 5) 4,R,S,T,a,b,c,d,e,3 4,R,S,a,T,b,c,d,e,3 4,R,S,a,b,T,c,d,e,3 4,R,S,a,b,c,T,d,e,3 4,R,S,a,b,c,d,T,e,3 4,R,a,S,b,T,c,d,e,3 4,R,a,S,b,c,T,d,e,3 # marked 3-neighbour survival g,R,S,T,a,b,c,d,e,g g,R,S,a,T,b,c,d,e,g g,R,S,a,b,T,c,d,e,g g,R,S,a,b,c,T,d,e,g g,R,S,a,b,c,d,T,e,g g,R,a,S,b,T,c,d,e,g g,R,a,S,b,c,T,d,e,g # normal 3-neighbour birth h,R,S,T,a,b,c,d,e,1 h,R,S,a,T,b,c,d,e,1 h,R,S,a,b,T,c,d,e,1 h,R,S,a,b,c,T,d,e,1 h,R,S,a,b,c,d,T,e,1 h,R,a,S,b,T,c,d,e,1 h,R,a,S,b,c,T,d,e,1 # 2-neighbour survival q,R,S,a,b,c,d,e,f,q q,R,a,S,b,c,d,e,f,q q,R,a,b,S,c,d,e,f,q q,R,a,b,c,S,d,e,f,q # ON states 3 and 5 go to history state 4 if they don't survive g,i,j,k,l,m,n,o,p,4 # Otherwise ON states die and become the history state q,i,j,k,l,m,n,o,p,2 @COLORS 1 0 255 0 2 0 0 128 3 216 255 216 4 255 0 0 5 255 255 0 6 96 96 96 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 186 5 1" /* colors */ ". c #000000" "B c #404040" "C c #808080" "D c #C0C0C0" "E c #FFFFFF" /* icon for state 1 */ "..............................." "..............................." "..........BCDEEEEEDCB.........." ".........CEEEEEEEEEEEC........." ".......BEEEEEEEEEEEEEEEB......." "......DEEEEEEEEEEEEEEEEED......" ".....DEEEEEEEEEEEEEEEEEEED....." "....BEEEEEEEEEEEEEEEEEEEEEB...." "....EEEEEEEEEEEEEEEEEEEEEEE...." "...CEEEEEEEEEEEEEEEEEEEEEEEC..." "..BEEEEEEEEEEEEEEEEEEEEEEEEEB.." "..CEEEEEEEEEEEEEEEEEEEEEEEEEC.." "..DEEEEEEEEEEEEEEEEEEEEEEEEED.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..DEEEEEEEEEEEEEEEEEEEEEEEEED.." "..CEEEEEEEEEEEEEEEEEEEEEEEEEC.." "..BEEEEEEEEEEEEEEEEEEEEEEEEEB.." "...CEEEEEEEEEEEEEEEEEEEEEEEC..." "....EEEEEEEEEEEEEEEEEEEEEEE...." "....BEEEEEEEEEEEEEEEEEEEEEB...." ".....DEEEEEEEEEEEEEEEEEEED....." "......DEEEEEEEEEEEEEEEEED......" ".......BEEEEEEEEEEEEEEEB......." ".........CEEEEEEEEEEEC........." "..........BCDEEEEEDCB.........." "..............................." "..............................." /* icon for state 2 */ ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." /* icon for state 3 */ "..............................." "..............................." "..........BCDEEEEEDCB.........." ".........CEEEEEEEEEEEC........." ".......BEEEEEEEEEEEEEEEB......." "......DEEEEEEEEEEEEEEEEED......" ".....DEEEEEEEEEEEEEEEEEEED....." "....BEEEEEEEEEEEEEEEEEEEEEB...." "....EEEEEEEEEEEEEEEEEEEEEEE...." "...CEEEEEEEEEEEEEEEEEEEEEEEC..." "..BEEEEEEEEEEEEEEEEEEEEEEEEEB.." "..CEEEEEEEEEEEEEEEEEEEEEEEEEC.." "..DEEEEEEEEEEEEEEEEEEEEEEEEED.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..DEEEEEEEEEEEEEEEEEEEEEEEEED.." "..CEEEEEEEEEEEEEEEEEEEEEEEEEC.." "..BEEEEEEEEEEEEEEEEEEEEEEEEEB.." "...CEEEEEEEEEEEEEEEEEEEEEEEC..." "....EEEEEEEEEEEEEEEEEEEEEEE...." "....BEEEEEEEEEEEEEEEEEEEEEB...." ".....DEEEEEEEEEEEEEEEEEEED....." "......DEEEEEEEEEEEEEEEEED......" ".......BEEEEEEEEEEEEEEEB......." ".........CEEEEEEEEEEEC........." "..........BCDEEEEEDCB.........." "..............................." "..............................." /* icon for state 4 */ ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." /* icon for state 5 */ "..............................." "..............................." "..........BCDEEEEEDCB.........." ".........CEEEEEEEEEEEC........." ".......BEEEEEEEEEEEEEEEB......." "......DEEEEEEEEEEEEEEEEED......" ".....DEEEEEEEEEEEEEEEEEEED....." "....BEEEEEEEEEEEEEEEEEEEEEB...." "....EEEEEEEEEEEEEEEEEEEEEEE...." "...CEEEEEEEEEEEEEEEEEEEEEEEC..." "..BEEEEEEEEEEEEEEEEEEEEEEEEEB.." "..CEEEEEEEEEEEEEEEEEEEEEEEEEC.." "..DEEEEEEEEEEEEEEEEEEEEEEEEED.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..DEEEEEEEEEEEEEEEEEEEEEEEEED.." "..CEEEEEEEEEEEEEEEEEEEEEEEEEC.." "..BEEEEEEEEEEEEEEEEEEEEEEEEEB.." "...CEEEEEEEEEEEEEEEEEEEEEEEC..." "....EEEEEEEEEEEEEEEEEEEEEEE...." "....BEEEEEEEEEEEEEEEEEEEEEB...." ".....DEEEEEEEEEEEEEEEEEEED....." "......DEEEEEEEEEEEEEEEEED......" ".......BEEEEEEEEEEEEEEEB......." ".........CEEEEEEEEEEEC........." "..........BCDEEEEEDCB.........." "..............................." "..............................." /* icon for state 6 */ ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E.E.E.E.E.E.E.E.E." XPM /* width height num_colors chars_per_pixel */ "15 90 5 1" /* colors */ ". c #000000" "B c #404040" "C c #808080" "D c #C0C0C0" "E c #FFFFFF" /* icon for state 1 */ "..............." "....BDEEEDB...." "...DEEEEEEED..." "..DEEEEEEEEED.." ".BEEEEEEEEEEEB." ".DEEEEEEEEEEED." ".EEEEEEEEEEEEE." ".EEEEEEEEEEEEE." ".EEEEEEEEEEEEE." ".DEEEEEEEEEEED." ".BEEEEEEEEEEEB." "..DEEEEEEEEED.." "...DEEEEEEED..." "....BDEEEDB...." "..............." /* icon for state 2 */ ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." /* icon for state 3 */ "..............." "....BDEEEDB...." "...DEEEEEEED..." "..DEEEEEEEEED.." ".BEEEEEEEEEEEB." ".DEEEEEEEEEEED." ".EEEEEEEEEEEEE." ".EEEEEEEEEEEEE." ".EEEEEEEEEEEEE." ".DEEEEEEEEEEED." ".BEEEEEEEEEEEB." "..DEEEEEEEEED.." "...DEEEEEEED..." "....BDEEEDB...." "..............." /* icon for state 4 */ "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" /* icon for state 5 */ "..............." "....BDEEEDB...." "...DEEEEEEED..." "..DEEEEEEEEED.." ".BEEEEEEEEEEEB." ".DEEEEEEEEEEED." ".EEEEEEEEEEEEE." ".EEEEEEEEEEEEE." ".EEEEEEEEEEEEE." ".DEEEEEEEEEEED." ".BEEEEEEEEEEEB." "..DEEEEEEEEED.." "...DEEEEEEED..." "....BDEEEDB...." "..............." /* icon for state 6 */ "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" ".E.E.E.E.E.E.E." "E.E.E.E.E.E.E.E" XPM /* width height num_colors chars_per_pixel */ "7 42 6 1" /* colors */ ". c #000000" "B c #404040" "C c #808080" "D c #C0C0C0" "E c #FFFFFF" "F c #E0E0E0" /* icon for state 1 */ ".BFEFB." "BEEEEEB" "FEEEEEF" "EEEEEEE" "FEEEEEF" "BEEEEEB" ".BFEFB." /* icon for state 2 */ ".E.E.E." "E.E.E.E" ".E.E.E." "E.E.E.E" ".E.E.E." "E.E.E.E" ".E.E.E." /* icon for state 3 */ ".BFEFB." "BEEEEEB" "FEEEEEF" "EEEEEEE" "FEEEEEF" "BEEEEEB" ".BFEFB." /* icon for state 4 */ "E.E.E.E" ".E.E.E." "E.E.E.E" ".E.E.E." "E.E.E.E" ".E.E.E." "E.E.E.E" /* icon for state 5 */ ".BFEFB." "BEEEEEB" "FEEEEEF" "EEEEEEE" "FEEEEEF" "BEEEEEB" ".BFEFB." /* icon for state 6 */ "E.E.E.E" ".E.E.E." "E.E.E.E" ".E.E.E." "E.E.E.E" ".E.E.E." "E.E.E.E" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/HPP.rule������������������������������������������������������������������������0000644�0001750�0001750�00000064661�12536111364�012647� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE HPP HPP Lattice gas J. Hardy, O. de Pazzis, and Y. Pomeau (1973) J. Math. Phys. 14, 470. The earliest lattice gas model. Later made obsolete by the FHP gas on a hexagonal lattice, which has better physical properties. States following http://pages.cs.wisc.edu/~wylie/doc/PhD_thesis.pdf Each cell can contain up to 4 particles, each moving in one of the four directions. Outgoing directions SENW map onto 4 bits, so W=0001=1, SEW=1101=13, etc. Next state is simply the collected inputs, in most cases. The exceptions are 5 (EW) and 10 (NS) which get swapped (bounce on collision). To make the gas useful in Golly's infinite area, I've added reflecting boundary states, 16-31. These work in the same way as gas particles (collecting inputs) but reverse their direction. Contact: Tim Hutton <tim.hutton@gmail.com> Sink boundary: (or you can vent to the outside but this way is neater) 32 Source boundary: (haven't really worked out how to use this well yet) 33 The HPP gas can also be run using the Margolus-neighborhood emulator in Golly (see e.g. Patterns/Margolus/BBM.rle) but this CA is neater. @TABLE n_states:34 neighborhood:vonNeumann symmetries:none # a = any of the gas states var a={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} # b = any of the reflecting boundary states var b={16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31} # s = has an outgoing south particle var s={8,9,10,11,12,13,14,15,24,25,26,27,28,29,30,31,33} # Ns = doesn't have an outgoing south particle var Ns={0,1,2,3,4,5,6,7,16,17,18,19,20,21,22,23,32} # e = has an outgoing east particle var e={4,5,6,7,12,13,14,15,20,21,22,23,28,29,30,31,33} # Ne = doesn't have an outgoing east particle var Ne={0,1,2,3,8,9,10,11,16,17,18,19,24,25,26,27,32} # n = has an outgoing north particle var n={2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31,33} # Nn = doesn't have an outgoing north particle var Nn={0,1,4,5,8,9,12,13,16,17,20,21,24,25,28,29,32} # w = has an outgoing west particle var w={1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33} # Nw = doesn't have an outgoing north particle var Nw={0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32} # straightforward transport (no interactions) except 5 and 10 which are swapped a,Ns,Nw,Nn,Ne,0 a,Ns,w,Nn,Ne,1 a,Ns,Nw,n,Ne,2 a,Ns,w,n,Ne,3 a,Ns,Nw,Nn,e,4 a,Ns,w,Nn,e,10 a,Ns,Nw,n,e,6 a,Ns,w,n,e,7 a,s,Nw,Nn,Ne,8 a,s,w,Nn,Ne,9 a,s,Nw,n,Ne,5 a,s,w,n,Ne,11 a,s,Nw,Nn,e,12 a,s,w,Nn,e,13 a,s,Nw,n,e,14 a,s,w,n,e,15 # reflecting boundaries: b,Ns,Nw,Nn,Ne,16 b,Ns,Nw,Nn,e,17 b,s,Nw,Nn,Ne,18 b,s,Nw,Nn,e,19 b,Ns,w,Nn,Ne,20 b,Ns,w,Nn,e,21 b,s,w,Nn,Ne,22 b,s,w,Nn,e,23 b,Ns,Nw,n,Ne,24 b,Ns,Nw,n,e,25 b,s,Nw,n,Ne,26 b,s,Nw,n,e,27 b,Ns,w,n,Ne,28 b,Ns,w,n,e,29 b,s,w,n,Ne,30 b,s,w,n,e,31 @COLORS # the grey-level intensity is proportional to the number of particles # in the square 1 120 120 120 2 120 120 120 3 160 160 160 4 120 120 120 5 160 160 160 6 160 160 160 7 220 220 220 8 120 120 120 9 160 160 160 10 160 160 160 11 220 220 220 12 160 160 160 13 220 220 220 14 220 220 220 15 255 255 255 16 200 180 0 17 255 255 0 18 255 255 0 19 255 255 0 20 255 255 0 21 255 255 0 22 255 255 0 23 255 255 0 24 255 255 0 25 255 255 0 26 255 255 0 27 255 255 0 28 255 255 0 29 255 255 0 30 255 255 0 31 255 255 0 32 255 0 0 33 0 255 0 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 496 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".....B........................." "....BB........................." "...BBB........................." "..BBBB........................." ".BBBBBBBBBBBBBBBBBBBBBBBBBB...." "BBBBBBBBBBBBBBBBBBBBBBBBBBB...." ".BBBBBBBBBBBBBBBBBBBBBBBBBB...." "..BBBB........................." "...BBB........................." "....BB........................." ".....B........................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 2 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............................." "..............................." "..............................." "..............................." /* icon for state 3 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." ".....B........BBB.............." "....BB........BBB.............." "...BBB........BBB.............." "..BBBB........BBB.............." ".BBBBBBBBBBBBBBBBBBBBBBBBBB...." "BBBBBBBBBBBBBBBBBBBBBBBBBBB...." ".BBBBBBBBBBBBBBBBBBBBBBBBBB...." "..BBBB........BBB.............." "...BBB........BBB.............." "....BB........BBB.............." ".....B........BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............................." "..............................." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".........................B....." ".........................BB...." ".........................BBB..." ".........................BBBB.." "....BBBBBBBBBBBBBBBBBBBBBBBBBB." "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBB." ".........................BBBB.." ".........................BBB..." ".........................BB...." ".........................B....." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 5 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".....B...................B....." "....BB...................BB...." "...BBB...................BBB..." "..BBBB...................BBBB.." ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBB." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBB." "..BBBB...................BBBB.." "...BBB...................BBB..." "....BB...................BB...." ".....B...................B....." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 6 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB........B....." "..............BBB........BB...." "..............BBB........BBB..." "..............BBB........BBBB.." "....BBBBBBBBBBBBBBBBBBBBBBBBBB." "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBB." "..............BBB........BBBB.." "..............BBB........BBB..." "..............BBB........BB...." "..............BBB........B....." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............................." "..............................." "..............................." "..............................." /* icon for state 7 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." ".....B........BBB........B....." "....BB........BBB........BB...." "...BBB........BBB........BBB..." "..BBBB........BBB........BBBB.." ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBB." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBB." "..BBBB........BBB........BBBB.." "...BBB........BBB........BBB..." "....BB........BBB........BB...." ".....B........BBB........B....." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............................." "..............................." "..............................." "..............................." /* icon for state 8 */ "..............................." "..............................." "..............................." "..............................." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for state 9 */ "..............................." "..............................." "..............................." "..............................." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." ".....B........BBB.............." "....BB........BBB.............." "...BBB........BBB.............." "..BBBB........BBB.............." ".BBBBBBBBBBBBBBBBBBBBBBBBBB...." "BBBBBBBBBBBBBBBBBBBBBBBBBBB...." ".BBBBBBBBBBBBBBBBBBBBBBBBBB...." "..BBBB........BBB.............." "...BBB........BBB.............." "....BB........BBB.............." ".....B........BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for state 10 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for state 11 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." ".....B........BBB.............." "....BB........BBB.............." "...BBB........BBB.............." "..BBBB........BBB.............." ".BBBBBBBBBBBBBBBBBBBBBBBBBB...." "BBBBBBBBBBBBBBBBBBBBBBBBBBB...." ".BBBBBBBBBBBBBBBBBBBBBBBBBB...." "..BBBB........BBB.............." "...BBB........BBB.............." "....BB........BBB.............." ".....B........BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for state 12 */ "..............................." "..............................." "..............................." "..............................." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB........B....." "..............BBB........BB...." "..............BBB........BBB..." "..............BBB........BBBB.." "....BBBBBBBBBBBBBBBBBBBBBBBBBB." "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBB." "..............BBB........BBBB.." "..............BBB........BBB..." "..............BBB........BB...." "..............BBB........B....." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for state 13 */ "..............................." "..............................." "..............................." "..............................." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." ".....B........BBB........B....." "....BB........BBB........BB...." "...BBB........BBB........BBB..." "..BBBB........BBB........BBBB.." ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBB." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBB." "..BBBB........BBB........BBBB.." "...BBB........BBB........BBB..." "....BB........BBB........BB...." ".....B........BBB........B....." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for state 14 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB........B....." "..............BBB........BB...." "..............BBB........BBB..." "..............BBB........BBBB.." "....BBBBBBBBBBBBBBBBBBBBBBBBBB." "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBB." "..............BBB........BBBB.." "..............BBB........BBB..." "..............BBB........BB...." "..............BBB........B....." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for state 15 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." ".....B........BBB........B....." "....BB........BBB........BB...." "...BBB........BBB........BBB..." "..BBBB........BBB........BBBB.." ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBB." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBB." "..BBBB........BBB........BBBB.." "...BBB........BBB........BBB..." "....BB........BBB........BB...." ".....B........BBB........B....." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..............BBB.............." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for states 16 to 33 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" XPM /* width height num_colors chars_per_pixel */ "15 240 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "..............." "..............." "..............." "..............." "..............." "..B............" ".BB............" "BBBBBBBBBBBBB.." ".BB............" "..B............" "..............." "..............." "..............." "..............." "..............." /* icon for state 2 */ ".......B......." "......BBB......" ".....BBBBB....." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." "..............." "..............." /* icon for state 3 */ ".......B......." "......BBB......" ".....BBBBB....." ".......B......." ".......B......." "..B....B......." ".BB....B......." "BBBBBBBBBBBBB.." ".BB....B......." "..B....B......." ".......B......." ".......B......." ".......B......." "..............." "..............." /* icon for state 4 */ "..............." "..............." "..............." "..............." "..............." "............B.." "............BB." "..BBBBBBBBBBBBB" "............BB." "............B.." "..............." "..............." "..............." "..............." "..............." /* icon for state 5 */ "..............." "..............." "..............." "..............." "..............." "..B.........B.." ".BB.........BB." "BBBBBBBBBBBBBBB" ".BB.........BB." "..B.........B.." "..............." "..............." "..............." "..............." "..............." /* icon for state 6 */ ".......B......." "......BBB......" ".....BBBBB....." ".......B......." ".......B......." ".......B....B.." ".......B....BB." "..BBBBBBBBBBBBB" ".......B....BB." ".......B....B.." ".......B......." ".......B......." ".......B......." "..............." "..............." /* icon for state 7 */ ".......B......." "......BBB......" ".....BBBBB....." ".......B......." ".......B......." "..B....B....B.." ".BB....B....BB." "BBBBBBBBBBBBBBB" ".BB....B....BB." "..B....B....B.." ".......B......." ".......B......." ".......B......." "..............." "..............." /* icon for state 8 */ "..............." "..............." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".....BBBBB....." "......BBB......" ".......B......." /* icon for state 9 */ "..............." "..............." ".......B......." ".......B......." ".......B......." "..B....B......." ".BB....B......." "BBBBBBBBBBBBB.." ".BB....B......." "..B....B......." ".......B......." ".......B......." ".....BBBBB....." "......BBB......" ".......B......." /* icon for state 10 */ ".......B......." "......BBB......" ".....BBBBB....." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".......B......." ".....BBBBB....." "......BBB......" ".......B......." /* icon for state 11 */ ".......B......." "......BBB......" ".....BBBBB....." ".......B......." ".......B......." "..B....B......." ".BB....B......." "BBBBBBBBBBBBB.." ".BB....B......." "..B....B......." ".......B......." ".......B......." ".....BBBBB....." "......BBB......" ".......B......." /* icon for state 12 */ "..............." "..............." ".......B......." ".......B......." ".......B......." ".......B....B.." ".......B....BB." "..BBBBBBBBBBBBB" ".......B....BB." ".......B....B.." ".......B......." ".......B......." ".....BBBBB....." "......BBB......" ".......B......." /* icon for state 13 */ "..............." "..............." ".......B......." ".......B......." ".......B......." "..B....B....B.." ".BB....B....BB." "BBBBBBBBBBBBBBB" ".BB....B....BB." "..B....B....B.." ".......B......." ".......B......." ".....BBBBB....." "......BBB......" ".......B......." /* icon for state 14 */ ".......B......." "......BBB......" ".....BBBBB....." ".......B......." ".......B......." ".......B....B.." ".......B....BB." "..BBBBBBBBBBBBB" ".......B....BB." ".......B....B.." ".......B......." ".......B......." ".....BBBBB....." "......BBB......" ".......B......." /* icon for state 15 */ ".......B......." "......BBB......" ".....BBBBB....." ".......B......." ".......B......." "..B....B....B.." ".BB....B....BB." "BBBBBBBBBBBBBBB" ".BB....B....BB." "..B....B....B.." ".......B......." ".......B......." ".....BBBBB....." "......BBB......" ".......B......." /* icon for states 16 to 33 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" XPM /* width height num_colors chars_per_pixel */ "7 112 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "......." "......." ".B....." "BBBBBB." ".B....." "......." "......." /* icon for state 2 */ "...B..." "..BBB.." "...B..." "...B..." "...B..." "...B..." "......." /* icon for state 3 */ "...B..." "..BBB.." ".B.B..." "BBBBBB." ".B.B..." "...B..." "......." /* icon for state 4 */ "......." "......." ".....B." ".BBBBBB" ".....B." "......." "......." /* icon for state 5 */ "......." "......." ".B...B." "BBBBBBB" ".B...B." "......." "......." /* icon for state 6 */ "...B..." "..BBB.." "...B.B." ".BBBBBB" "...B.B." "...B..." "......." /* icon for state 7 */ "...B..." "..BBB.." ".B.B.B." "BBBBBBB" ".B.B.B." "...B..." "......." /* icon for state 8 */ "......." "...B..." "...B..." "...B..." "...B..." "..BBB.." "...B..." /* icon for state 9 */ "......." "......." ".B....." "BBBB..." ".B.B..." "..BBB.." "...B..." /* icon for state 10 */ "...B..." "..BBB.." "...B..." "...B..." "...B..." "..BBB.." "...B..." /* icon for state 11 */ "...B..." "..BBB.." ".B.B..." "BBBBBB." ".B.B..." "..BBB.." "...B..." /* icon for state 12 */ "......." "...B..." "...B.B." ".BBBBBB" "...B.B." "..BBB.." "...B..." /* icon for state 13 */ "......." "...B..." ".B.B.B." "BBBBBBB" ".B.B.B." "..BBB.." "...B..." /* icon for state 14 */ "...B..." "..BBB.." "...B.B." ".BBBBBB" "...B.B." "..BBB.." "...B..." /* icon for state 15 */ "...B..." "..BBB.." ".B.B.B." "BBBBBBB" ".B.B.B." "..BBB.." "...B..." /* icon for states 16 to 33 */ "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" �������������������������������������������������������������������������������golly-2.7-src/Rules/Langtons-Loops.rule�������������������������������������������������������������0000644�0001750�0001750�00000015746�12536111364�015077� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Langtons-Loops C.G.Langton. "Self-reproduction in cellular automata." Physica D, Vol. 10, pages 135-144, 1984. Transition rules from: http://necsi.org/postdocs/sayama/sdsr/java/loops.java Credits: "Self-Replicating Loops & Ant, Programmed by Eli Bachmutsky, Copyleft Feb.1999" @TABLE # rules: 219 # format: CNESWC' n_states:8 neighborhood:vonNeumann symmetries:rotate4 000000 000012 000020 000030 000050 000063 000071 000112 000122 000132 000212 000220 000230 000262 000272 000320 000525 000622 000722 001022 001120 002020 002030 002050 002125 002220 002322 005222 012321 012421 012525 012621 012721 012751 014221 014321 014421 014721 016251 017221 017255 017521 017621 017721 025271 100011 100061 100077 100111 100121 100211 100244 100277 100511 101011 101111 101244 101277 102026 102121 102211 102244 102263 102277 102327 102424 102626 102644 102677 102710 102727 105427 111121 111221 111244 111251 111261 111277 111522 112121 112221 112244 112251 112277 112321 112424 112621 112727 113221 122244 122277 122434 122547 123244 123277 124255 124267 125275 200012 200022 200042 200071 200122 200152 200212 200222 200232 200242 200250 200262 200272 200326 200423 200517 200522 200575 200722 201022 201122 201222 201422 201722 202022 202032 202052 202073 202122 202152 202212 202222 202272 202321 202422 202452 202520 202552 202622 202722 203122 203216 203226 203422 204222 205122 205212 205222 205521 205725 206222 206722 207122 207222 207422 207722 211222 211261 212222 212242 212262 212272 214222 215222 216222 217222 222272 222442 222462 222762 222772 300013 300022 300041 300076 300123 300421 300622 301021 301220 302511 401120 401220 401250 402120 402221 402326 402520 403221 500022 500215 500225 500232 500272 500520 502022 502122 502152 502220 502244 502722 512122 512220 512422 512722 600011 600021 602120 612125 612131 612225 700077 701120 701220 701250 702120 702221 702251 702321 702525 702720 @TREE num_states=8 num_neighbors=4 num_nodes=222 1 0 1 2 3 4 5 6 7 1 2 1 2 3 4 5 1 7 1 0 1 2 2 4 2 1 7 1 0 1 2 1 4 5 6 7 1 3 1 2 3 4 5 6 7 1 1 7 1 6 4 5 6 7 2 0 1 2 0 3 0 4 5 1 2 1 2 3 4 5 6 7 2 1 7 7 7 0 0 0 0 1 0 1 2 3 4 2 6 7 1 0 4 2 3 4 5 6 7 1 0 1 0 3 4 5 6 7 1 2 7 2 3 4 2 6 7 2 2 7 0 9 10 11 7 12 1 0 1 6 3 4 5 6 7 2 0 0 14 0 0 0 0 0 1 0 1 3 1 4 5 6 7 2 3 0 16 0 0 0 0 0 1 0 1 7 3 4 5 6 7 1 5 1 2 3 4 0 6 7 1 0 1 5 3 4 5 6 7 2 0 18 19 0 0 0 0 20 1 2 1 2 2 4 5 6 7 2 4 0 22 0 0 0 0 0 2 5 0 7 0 0 0 0 0 3 6 8 13 15 17 21 23 24 2 1 7 7 0 0 18 0 0 2 0 0 0 0 0 0 0 0 1 2 1 2 1 4 5 6 7 1 0 0 2 3 4 5 6 7 2 28 0 0 0 0 3 0 29 3 26 27 30 15 27 27 27 27 2 2 7 0 14 16 19 22 7 1 0 1 2 3 0 5 6 0 1 0 1 2 0 0 5 6 0 2 28 33 34 0 0 0 0 0 1 0 6 2 3 4 2 6 7 1 5 1 2 3 0 2 0 0 1 0 1 2 3 1 0 6 1 1 2 7 1 3 6 5 6 1 1 0 1 0 3 0 5 6 5 1 0 6 2 3 4 5 6 7 1 0 7 2 3 4 2 6 0 2 36 37 38 39 10 40 41 42 1 0 1 6 3 1 5 6 7 2 0 0 44 0 0 0 0 0 1 0 7 2 3 4 5 6 7 1 0 1 1 3 4 5 6 7 2 0 0 7 0 46 47 0 20 1 0 1 3 3 4 5 6 7 2 49 0 0 0 0 0 0 0 3 32 35 43 45 27 48 27 50 2 0 7 9 0 0 0 0 0 3 52 27 27 27 27 27 27 27 2 3 0 10 0 0 0 0 0 2 0 0 10 0 0 0 0 0 1 0 4 2 3 4 4 6 7 2 0 0 56 0 0 0 10 0 3 54 55 57 27 27 27 27 27 2 0 0 11 0 0 0 0 0 2 0 0 33 0 0 0 0 0 1 0 1 2 3 4 5 6 1 2 0 9 61 0 0 0 0 0 3 59 60 62 27 27 27 27 27 2 4 0 7 0 0 0 0 0 1 0 3 2 3 4 5 6 7 2 0 0 65 0 0 0 0 0 3 64 27 66 27 27 27 27 27 2 5 0 12 0 0 20 0 0 2 0 0 46 0 0 0 0 0 2 49 0 46 0 0 0 46 0 3 68 69 70 27 27 27 27 27 4 25 31 51 53 58 63 67 71 2 1 0 28 0 0 0 0 0 2 7 0 33 0 0 0 0 0 2 7 0 34 0 10 33 0 46 2 7 0 0 0 0 0 0 0 3 73 74 75 76 27 27 27 27 2 33 0 0 0 10 0 47 46 1 0 2 2 3 4 5 6 7 2 0 0 79 0 0 0 0 0 3 76 27 78 27 27 80 27 27 2 7 0 0 14 0 0 0 0 2 0 0 0 0 0 79 0 0 1 0 1 2 3 4 2 5 7 1 0 1 2 3 4 0 5 7 1 1 1 2 3 4 5 6 7 1 1 4 2 3 4 2 6 7 1 5 1 2 3 4 5 6 7 1 1 7 2 3 4 2 6 7 2 37 84 85 86 87 88 86 89 1 0 1 2 3 4 5 1 7 2 0 91 0 0 0 0 0 0 2 0 0 86 86 86 0 0 86 2 9 0 0 0 0 0 0 0 2 0 0 86 0 0 86 86 86 3 82 83 90 92 93 94 27 95 3 27 27 92 27 27 27 27 27 3 27 55 55 27 27 27 27 27 2 18 0 3 0 0 0 0 0 2 0 0 0 0 0 0 0 86 2 0 0 86 0 0 0 0 0 2 0 0 88 0 0 0 0 0 3 99 27 100 27 27 27 101 102 2 0 0 47 0 0 0 0 0 3 27 104 27 27 27 27 27 27 2 0 0 29 0 0 0 0 0 3 106 69 69 27 27 27 27 27 4 77 81 96 97 98 103 105 107 2 2 28 36 0 0 0 0 49 2 7 0 37 0 0 9 0 0 2 0 0 38 0 56 61 65 46 2 9 0 39 0 0 0 0 0 2 10 0 10 0 0 0 0 0 2 11 3 40 0 0 0 0 0 2 7 0 41 0 10 0 0 46 2 12 29 42 0 0 0 0 0 3 109 110 111 112 113 114 115 116 2 7 33 37 0 0 0 0 0 2 0 0 84 91 0 0 0 0 2 34 0 85 0 10 0 0 46 2 10 10 87 0 0 0 0 0 2 33 0 88 0 0 0 0 0 2 0 47 86 0 0 0 0 0 2 46 46 89 0 0 86 0 0 3 118 119 120 101 121 122 123 124 2 0 34 38 44 0 7 0 0 2 0 0 85 0 86 0 0 86 2 38 85 0 0 10 0 0 46 2 56 10 10 10 0 0 0 0 2 61 0 0 0 46 0 0 0 2 65 0 0 0 0 0 0 0 2 46 46 46 0 0 0 0 0 3 126 127 128 27 129 130 131 132 2 14 0 39 0 0 0 0 0 2 14 0 86 0 86 0 0 0 2 44 0 0 0 10 0 0 0 3 134 135 136 27 55 27 27 69 2 16 0 10 0 0 46 0 0 2 0 0 87 0 86 0 0 0 2 0 86 10 0 0 46 0 0 1 0 5 2 3 4 5 6 7 2 0 0 141 0 0 0 0 0 3 138 139 140 55 27 142 69 27 2 19 0 40 0 0 47 0 0 2 0 79 88 0 0 0 0 86 1 1 5 2 3 4 5 6 7 2 0 0 146 0 0 0 0 0 3 144 145 76 27 142 27 27 147 2 22 0 41 0 0 0 0 0 2 0 0 86 0 0 0 0 86 2 0 86 0 0 0 0 0 0 3 149 150 27 27 69 151 27 27 2 7 0 42 0 0 20 0 0 2 0 0 89 0 86 0 0 86 2 0 86 46 0 0 0 0 0 2 0 88 146 0 0 0 0 0 3 153 154 155 69 27 156 27 27 4 117 125 133 137 143 148 152 157 2 14 14 44 0 0 0 0 0 3 27 27 159 27 27 27 27 27 2 0 0 91 0 0 0 0 0 3 76 161 27 27 27 27 27 27 2 39 86 0 0 10 0 0 46 3 94 27 163 27 27 27 27 27 3 27 27 27 27 27 27 27 27 2 0 86 10 0 0 0 0 0 3 27 27 166 27 27 27 27 27 4 160 162 164 165 167 165 165 165 2 3 0 0 0 0 0 0 0 2 16 0 0 0 0 0 0 0 3 169 27 170 27 27 27 27 27 3 27 27 101 101 101 27 27 101 2 10 10 56 0 0 0 0 0 2 0 10 10 0 0 0 0 0 2 10 87 10 10 0 141 46 0 3 173 174 175 55 27 27 27 27 3 27 27 151 27 27 27 27 27 2 46 0 46 0 0 0 0 0 3 27 27 178 27 27 27 27 27 3 55 27 27 27 27 27 27 27 4 171 172 176 165 177 179 180 165 2 18 0 0 0 0 0 0 0 2 19 0 7 0 0 0 0 0 2 20 0 20 0 0 0 0 0 3 27 182 183 27 69 104 27 184 2 0 0 9 0 0 0 0 0 2 0 79 0 0 0 0 0 0 3 186 27 187 27 27 27 27 27 2 11 33 61 0 0 0 0 0 2 3 0 0 0 0 0 86 88 2 40 88 0 0 141 0 0 146 3 189 190 191 27 69 27 27 27 2 47 0 0 0 0 0 0 0 3 27 27 193 27 27 27 27 27 3 27 101 151 27 27 27 27 27 4 185 188 192 165 165 194 165 195 2 4 0 0 0 0 0 0 0 2 22 0 0 0 0 0 0 0 3 197 27 198 27 27 27 27 27 2 0 0 0 0 0 86 0 0 3 27 27 200 27 27 27 27 27 2 7 0 65 0 0 0 0 0 2 0 47 0 0 0 0 0 0 2 41 86 0 0 46 0 0 0 2 10 0 0 0 0 0 0 0 2 46 0 0 0 0 0 0 0 3 202 203 204 27 205 27 27 206 4 199 201 207 165 165 165 165 177 2 5 0 49 0 0 0 0 0 3 209 27 76 27 27 27 27 27 2 0 0 86 0 0 88 0 0 3 27 27 211 27 27 101 101 101 2 12 46 46 0 0 0 0 0 2 29 46 46 0 0 0 0 0 2 42 89 46 46 0 146 0 0 3 213 214 215 27 27 151 27 27 2 20 0 0 0 0 0 0 0 3 217 27 217 27 27 27 27 27 3 69 27 27 27 27 27 27 27 4 210 212 216 165 177 218 219 177 5 72 108 158 168 181 196 208 220 @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 8 255 128 0 ��������������������������golly-2.7-src/Rules/HPPMargolus_emulated.rule�������������������������������������������������������0000644�0001750�0001750�00000004261�12536111364�016227� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE HPPMargolus_emulated @TREE num_states=5 num_neighbors=8 num_nodes=132 1 0 2 2 4 4 1 0 1 2 3 4 2 0 1 0 1 0 2 1 1 1 1 1 1 0 2 1 4 3 2 0 1 4 1 4 3 2 3 5 3 5 3 3 3 3 3 3 3 5 3 5 3 5 4 6 7 8 7 8 4 7 7 7 7 7 2 4 1 4 1 4 3 2 3 11 3 11 3 11 3 11 3 11 4 12 7 13 7 13 5 9 10 14 10 14 1 0 1 1 3 3 2 16 1 16 1 16 3 17 3 17 3 17 4 18 7 18 7 18 5 19 10 19 10 19 1 0 2 2 2 4 2 0 1 21 1 21 1 0 4 2 2 4 2 0 1 21 1 23 3 2 3 22 3 24 4 25 7 25 7 25 5 26 10 26 10 26 1 0 4 2 4 4 2 0 1 23 1 28 2 0 1 28 1 28 3 2 3 29 3 30 4 31 7 31 7 31 5 32 10 32 10 32 6 15 20 27 20 33 5 10 10 10 10 10 6 20 20 35 20 35 3 2 3 2 3 2 1 0 1 2 3 2 2 1 1 38 1 38 3 39 39 3 39 3 1 0 1 4 3 2 2 1 1 38 1 41 3 42 42 3 42 3 4 37 40 37 43 37 5 44 10 44 10 44 4 25 40 25 43 25 5 46 10 46 10 46 4 31 40 31 43 31 5 48 10 48 10 48 6 45 35 47 35 49 1 0 1 4 3 4 2 1 1 41 1 51 3 52 52 3 52 3 2 1 1 51 1 51 3 54 54 3 54 3 4 37 53 37 55 37 5 56 10 56 10 56 4 25 53 25 55 25 5 58 10 58 10 58 4 31 53 31 55 31 5 60 10 60 10 60 6 57 35 59 35 61 7 34 36 50 36 62 6 35 35 35 35 35 7 36 36 64 36 64 4 37 7 37 7 37 2 38 38 1 38 1 3 3 3 67 3 67 4 68 7 68 7 68 2 41 41 1 41 1 3 3 3 67 3 70 4 71 7 71 7 71 5 66 69 66 72 66 5 26 69 26 72 26 5 32 69 32 72 32 6 73 35 74 35 75 5 44 69 44 72 44 5 46 69 46 72 46 5 48 69 48 72 48 6 77 35 78 35 79 5 56 69 56 72 56 5 58 69 58 72 58 5 60 69 60 72 60 6 81 35 82 35 83 7 76 64 80 64 84 2 51 51 1 51 1 3 3 3 70 3 86 4 87 7 87 7 87 3 3 3 86 3 86 4 89 7 89 7 89 5 66 88 66 90 66 5 26 88 26 90 26 5 32 88 32 90 32 6 91 35 92 35 93 5 44 88 44 90 44 5 46 88 46 90 46 5 48 88 48 90 48 6 95 35 96 35 97 5 56 88 56 90 56 5 58 88 58 90 58 5 60 88 60 90 60 6 99 35 100 35 101 7 94 64 98 64 102 8 63 65 85 65 103 1 0 1 1 3 1 2 105 1 105 1 105 3 106 3 106 3 106 4 18 7 107 7 107 1 0 1 3 3 1 2 109 1 109 1 109 3 110 3 110 3 110 4 18 7 107 7 111 5 19 10 108 10 112 6 113 113 35 113 35 7 114 114 64 114 64 7 64 64 64 64 64 8 115 115 116 115 116 5 66 10 66 10 66 6 118 35 27 35 33 7 119 64 50 64 62 8 120 116 85 116 103 1 0 1 3 3 3 2 122 1 122 1 122 3 123 3 123 3 123 4 18 7 111 7 124 4 18 7 124 7 124 5 19 10 125 10 126 6 127 127 35 127 35 7 128 128 64 128 64 8 129 129 116 129 116 9 104 117 121 130 121 @COLORS 1 90 90 90 2 62 62 62 3 0 255 127 4 0 178 88 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/WireWorld.rule������������������������������������������������������������������0000644�0001750�0001750�00000006056�12536111364�014130� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE WireWorld A 4-state CA created by Brian Silverman. WireWorld models the flow of currents in wires and makes it relatively easy to build logic gates and other digital circuits. @TABLE # Golly rule-table format. # Each rule: C,N,NE,E,SE,S,SW,W,NW,C' # # Default for transitions not listed: no change # # Variables are bound within each transition. # For example, if a={1,2} then 4,a,0->a represents # two transitions: 4,1,0->1 and 4,2,0->2 # (This is why we need to repeat the variables below. # In this case the method isn't really helping.) n_states:4 neighborhood:Moore symmetries:rotate8 var a={0,1,2,3} var b={0,1,2,3} var c={0,1,2,3} var d={0,1,2,3} var e={0,1,2,3} var f={0,1,2,3} var g={0,1,2,3} var h={0,1,2,3} var i={0,2,3} var j={0,2,3} var k={0,2,3} var l={0,2,3} var m={0,2,3} var n={0,2,3} 1,a,b,c,d,e,f,g,h,2 2,a,b,c,d,e,f,g,h,3 3,i,j,k,l,m,n,a,1,1 3,i,j,k,l,m,1,n,1,1 3,i,j,k,l,1,m,n,1,1 3,i,j,k,1,l,m,n,1,1 @NAMES # these state names are not yet used by Golly 0 empty 1 electron tail 2 electron head 3 copper wire @COLORS # same colors used at http://www.quinapalus.com/wi-index.html 0 48 48 48 dark gray 1 0 128 255 light blue 2 255 255 255 white 3 255 128 0 orange @ICONS # icon info is in XPM format (order is not important) XPM /* width height num_colors chars_per_pixel */ "31 31 5 1" /* colors */ ". c #000000" "D c #404040" "C c #808080" "B c #C0C0C0" "W c #FFFFFF" /* pixels */ "..............................." "..............................." "..........DCBWWWWWBCD.........." ".........CWWWWWWWWWWWC........." ".......DWWWWWWWWWWWWWWWD......." "......BWWWWWWWWWWWWWWWWWB......" ".....BWWWWWWWWWWWWWWWWWWWB....." "....DWWWWWWWWWWWWWWWWWWWWWD...." "....WWWWWWWWWWWWWWWWWWWWWWW...." "...CWWWWWWWWWWWWWWWWWWWWWWWC..." "..DWWWWWWWWWWWWWWWWWWWWWWWWWD.." "..CWWWWWWWWWWWWWWWWWWWWWWWWWC.." "..BWWWWWWWWWWWWWWWWWWWWWWWWWB.." "..WWWWWWWWWWWWWWWWWWWWWWWWWWW.." "..WWWWWWWWWWWWWWWWWWWWWWWWWWW.." "..WWWWWWWWWWWWWWWWWWWWWWWWWWW.." "..WWWWWWWWWWWWWWWWWWWWWWWWWWW.." "..WWWWWWWWWWWWWWWWWWWWWWWWWWW.." "..BWWWWWWWWWWWWWWWWWWWWWWWWWB.." "..CWWWWWWWWWWWWWWWWWWWWWWWWWC.." "..DWWWWWWWWWWWWWWWWWWWWWWWWWD.." "...CWWWWWWWWWWWWWWWWWWWWWWWC..." "....WWWWWWWWWWWWWWWWWWWWWWW...." "....DWWWWWWWWWWWWWWWWWWWWWD...." ".....BWWWWWWWWWWWWWWWWWWWB....." "......BWWWWWWWWWWWWWWWWWB......" ".......DWWWWWWWWWWWWWWWD......." ".........CWWWWWWWWWWWC........." "..........DCBWWWWWBCD.........." "..............................." "..............................." XPM /* width height num_colors chars_per_pixel */ "15 15 4 1" /* colors */ ". c #000000" "D c #404040" "B c #C0C0C0" "W c #FFFFFF" /* pixels */ "..............." "....DBWWWBD...." "...BWWWWWWWB..." "..BWWWWWWWWWB.." ".DWWWWWWWWWWWD." ".BWWWWWWWWWWWB." ".WWWWWWWWWWWWW." ".WWWWWWWWWWWWW." ".WWWWWWWWWWWWW." ".BWWWWWWWWWWWB." ".DWWWWWWWWWWWD." "..BWWWWWWWWWB.." "...BWWWWWWWB..." "....DBWWWBD...." "..............." XPM /* width height num_colors chars_per_pixel */ "7 7 4 1" /* colors */ ". c #000000" "D c #404040" "E c #E0E0E0" "W c #FFFFFF" /* pixels */ ".DEWED." "DWWWWWD" "EWWWWWE" "WWWWWWW" "EWWWWWE" "DWWWWWD" ".DEWED." ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Tempesti.rule�������������������������������������������������������������������0000644�0001750�0001750�00000053205�12536111364�014002� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Tempesti Transitions rules for Tempesti's self-replicating loops. Converted from rules given in Tempesti's thesis: http://lslwww.epfl.ch/pages/embryonics/thesis/ Note that there's an error in the text, where it says that states are given as clockwise from north: PS,N,NE,E,... but actually they start at NW: PS,NW,N,NE,... Note also that Table A-3 in his thesis has rules that are rotationally symmetric, but Table A-4's rules are not, despite what footnote 39 says. To make a single rule file we've had to expand A-3, giving 175*4+326=1026 rules. Hopefully this can be compressed further. As in Tempesti's thesis, variables are bound within each transition. For example, if a={1,2} then 4,a,0->a represents two transitions: 4,1,0->1 and 4,2,0->2 @TABLE # rules: 1026 # variables: 4 # format: C,N,NE,E,SE,S,SW,W,NW,C' # remaining cases default: state doesn't change # symmetry: none (no rotation/reflection) n_states:10 neighborhood:Moore symmetries:none var a={5,6,7,8,9} var b={5,6,7,8,9} var c={5,6,7,8,9} var d={5,6,7,8,9} 2,b,0,0,0,a,1,1,1,a a,0,0,b,1,1,1,2,0,b b,0,1,c,1,1,1,a,0,c b,1,0,c,d,1,1,a,0,c b,0,0,0,0,c,1,a,1,c c,b,0,0,0,d,1,1,a,d b,a,0,0,0,2,1,1,1,2 b,0,0,c,1,1,1,a,0,c c,b,0,0,0,2,1,1,a,2 b,0,0,0,0,2,1,a,1,2 2,b,0,0,0,a,1,1,c,a b,1,0,c,2,1,1,a,0,c b,2,0,0,0,c,1,1,a,c b,1,0,2,c,1,1,a,0,2 2,0,0,0,0,b,1,a,1,b 0,0,0,0,0,2,a,1,0,2 b,0,1,2,1,1,1,a,0,2 b,c,0,0,0,a,1,1,2,a 2,1,2,b,c,1,1,a,0,b a,2,0,0,0,b,1,2,1,b 0,0,0,0,2,2,0,0,0,2 2,0,0,0,0,a,2,2,0,0 2,0,1,b,1,1,1,a,0,b a,1,0,b,c,1,1,2,0,b 0,0,0,0,0,0,1,2,0,2 a,0,1,b,1,1,1,2,0,b 2,0,0,0,0,0,1,2,0,0 0,0,0,0,0,2,a,1,1,2 2,0,0,0,0,a,2,1,1,0 0,0,0,0,0,2,1,1,1,2 2,0,0,0,0,0,1,1,1,0 0,2,0,0,0,2,1,1,2,2 0,0,0,0,0,2,1,1,2,3 0,0,0,0,3,3,0,0,0,3 3,0,0,0,0,0,1,3,0,0 3,0,0,3,0,1,0,0,0,1 0,0,0,0,0,0,1,3,0,3 0,3,0,0,0,2,1,1,3,2 0,0,0,0,0,2,1,1,3,2 3,3,2,1,0,0,0,3,0,2 3,0,3,2,0,0,0,0,0,1 0,2,1,0,0,0,0,0,3,3 2,3,2,1,0,0,0,3,0,3 1,2,0,1,0,0,0,2,3,3 3,0,0,2,3,3,1,0,0,0 2,0,0,0,1,3,3,3,0,0 3,3,2,3,0,3,0,1,0,0 0,3,1,0,0,0,0,3,3,3 3,2,0,1,0,0,3,3,3,1 3,1,1,0,0,0,0,3,0,1 3,0,1,3,0,0,0,0,1,0 0,0,0,2,1,1,0,0,0,2 0,0,0,2,1,0,1,0,0,2 0,2,0,1,1,0,0,1,0,2 0,2,1,1,1,0,0,0,1,2 2,0,0,0,1,2,1,0,0,0 2,0,1,1,1,0,0,0,1,0 0,1,1,0,3,3,0,0,1,1 0,1,1,1,1,0,0,2,1,3 1,0,1,1,1,0,2,1,0,3 1,1,0,0,0,1,0,3,3,3 1,1,0,0,0,1,3,3,0,3 3,3,1,1,1,0,0,0,1,0 3,0,1,1,1,3,0,1,0,1 0,0,0,0,0,2,1,3,3,3 3,3,0,0,2,1,0,0,1,1 2,0,0,0,0,0,1,1,3,0 0,0,0,0,0,3,1,3,1,2 3,0,0,0,0,0,1,1,3,0 3,1,0,0,3,1,0,1,0,1 0,3,0,0,0,0,1,1,1,3 3,0,0,0,0,0,1,1,1,0 3,0,0,0,0,2,1,1,1,2 2,3,0,0,0,0,1,1,1,3 3,2,0,0,0,0,1,1,1,0 2,0,0,0,0,3,1,1,1,0 0,a,b,1,1,3,0,0,0,3 a,2,1,b,1,3,0,0,0,2 b,1,1,c,0,1,3,a,2,a b,1,1,c,0,1,3,2,a,2 3,2,a,1,1,0,0,0,0,2 2,b,1,a,1,3,0,0,0,b 1,a,b,0,0,1,0,3,2,2 0,2,2,1,1,0,0,0,0,2 2,a,2,2,1,0,0,0,0,a a,b,1,2,2,2,0,0,0,b a,2,1,1,1,b,0,0,2,2 2,1,1,c,0,2,2,a,b,a 2,2,b,0,0,1,0,2,a,1 2,a,1,1,1,0,0,0,0,a a,b,a,1,1,2,0,0,0,b a,1,1,2,0,1,a,b,c,b b,c,1,a,1,a,0,0,0,c b,c,b,1,1,a,0,0,0,c a,1,1,d,0,1,a,b,c,b 2,a,1,1,1,3,0,0,0,a 2,a,1,1,3,0,0,0,0,a 3,a,1,1,3,0,0,0,0,a a,b,1,1,1,3,0,0,0,b b,2,1,a,1,a,0,0,0,3 b,1,1,c,0,1,b,a,2,a b,3,c,1,1,a,0,0,0,3 a,1,1,b,0,1,a,3,c,2 3,a,1,b,1,b,0,0,0,a a,b,1,1,c,3,0,0,0,b b,3,1,1,1,a,0,0,0,3 2,1,1,a,0,1,3,b,c,b a,b,1,2,1,3,0,0,0,b 3,b,2,1,1,a,0,0,0,b 3,b,1,1,1,a,0,0,0,b a,b,a,1,1,3,0,0,0,b 2,a,1,1,0,0,0,0,0,a a,b,1,1,0,2,0,0,0,b 2,a,1,0,1,0,0,0,0,a 0,1,1,0,0,1,0,2,a,2 a,b,1,2,1,0,0,0,0,b 2,1,1,0,0,1,0,a,b,a 2,1,1,0,0,0,1,a,1,a c,3,1,1,a,b,0,0,0,2 0,0,0,0,a,3,1,1,1,4 3,0,0,a,1,3,1,1,1,a a,0,0,b,1,1,3,3,0,b 3,3,a,1,0,0,1,1,1,1 1,1,4,c,1,1,a,b,3,c a,4,0,b,1,1,1,1,1,b b,0,0,c,1,1,1,a,4,c 1,1,0,4,b,1,a,3,b,4 4,0,0,0,b,a,1,1,1,0 3,b,4,b,1,a,0,0,0,b 4,1,0,0,a,b,3,b,a,0 b,4,0,c,1,1,a,3,b,c a,b,1,4,a,3,0,0,0,0 1,1,0,0,0,4,a,b,c,4 3,b,c,1,1,a,0,0,0,b a,0,0,b,1,3,0,0,0,b b,0,0,c,1,1,3,a,0,c a,b,1,4,0,0,0,0,0,0 4,1,0,0,0,0,0,a,b,0 0,0,0,a,3,0,0,0,0,1 a,b,c,1,1,3,0,0,1,b b,0,0,c,1,a,0,1,0,c b,c,d,1,1,a,0,0,1,c 1,1,0,0,0,4,a,b,3,4 b,c,1,1,4,a,0,0,0,c b,c,b,1,4,a,0,0,0,1 1,b,a,0,0,4,a,b,c,0 a,2,1,b,0,1,0,0,0,2 b,1,1,c,0,0,1,a,2,a 1,a,b,0,0,0,0,0,2,2 2,2,b,0,0,0,0,2,a,1 2,2,0,1,0,0,0,0,0,1 1,1,0,0,0,2,0,0,2,3 2,3,3,2,0,0,0,0,0,3 2,3,0,0,0,0,0,2,3,3 3,1,0,0,0,2,2,3,0,1 3,0,1,3,2,2,0,0,0,0 0,3,3,2,0,0,0,0,0,3 2,3,0,0,0,0,0,0,3,3 3,1,0,0,0,2,0,3,0,1 3,0,1,3,2,0,0,0,0,0 2,0,1,1,0,0,0,0,0,0 2,1,1,0,0,1,0,2,0,0 2,a,1,b,0,1,0,0,0,a b,1,1,c,0,0,1,2,a,2 a,b,1,2,0,1,0,0,0,b 2,1,1,a,0,0,1,b,c,b a,1,1,2,0,0,1,b,c,b 1,1,0,0,0,0,0,0,0,4 2,0,1,1,4,0,0,0,0,0 4,1,0,0,0,0,0,0,0,0 1,1,0,0,0,4,0,0,0,4 0,a,b,1,4,0,0,0,0,1 1,b,c,0,0,4,0,0,a,0 2,a,2,1,4,0,0,0,0,0 1,b,2,0,0,4,0,0,a,0 2,0,0,a,1,1,1,b,0,a a,b,1,1,1,2,0,0,0,b b,c,1,1,1,a,0,0,1,c b,c,d,1,1,a,0,1,0,c b,0,0,c,1,a,1,0,0,c c,0,0,d,1,1,a,b,0,d b,0,0,2,1,1,1,a,0,2 b,c,1,1,1,a,0,0,0,c c,0,0,2,1,1,a,b,0,2 b,0,0,2,1,a,1,0,0,2 2,0,0,a,1,1,c,b,0,a b,c,2,1,1,a,0,1,0,c b,0,0,c,1,1,a,2,0,c b,2,c,1,1,a,0,1,0,2 2,0,0,b,1,a,1,0,0,b 0,0,0,2,a,1,0,0,0,2 b,2,1,1,1,a,0,0,1,2 b,0,0,a,1,1,2,c,0,a 2,b,c,1,1,a,0,1,2,b a,0,0,b,1,2,1,2,0,b 0,0,2,2,0,0,0,0,0,2 2,0,0,a,2,2,0,0,0,0 2,b,1,1,1,a,0,0,1,b a,b,c,1,1,2,0,1,0,b 0,0,0,0,1,2,0,0,0,2 a,b,1,1,1,2,0,0,1,b 2,0,0,0,1,2,0,0,0,0 0,0,0,2,a,1,1,0,0,2 2,0,0,a,2,1,1,0,0,0 0,0,0,2,1,1,1,0,0,2 2,0,0,0,1,1,1,0,0,0 0,0,0,2,1,1,2,2,0,2 0,0,0,2,1,1,2,0,0,3 0,0,3,3,0,0,0,0,0,3 3,0,0,0,1,3,0,0,0,0 3,3,0,1,0,0,0,0,0,1 0,0,0,0,1,3,0,0,0,3 0,0,0,2,1,1,3,3,0,2 0,0,0,2,1,1,3,0,0,2 3,1,0,0,0,3,0,3,2,2 3,2,0,0,0,0,0,0,3,1 0,0,0,0,0,0,3,2,1,3 2,1,0,0,0,3,0,3,2,3 1,1,0,0,0,2,3,2,0,3 3,2,3,3,1,0,0,0,0,0 2,0,1,3,3,3,0,0,0,0 3,3,0,3,0,1,0,3,2,0 0,0,0,0,0,3,3,3,1,3 3,1,0,0,3,3,3,2,0,1 3,0,0,0,0,3,0,1,1,1 3,3,0,0,0,0,1,0,1,0 0,2,1,1,0,0,0,0,0,2 0,2,1,0,1,0,0,0,0,2 0,1,1,0,0,1,0,2,0,2 0,1,1,0,0,0,1,2,1,2 2,0,1,2,1,0,0,0,0,0 2,1,1,0,0,0,1,0,1,0 0,0,3,3,0,0,1,1,1,1 0,1,1,0,0,2,1,1,1,3 1,1,1,0,2,1,0,0,1,3 1,0,0,1,0,3,3,1,0,3 1,0,0,1,3,3,0,1,0,3 3,1,1,0,0,0,1,3,1,0 3,1,1,3,0,1,0,0,1,1 0,0,0,2,1,3,3,0,0,3 3,0,2,1,0,0,1,3,0,1 2,0,0,0,1,1,3,0,0,0 0,0,0,3,1,3,1,0,0,2 3,0,0,0,1,1,3,0,0,0 3,0,3,1,0,1,0,1,0,1 0,0,0,0,1,1,1,3,0,3 3,0,0,0,1,1,1,0,0,0 3,0,0,2,1,1,1,0,0,2 2,0,0,0,1,1,1,3,0,3 3,0,0,0,1,1,1,2,0,0 2,0,0,3,1,1,1,0,0,0 0,1,1,3,0,0,0,a,b,3 a,b,1,3,0,0,0,2,1,2 b,c,0,1,3,a,2,1,1,a b,c,0,1,3,2,a,1,1,2 3,1,1,0,0,0,0,2,a,2 2,a,1,3,0,0,0,b,1,b 1,0,0,1,0,3,2,a,b,2 0,1,1,0,0,0,0,2,2,2 2,2,1,0,0,0,0,a,2,a a,2,2,2,0,0,0,b,1,b a,1,1,b,0,0,2,2,1,2 2,c,0,2,2,a,b,1,1,a 2,0,0,1,0,2,a,2,b,1 2,1,1,0,0,0,0,a,1,a a,1,1,2,0,0,0,b,a,b a,2,0,1,a,b,c,1,1,b b,a,1,a,0,0,0,c,1,c b,1,1,a,0,0,0,c,b,c a,d,0,1,a,b,c,1,1,b 2,1,1,3,0,0,0,a,1,a 2,1,3,0,0,0,0,a,1,a 3,1,3,0,0,0,0,a,1,a a,1,1,3,0,0,0,b,1,b b,a,1,a,0,0,0,2,1,3 b,c,0,1,b,a,2,1,1,a b,1,1,a,0,0,0,3,c,3 a,b,0,1,a,3,c,1,1,2 3,b,1,b,0,0,0,a,1,a a,1,c,3,0,0,0,b,1,b b,1,1,a,0,0,0,3,1,3 2,a,0,1,3,b,c,1,1,b a,2,1,3,0,0,0,b,1,b 3,1,1,a,0,0,0,b,2,b 3,1,1,a,0,0,0,b,1,b a,1,1,3,0,0,0,b,a,b 2,1,0,0,0,0,0,a,1,a a,1,0,2,0,0,0,b,1,b 2,0,1,0,0,0,0,a,1,a 0,0,0,1,0,2,a,1,1,2 a,2,1,0,0,0,0,b,1,b 2,0,0,1,0,a,b,1,1,a 2,0,0,0,1,a,1,1,1,a c,1,a,b,0,0,0,3,1,2 0,0,a,3,1,1,1,0,0,4 3,a,1,3,1,1,1,0,0,a a,b,1,1,3,3,0,0,0,b 3,1,0,0,1,1,1,3,a,1 1,c,1,1,a,b,3,1,4,c a,b,1,1,1,1,1,4,0,b b,c,1,1,1,a,4,0,0,c 1,4,b,1,a,3,b,1,0,4 4,0,b,a,1,1,1,0,0,0 3,b,1,a,0,0,0,b,4,b 4,0,a,b,3,b,a,1,0,0 b,c,1,1,a,3,b,4,0,c a,4,a,3,0,0,0,b,1,0 1,0,0,4,a,b,c,1,0,4 3,1,1,a,0,0,0,b,c,b a,b,1,3,0,0,0,0,0,b b,c,1,1,3,a,0,0,0,c a,4,0,0,0,0,0,b,1,0 4,0,0,0,0,a,b,1,0,0 0,a,3,0,0,0,0,0,0,1 a,1,1,3,0,0,1,b,c,b b,c,1,a,0,1,0,0,0,c b,1,1,a,0,0,1,c,d,c 1,0,0,4,a,b,3,1,0,4 b,1,4,a,0,0,0,c,1,c b,1,4,a,0,0,0,c,b,1 1,0,0,4,a,b,c,b,a,0 a,b,0,1,0,0,0,2,1,2 b,c,0,0,1,a,2,1,1,a 1,0,0,0,0,0,2,a,b,2 2,0,0,0,0,2,a,2,b,1 2,1,0,0,0,0,0,2,0,1 1,0,0,2,0,0,2,1,0,3 2,2,0,0,0,0,0,3,3,3 2,0,0,0,0,2,3,3,0,3 3,0,0,2,2,3,0,1,0,1 3,3,2,2,0,0,0,0,1,0 0,2,0,0,0,0,0,3,3,3 2,0,0,0,0,0,3,3,0,3 3,0,0,2,0,3,0,1,0,1 3,3,2,0,0,0,0,0,1,0 2,1,0,0,0,0,0,0,1,0 2,0,0,1,0,2,0,1,1,0 2,b,0,1,0,0,0,a,1,a b,c,0,0,1,2,a,1,1,2 a,2,0,1,0,0,0,b,1,b 2,a,0,0,1,b,c,1,1,b a,2,0,0,1,b,c,1,1,b 1,0,0,0,0,0,0,1,0,4 2,1,4,0,0,0,0,0,1,0 4,0,0,0,0,0,0,1,0,0 1,0,0,4,0,0,0,1,0,4 0,1,4,0,0,0,0,a,b,1 1,0,0,4,0,0,a,b,c,0 2,1,4,0,0,0,0,a,2,0 1,0,0,4,0,0,a,b,2,0 2,a,1,1,1,b,0,0,0,a a,1,1,2,0,0,0,b,1,b b,1,1,a,0,0,1,c,1,c b,1,1,a,0,1,0,c,d,c b,c,1,a,1,0,0,0,0,c c,d,1,1,a,b,0,0,0,d b,2,1,1,1,a,0,0,0,2 b,1,1,a,0,0,0,c,1,c c,2,1,1,a,b,0,0,0,2 b,2,1,a,1,0,0,0,0,2 2,a,1,1,c,b,0,0,0,a b,1,1,a,0,1,0,c,2,c b,c,1,1,a,2,0,0,0,c b,1,1,a,0,1,0,2,c,2 2,b,1,a,1,0,0,0,0,b 0,2,a,1,0,0,0,0,0,2 b,1,1,a,0,0,1,2,1,2 b,a,1,1,2,c,0,0,0,a 2,1,1,a,0,1,2,b,c,b a,b,1,2,1,2,0,0,0,b 0,2,0,0,0,0,0,0,2,2 2,a,2,2,0,0,0,0,0,0 2,1,1,a,0,0,1,b,1,b a,1,1,2,0,1,0,b,c,b 0,0,1,2,0,0,0,0,0,2 a,1,1,2,0,0,1,b,1,b 2,0,1,2,0,0,0,0,0,0 0,2,a,1,1,0,0,0,0,2 2,a,2,1,1,0,0,0,0,0 0,2,1,1,1,0,0,0,0,2 2,0,1,1,1,0,0,0,0,0 0,2,1,1,2,2,0,0,0,2 0,2,1,1,2,0,0,0,0,3 0,3,0,0,0,0,0,0,3,3 3,0,1,3,0,0,0,0,0,0 3,1,0,0,0,0,0,3,0,1 0,0,1,3,0,0,0,0,0,3 0,2,1,1,3,3,0,0,0,2 0,2,1,1,3,0,0,0,0,2 3,0,0,3,0,3,2,1,0,2 3,0,0,0,0,0,3,2,0,1 0,0,0,0,3,2,1,0,0,3 2,0,0,3,0,3,2,1,0,3 1,0,0,2,3,2,0,1,0,3 3,3,1,0,0,0,0,2,3,0 2,3,3,3,0,0,0,0,1,0 3,3,0,1,0,3,2,3,0,0 0,0,0,3,3,3,1,0,0,3 3,0,3,3,3,2,0,1,0,1 3,0,0,3,0,1,1,0,0,1 3,0,0,0,1,0,1,3,0,0 0,1,0,0,0,0,0,2,1,2 0,0,1,0,0,0,0,2,1,2 0,0,0,1,0,2,0,1,1,2 0,0,0,0,1,2,1,1,1,2 2,2,1,0,0,0,0,0,1,0 2,0,0,0,1,0,1,1,1,0 0,3,0,0,1,1,1,0,3,1 0,0,0,2,1,1,1,1,1,3 1,0,2,1,0,0,1,1,1,3 1,1,0,3,3,1,0,0,0,3 1,1,3,3,0,1,0,0,0,3 3,0,0,0,1,3,1,1,1,0 3,3,0,1,0,0,1,1,1,1 0,2,1,3,3,0,0,0,0,3 3,1,0,0,1,3,0,0,2,1 2,0,1,1,3,0,0,0,0,0 0,3,1,3,1,0,0,0,0,2 3,0,1,1,3,0,0,0,0,0 3,1,0,1,0,1,0,0,3,1 0,0,1,1,1,3,0,0,0,3 3,0,1,1,1,0,0,0,0,0 3,2,1,1,1,0,0,0,0,2 2,0,1,1,1,3,0,0,0,3 3,0,1,1,1,2,0,0,0,0 2,3,1,1,1,0,0,0,0,0 0,3,0,0,0,a,b,1,1,3 a,3,0,0,0,2,1,b,1,2 b,1,3,a,2,1,1,c,0,a b,1,3,2,a,1,1,c,0,2 3,0,0,0,0,2,a,1,1,2 2,3,0,0,0,b,1,a,1,b 1,1,0,3,2,a,b,0,0,2 0,0,0,0,0,2,2,1,1,2 2,0,0,0,0,a,2,2,1,a a,2,0,0,0,b,1,2,2,b a,b,0,0,2,2,1,1,1,2 2,2,2,a,b,1,1,c,0,a 2,1,0,2,a,2,b,0,0,1 2,0,0,0,0,a,1,1,1,a a,2,0,0,0,b,a,1,1,b a,1,a,b,c,1,1,2,0,b b,a,0,0,0,c,1,a,1,c b,a,0,0,0,c,b,1,1,c a,1,a,b,c,1,1,d,0,b 2,3,0,0,0,a,1,1,1,a 2,0,0,0,0,a,1,1,3,a 3,0,0,0,0,a,1,1,3,a a,3,0,0,0,b,1,1,1,b b,a,0,0,0,2,1,a,1,3 b,1,b,a,2,1,1,c,0,a b,a,0,0,0,3,c,1,1,3 a,1,a,3,c,1,1,b,0,2 3,b,0,0,0,a,1,b,1,a a,3,0,0,0,b,1,1,c,b b,a,0,0,0,3,1,1,1,3 2,1,3,b,c,1,1,a,0,b a,3,0,0,0,b,1,2,1,b 3,a,0,0,0,b,2,1,1,b 3,a,0,0,0,b,1,1,1,b a,3,0,0,0,b,a,1,1,b 2,0,0,0,0,a,1,1,0,a a,2,0,0,0,b,1,1,0,b 2,0,0,0,0,a,1,0,1,a 0,1,0,2,a,1,1,0,0,2 a,0,0,0,0,b,1,2,1,b 2,1,0,a,b,1,1,0,0,a 2,0,1,a,1,1,1,0,0,a c,b,0,0,0,3,1,1,a,2 0,3,1,1,1,0,0,0,a,4 3,3,1,1,1,0,0,a,1,a a,1,3,3,0,0,0,b,1,b 3,0,1,1,1,3,a,1,0,1 1,1,a,b,3,1,4,c,1,c a,1,1,1,1,4,0,b,1,b b,1,1,a,4,0,0,c,1,c 1,1,a,3,b,1,0,4,b,4 4,a,1,1,1,0,0,0,b,0 3,a,0,0,0,b,4,b,1,b 4,b,3,b,a,1,0,0,a,0 b,1,a,3,b,4,0,c,1,c a,3,0,0,0,b,1,4,a,0 1,4,a,b,c,1,0,0,0,4 3,a,0,0,0,b,c,1,1,b a,3,0,0,0,0,0,b,1,b b,1,3,a,0,0,0,c,1,c a,0,0,0,0,b,1,4,0,0 4,0,0,a,b,1,0,0,0,0 0,0,0,0,0,0,0,a,3,1 a,3,0,0,1,b,c,1,1,b b,a,0,1,0,0,0,c,1,c b,a,0,0,1,c,d,1,1,c 1,4,a,b,3,1,0,0,0,4 b,a,0,0,0,c,1,1,4,c b,a,0,0,0,c,b,1,4,1 1,4,a,b,c,b,a,0,0,0 a,1,0,0,0,2,1,b,0,2 b,0,1,a,2,1,1,c,0,a 1,0,0,0,2,a,b,0,0,2 2,0,0,2,a,2,b,0,0,1 2,0,0,0,0,2,0,1,0,1 1,2,0,0,2,1,0,0,0,3 2,0,0,0,0,3,3,2,0,3 2,0,0,2,3,3,0,0,0,3 3,2,2,3,0,1,0,0,0,1 3,2,0,0,0,0,1,3,2,0 0,0,0,0,0,3,3,2,0,3 2,0,0,0,3,3,0,0,0,3 3,2,0,3,0,1,0,0,0,1 3,0,0,0,0,0,1,3,2,0 2,0,0,0,0,0,1,1,0,0 2,1,0,2,0,1,1,0,0,0 2,1,0,0,0,a,1,b,0,a b,0,1,2,a,1,1,c,0,2 a,1,0,0,0,b,1,2,0,b 2,0,1,b,c,1,1,a,0,b a,0,1,b,c,1,1,2,0,b 1,0,0,0,0,1,0,0,0,4 2,0,0,0,0,0,1,1,4,0 4,0,0,0,0,1,0,0,0,0 1,4,0,0,0,1,0,0,0,4 0,0,0,0,0,a,b,1,4,1 1,4,0,0,a,b,c,0,0,0 2,0,0,0,0,a,2,1,4,0 1,4,0,0,a,b,2,0,0,0 2,1,1,b,0,0,0,a,1,a a,2,0,0,0,b,1,1,1,b b,a,0,0,1,c,1,1,1,c b,a,0,1,0,c,d,1,1,c b,a,1,0,0,0,0,c,1,c c,1,a,b,0,0,0,d,1,d b,1,1,a,0,0,0,2,1,2 b,a,0,0,0,c,1,1,1,c c,1,a,b,0,0,0,2,1,2 b,a,1,0,0,0,0,2,1,2 2,1,c,b,0,0,0,a,1,a b,a,0,1,0,c,2,1,1,c b,1,a,2,0,0,0,c,1,c b,a,0,1,0,2,c,1,1,2 2,a,1,0,0,0,0,b,1,b 0,1,0,0,0,0,0,2,a,2 b,a,0,0,1,2,1,1,1,2 b,1,2,c,0,0,0,a,1,a 2,a,0,1,2,b,c,1,1,b a,2,1,2,0,0,0,b,1,b 0,0,0,0,0,0,2,2,0,2 2,2,0,0,0,0,0,a,2,0 2,a,0,0,1,b,1,1,1,b a,2,0,1,0,b,c,1,1,b 0,2,0,0,0,0,0,0,1,2 a,2,0,0,1,b,1,1,1,b 2,2,0,0,0,0,0,0,1,0 0,1,1,0,0,0,0,2,a,2 2,1,1,0,0,0,0,a,2,0 0,1,1,0,0,0,0,2,1,2 2,1,1,0,0,0,0,0,1,0 0,1,2,2,0,0,0,2,1,2 0,1,2,0,0,0,0,2,1,3 0,0,0,0,0,0,3,3,0,3 3,3,0,0,0,0,0,0,1,0 3,0,0,0,0,3,0,1,0,1 0,3,0,0,0,0,0,0,1,3 0,1,3,3,0,0,0,2,1,2 0,1,3,0,0,0,0,2,1,2 3,3,0,3,2,1,0,0,0,2 3,0,0,0,3,2,0,0,0,1 0,0,3,2,1,0,0,0,0,3 2,3,0,3,2,1,0,0,0,3 1,2,3,2,0,1,0,0,0,3 3,0,0,0,0,2,3,3,1,0 2,3,0,0,0,0,1,3,3,0 3,1,0,3,2,3,0,3,0,0 0,3,3,3,1,0,0,0,0,3 3,3,3,2,0,1,0,0,3,1 3,3,0,1,1,0,0,0,0,1 3,0,1,0,1,3,0,0,0,0 0,0,0,0,0,2,1,1,0,2 0,0,0,0,0,2,1,0,1,2 0,1,0,2,0,1,1,0,0,2 0,0,1,2,1,1,1,0,0,2 2,0,0,0,0,0,1,2,1,0 2,0,1,0,1,1,1,0,0,0 0,0,1,1,1,0,3,3,0,1 0,2,1,1,1,1,1,0,0,3 1,1,0,0,1,1,1,0,2,3 1,3,3,1,0,0,0,1,0,3 1,3,0,1,0,0,0,1,3,3 3,0,1,3,1,1,1,0,0,0 3,1,0,0,1,1,1,3,0,1 0,3,3,0,0,0,0,2,1,3 3,0,1,3,0,0,2,1,0,1 2,1,3,0,0,0,0,0,1,0 0,3,1,0,0,0,0,3,1,2 3,1,3,0,0,0,0,0,1,0 3,1,0,1,0,0,3,1,0,1 0,1,1,3,0,0,0,0,1,3 3,1,1,0,0,0,0,0,1,0 3,1,1,0,0,0,0,2,1,2 2,1,1,3,0,0,0,0,1,3 3,1,1,2,0,0,0,0,1,0 2,1,1,0,0,0,0,3,1,0 0,0,0,a,b,1,1,3,0,3 a,0,0,2,1,b,1,3,0,2 b,a,2,1,1,c,0,1,3,a b,2,a,1,1,c,0,1,3,2 3,0,0,2,a,1,1,0,0,2 2,0,0,b,1,a,1,3,0,b 1,3,2,a,b,0,0,1,0,2 0,0,0,2,2,1,1,0,0,2 2,0,0,a,2,2,1,0,0,a a,0,0,b,1,2,2,2,0,b a,0,2,2,1,1,1,b,0,2 2,a,b,1,1,c,0,2,2,a 2,2,a,2,b,0,0,1,0,1 2,0,0,a,1,1,1,0,0,a a,0,0,b,a,1,1,2,0,b a,b,c,1,1,2,0,1,a,b b,0,0,c,1,a,1,a,0,c b,0,0,c,b,1,1,a,0,c a,b,c,1,1,d,0,1,a,b 2,0,0,a,1,1,1,3,0,a 2,0,0,a,1,1,3,0,0,a 3,0,0,a,1,1,3,0,0,a a,0,0,b,1,1,1,3,0,b b,0,0,2,1,a,1,a,0,3 b,a,2,1,1,c,0,1,b,a b,0,0,3,c,1,1,a,0,3 a,3,c,1,1,b,0,1,a,2 3,0,0,a,1,b,1,b,0,a a,0,0,b,1,1,c,3,0,b b,0,0,3,1,1,1,a,0,3 2,b,c,1,1,a,0,1,3,b a,0,0,b,1,2,1,3,0,b 3,0,0,b,2,1,1,a,0,b 3,0,0,b,1,1,1,a,0,b a,0,0,b,a,1,1,3,0,b 2,0,0,a,1,1,0,0,0,a a,0,0,b,1,1,0,2,0,b 2,0,0,a,1,0,1,0,0,a 0,2,a,1,1,0,0,1,0,2 a,0,0,b,1,2,1,0,0,b 2,a,b,1,1,0,0,1,0,a 2,a,1,1,1,0,0,0,1,a c,0,0,3,1,1,a,b,0,2 0,1,1,0,0,0,a,3,1,4 3,1,1,0,0,a,1,3,1,a a,3,0,0,0,b,1,1,3,b 3,1,1,3,a,1,0,0,1,1 1,b,3,1,4,c,1,1,a,c a,1,1,4,0,b,1,1,1,b b,a,4,0,0,c,1,1,1,c 1,3,b,1,0,4,b,1,a,4 4,1,1,0,0,0,b,a,1,0 3,0,0,b,4,b,1,a,0,b 4,b,a,1,0,0,a,b,3,0 b,3,b,4,0,c,1,1,a,c a,0,0,b,1,4,a,3,0,0 1,b,c,1,0,0,0,4,a,4 3,0,0,b,c,1,1,a,0,b a,0,0,0,0,b,1,3,0,b b,a,0,0,0,c,1,1,3,c a,0,0,b,1,4,0,0,0,0 4,a,b,1,0,0,0,0,0,0 0,0,0,0,0,a,3,0,0,1 a,0,1,b,c,1,1,3,0,b b,1,0,0,0,c,1,a,0,c b,0,1,c,d,1,1,a,0,c 1,b,3,1,0,0,0,4,a,4 b,0,0,c,1,1,4,a,0,c b,0,0,c,b,1,4,a,0,1 1,b,c,b,a,0,0,4,a,0 a,0,0,2,1,b,0,1,0,2 b,a,2,1,1,c,0,0,1,a 1,0,2,a,b,0,0,0,0,2 2,2,a,2,b,0,0,0,0,1 2,0,0,2,0,1,0,0,0,1 1,0,2,1,0,0,0,2,0,3 2,0,0,3,3,2,0,0,0,3 2,2,3,3,0,0,0,0,0,3 3,3,0,1,0,0,0,2,2,1 3,0,0,0,1,3,2,2,0,0 0,0,0,3,3,2,0,0,0,3 2,0,3,3,0,0,0,0,0,3 3,3,0,1,0,0,0,2,0,1 3,0,0,0,1,3,2,0,0,0 2,0,0,0,1,1,0,0,0,0 2,2,0,1,1,0,0,1,0,0 2,0,0,a,1,b,0,1,0,a b,2,a,1,1,c,0,0,1,2 a,0,0,b,1,2,0,1,0,b 2,b,c,1,1,a,0,0,1,b a,b,c,1,1,2,0,0,1,b 1,0,0,1,0,0,0,0,0,4 2,0,0,0,1,1,4,0,0,0 4,0,0,1,0,0,0,0,0,0 1,0,0,1,0,0,0,4,0,4 0,0,0,a,b,1,4,0,0,1 1,0,a,b,c,0,0,4,0,0 2,0,0,a,2,1,4,0,0,0 1,0,a,b,2,0,0,4,0,0 # # rules for construction: # 1,7,2,1,0,0,1,1,5,5 7,0,0,2,5,1,5,5,0,2 2,0,0,7,1,5,1,7,0,7 1,7,5,1,0,0,0,5,2,5 5,2,7,1,0,0,1,1,7,1 7,0,0,5,5,1,1,2,0,5 5,0,0,6,1,5,1,7,0,6 1,6,6,1,0,0,0,5,5,6 0,5,6,0,0,0,0,0,1,5 0,6,1,0,0,0,0,5,5,6 0,5,6,0,0,0,0,0,0,5 0,6,0,0,0,0,0,5,5,6 6,0,0,7,1,6,5,6,0,7 6,7,6,1,0,6,5,5,6,7 6,0,0,7,6,5,1,6,0,7 7,0,0,6,1,6,5,6,0,6 7,6,6,1,0,6,5,5,7,6 6,7,1,0,0,6,5,5,5,7 6,0,0,9,1,6,5,6,0,9 7,6,1,0,0,6,5,5,5,6 6,7,0,0,0,6,5,5,5,7 7,6,0,0,0,6,5,5,5,6 6,0,0,9,6,5,1,6,0,9 6,9,6,1,0,6,5,5,6,9 9,0,0,6,1,6,5,6,0,6 9,0,0,6,9,5,1,6,0,6 6,9,1,0,0,6,5,5,5,9 9,6,1,0,0,6,5,5,5,6 6,9,0,0,0,6,5,5,5,9 9,6,0,0,0,6,5,5,5,6 2,0,0,6,1,6,5,6,0,6 2,0,0,6,6,5,1,6,0,6 9,6,2,1,0,6,5,5,9,6 6,0,0,2,1,9,5,9,0,2 6,0,0,2,6,5,1,9,0,2 6,7,0,0,0,0,5,5,5,7 6,7,0,0,0,0,0,5,5,7 5,5,7,0,0,0,0,0,0,7 0,7,0,0,0,0,0,5,5,7 0,0,0,0,0,0,0,7,6,7 7,6,0,0,0,0,5,5,5,6 6,9,0,0,7,6,5,5,5,9 7,0,0,0,0,0,7,6,6,6 7,5,6,7,0,0,0,0,0,5 7,6,7,0,0,0,0,7,5,5 0,7,0,0,0,0,0,7,6,5 0,0,0,0,0,0,0,5,6,5 9,6,0,0,6,6,5,5,5,6 6,9,0,6,5,5,5,5,5,9 6,0,0,8,1,6,5,6,0,8 6,8,6,1,0,6,5,5,6,8 6,0,0,8,6,5,1,6,0,8 8,0,0,6,1,6,5,6,0,6 0,0,0,0,0,5,5,6,0,6 6,0,0,0,5,5,5,9,6,9 9,6,0,6,5,5,5,5,5,6 6,8,1,0,0,6,5,5,5,8 8,0,0,6,8,5,1,6,0,6 8,6,6,1,0,6,5,5,8,6 6,8,0,0,0,6,5,5,5,8 8,6,1,0,0,6,5,5,5,6 8,6,0,0,0,6,5,5,5,6 6,0,0,0,0,5,5,9,0,9 9,0,0,6,5,5,5,6,6,6 9,0,0,0,5,5,5,6,0,6 5,0,0,0,0,0,0,5,9,7 0,0,0,0,0,5,5,9,0,9 6,7,0,0,6,6,5,5,5,7 9,0,0,0,0,7,5,6,0,6 0,0,0,0,0,0,0,7,9,6 7,9,0,0,0,0,0,5,6,0 7,6,0,0,6,6,5,5,5,6 6,7,0,6,5,5,5,5,5,7 0,0,0,0,0,6,0,6,0,6 7,6,0,6,5,5,5,5,5,6 6,0,0,6,5,5,5,7,6,7 6,6,0,0,0,0,0,0,6,5 6,0,0,6,0,5,5,7,0,7 7,0,0,6,5,5,5,6,6,6 6,7,0,0,7,6,5,5,5,7 6,0,0,6,5,0,5,7,0,7 7,0,0,6,0,5,5,6,0,6 7,0,0,6,5,0,5,6,0,6 6,0,0,6,5,5,0,7,0,7 6,8,0,0,7,6,5,5,5,8 7,0,0,6,5,5,0,6,0,6 6,0,0,0,5,5,5,7,0,7 6,9,2,1,0,6,5,5,6,9 9,0,0,2,1,6,5,6,0,2 9,0,0,2,9,5,1,6,0,2 2,0,0,6,1,9,5,9,0,6 9,2,6,1,0,6,5,5,9,6 2,0,0,6,6,5,1,9,0,6 7,0,0,6,5,5,5,6,0,6 6,0,0,0,0,5,5,7,0,7 0,0,0,0,0,5,5,7,0,7 5,0,0,0,0,0,0,5,7,7 0,0,0,0,0,7,6,0,0,7 7,0,0,0,5,5,5,6,0,6 7,0,0,0,7,6,6,0,0,6 6,0,7,6,5,5,5,7,0,7 7,0,0,0,0,7,5,6,7,5 7,7,0,0,0,0,0,5,6,5 0,0,0,0,0,7,6,7,0,5 0,0,0,0,0,5,6,0,0,5 6,6,5,5,5,5,5,7,0,7 7,0,6,6,5,5,5,6,0,6 6,8,0,6,5,5,5,5,5,8 8,6,0,0,6,6,5,5,5,6 6,0,0,6,5,5,5,8,6,8 8,6,0,6,5,5,5,5,5,6 8,0,0,6,5,5,5,6,6,6 6,0,0,6,0,5,5,8,0,8 6,0,0,6,5,0,5,8,0,8 8,0,0,6,0,5,5,6,0,6 8,0,0,6,5,0,5,6,0,6 7,6,5,5,5,5,5,6,0,6 0,0,0,5,5,6,0,0,0,6 6,0,5,5,5,7,6,0,0,7 6,0,0,6,5,5,0,8,0,8 6,8,0,0,6,6,5,5,5,8 6,0,7,6,5,5,5,8,0,8 6,0,0,5,5,7,0,0,0,7 7,6,5,5,5,6,6,0,0,6 8,0,0,6,5,5,0,6,0,6 0,0,0,5,5,7,0,0,0,7 5,0,0,0,0,5,7,0,0,7 0,0,0,7,6,0,0,0,0,7 7,0,5,5,5,6,0,0,0,6 6,6,5,5,5,5,5,8,0,8 8,0,6,6,5,5,5,6,0,6 0,0,0,7,6,7,0,0,0,5 7,0,0,7,5,6,7,0,0,5 7,0,0,0,0,5,6,7,0,5 7,0,7,6,6,0,0,0,0,6 8,6,5,5,5,5,5,6,0,6 6,6,5,5,5,8,6,0,7,8 6,5,5,5,5,8,0,6,5,8 8,6,5,5,5,6,6,0,6,6 0,0,0,5,6,0,0,0,0,5 6,0,0,8,1,6,5,2,0,8 6,0,0,8,6,5,1,2,0,8 6,0,0,8,5,1,1,2,0,8 6,5,5,8,6,0,0,0,5,8 0,5,5,6,0,0,0,0,0,6 8,5,5,5,5,6,0,6,5,6 6,9,0,0,6,6,5,5,5,9 6,5,5,8,0,0,0,0,0,8 6,0,6,6,5,5,5,8,0,8 6,0,0,6,5,5,5,9,6,9 8,5,5,6,6,0,0,6,5,6 6,0,0,6,0,5,5,9,0,9 0,5,5,8,0,0,0,0,0,8 6,8,0,0,9,6,5,5,5,8 8,5,5,6,0,0,0,0,5,6 5,0,0,5,6,8,0,0,0,8 6,6,5,5,5,8,6,0,6,8 6,0,0,6,5,0,5,9,0,9 9,0,0,6,0,5,5,6,0,6 8,5,5,6,0,0,0,0,0,6 6,0,0,6,5,5,0,9,0,9 8,0,0,5,6,6,0,0,0,6 9,0,0,6,5,0,5,6,0,6 0,0,0,0,5,5,8,0,0,5 6,0,0,5,1,6,5,6,0,5 6,5,5,8,6,0,0,6,5,8 6,0,6,6,5,5,5,9,0,9 9,0,0,6,5,5,0,6,0,6 6,0,0,5,6,5,1,6,0,5 6,5,5,1,0,6,5,5,6,5 6,5,5,8,0,0,0,6,6,8 9,0,6,6,5,5,5,6,0,6 6,6,5,5,5,5,5,9,0,9 6,5,1,0,0,6,5,5,5,5 6,5,0,0,0,6,5,5,5,0 5,5,5,6,6,5,0,0,0,0 5,5,1,0,0,6,5,5,5,0 5,5,5,5,6,5,0,0,1,0 6,6,5,8,0,0,0,0,0,8 6,6,5,5,5,9,6,0,6,9 8,5,5,6,0,0,0,6,6,6 9,6,5,5,5,5,5,6,0,6 6,0,0,0,0,6,5,5,0,0 6,6,5,5,6,8,0,0,0,8 6,0,9,6,5,5,5,8,0,8 6,5,5,5,5,9,0,6,5,9 9,6,5,5,5,6,6,0,6,6 8,6,5,6,0,0,0,0,0,6 6,0,0,0,0,6,5,5,5,0 6,5,5,9,6,0,0,6,5,9 6,6,5,5,5,8,0,0,0,8 8,6,5,5,6,6,0,0,0,6 9,5,5,5,5,6,0,6,5,6 8,6,5,5,5,6,0,0,0,6 9,5,5,6,6,0,0,6,5,6 6,6,5,5,5,8,6,0,9,8 6,5,5,9,0,0,0,6,6,9 6,0,5,5,5,8,0,0,0,8 6,6,5,9,0,0,0,0,0,9 9,5,5,6,0,0,0,6,6,6 6,0,0,5,5,8,0,0,0,8 6,6,5,5,6,9,0,0,0,9 9,6,5,6,0,0,0,0,0,6 0,0,0,5,5,8,0,0,0,8 6,6,5,5,5,9,0,0,0,9 6,5,5,8,0,0,0,6,9,8 9,6,5,5,6,6,0,0,0,6 8,0,5,5,5,6,0,0,0,6 8,0,0,5,5,6,0,0,0,6 9,6,5,5,5,6,0,0,0,6 5,0,0,0,0,5,6,8,0,8 8,0,0,0,0,5,6,6,0,6 0,0,0,0,0,0,5,5,8,5 6,0,0,0,7,6,5,5,5,0 6,0,0,6,5,5,5,5,5,0 6,6,6,5,5,9,0,0,0,9 6,0,0,6,5,9,0,0,0,9 9,6,6,5,5,6,0,0,0,6 6,0,0,6,5,5,5,0,0,0 6,0,0,6,0,5,5,0,0,0 6,0,6,6,5,5,5,7,0,7 6,0,0,6,5,5,6,9,0,9 9,0,0,6,5,6,0,0,0,6 9,0,0,6,5,5,6,6,0,6 6,0,0,6,5,5,5,9,0,9 6,6,9,5,5,8,0,0,0,8 6,0,0,6,5,0,5,0,0,0 6,6,5,5,5,7,6,0,6,7 6,0,0,6,5,5,0,0,0,0 6,0,0,6,5,8,0,0,0,8 6,0,0,0,5,5,5,9,0,9 8,6,6,5,5,6,0,0,0,6 9,0,0,6,5,5,5,6,0,6 6,0,0,6,5,5,6,8,0,8 8,0,0,6,5,6,0,0,0,6 8,0,0,6,5,5,6,6,0,6 7,6,5,5,5,6,6,0,6,6 6,5,5,5,5,7,0,6,5,7 6,0,0,6,5,5,5,8,0,8 6,0,7,6,5,5,5,0,0,0 6,6,5,5,5,5,5,0,0,0 6,5,5,7,6,0,0,6,5,7 8,0,0,6,5,5,5,6,0,6 7,5,5,5,5,6,0,6,5,6 6,5,5,7,0,0,0,6,6,7 7,5,5,6,6,0,0,6,5,6 6,6,5,5,5,0,0,0,7,0 6,0,0,6,6,0,5,8,0,8 6,6,5,7,0,0,0,0,0,7 7,5,5,6,0,0,0,6,6,6 6,5,5,5,5,0,0,6,5,0 6,0,0,0,0,5,0,8,0,8 6,6,5,5,6,7,0,0,0,7 7,6,5,6,0,0,0,0,0,6 6,5,5,0,0,0,0,6,5,0 0,0,0,0,0,5,5,8,0,8 8,0,0,0,5,5,0,6,0,6 5,8,0,0,0,0,0,5,6,8 8,0,0,0,0,5,5,6,0,6 8,6,0,0,0,0,0,5,6,6 0,5,8,0,0,0,0,0,0,5 6,6,5,5,5,7,0,0,0,7 7,6,5,5,6,6,0,0,0,6 6,5,5,0,0,0,0,6,7,0 6,6,5,0,0,0,0,0,0,0 7,6,5,5,5,6,0,0,0,6 6,6,5,5,0,0,0,0,0,0 6,6,5,5,5,0,0,0,0,0 6,6,6,5,5,7,0,0,0,7 6,0,0,6,5,7,0,0,0,7 7,6,6,5,5,6,0,0,0,6 7,0,0,6,5,6,0,0,0,6 6,0,0,6,5,5,6,7,0,7 7,0,0,6,6,0,0,0,0,0 6,6,7,5,5,0,0,0,7,0 7,0,0,6,5,5,6,6,0,6 6,0,0,6,5,5,5,7,0,7 6,0,0,6,5,0,0,0,0,0 6,0,0,6,6,5,0,7,0,7 6,0,0,0,0,6,5,7,0,7 7,0,0,6,6,5,0,6,0,6 7,0,0,0,0,6,5,6,0,6 6,7,0,0,0,6,5,5,6,7 7,6,0,0,0,6,5,5,6,6 6,0,0,6,7,5,0,0,0,0 6,0,0,0,0,6,5,0,0,0 6,0,0,0,0,5,5,0,0,0 6,0,0,0,5,5,5,0,0,0 5,5,5,1,0,5,5,5,5,7 5,0,0,2,1,7,5,5,0,2 5,0,0,2,7,5,1,5,0,2 2,0,0,5,1,7,5,5,0,5 2,0,0,5,7,5,1,5,0,5 a,0,0,b,1,7,5,c,0,b a,0,0,b,7,5,1,c,0,b 7,0,0,2,1,7,5,5,0,2 7,0,0,2,7,5,1,5,0,2 2,0,0,7,1,7,5,7,0,7 2,0,0,7,7,5,1,7,0,7 7,0,0,5,1,7,5,2,0,5 7,0,0,5,7,5,1,2,0,5 6,0,0,2,1,7,5,9,0,2 6,0,0,2,7,5,1,9,0,2 2,0,0,6,1,7,5,6,0,6 2,0,0,6,7,5,1,6,0,6 9,0,0,2,1,7,5,6,0,2 9,0,0,2,7,5,1,6,0,2 2,0,0,6,1,7,5,9,0,6 2,0,0,6,7,5,1,9,0,6 6,0,0,8,1,7,5,2,0,8 6,0,0,8,7,5,1,2,0,8 6,0,0,7,5,1,1,6,0,7 7,0,0,6,5,1,1,6,0,6 6,0,0,9,5,1,1,6,0,9 9,0,0,6,5,1,1,6,0,6 6,0,0,2,5,1,1,9,0,2 2,0,0,6,5,1,1,6,0,6 6,0,0,8,5,1,1,6,0,8 8,0,0,6,5,1,1,6,0,6 9,0,0,2,5,1,1,6,0,2 2,0,0,6,5,1,1,9,0,6 6,0,0,5,5,1,1,6,0,5 5,0,0,2,5,1,1,5,0,2 2,0,0,5,5,1,1,5,0,5 7,0,0,2,5,1,1,5,0,2 2,0,0,7,5,1,1,7,0,7 @COLORS # colors from # http://lslwww.epfl.ch/pages/embryonics/thesis/AppendixA.html 1 255 255 255 2 255 0 0 3 0 255 255 4 0 255 0 5 255 0 255 6 0 0 255 7 255 255 0 8 85 85 85 9 170 170 170 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/AbsoluteTurmite_0N21S10E00S01W11N2.rule�����������������������������������������0000644�0001750�0001750�00000026337�12536111364�017554� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE AbsoluteTurmite_0N21S10E00S01W11N2 @TREE num_states=8 num_neighbors=4 num_nodes=16 1 0 1 0 0 1 1 0 1 1 4 7 4 4 7 7 4 7 2 0 0 1 0 0 0 0 1 1 3 6 3 3 6 6 3 6 2 3 3 0 3 3 3 3 0 3 2 2 2 2 4 2 2 2 1 2 5 2 2 5 5 2 5 2 6 6 0 6 6 6 6 0 2 0 0 0 0 0 0 0 0 3 7 7 7 7 8 7 7 7 4 5 5 5 9 5 5 5 5 3 4 4 4 4 8 4 4 4 3 8 8 8 8 8 8 8 8 4 11 11 11 12 11 11 11 11 4 9 9 9 12 9 9 9 9 5 10 10 10 10 10 13 14 10 @COLORS 0 0 0 0 1 0 155 67 2 123 4 243 3 124 124 124 4 178 177 94 5 71 72 170 6 71 141 101 7 102 171 84 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 217 12 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #3F4DA1" "G c #408D61" "H c #5CA951" "I c #7F00FF" "J c #808080" "K c #B9B860" "L c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ "..............................." "..............................." ".............CCCCC............." "..........CIIIIIIIIIC.........." "........CIIIIIIIIIIIIIC........" ".......CIIIIIIIIIIIIIIIC......." "......CIIIIIIIIIIIIIIIIIC......" ".....CIIIIIIIIIIIIIIIIIIIC....." "....CIIIIILLIIIIIIIIIIIIIIC...." "....IIIIILLIIIIIIIIIIIIIIII...." "...CIIIILLIIIIIIIIIIIIIIIIIC..." "...IIIIILLIIIIIIIIIIIIIIIIII..." "...IIIIILIIIIIIIIIIIIIIIIIII..." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "...IIIIIIIIIIIIIIIIIIIIIIIII..." "...IIIIIIIIIIIIIIIIIIIIIIIII..." "...CIIIIIIIIIIIIIIIIIIIIIIIC..." "....IIIIIIIIIIIIIIIIIIIIIII...." "....CIIIIIIIIIIIIIIIIIIIIIC...." ".....CIIIIIIIIIIIIIIIIIIIC....." "......CIIIIIIIIIIIIIIIIIC......" ".......CIIIIIIIIIIIIIIIC......." "........CIIIIIIIIIIIIIC........" "..........CIIIIIIIIIC.........." ".............CCCCC............." "..............................." "..............................." /* icon for state 3 */ "..............................." "..............................." ".............DDDDD............." "..........DJJJJJJJJJD.........." "........DJJJJJJJJJJJJJD........" ".......DJJJJJJJJJJJJJJJD......." "......DJJJJJJJJJJJJJJJJJD......" ".....DJJJJJJJJJJJJJJJJJJJD....." "....DJJJJJLLJJJJJJJJJJJJJJD...." "....JJJJJLLJJJJJJJJJJJJJJJJ...." "...DJJJJLLJJJJJJJJJJJJJJJJJD..." "...JJJJJLLJJJJJJJJJJJJJJJJJJ..." "...JJJJJLJJJJJJJJJJJJJJJJJJJ..." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "...JJJJJJJJJJJJJJJJJJJJJJJJJ..." "...JJJJJJJJJJJJJJJJJJJJJJJJJ..." "...DJJJJJJJJJJJJJJJJJJJJJJJD..." "....JJJJJJJJJJJJJJJJJJJJJJJ...." "....DJJJJJJJJJJJJJJJJJJJJJD...." ".....DJJJJJJJJJJJJJJJJJJJD....." "......DJJJJJJJJJJJJJJJJJD......" ".......DJJJJJJJJJJJJJJJD......." "........DJJJJJJJJJJJJJD........" "..........DJJJJJJJJJD.........." ".............DDDDD............." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." ".............EEEEE............." "..........EKKKKKKKKKE.........." "........EKKKKKKKKKKKKKE........" ".......EKKKKKKKKKKKKKKKE......." "......EKKKKKKKKKKKKKKKKKE......" ".....EKKKKKKKKKKKKKKKKKKKE....." "....EKKKKKLLKKKKKKKKKKKKKKE...." "....KKKKKLLKKKKKKKKKKKKKKKK...." "...EKKKKLLKKKKKKKKKKKKKKKKKE..." "...KKKKKLLKKKKKKKKKKKKKKKKKK..." "...KKKKKLKKKKKKKKKKKKKKKKKKK..." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "...KKKKKKKKKKKKKKKKKKKKKKKKK..." "...KKKKKKKKKKKKKKKKKKKKKKKKK..." "...EKKKKKKKKKKKKKKKKKKKKKKKE..." "....KKKKKKKKKKKKKKKKKKKKKKK...." "....EKKKKKKKKKKKKKKKKKKKKKE...." ".....EKKKKKKKKKKKKKKKKKKKE....." "......EKKKKKKKKKKKKKKKKKE......" ".......EKKKKKKKKKKKKKKKE......." "........EKKKKKKKKKKKKKE........" "..........EKKKKKKKKKE.........." ".............EEEEE............." "..............................." "..............................." /* icon for state 5 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAFIIIIIIIIIFAAAAAAAAAA" "AAAAAAAAFIIIIIIIIIIIIIFAAAAAAAA" "AAAAAAAFIIIIIIIIIIIIIIIFAAAAAAA" "AAAAAAFIIIIIIIIIIIIIIIIIFAAAAAA" "AAAAAFIIIIIIIIIIIIIIIIIIIFAAAAA" "AAAAFIIIIILLIIIIIIIIIIIIIIFAAAA" "AAAAIIIIILLIIIIIIIIIIIIIIIIAAAA" "AAAFIIIILLIIIIIIIIIIIIIIIIIFAAA" "AAAIIIIILLIIIIIIIIIIIIIIIIIIAAA" "AAAIIIIILIIIIIIIIIIIIIIIIIIIAAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAAIIIIIIIIIIIIIIIIIIIIIIIIIAAA" "AAAIIIIIIIIIIIIIIIIIIIIIIIIIAAA" "AAAFIIIIIIIIIIIIIIIIIIIIIIIFAAA" "AAAAIIIIIIIIIIIIIIIIIIIIIIIAAAA" "AAAAFIIIIIIIIIIIIIIIIIIIIIFAAAA" "AAAAAFIIIIIIIIIIIIIIIIIIIFAAAAA" "AAAAAAFIIIIIIIIIIIIIIIIIFAAAAAA" "AAAAAAAFIIIIIIIIIIIIIIIFAAAAAAA" "AAAAAAAAFIIIIIIIIIIIIIFAAAAAAAA" "AAAAAAAAAAFIIIIIIIIIFAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 6 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAGGGGGAAAAAAAAAAAAA" "AAAAAAAAAAGJJJJJJJJJGAAAAAAAAAA" "AAAAAAAAGJJJJJJJJJJJJJGAAAAAAAA" "AAAAAAAGJJJJJJJJJJJJJJJGAAAAAAA" "AAAAAAGJJJJJJJJJJJJJJJJJGAAAAAA" "AAAAAGJJJJJJJJJJJJJJJJJJJGAAAAA" "AAAAGJJJJJLLJJJJJJJJJJJJJJGAAAA" "AAAAJJJJJLLJJJJJJJJJJJJJJJJAAAA" "AAAGJJJJLLJJJJJJJJJJJJJJJJJGAAA" "AAAJJJJJLLJJJJJJJJJJJJJJJJJJAAA" "AAAJJJJJLJJJJJJJJJJJJJJJJJJJAAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAAJJJJJJJJJJJJJJJJJJJJJJJJJAAA" "AAAJJJJJJJJJJJJJJJJJJJJJJJJJAAA" "AAAGJJJJJJJJJJJJJJJJJJJJJJJGAAA" "AAAAJJJJJJJJJJJJJJJJJJJJJJJAAAA" "AAAAGJJJJJJJJJJJJJJJJJJJJJGAAAA" "AAAAAGJJJJJJJJJJJJJJJJJJJGAAAAA" "AAAAAAGJJJJJJJJJJJJJJJJJGAAAAAA" "AAAAAAAGJJJJJJJJJJJJJJJGAAAAAAA" "AAAAAAAAGJJJJJJJJJJJJJGAAAAAAAA" "AAAAAAAAAAGJJJJJJJJJGAAAAAAAAAA" "AAAAAAAAAAAAAGGGGGAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 7 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAHHHHHAAAAAAAAAAAAA" "AAAAAAAAAAHKKKKKKKKKHAAAAAAAAAA" "AAAAAAAAHKKKKKKKKKKKKKHAAAAAAAA" "AAAAAAAHKKKKKKKKKKKKKKKHAAAAAAA" "AAAAAAHKKKKKKKKKKKKKKKKKHAAAAAA" "AAAAAHKKKKKKKKKKKKKKKKKKKHAAAAA" "AAAAHKKKKKLLKKKKKKKKKKKKKKHAAAA" "AAAAKKKKKLLKKKKKKKKKKKKKKKKAAAA" "AAAHKKKKLLKKKKKKKKKKKKKKKKKHAAA" "AAAKKKKKLLKKKKKKKKKKKKKKKKKKAAA" "AAAKKKKKLKKKKKKKKKKKKKKKKKKKAAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAAKKKKKKKKKKKKKKKKKKKKKKKKKAAA" "AAAKKKKKKKKKKKKKKKKKKKKKKKKKAAA" "AAAHKKKKKKKKKKKKKKKKKKKKKKKHAAA" "AAAAKKKKKKKKKKKKKKKKKKKKKKKAAAA" "AAAAHKKKKKKKKKKKKKKKKKKKKKHAAAA" "AAAAAHKKKKKKKKKKKKKKKKKKKHAAAAA" "AAAAAAHKKKKKKKKKKKKKKKKKHAAAAAA" "AAAAAAAHKKKKKKKKKKKKKKKHAAAAAAA" "AAAAAAAAHKKKKKKKKKKKKKHAAAAAAAA" "AAAAAAAAAAHKKKKKKKKKHAAAAAAAAAA" "AAAAAAAAAAAAAHHHHHAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "15 105 12 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #3F4DA1" "G c #408D61" "H c #5CA951" "I c #7F00FF" "J c #808080" "K c #B9B860" "L c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "..............." "......CCC......" "....CIIIIIC...." "...CIIIIIIIC..." "..CIILIIIIIIC.." "..IILIIIIIIII.." ".CIILIIIIIIIIC." ".CIIIIIIIIIIIC." ".CIIIIIIIIIIIC." "..IIIIIIIIIII.." "..CIIIIIIIIIC.." "...CIIIIIIIC..." "....CIIIIIC...." "......CCC......" "..............." /* icon for state 3 */ "..............." "......DDD......" "....DJJJJJD...." "...DJJJJJJJD..." "..DJJLJJJJJJD.." "..JJLJJJJJJJJ.." ".DJJLJJJJJJJJD." ".DJJJJJJJJJJJD." ".DJJJJJJJJJJJD." "..JJJJJJJJJJJ.." "..DJJJJJJJJJD.." "...DJJJJJJJD..." "....DJJJJJD...." "......DDD......" "..............." /* icon for state 4 */ "..............." "......EEE......" "....EKKKKKE...." "...EKKKKKKKE..." "..EKKLKKKKKKE.." "..KKLKKKKKKKK.." ".EKKLKKKKKKKKE." ".EKKKKKKKKKKKE." ".EKKKKKKKKKKKE." "..KKKKKKKKKKK.." "..EKKKKKKKKKE.." "...EKKKKKKKE..." "....EKKKKKE...." "......EEE......" "..............." /* icon for state 5 */ "AAAAAAAAAAAAAAA" "AAAAAAFFFAAAAAA" "AAAAFIIIIIFAAAA" "AAAFIIIIIIIFAAA" "AAFIILIIIIIIFAA" "AAIILIIIIIIIIAA" "AFIILIIIIIIIIFA" "AFIIIIIIIIIIIFA" "AFIIIIIIIIIIIFA" "AAIIIIIIIIIIIAA" "AAFIIIIIIIIIFAA" "AAAFIIIIIIIFAAA" "AAAAFIIIIIFAAAA" "AAAAAAFFFAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 6 */ "AAAAAAAAAAAAAAA" "AAAAAAGGGAAAAAA" "AAAAGJJJJJGAAAA" "AAAGJJJJJJJGAAA" "AAGJJLJJJJJJGAA" "AAJJLJJJJJJJJAA" "AGJJLJJJJJJJJGA" "AGJJJJJJJJJJJGA" "AGJJJJJJJJJJJGA" "AAJJJJJJJJJJJAA" "AAGJJJJJJJJJGAA" "AAAGJJJJJJJGAAA" "AAAAGJJJJJGAAAA" "AAAAAAGGGAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 7 */ "AAAAAAAAAAAAAAA" "AAAAAAHHHAAAAAA" "AAAAHKKKKKHAAAA" "AAAHKKKKKKKHAAA" "AAHKKLKKKKKKHAA" "AAKKLKKKKKKKKAA" "AHKKLKKKKKKKKHA" "AHKKKKKKKKKKKHA" "AHKKKKKKKKKKKHA" "AAKKKKKKKKKKKAA" "AAHKKKKKKKKKHAA" "AAAHKKKKKKKHAAA" "AAAAHKKKKKHAAAA" "AAAAAAHHHAAAAAA" "AAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "7 49 12 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #3F4DA1" "G c #408D61" "H c #5CA951" "I c #7F00FF" "J c #808080" "K c #B9B860" "L c #FFFFFF" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ "..CCC.." ".CIIIC." "CILIIIC" "CIIIIIC" "CIIIIIC" ".CIIIC." "..CCC.." /* icon for state 3 */ "..DDD.." ".DJJJD." "DJLJJJD" "DJJJJJD" "DJJJJJD" ".DJJJD." "..DDD.." /* icon for state 4 */ "..EEE.." ".EKKKE." "EKLKKKE" "EKKKKKE" "EKKKKKE" ".EKKKE." "..EEE.." /* icon for state 5 */ "AAFFFAA" "AFIIIFA" "FILIIIF" "FIIIIIF" "FIIIIIF" "AFIIIFA" "AAFFFAA" /* icon for state 6 */ "AAGGGAA" "AGJJJGA" "GJLJJJG" "GJJJJJG" "GJJJJJG" "AGJJJGA" "AAGGGAA" /* icon for state 7 */ "AAHHHAA" "AHKKKHA" "HKLKKKH" "HKKKKKH" "HKKKKKH" "AHKKKHA" "AAHHHAA" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Worm-shared.rule����������������������������������������������������������������0000644�0001750�0001750�00000056602�12536111364�014404� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Worm-shared This file contains the icons shared by all Worm-* rules. @TABLE n_states:17 neighborhood:Moore symmetries:none # do nothing @ICONS XPM /* width height num_colors chars_per_pixel */ "31 496 3 1" /* colors */ ". c #000000" "B c #FFFFFF" "C c #C0C0C0" /* icon for state 1 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".....B........................." ".....BB........................" ".....BBB......................." ".....BBBB......................" "BBBBBBBBBB....................." "BBBBBBBBBBB...................." "BBBBBBBBBB....................." ".....BBBB......................" ".....BBB......................." ".....BB........................" ".....B........................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 2 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".B............................." "BBB............................" ".BBB..........................." "..BBB.....B...................." "...BBB...BB...................." "....BBB.BBB...................." ".....BBBBBB...................." "......BBBBB...................." ".....BBBBBB...................." "....BBBBBBB...................." "...BBBBBBBB...................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 3 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".........B....................." "........BBB...................." ".......BBB....................." "B.....BBB......................" "BB...BBB......................." "BBB.BBB........................" "BBBBBB........................." "BBBBB.........................." "BBBBBB........................." "BBBBBBB........................" "BBBBBBBB......................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".....B........................." "....BB........................." "...BBB........................." "..BBBB........................." ".BBBBBBBBBB...................." "BBBBBBBBBBB...................." ".BBBBBBBBBB...................." "..BBBB........................." "...BBB........................." "....BB........................." ".....B........................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 5 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "BBBBBBBB......................." "BBBBBBB........................" "BBBBBB........................." "BBBBB.........................." "BBBBBB........................." "BBB.BBB........................" "BB...BBB......................." "B.....BBB......................" ".......BBB....................." "........BBB...................." ".........B....................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 6 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "...BBBBBBBB...................." "....BBBBBBB...................." ".....BBBBBB...................." "......BBBBB...................." ".....BBBBBB...................." "....BBB.BBB...................." "...BBB...BB...................." "..BBB.....B...................." ".BBB..........................." "BBB............................" ".B............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 7 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..BB......BB..................." "..BBB....BBB..................." "...BBB..BBB...................." "....BBBBBB....................." ".....BBBB......................" "......BB......................." "BBBBBBBBBBBBBB................." "BBBBBBBBBBBBBB................." "BBBBBBBBBBBBBB................." "......BB......................." ".....BBBB......................" "....BBBBBB....................." "...BBB..BBB...................." "..BBB....BBB..................." "..BB......BB..................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 8 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBB.." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBB.." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBB.." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 9 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".....................B........." ".....................BB........" ".....................BBB......." ".....................BBBB......" ".....................BBBBB....." ".....................BBBBBB...." "BBBBBBBBBBBBBBBBBBBBBBBBBBBB..." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBB.." "BBBBBBBBBBBBBBBBBBBBBBBBBBBB..." ".....................BBBBBB...." ".....................BBBBB....." ".....................BBBB......" ".....................BBB......." ".....................BB........" ".....................B........." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 10 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".......B......................." "......BB......................." ".....BBB......................." "....BBBB......................." "...BBBBB......................." "..BBBBBB......................." ".BBBBBBBBBBBBBBBBBBBBBBBBBBBB.." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBB.." ".BBBBBBBBBBBBBBBBBBBBBBBBBBBB.." "..BBBBBB......................." "...BBBBB......................." "....BBBB......................." ".....BBB......................." "......BB......................." ".......B......................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 11 */ ".............................BB" "............................CBB" "............................BBC" "...........................CBB." "...........................BBC." "..........................CBB.." "..........................BBC.." ".........................CBB..." ".........................BBC..." "........................CBB...." "........................BBC...." ".......................CBB....." ".......................BBC....." "......................CBB......" "......................BBC......" ".....................CBB......." ".....................BBC......." "....................CBB........" "....................BBC........" "...................CBB........." "...................BBC........." "..................CBB.........." "..................BBC.........." ".................CBB..........." ".................BBC..........." "................CBB............" "................BBC............" "...............CBB............." "...............BBC............." "..............CBB.............." "..............BBC.............." /* icon for state 12 */ ".....................BBBBBBBBBB" "......................BBBBBBBBB" ".......................BBBBBBBB" "........................BBBBBBB" ".........................BBBBBB" "..........................BBBBB" "..........................BBBBB" ".........................CBBBBB" ".........................BBC.BB" "........................CBB...B" "........................BBC...." ".......................CBB....." ".......................BBC....." "......................CBB......" "......................BBC......" ".....................CBB......." ".....................BBC......." "....................CBB........" "....................BBC........" "...................CBB........." "...................BBC........." "..................CBB.........." "..................BBC.........." ".................CBB..........." ".................BBC..........." "................CBB............" "................BBC............" "...............CBB............." "...............BBC............." "..............CBB.............." "..............BBC.............." /* icon for state 13 */ ".............................BB" "............................CBB" "............................BBC" "...........................CBB." "...........................BBC." "..........................CBB.." "..........................BBC.." ".........................CBB..." ".........................BBC..." "........................CBB...." "........................BBC...." ".......................CBB....." ".......................BBC....." "......................CBB......" "......................BBC......" ".....................CBB......." ".....................BBC......." "....................CBB........" "....................BBC........" "...................CBB........." "...................BBC........." "..................CBB.........." "..................BBC.........." "........BBBBBBBBBBBBBBB........" ".........BBBBBBBBBBBBB........." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." /* icon for state 14 */ "..............BB..............." "..............BBC.............." "..............CBB.............." "...............BBC............." "...............CBB............." "................BBC............" "................CBB............" ".................BBC..........." ".................CBB..........." "..................BBC.........." "..................CBB.........." "...................BBC........." "...................CBB........." "....................BBC........" "....................CBB........" ".....................BBC......." ".....................CBB......." "......................BBC......" "......................CBB......" ".......................BBC....." ".......................CBB....." "........................BBC...." "........................CBB...." ".........................BBC..." ".........................CBB..." "..........................BBC.." "..........................CBB.." "...........................BBC." "...........................CBB." "............................BBC" "............................CBB" /* icon for state 15 */ "..............BB..............." "..............BBC.............." "..............CBB.............." "...............BBC............." "...............CBB............." "................BBC............" "................CBB............" ".................BBC..........." ".................CBB..........." "..................BBC.........." "..................CBB.........." "...................BBC........." "...................CBB........." "....................BBC........" "....................CBB........" ".....................BBC......." ".....................CBB......." "......................BBC......" "......................CBB......" ".......................BBC....." ".......................CBB....." "........................BBC...B" "........................CBB..BB" ".........................BBCBBB" ".........................CBBBBB" "..........................BBBBB" ".........................BBBBBB" "........................BBBBBBB" ".......................BBBBBBBB" "......................BBBBBBBBB" ".....................BBBBBBBBBB" /* icon for state 16 */ "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." ".........BBBBBBBBBBBBB........." "........BBBBBBBBBBBBBBB........" "..................BBC.........." "..................CBB.........." "...................BBC........." "...................CBB........." "....................BBC........" "....................CBB........" ".....................BBC......." ".....................CBB......." "......................BBC......" "......................CBB......" ".......................BBC....." ".......................CBB....." "........................BBC...." "........................CBB...." ".........................BBC..." ".........................CBB..." "..........................BBC.." "..........................CBB.." "...........................BBC." "...........................CBB." "............................BBC" "............................CBB" ".............................BB" XPM /* width height num_colors chars_per_pixel */ "15 240 3 1" /* colors */ ". c #000000" "B c #FFFFFF" "C c #C0C0C0" /* icon for state 1 */ "..............." "..............." "..............." "..............." "..............." "..B............" "...B..........." "BBBBB.........." "...B..........." "..B............" "..............." "..............." "..............." "..............." "..............." /* icon for state 2 */ "..............." "..............." "..............." "..............." "..............." "B.............." ".B............." "..B.B.........." "...BB.........." "..BBB.........." "..............." "..............." "..............." "..............." "..............." /* icon for state 3 */ "..............." "..............." "..............." "..............." "..............." "....B.........." "...B..........." "B.B............" "BB............." "BBB............" "..............." "..............." "..............." "..............." "..............." /* icon for state 4 */ "..............." "..............." "..............." "..............." "..............." "..B............" ".B............." "BBBBB.........." ".B............." "..B............" "..............." "..............." "..............." "..............." "..............." /* icon for state 5 */ "..............." "..............." "..............." "..............." "..............." "BBB............" "BB............." "B.B............" "...B..........." "....B.........." "..............." "..............." "..............." "..............." "..............." /* icon for state 6 */ "..............." "..............." "..............." "..............." "..............." "..BBB.........." "...BB.........." "..B.B.........." ".B............." "B.............." "..............." "..............." "..............." "..............." "..............." /* icon for state 7 */ "..............." "..............." "..............." "..............." ".B...B........." "..B.B.........." "...B..........." "BBBBBBB........" "...B..........." "..B.B.........." ".B...B........." "..............." "..............." "..............." "..............." /* icon for state 8 */ "..............." "..............." "..............." "..............." "..............." "..............." "..............." "BBBBBBBBBBBBBB." "..............." "..............." "..............." "..............." "..............." "..............." "..............." /* icon for state 9 */ "..............." "..............." "..............." "..............." "..........B...." "..........BB..." "..........BBB.." "BBBBBBBBBBBBBB." "..........BBB.." "..........BB..." "..........B...." "..............." "..............." "..............." "..............." /* icon for state 10 */ "..............." "..............." "..............." "..............." "...B..........." "..BB..........." ".BBB..........." "BBBBBBBBBBBBBB." ".BBB..........." "..BB..........." "...B..........." "..............." "..............." "..............." "..............." /* icon for state 11 */ "..............B" ".............B." ".............B." "............B.." "............B.." "...........B..." "...........B..." "..........B...." "..........B...." ".........B....." ".........B....." "........B......" "........B......" ".......B......." ".......B......." /* icon for state 12 */ "..........BBBBB" "...........BBBB" "............BBB" "............BBB" "...........B..B" "...........B..." "...........B..." "..........B...." "..........B...." ".........B....." ".........B....." "........B......" "........B......" ".......B......." ".......B......." /* icon for state 13 */ "..............B" ".............B." ".............B." "............B.." "...........B..." "...........B..." "..........B...." "..........B...." ".........B....." ".........B....." "........B......" "....BBBBBBB...." ".....BBBBB....." "......BBB......" ".......B......." /* icon for state 14 */ ".......B......." ".......B......." "........B......" "........B......" ".........B....." ".........B....." "..........B...." "..........B...." "...........B..." "...........B..." "............B.." "............B.." ".............B." ".............B." "..............B" /* icon for state 15 */ ".......B......." ".......B......." "........B......" "........B......" ".........B....." ".........B....." "..........B...." "..........B...." "...........B..." "...........B..." "............B.B" "............BBB" "............BBB" "...........BBBB" "..........BBBBB" /* icon for state 16 */ ".......B......." "......BBB......" ".....BBBBB....." "....BBBBBBB...." "........B......" ".........B....." ".........B....." "..........B...." "..........B...." "...........B..." "...........B..." "............B.." ".............B." ".............B." "..............B" XPM /* width height num_colors chars_per_pixel */ "7 112 3 1" /* colors */ ". c #000000" "B c #FFFFFF" "C c #C0C0C0" /* icon for state 1 */ "......." "...B..." "....B.." ".BBBBB." "....B.." "...B..." "......." /* icon for state 2 */ "......." ".B....." "..B...." "...B.B." "....BB." "...BBB." "......." /* icon for state 3 */ "......." ".....B." "....B.." ".B.B..." ".BB...." ".BBB..." "......." /* icon for state 4 */ "......." "...B..." "..B...." ".BBBBB." "..B...." "...B..." "......." /* icon for state 5 */ "......." ".BBB..." ".BB...." ".B.B..." "....B.." ".....B." "......." /* icon for state 6 */ "......." "...BBB." "....BB." "...B.B." "..B...." ".B....." "......." /* icon for state 7 */ "......." "B.B...." ".B....." "BBB...." ".B....." "B.B...." "......." /* icon for state 8 */ "......." "......." "......." "BBBBBB." "......." "......." "......." /* icon for state 9 */ "......." "...B..." "....B.." "BBBBBB." "....B.." "...B..." "......." /* icon for state 10 */ "......." "..B...." ".B....." "BBBBBB." ".B....." "..B...." "......." /* icon for state 11 */ "......B" ".....B." ".....B." "....B.." "....B.." "...B..." "...B..." /* icon for state 12 */ "...BBBB" ".....BB" "....B.B" "....B.B" "....B.." "...B..." "...B..." /* icon for state 13 */ "......B" ".....B." "....B.." "...B..." ".B.B.B." "..BBB.." "...B..." /* icon for state 14 */ "...B..." "...B..." "....B.." "....B.." ".....B." ".....B." "......B" /* icon for state 15 */ "...B..." "...B..." "....B.." "....B.B" "....B.B" ".....BB" "...BBBB" /* icon for state 16 */ "...B..." "..BBB.." ".B.B.B." "...B..." "....B.." ".....B." "......B" ������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Worm-1042020.rule���������������������������������������������������������������0000644�0001750�0001750�00000011220�12536111364�013731� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Worm-1042020 Paterson's worms (by Dean Hickerson, 11/25/2008) Pattern #062a Sven Kahrkling's notation 1042020 Gardner's notation 1a2c3aaca4a Finishes after 57,493,855,205,939 steps. Points and lines of hexagonal grid are mapped to points of square grid as below. "*" is a point of the hex grid, "-", "/", and "\" are lines of the hex grid. +--+--+--+--+ |- |* |- |* | +--+--+--+--+ | /| \| /| \| +--+--+--+--+ |* |- |* |- | +--+--+--+--+ Each step of the worm is simulated by 2 gens in the rule. In even gens, there's an arrow at one point of the hex grid showing which way the worm will move next. In odd gens, there's an arrow on one line of the hex grid. The transitions from even to odd gens are the same for all worms. Those from odd to even depend on the specific type of worm: If a point (state 0 or 1) has a line with an arrow pointing at it, it becomes a 'point with arrow'; the direction depends on the 6 neighboring lines, which are the NW, N, E, S, SW, and W neighbors in the square grid. Gen 0 consists of a single point in state 1, a 'point with arrow' pointing east. (Starting with a point in state 2, 3, 4, 5, or 6 would also work, rotating the whole pattern.) States are: 0 empty (unvisited point or line) 1-6 'point with arrow', showing direction of next movement (1=E; 2=SE; 3=SW; 4=W; 5=NW; 6=NE) 7 point that's been visited 8,9,10 edge - (8=line; 9=E arrow; 10=W arrow) 11,12,13 edge / (11=line; 12=NE arrow; 13=SW arrow) 14,15,16 edge \ (14=line; 15=SE arrow; 16=NW arrow) @TABLE n_states:17 neighborhood:Moore symmetries:none var point={1,2,3,4,5,6} var a0={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a1={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a2={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a3={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a4={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a5={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a6={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a7={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var n={8,11,14} var o={8,11,14} var p={8,11,14} var q={8,11,14} var b={0,7} # point with arrow becomes point that's been visited point,a0,a1,a2,a3,a4,a5,a6,a7,7 # line with arrow becomes line without arrow 9,a0,a1,a2,a3,a4,a5,a6,a7,8 10,a0,a1,a2,a3,a4,a5,a6,a7,8 12,a0,a1,a2,a3,a4,a5,a6,a7,11 13,a0,a1,a2,a3,a4,a5,a6,a7,11 15,a0,a1,a2,a3,a4,a5,a6,a7,14 16,a0,a1,a2,a3,a4,a5,a6,a7,14 # point with arrow creates line with arrow next to it 0,a0,a1,a2,a3,a4,a5,1,a6,9 0,2,a0,a1,a2,a3,a4,a5,a6,15 0,a0,3,a1,a2,a3,a4,a5,a6,13 0,a0,a1,4,a2,a3,a4,a5,a6,10 0,a0,a1,a2,5,a3,a4,a5,a6,16 0,a0,a1,a2,a3,6,a4,a5,a6,12 # 4 eaten: use only remaining direction # 0 (straight): b,0,a0,n,a1,o,12,p,q,6 b,n,a0,0,a1,o,p,9,q,1 b,n,a0,o,a1,0,p,q,15,2 b,13,a0,n,a1,o,0,p,q,3 b,n,a0,10,a1,o,p,0,q,4 b,n,a0,o,a1,16,p,q,0,5 # 1 (gentle right): b,n,a0,0,a1,o,12,p,q,1 b,n,a0,o,a1,0,p,9,q,2 b,n,a0,o,a1,p,0,q,15,3 b,13,a0,n,a1,o,p,0,q,4 b,n,a0,10,a1,o,p,q,0,5 b,0,a0,n,a1,16,o,p,q,6 # 2 (sharp right): b,n,a0,o,a1,0,12,p,q,2 b,n,a0,o,a1,p,0,9,q,3 b,n,a0,o,a1,p,q,0,15,4 b,13,a0,n,a1,o,p,q,0,5 b,0,a0,10,a1,n,o,p,q,6 b,n,a0,0,a1,16,o,p,q,1 # 4 (sharp left): b,n,a0,o,a1,p,12,0,q,4 b,n,a0,o,a1,p,q,9,0,5 b,0,a0,n,a1,o,p,q,15,6 b,13,a0,0,a1,n,o,p,q,1 b,n,a0,10,a1,0,o,p,q,2 b,n,a0,o,a1,16,0,p,q,3 # 5 (gentle left): b,n,a0,o,a1,p,12,q,0,5 b,0,a0,n,a1,o,p,9,q,6 b,n,a0,0,a1,o,p,q,15,1 b,13,a0,n,a1,0,o,p,q,2 b,n,a0,10,a1,o,0,p,q,3 b,n,a0,o,a1,16,p,0,q,4 # rule-specific transitions at point with arrow coming in # rule 1042020 # none eaten: 1 = gentle right b,0,a0,0,a1,0,12,0,0,1 b,0,a0,0,a1,0,0,9,0,2 b,0,a0,0,a1,0,0,0,15,3 b,13,a0,0,a1,0,0,0,0,4 b,0,a0,10,a1,0,0,0,0,5 b,0,a0,0,a1,16,0,0,0,6 # 1 eaten(1): 0 = straight b,0,a0,n,a1,0,12,0,0,6 b,0,a0,0,a1,n,0,9,0,1 b,0,a0,0,a1,0,n,0,15,2 b,13,a0,0,a1,0,0,n,0,3 b,0,a0,10,a1,0,0,0,n,4 b,n,a0,0,a1,16,0,0,0,5 # 2 eaten(02): 4 = sharp left b,n,a0,0,a1,o,12,0,0,4 b,0,a0,n,a1,0,o,9,0,5 b,0,a0,0,a1,n,0,o,15,6 b,13,a0,0,a1,0,n,0,o,1 b,o,a0,10,a1,0,0,n,0,2 b,0,a0,o,a1,16,0,0,n,3 # 2 eaten(15): 2 = sharp right b,0,a0,o,a1,0,12,0,n,2 b,n,a0,0,a1,o,0,9,0,3 b,0,a0,n,a1,0,o,0,15,4 b,13,a0,0,a1,n,0,o,0,5 b,0,a0,10,a1,0,n,0,o,6 b,o,a0,0,a1,16,0,n,0,1 # 2 eaten(24): 0 = straight b,0,a0,0,a1,n,12,o,0,6 b,0,a0,0,a1,0,n,9,o,1 b,o,a0,0,a1,0,0,n,15,2 b,13,a0,o,a1,0,0,0,n,3 b,n,a0,10,a1,o,0,0,0,4 b,0,a0,n,a1,16,o,0,0,5 # 2 eaten(04): 2 = sharp right b,n,a0,0,a1,0,12,o,0,2 b,0,a0,n,a1,0,0,9,o,3 b,o,a0,0,a1,n,0,0,15,4 b,13,a0,o,a1,0,n,0,0,5 b,0,a0,10,a1,o,0,n,0,6 b,0,a0,0,a1,16,o,0,n,1 # 3 eaten(145): 0 = straight b,0,a0,n,a1,0,12,o,p,6 b,p,a0,0,a1,n,0,9,o,1 b,o,a0,p,a1,0,n,0,15,2 b,13,a0,o,a1,p,0,n,0,3 b,0,a0,10,a1,o,p,0,n,4 b,n,a0,0,a1,16,o,p,0,5 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Codd.rule�����������������������������������������������������������������������0000644�0001750�0001750�00000020161�12536111364�013054� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Codd Codd's cellular automaton. Codd, E.F., _Cellular_Automata_, Academic Press 1968 (ACM Monograph #3). Originally distributed with XLife as codd.r. Several corrections have been made. Stasis transitions have been taken out. Tim Hutton <tim.hutton@gmail.com> @TABLE n_states:8 neighborhood:vonNeumann symmetries:rotate4 var a={4,5} var b={2,3} var c={2,3} var d={4,5,6,7} var e={4,5,6} var f={0,1} var g={1,2} var h={0,1,2} var i={1,2,6} var j={1,6} var k={4,5} var l={4,6,7} var m={1,2,3} var n={6,7} var o={1,2,7} var p={0,2,3} # Almost all configurations with neighborhoods in [0-3] are stable # These are the exceptions (Codd's `short table', page 66) 0,1,2,1,2,1 # Path self-repair 3,0,0,0,2,2 # Path self-repair 3,0,1,0,2,2 # Gate control 3,0,1,0,3,0 # Gate control 2,1,2,3,2,3 # Gate control 3,1,2,3,2,2 # Gate control 0,0,2,1,3,1 # Path end self-repair 0,1,2,3,2,6 # Echo generation 0,1,2,2,2,7 # Echo generation # The long table 0,0,2,7,2,1 # j 0,0,3,6,3,1 # i 0,1,1,2,d,1 # fi = fan-in 0,1,1,e,2,1 # fi 0,1,2,1,d,1 # fi 0,1,2,2,d,1 # p = signal propagation 0,1,2,3,5,1 # p 0,1,2,4,2,1 # p 0,1,2,4,4,1 # fo = fan-out 0,1,2,5,b,1 # p (was fi) 0,1,2,5,5,1 # fo 0,1,2,6,2,1 # p 0,1,2,6,6,1 # fo 0,1,2,7,b,1 # p 0,1,2,7,7,1 # fo 0,1,3,2,4,1 # p 0,1,3,d,2,1 # pg - propagation at gate (subordibate path) 0,1,3,7,3,1 # t7 = transforming to 07 0,1,4,2,2,1 # p 0,1,4,2,4,1 # fo 0,1,4,3,2,1 # p 0,1,4,4,2,1 # fo 0,1,5,2,b,1 # p 0,1,5,2,5,1 # fo 0,1,5,3,2,1 # p 0,1,5,5,2,1 # fo 0,1,6,2,2,1 # p 0,1,6,2,6,1 # fo 0,1,6,6,2,1 # fo 0,1,7,2,2,1 # p 0,1,7,2,7,1 # fo 0,1,7,7,2,1 # fo 0,0,0,f,6,2 # k 0,0,0,2,5,2 # xl = extend left 0,0,0,2,6,2 # sh = sheathing 0,0,0,4,2,2 # xr = extend right 0,0,0,6,1,2 # k 0,0,0,6,2,2 # sh 0,0,0,6,6,2 # sh 0,0,1,0,6,2 # sh 0,0,1,1,6,2 # k 0,0,1,2,6,2 # sh 0,0,1,6,1,2 # k 0,0,1,6,2,2 # sh 0,0,1,6,6,2 # sh 0,0,2,0,6,2 # g = gate control 0,0,2,2,6,2 # sh 0,0,2,6,g,2 # sh 0,0,6,1,1,2 # k 0,0,6,2,1,2 # sh 0,0,6,2,2,2 # sh 0,0,6,2,6,2 # sh 0,0,6,6,1,2 # sh 0,1,1,1,6,2 # k 0,1,1,6,6,2 # sh 0,2,2,2,6,2 # sh 0,2,2,6,6,2 # sh 0,0,0,0,7,3 # k 0,0,0,1,5,3 # i 0,0,0,5,1,3 # i 0,0,1,0,7,3 # e 0,0,2,0,7,3 # g 1,0,0,0,4,0 # e 1,0,0,1,4,0 # e 1,0,0,4,1,0 # e 1,0,1,0,4,0 # e 1,0,1,1,4,0 # e 1,0,1,4,1,0 # e 1,0,4,1,1,0 # e 1,1,1,1,4,0 # e 1,0,0,3,6,2 # i 1,0,0,6,3,2 # i # error in codd.r: 10107[23] # s = sense 1,0,1,0,7,2 # s = sense 1,0,0,0,7,3 # s 1,0,0,2,4,4 # xr 1,0,b,4,c,4 # pe = path end 1,1,1,2,4,4 # fo 1,1,g,4,2,4 # fo,p 1,1,2,g,4,4 # fo,p 1,1,2,4,3,4 # pg 1,1,2,7,7,4 # fi 1,1,4,2,2,4 # p 1,1,7,2,7,4 # fi 1,1,7,7,2,4 # fi 1,2,b,2,4,4 # pe 1,2,b,4,3,4 # pe 1,2,2,4,4,4 # c = collision 1,2,3,2,4,4 # pe 1,b,3,3,4,4 # pe 1,2,4,2,2,4 # c 1,2,4,3,3,4 # pe 1,0,0,5,2,5 # xl 1,0,1,0,5,5 # i 1,0,b,5,c,5 # pe 1,1,1,2,5,5 # fo 1,1,g,5,2,5 # fo,p 1,1,2,g,5,5 # fo,p 1,1,2,4,4,5 # fi 1,1,2,5,3,5 # pg 1,1,4,2,4,5 # fi 1,1,4,4,2,5 # fi 1,1,5,2,2,5 # p 1,2,2,b,5,5 # pe 1,2,2,5,3,5 # pe 1,2,2,5,5,5 # c 1,2,3,b,5,5 # pe 1,2,3,5,3,5 # pe 1,2,5,2,5,5 # c 1,2,5,3,3,5 # pe 1,3,3,3,5,5 # pe 1,0,0,h,6,6 # sh 1,0,0,6,i,6 # sh 1,0,1,h,6,6 # sh 1,0,1,6,i,6 # sh 1,0,2,2,6,6 # pe 1,0,2,6,1,6 # sh 1,0,b,6,c,6 # pe 1,0,6,0,6,6 # sh 1,0,6,1,j,6 # sh 1,0,6,2,g,6 # sh,pe 1,0,6,2,6,6 # c 1,0,6,0,6,6 # sh 1,0,6,1,j,6 # sh 1,0,6,2,i,6 # sh,pe,c 1,0,6,6,1,6 # sh 1,1,1,1,5,6 # i 1,1,1,2,6,6 # fo 1,1,1,6,2,6 # fo 1,1,2,1,6,6 # fo 1,1,2,2,6,6 # p 1,1,2,5,5,6 # fi 1,1,2,6,2,6 # p 1,1,2,6,3,6 # pg 1,1,2,6,6,6 # fi 1,1,5,2,5,6 # fi 1,1,5,5,2,6 # fi 1,1,6,2,2,6 # p 1,1,6,2,6,6 # fi 1,1,6,6,2,6 # fi 1,2,2,b,6,6 # pe 1,2,2,6,3,6 # pe 1,2,2,6,6,6 # c 1,2,3,b,6,6 # pe 1,2,3,6,3,6 # pe 1,2,6,2,6,6 # c 1,2,6,3,3,6 # pe 1,3,3,3,6,6 # pe 1,0,2,7,b,7 # pe 1,0,3,7,b,7 # pe 1,1,1,2,7,7 # fo 1,1,1,7,2,7 # fo 1,1,2,g,7,7 # fo,p 1,1,2,7,b,7 # p,pg 1,1,3,e,3,7 # t7 1,1,3,7,3,7 # t7 1,1,7,2,2,7 # p 1,2,2,b,7,7 # pe 1,2,2,7,3,7 # pe 1,2,2,7,7,7 # c 1,2,3,b,7,7 # pe 1,2,3,7,3,7 # pe 1,2,7,2,7,7 # c 1,2,7,3,3,7 # pe 1,3,3,3,7,7 # pe 2,0,h,0,6,0 # k,k,g 2,0,0,f,7,1 # s,x 2,0,0,7,1,1 # x = extend 2,0,1,0,7,1 # s 2,0,1,1,7,1 # x 2,0,1,7,1,1 # x 2,0,7,1,1,1 # x 2,1,1,1,7,1 # x 2,0,0,2,5,3 # qm = cell q change of state 2,0,0,4,2,3 # pm = cell p change of state 2,0,1,4,2,3 # pm (was missing in codd.r) 2,0,2,0,7,3 # g 2,0,2,5,1,3 # qm 2,0,3,0,n,3 # g 2,2,3,2,d,3 # g (was missing in codd.r) 3,0,0,2,n,0 # r,m 3,0,0,6,2,0 # r 3,0,0,7,2,0 # m 3,0,1,6,2,0 # pm 3,0,1,7,2,0 # m 3,0,2,6,1,0 # qm 3,0,2,7,1,0 # m 3,0,0,0,6,1 # s 3,0,0,2,5,1 # qm 3,0,0,4,2,1 # pm 3,2,3,2,d,2 # g 3,0,1,0,6,4 # e 3,0,1,0,7,7 # j 4,0,0,0,1,0 # e 4,0,0,1,2,0 # fi 4,0,0,2,1,0 # fi 4,0,1,0,2,0 # fi 4,0,1,1,2,0 # fo 4,0,1,2,1,0 # fo 4,0,1,2,2,0 # p 4,0,2,1,1,0 # fo 4,0,2,1,2,0 # p 4,0,2,2,1,0 # p 4,0,3,1,2,0 # pg 4,0,0,0,2,1 # xr 4,0,0,2,2,1 # c 4,0,2,0,2,1 # pe 4,0,2,2,2,1 # pe 4,0,2,2,3,1 # pe 4,0,2,3,2,1 # pe 4,0,2,3,3,1 # pe 4,0,3,2,2,1 # pe 4,0,3,2,3,1 # pe 4,0,3,3,2,1 # pe 4,0,3,3,3,1 # pe 5,0,0,0,1,0 # i 5,0,0,1,2,0 # fi 5,0,0,2,1,0 # fi 5,0,1,0,2,0 # fi 5,0,1,1,2,0 # fo 5,0,1,2,1,0 # fo 5,0,1,2,2,0 # p 5,0,2,1,1,0 # fo 5,0,2,1,2,0 # p 5,0,2,2,1,0 # p 5,0,3,1,2,0 # pg 5,0,0,0,2,1 # xl 5,0,0,2,2,1 # c 5,0,2,p,b,1 # pe 5,0,3,b,c,1 # pe (was missing in codd.r) 6,0,0,0,1,0 # sh 6,0,0,1,1,0 # sh 6,0,0,1,2,0 # fi 6,0,0,2,1,0 # fi 6,0,1,0,1,0 # sh 6,0,1,0,2,0 # fi 6,0,1,1,1,0 # i 6,0,1,1,2,0 # fo 6,0,1,2,1,0 # fo 6,0,1,2,2,0 # p 6,0,2,1,1,0 # fo 6,0,2,1,2,0 # p 6,0,2,2,1,0 # p 6,0,2,2,3,0 # pe 6,0,2,3,2,0 # pe 6,0,2,3,3,0 # pe 6,0,3,1,2,0 # pg 6,0,3,2,2,0 # pe 6,0,3,2,3,0 # pe 6,0,3,3,2,0 # pe 6,0,3,3,3,0 # pe 6,1,2,3,2,0 # s 6,0,0,0,0,1 # sh 6,0,0,0,2,1 # sh 6,0,0,2,2,1 # c 6,0,2,0,2,1 # pe 6,0,2,2,2,1 # sh 7,0,0,0,1,0 # j 7,0,1,1,2,0 # fo 7,0,1,2,1,0 # fo 7,0,1,2,2,0 # p 7,0,2,1,1,0 # fo 7,0,2,1,2,0 # p 7,0,2,2,1,0 # p 7,0,2,2,3,0 # pe 7,0,2,3,2,0 # pe 7,0,2,3,3,0 # pe 7,0,3,1,2,0 # pg 7,0,3,1,3,0 # pe 7,0,3,2,2,0 # pe 7,0,3,2,3,0 # pe 7,0,3,3,2,0 # pe 7,0,3,3,3,0 # pe 7,1,2,2,2,0 # s 7,0,0,0,2,1 # pe 7,0,0,2,2,1 # c 7,0,2,0,2,1 # pe 7,0,2,2,2,1 # x # End of ruleset @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Ed-rep.rule���������������������������������������������������������������������0000644�0001750�0001750�00000002024�12536111364�013315� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Ed-rep Rule tree written automatically by Scripts/Python/Rule-Generators/FredkinModN-gen.py. Winograd's generalization of Fredkin's parity rule (B1357/S1357) to modulo-n: c,{s} -> sum(s)%n, where n=2 for original rule. Winograd, T. (1970) A simple algorithm for self-replication A. I. Memo 197, Project MAC. MIT. http://hdl.handle.net/1721.1/5843 @TREE num_states=7 num_neighbors=4 num_nodes=29 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 1 3 3 3 3 3 3 3 1 4 4 4 4 4 4 4 1 5 5 5 5 5 5 5 1 6 6 6 6 6 6 6 2 0 1 2 3 4 5 6 2 1 2 3 4 5 6 0 2 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 2 4 5 6 0 1 2 3 2 5 6 0 1 2 3 4 2 6 0 1 2 3 4 5 3 7 8 9 10 11 12 13 3 8 9 10 11 12 13 7 3 9 10 11 12 13 7 8 3 10 11 12 13 7 8 9 3 11 12 13 7 8 9 10 3 12 13 7 8 9 10 11 3 13 7 8 9 10 11 12 4 14 15 16 17 18 19 20 4 15 16 17 18 19 20 14 4 16 17 18 19 20 14 15 4 17 18 19 20 14 15 16 4 18 19 20 14 15 16 17 4 19 20 14 15 16 17 18 4 20 14 15 16 17 18 19 5 21 22 23 24 25 26 27 @COLORS 1 56 32 16 2 104 80 56 3 120 120 72 4 168 120 104 5 200 168 120 6 216 176 168 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Worm-1252121.rule���������������������������������������������������������������0000644�0001750�0001750�00000011351�12536111364�013743� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Worm-1252121 Paterson's worms (by Dean Hickerson, 11/20/2008) Pattern #155 Sven Kahrkling's notation 1252121 Gardner's notation 1a2d3cbcc4b Final outcome unknown; doesn't finish within 1.1*10^17 steps. Forms almost full regular hexagons at certain times. Points and lines of hexagonal grid are mapped to points of square grid as below. "*" is a point of the hex grid, "-", "/", and "\" are lines of the hex grid. +--+--+--+--+ |- |* |- |* | +--+--+--+--+ | /| \| /| \| +--+--+--+--+ |* |- |* |- | +--+--+--+--+ Each step of the worm is simulated by 2 gens in the rule. In even gens, there's an arrow at one point of the hex grid showing which way the worm will move next. In odd gens, there's an arrow on one line of the hex grid. The transitions from even to odd gens are the same for all worms. Those from odd to even depend on the specific type of worm: If a point (state 0 or 1) has a line with an arrow pointing at it, it becomes a 'point with arrow'; the direction depends on the 6 neighboring lines, which are the NW, N, E, S, SW, and W neighbors in the square grid. Gen 0 consists of a single point in state 1, a 'point with arrow' pointing east. (Starting with a point in state 2, 3, 4, 5, or 6 would also work, rotating the whole pattern.) States are: 0 empty (unvisited point or line) 1-6 'point with arrow', showing direction of next movement (1=E; 2=SE; 3=SW; 4=W; 5=NW; 6=NE) 7 point that's been visited 8,9,10 edge - (8=line; 9=E arrow; 10=W arrow) 11,12,13 edge / (11=line; 12=NE arrow; 13=SW arrow) 14,15,16 edge \ (14=line; 15=SE arrow; 16=NW arrow) @TABLE n_states:17 neighborhood:Moore symmetries:none var point={1,2,3,4,5,6} var a0={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a1={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a2={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a3={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a4={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a5={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a6={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a7={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var n={8,11,14} var o={8,11,14} var p={8,11,14} var q={8,11,14} var b={0,7} # point with arrow becomes point that's been visited point,a0,a1,a2,a3,a4,a5,a6,a7,7 # line with arrow becomes line without arrow 9,a0,a1,a2,a3,a4,a5,a6,a7,8 10,a0,a1,a2,a3,a4,a5,a6,a7,8 12,a0,a1,a2,a3,a4,a5,a6,a7,11 13,a0,a1,a2,a3,a4,a5,a6,a7,11 15,a0,a1,a2,a3,a4,a5,a6,a7,14 16,a0,a1,a2,a3,a4,a5,a6,a7,14 # point with arrow creates line with arrow next to it 0,a0,a1,a2,a3,a4,a5,1,a6,9 0,2,a0,a1,a2,a3,a4,a5,a6,15 0,a0,3,a1,a2,a3,a4,a5,a6,13 0,a0,a1,4,a2,a3,a4,a5,a6,10 0,a0,a1,a2,5,a3,a4,a5,a6,16 0,a0,a1,a2,a3,6,a4,a5,a6,12 # 4 eaten: use only remaining direction # 0 (straight): b,0,a0,n,a1,o,12,p,q,6 b,n,a0,0,a1,o,p,9,q,1 b,n,a0,o,a1,0,p,q,15,2 b,13,a0,n,a1,o,0,p,q,3 b,n,a0,10,a1,o,p,0,q,4 b,n,a0,o,a1,16,p,q,0,5 # 1 (gentle right): b,n,a0,0,a1,o,12,p,q,1 b,n,a0,o,a1,0,p,9,q,2 b,n,a0,o,a1,p,0,q,15,3 b,13,a0,n,a1,o,p,0,q,4 b,n,a0,10,a1,o,p,q,0,5 b,0,a0,n,a1,16,o,p,q,6 # 2 (sharp right): b,n,a0,o,a1,0,12,p,q,2 b,n,a0,o,a1,p,0,9,q,3 b,n,a0,o,a1,p,q,0,15,4 b,13,a0,n,a1,o,p,q,0,5 b,0,a0,10,a1,n,o,p,q,6 b,n,a0,0,a1,16,o,p,q,1 # 4 (sharp left): b,n,a0,o,a1,p,12,0,q,4 b,n,a0,o,a1,p,q,9,0,5 b,0,a0,n,a1,o,p,q,15,6 b,13,a0,0,a1,n,o,p,q,1 b,n,a0,10,a1,0,o,p,q,2 b,n,a0,o,a1,16,0,p,q,3 # 5 (gentle left): b,n,a0,o,a1,p,12,q,0,5 b,0,a0,n,a1,o,p,9,q,6 b,n,a0,0,a1,o,p,q,15,1 b,13,a0,n,a1,0,o,p,q,2 b,n,a0,10,a1,o,0,p,q,3 b,n,a0,o,a1,16,p,0,q,4 # rule-specific transitions at point with arrow coming in # rule 1252121 # none eaten: 1 = gentle right b,0,a0,0,a1,0,12,0,0,1 b,0,a0,0,a1,0,0,9,0,2 b,0,a0,0,a1,0,0,0,15,3 b,13,a0,0,a1,0,0,0,0,4 b,0,a0,10,a1,0,0,0,0,5 b,0,a0,0,a1,16,0,0,0,6 # 1 eaten(1): 2 = sharp right b,0,a0,n,a1,0,12,0,0,2 b,0,a0,0,a1,n,0,9,0,3 b,0,a0,0,a1,0,n,0,15,4 b,13,a0,0,a1,0,0,n,0,5 b,0,a0,10,a1,0,0,0,n,6 b,n,a0,0,a1,16,0,0,0,1 # 2 eaten(24): 5 = gentle left b,0,a0,0,a1,n,12,o,0,5 b,0,a0,0,a1,0,n,9,o,6 b,o,a0,0,a1,0,0,n,15,1 b,13,a0,o,a1,0,0,0,n,2 b,n,a0,10,a1,o,0,0,0,3 b,0,a0,n,a1,16,o,0,0,4 # 3 eaten(045): 2 = sharp right b,n,a0,0,a1,0,12,o,p,2 b,p,a0,n,a1,0,0,9,o,3 b,o,a0,p,a1,n,0,0,15,4 b,13,a0,o,a1,p,n,0,0,5 b,0,a0,10,a1,o,p,n,0,6 b,0,a0,0,a1,16,o,p,n,1 # 2 eaten(04): 1 = gentle right b,n,a0,0,a1,0,12,o,0,1 b,0,a0,n,a1,0,0,9,o,2 b,o,a0,0,a1,n,0,0,15,3 b,13,a0,o,a1,0,n,0,0,4 b,0,a0,10,a1,o,0,n,0,5 b,0,a0,0,a1,16,o,0,n,6 # 2 eaten(15): 2 = sharp right b,0,a0,o,a1,0,12,0,n,2 b,n,a0,0,a1,o,0,9,0,3 b,0,a0,n,a1,0,o,0,15,4 b,13,a0,0,a1,n,0,o,0,5 b,0,a0,10,a1,0,n,0,o,6 b,o,a0,0,a1,16,0,n,0,1 # 2 eaten(02): 1 = gentle right b,n,a0,0,a1,o,12,0,0,1 b,0,a0,n,a1,0,o,9,0,2 b,0,a0,0,a1,n,0,o,15,3 b,13,a0,0,a1,0,n,0,o,4 b,o,a0,10,a1,0,0,n,0,5 b,0,a0,o,a1,16,0,0,n,6 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/LifeOnTheEdge.rule��������������������������������������������������������������0000644�0001750�0001750�00000012577�12536111364�014621� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE LifeOnTheEdge @TREE num_states=4 num_neighbors=8 num_nodes=58 1 0 0 0 3 1 0 1 1 2 1 1 0 0 2 2 0 1 1 2 1 0 2 2 1 1 0 3 3 0 1 1 2 2 0 2 4 5 5 6 1 2 0 0 1 1 2 1 1 0 1 3 0 0 0 2 8 9 9 10 3 3 7 7 11 1 0 2 2 0 2 5 6 6 13 1 2 0 0 0 2 9 10 10 15 1 0 1 1 0 1 1 0 0 0 1 0 0 0 0 2 17 18 18 19 3 14 16 16 20 4 12 12 21 21 2 10 15 15 15 2 18 19 19 19 3 23 24 24 24 4 21 21 25 25 5 22 26 22 26 6 27 27 27 27 1 0 0 0 2 2 1 2 2 29 3 30 14 14 16 2 6 13 13 13 3 32 23 23 24 4 31 31 33 33 2 15 15 15 15 2 19 19 19 19 3 35 36 36 36 4 33 33 37 37 5 34 38 34 38 6 39 39 39 39 7 28 28 40 40 1 0 0 0 1 2 42 17 17 18 3 7 11 11 43 3 16 20 20 20 4 44 44 45 45 3 24 24 24 24 4 45 45 47 47 5 46 48 46 48 6 49 49 49 49 3 36 36 36 36 4 25 25 51 51 5 26 52 26 52 6 53 53 53 53 7 50 50 54 54 8 41 55 41 55 9 56 56 56 56 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 93 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "..............................." "..............................." "..............................." "..............................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." /* icon for state 2 */ "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 3 */ "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." "BBBB..........................." XPM /* width height num_colors chars_per_pixel */ "15 45 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "..............." "..............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." /* icon for state 2 */ "..BBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." "..............." /* icon for state 3 */ "..BBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." "BB............." XPM /* width height num_colors chars_per_pixel */ "7 21 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "......." "B......" "B......" "B......" "B......" "B......" "B......" /* icon for state 2 */ ".BBBBBB" "......." "......." "......." "......." "......." "......." /* icon for state 3 */ ".BBBBBB" "B......" "B......" "B......" "B......" "B......" "B......" ���������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/DLA-Margolus-emulated.rule������������������������������������������������������0000644�0001750�0001750�00000011070�12536111364�016167� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE DLA-Margolus-emulated @TREE num_states=7 num_neighbors=8 num_nodes=204 1 0 2 2 4 4 6 6 1 0 1 2 3 4 5 6 2 0 1 0 1 0 1 0 2 1 1 1 1 1 1 1 1 0 2 1 4 3 6 5 2 0 1 4 1 4 1 4 3 2 3 5 3 5 3 5 3 3 3 3 3 3 3 3 3 5 3 5 3 5 3 5 4 6 7 8 7 8 7 8 4 7 7 7 7 7 7 7 2 4 1 4 1 4 1 4 3 2 3 11 3 11 3 11 3 11 3 11 3 11 3 11 4 12 7 13 7 13 7 13 5 9 10 14 10 14 10 14 1 0 1 1 3 3 5 5 2 16 1 16 1 16 1 16 3 17 3 17 3 17 3 17 4 18 7 18 7 18 7 18 5 19 10 19 10 19 10 19 1 0 2 2 2 4 6 6 1 0 2 2 6 4 6 6 2 0 1 21 1 0 1 22 1 0 4 2 4 4 6 6 2 0 1 0 1 24 1 0 2 0 1 22 1 0 1 0 3 2 3 23 3 25 3 26 4 27 7 27 7 27 7 27 5 28 10 28 10 28 10 28 1 0 4 2 2 4 6 6 2 0 1 30 1 0 1 0 2 0 1 21 1 24 1 0 3 2 3 31 3 32 3 2 4 33 7 33 7 33 7 33 5 34 10 34 10 34 10 34 2 0 1 0 1 0 1 22 3 2 3 36 3 2 3 26 4 37 7 37 7 37 7 37 5 38 10 38 10 38 10 38 6 15 20 29 20 35 20 39 5 10 10 10 10 10 10 10 6 20 20 41 20 41 20 41 3 2 3 2 3 2 3 2 1 0 1 2 3 2 5 6 1 0 1 2 3 6 5 6 2 1 1 44 1 1 1 45 3 46 46 3 46 3 46 3 1 0 1 4 3 4 5 6 2 1 1 1 1 48 1 1 3 49 49 3 49 3 49 3 2 1 1 45 1 1 1 1 3 51 51 3 51 3 51 3 4 43 47 43 50 43 52 43 5 53 10 53 10 53 10 53 4 27 47 27 50 27 52 27 5 55 10 55 10 55 10 55 4 33 47 33 50 33 52 33 5 57 10 57 10 57 10 57 4 37 47 37 50 37 52 37 5 59 10 59 10 59 10 59 6 54 41 56 41 58 41 60 1 0 1 4 3 2 5 6 2 1 1 62 1 44 1 1 3 63 63 3 63 3 63 3 4 43 64 43 50 43 7 43 5 65 10 65 10 65 10 65 4 27 64 27 50 27 7 27 5 67 10 67 10 67 10 67 4 33 64 33 50 33 7 33 5 69 10 69 10 69 10 69 4 37 64 37 50 37 7 37 5 71 10 71 10 71 10 71 6 66 41 68 41 70 41 72 2 1 1 1 1 1 1 45 3 74 74 3 74 3 74 3 4 43 75 43 7 43 52 43 5 76 10 76 10 76 10 76 4 27 75 27 7 27 52 27 5 78 10 78 10 78 10 78 4 33 75 33 7 33 52 33 5 80 10 80 10 80 10 80 4 37 75 37 7 37 52 37 5 82 10 82 10 82 10 82 6 77 41 79 41 81 41 83 7 40 42 61 42 73 42 84 6 41 41 41 41 41 41 41 7 42 42 86 42 86 42 86 4 43 7 43 7 43 7 43 2 44 44 1 44 1 44 1 2 45 45 1 45 1 45 1 3 3 3 89 3 3 3 90 4 91 7 91 7 91 7 91 2 48 48 1 48 1 48 1 3 3 3 3 3 93 3 3 4 94 7 94 7 94 7 94 3 3 3 90 3 3 3 3 4 96 7 96 7 96 7 96 5 88 92 88 95 88 97 88 5 28 92 28 95 28 97 28 5 34 92 34 95 34 97 34 5 38 92 38 95 38 97 38 6 98 41 99 41 100 41 101 5 53 92 53 95 53 97 53 5 55 92 55 95 55 97 55 5 57 92 57 95 57 97 57 5 59 92 59 95 59 97 59 6 103 41 104 41 105 41 106 5 65 92 65 95 65 97 65 5 67 92 67 95 67 97 67 5 69 92 69 95 69 97 69 5 71 92 71 95 71 97 71 6 108 41 109 41 110 41 111 5 76 92 76 95 76 97 76 5 78 92 78 95 78 97 78 5 80 92 80 95 80 97 80 5 82 92 82 95 82 97 82 6 113 41 114 41 115 41 116 7 102 86 107 86 112 86 117 2 62 62 1 62 1 62 1 3 3 3 119 3 3 3 3 4 120 7 120 7 120 7 120 3 3 3 89 3 93 3 3 4 122 7 122 7 122 7 122 5 88 121 88 123 88 10 88 5 28 121 28 123 28 10 28 5 34 121 34 123 34 10 34 5 38 121 38 123 38 10 38 6 124 41 125 41 126 41 127 5 53 121 53 123 53 10 53 5 55 121 55 123 55 10 55 5 57 121 57 123 57 10 57 5 59 121 59 123 59 10 59 6 129 41 130 41 131 41 132 5 65 121 65 123 65 10 65 5 67 121 67 123 67 10 67 5 69 121 69 123 69 10 69 5 71 121 71 123 71 10 71 6 134 41 135 41 136 41 137 5 76 121 76 123 76 10 76 5 78 121 78 123 78 10 78 5 80 121 80 123 80 10 80 5 82 121 82 123 82 10 82 6 139 41 140 41 141 41 142 7 128 86 133 86 138 86 143 3 3 3 3 3 3 3 90 4 145 7 145 7 145 7 145 5 88 146 88 10 88 97 88 5 28 146 28 10 28 97 28 5 34 146 34 10 34 97 34 5 38 146 38 10 38 97 38 6 147 41 148 41 149 41 150 5 53 146 53 10 53 97 53 5 55 146 55 10 55 97 55 5 57 146 57 10 57 97 57 5 59 146 59 10 59 97 59 6 152 41 153 41 154 41 155 5 65 146 65 10 65 97 65 5 67 146 67 10 67 97 67 5 69 146 69 10 69 97 69 5 71 146 71 10 71 97 71 6 157 41 158 41 159 41 160 5 76 146 76 10 76 97 76 5 78 146 78 10 78 97 78 5 80 146 80 10 80 97 80 5 82 146 82 10 82 97 82 6 162 41 163 41 164 41 165 7 151 86 156 86 161 86 166 8 85 87 118 87 144 87 167 1 0 1 1 3 1 5 5 2 169 1 169 1 169 1 169 3 170 3 170 3 170 3 170 1 0 1 1 3 5 5 5 2 172 1 172 1 172 1 172 3 173 3 173 3 173 3 173 4 18 7 171 7 18 7 174 1 0 1 3 3 3 5 5 2 176 1 176 1 176 1 176 3 177 3 177 3 177 3 177 4 18 7 18 7 178 7 18 4 18 7 174 7 18 7 18 5 19 10 175 10 179 10 180 6 181 181 41 181 41 181 41 7 182 182 86 182 86 182 86 7 86 86 86 86 86 86 86 8 183 183 184 183 184 183 184 5 88 10 88 10 88 10 88 6 186 41 29 41 35 41 39 7 187 86 61 86 73 86 84 8 188 184 118 184 144 184 167 1 0 1 3 3 1 5 5 2 190 1 190 1 190 1 190 3 191 3 191 3 191 3 191 4 18 7 192 7 171 7 18 5 19 10 193 10 179 10 19 6 194 194 41 194 41 194 41 7 195 195 86 195 86 195 86 8 196 196 184 196 184 196 184 4 18 7 18 7 18 7 174 5 19 10 198 10 19 10 180 6 199 199 41 199 41 199 41 7 200 200 86 200 86 200 86 8 201 201 184 201 184 201 184 9 168 185 189 197 189 202 189 @COLORS 1 90 90 90 2 62 62 62 3 0 0 255 4 0 0 220 5 255 255 255 6 220 220 220 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Life.rule�����������������������������������������������������������������������0000644�0001750�0001750�00000000441�12536111364�013061� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Life @TREE num_states=2 num_neighbors=8 num_nodes=32 1 0 0 2 0 0 1 0 1 2 0 2 3 1 3 1 1 1 2 2 5 3 3 6 4 4 7 2 5 0 3 6 9 4 7 10 5 8 11 3 9 1 4 10 13 5 11 14 6 12 15 3 1 1 4 13 17 5 14 18 6 15 19 7 16 20 4 17 17 5 18 22 6 19 23 7 20 24 8 21 25 5 22 22 6 23 27 7 24 28 8 25 29 9 26 30 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/BriansBrain.rule����������������������������������������������������������������0000644�0001750�0001750�00000000505�12536111364�014375� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE BriansBrain @TREE num_states=3 num_neighbors=8 num_nodes=27 1 0 2 0 2 0 0 0 1 1 2 0 2 0 2 0 3 1 3 1 2 2 0 2 3 3 5 3 4 4 6 4 3 5 1 5 4 6 8 6 5 7 9 7 3 1 1 1 4 8 11 8 5 9 12 9 6 10 13 10 4 11 11 11 5 12 15 12 6 13 16 13 7 14 17 14 5 15 15 15 6 16 19 16 7 17 20 17 8 18 21 18 6 19 19 19 7 20 23 20 8 21 24 21 9 22 25 22 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Evoloop-finite.rule�������������������������������������������������������������0000644�0001750�0001750�00000010365�12536111364�015107� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Evoloop-finite @TABLE # a mod of Evoloop, using state 9 as the background # rules: 132 n_states:10 neighborhood:vonNeumann symmetries:rotate4 var a={9,2,5} var b={9,1,2,3,4,5,6,7} var c={9,1,2,3,4,5,6,7} var d={1,4,6,7} var e={1,4} var f={9,1} var g={9,1,2,3,4,5,6,7,8} var h={9,1,2,3,4,5,6,7,8} var i={2,3,4,5,6,7} var j={9,2,3,5} var k={9,2,3,4,5,6,7} var l={4,6,7} var m={2,5} var n={9,1,8} var o={9,3,5} var p={2,3,5} var q={3,5} var r={2,4,6,7} var s={9,1} var t={9,1} var u={9,1,2,3,4,7} var v={5,6} var w={1,6,7} var x={9,3,5} var y={9,3,5} var z={1,3,5} var A={9,1,3,5} var B={9,1,3,5} var C={1,3,5} var D={1,3,5} var E={9,1,2,3,4,5} var F={9,1,2,4,5} var G={1,2,4} var H={9,1,3,4,5,6} var I={9,1,2,3,4,5,6} var J={1,2,4,6} var K={9,1,2,4,5,6,7} var L={9,1,2,3,4,5,7} var M={1,2,4,6,7} var N={9,3} var O={9,1,2,3,5} var P={9,1,2,3,4} var Q={9,2,3,5,6} var R={9,1,3,4,5,6,7} var S={1,3} var T={1,2,3,5} var U={9,1,3,4,5} var V={9,1,4,5,6} var W={1,4,6} var X={2,3,5} var Y={9,5} var Z={1,2} var aa={9,1,5} var ab={9,2} var ac={2,3,4,5} var ad={2,3,4,5,6} var ae={9,3} var af={9,3} var ag={3,7} var ah={2,8} var ai={9,2,8} var aj={9,8} var ak={9,2,8} var al={6,8} var am={9,1,4,5,6,7} var an={9,1,4,5,6,7} var ao={1,4,6,7} var ap={1,3,4,5,6,7} var aq={2,3,5,8} var ar={9,1,2,3,4,5,6,7,8} var as={9,1,4,6,7} var at={1,5,6} var au={4,7} var av={1,3,4,5,7} var aw={9,4,5,7} var ax={1,4,5,6,7} var ay={9,4,5,7} var az={1,4,5,6,7} var aA={9,1,3,5,6,7} var aB={1,2,3,4,5,7} var aC={9,1,4,7} var aD={2,4,6,7,8} var aE={3,5,6} var aF={2,3,5,6} var aG={2,3,5,6} var aH={2,3} var aI={9,1,3,4,7} var aJ={2,5,6,7} var aK={1,2,3,4,6,7} var aL={1,3,4,7} var aM={9,2,3} var aN={1,2,4,7} var aO={3,6} var aP={1,2,3,4,7} var aQ={3,4,7} var aR={1,2,3,4,5,6,7} var aS={3,4,6,7,8} var aT={9,3,6} var aU={3,4,5,7} var aV={2,3,6} var aW={1,2,3,4,5,6,7} var aX={9,8} var aY={9,8} var aZ={4,5,6,7} var ba={4,6,7,8} var bb={1,2,4,6,7} var bc={4,5} var bd={4,7,8} var be={9,1,4,5,7} var bf={4,5,7} var bg={1,2,4,5,7} var bh={1,2,4,5,7} var bi={9,1,2,3,4,6,7} var bj={2,5,6} var bk={1,3,4,6,7} var bl={9,4,6,7} var bm={6,7,8} var bn={1,3,4,5,6,7} var bo={1,4,7} var bp={2,3,5,6} var bq={2,3,5,6} var br={9,1,2,3,4,5,6,7} var bs={9,1,2,3,4,5,6,7} 9,a,9,9,1,2 9,9,9,9,4,3 9,b,c,1,d,1 9,9,9,2,e,2 f,g,h,i,8,8 9,j,k,l,1,1 9,9,9,4,m,2 9,9,9,7,5,2 f,b,n,8,i,8 9,o,1,j,d,1 9,9,1,9,2,2 9,o,1,2,p,1 9,j,1,q,r,1 f,s,i,t,8,8 9,u,2,1,p,1 9,9,r,p,1,1 9,9,2,3,2,2 9,9,q,1,2,1 9,o,q,2,1,1 9,1,2,v,2,6 w,o,x,y,k,8 z,A,B,C,D,8 1,E,F,G,4,4 1,H,I,J,6,6 1,K,L,M,7,7 1,N,A,j,p,8 1,O,P,4,G,4 1,Q,I,6,J,6 1,b,R,7,M,7 1,N,S,f,T,8 1,O,e,o,4,4 1,U,J,o,6,6 1,V,M,I,7,7 1,I,W,7,3,7 1,o,2,N,4,4 S,j,p,O,5,8 C,j,p,2,X,8 1,9,2,3,2,4 1,f,2,5,2,7 1,f,2,5,4,3 1,f,2,7,3,5 1,Y,3,Z,4,4 C,aa,q,ab,D,8 1,o,5,4,Z,4 1,f,6,2,4,4 1,o,7,3,M,7 C,f,2,X,q,8 1,e,ac,6,2,6 C,f,A,5,ab,8 1,1,4,3,3,4 1,X,2,5,4,4 1,ad,2,7,3,7 1,2,4,3,3,3 1,2,6,2,7,6 X,9,9,9,9,8 2,N,ae,af,ag,1 ah,ai,aj,ak,al,9 X,am,an,d,ao,8 2,b,R,ap,3,1 aq,g,h,ar,8,9 2,as,ab,3,ap,1 2,9,9,3,2,4 2,9,9,4,2,3 X,am,an,v,at,8 2,ab,9,5,au,5 2,9,9,8,av,9 X,aw,ax,ay,az,8 2,aA,ap,ab,3,1 2,9,aB,9,8,9 2,aC,2,9,6,5 2,9,2,9,7,3 2,am,2,ax,3,1 2,aC,2,3,2,3 2,9,2,5,2,5 aD,9,2,6,Y,9 2,9,3,2,ax,1 2,ab,3,aE,2,1 2,2,aF,aG,3,1 2,2,3,4,5,1 3,9,9,9,aH,2 3,R,k,b,v,8 3,9,9,9,7,4 3,aI,R,aJ,aK,8 3,9,9,3,2,2 3,u,U,aL,ao,8 3,9,9,4,2,1 3,aM,b,aN,aO,8 3,9,1,9,2,1 3,f,aP,s,aQ,8 q,R,ax,aR,aK,8 aS,9,1,2,5,9 3,9,2,aT,2,8 3,aC,2,5,2,1 3,9,3,3,2,1 aU,ap,aR,aV,aW,8 4,aj,aX,aY,ai,1 aZ,o,x,y,ap,8 ba,9,am,M,bb,9 l,ar,g,h,8,1 4,o,x,2,q,8 bc,9,o,q,2,8 4,9,9,8,ap,1 ba,9,ao,o,M,9 4,9,ap,9,8,1 ba,9,M,bb,ap,9 bd,9,2,be,M,9 4,9,2,9,q,8 ba,9,2,C,ao,9 4,9,2,aH,2,1 au,9,2,6,2,6 ba,9,3,ao,M,9 ba,9,3,2,ao,9 4,9,3,2,2,1 bf,bg,bh,aR,aW,8 5,b,bi,aF,bj,8 5,9,9,2,3,2 5,aI,bk,bl,bi,8 5,9,1,2,1,8 5,9,2,9,m,2 5,9,2,1,5,2 5,9,2,au,5,8 5,9,3,1,2,9 6,9,2,aC,2,2 al,9,2,aF,2,9 bm,9,3,2,2,9 6,ap,bn,aR,aW,8 6,ap,2,bn,2,8 al,bo,2,2,2,9 6,aF,aG,bp,bq,8 7,9,2,2,2,1 7,9,2,3,2,9 8,b,c,br,bs,9 @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 8 255 128 0 # this is the background state for Evoloop-finite 9 0 0 0 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Chou-Reggia-2.rule��������������������������������������������������������������0000644�0001750�0001750�00000006305�12536111364�014440� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Chou-Reggia-2 J. A. Reggia, S.L.Armentrout, H.-H. Chou, and Y. Peng. ``Simple systems that exhibit self-directed replication.'' Science, Vol. 259, pages 1282-1287, February 1993. Transition rules from: http://necsi.org/postdocs/sayama/sdsr/java/loops.java Credits: "Self-Replicating Loops & Ant, Programmed by Eli Bachmutsky, Copyleft Feb.1999" @TABLE # rules: 65 # format: CNESWC' n_states:8 neighborhood:vonNeumann symmetries:rotate4 000000 000440 000547 000100 000110 000330 004040 004445 004100 001040 001010 001740 003000 003010 003030 007040 007030 007104 007110 040000 040070 047100 050007 017000 070000 070077 071010 400101 400313 401033 407103 411033 431033 500033 503330 100045 100011 100414 101044 101301 103011 107131 140414 141044 111044 133011 177711 304011 305011 305141 307141 344011 345011 354010 314001 377711 700000 700337 707100 707141 707110 717000 730007 770070 770711 @TREE num_states=8 num_neighbors=4 num_nodes=101 1 0 1 2 3 4 5 6 0 1 0 1 2 3 1 5 6 7 1 0 1 2 3 4 5 6 7 1 0 1 2 3 4 3 6 7 1 0 5 2 3 4 5 6 7 1 7 1 2 3 4 5 6 7 2 0 1 2 3 4 5 2 2 1 0 1 2 1 4 5 6 7 2 1 2 2 2 7 2 2 0 2 2 2 2 2 2 2 2 2 1 0 1 2 3 3 5 6 7 2 3 10 2 2 2 2 2 2 1 0 4 2 3 4 5 6 7 2 4 12 2 2 2 2 2 2 2 5 2 2 2 5 2 2 2 1 4 1 2 3 3 5 6 0 1 7 1 2 3 4 5 6 0 2 2 15 2 2 2 2 2 16 3 6 8 9 11 13 14 9 17 2 1 2 2 10 12 2 2 15 2 10 10 2 10 2 2 2 2 1 0 4 2 1 4 5 6 7 2 21 12 2 2 12 2 2 2 2 7 2 2 2 2 2 2 2 2 2 0 2 2 2 2 2 2 3 19 9 9 20 22 23 9 24 3 9 9 9 9 9 9 9 9 2 3 2 2 2 2 2 2 2 2 10 2 2 2 2 2 2 2 1 0 1 2 3 4 0 6 7 2 2 2 2 29 2 2 2 2 3 27 28 9 30 9 9 9 9 2 4 7 2 2 2 5 2 2 1 0 1 2 0 4 5 6 7 2 21 2 2 2 7 33 2 2 1 5 1 2 3 4 5 6 7 2 2 12 2 2 35 2 2 2 2 2 7 2 2 2 2 2 2 1 0 1 2 1 4 5 6 1 2 2 38 2 2 2 2 2 2 3 32 34 9 9 36 37 9 39 2 5 2 2 2 2 2 2 2 2 7 2 2 2 7 2 2 2 3 41 42 9 9 9 9 9 9 2 2 0 2 2 2 2 2 16 1 0 1 2 3 4 5 6 1 2 2 45 2 2 2 2 2 2 3 44 9 9 9 9 9 9 46 4 18 25 26 31 40 43 26 47 2 1 2 2 10 21 7 2 2 2 7 2 2 2 7 7 2 2 2 2 2 2 2 33 2 2 2 2 0 2 2 2 2 2 2 2 3 49 9 9 9 50 51 9 52 2 2 2 2 10 12 2 2 0 3 54 9 9 9 9 9 9 9 2 10 2 2 10 2 2 2 2 3 56 28 9 9 9 9 9 9 2 12 2 2 2 12 2 2 2 2 12 2 2 2 2 2 2 2 3 58 59 9 9 59 9 9 9 3 9 9 9 9 23 9 9 9 2 15 2 2 2 2 2 2 2 2 38 2 2 2 2 2 2 2 2 45 2 2 2 2 2 2 7 3 62 52 9 9 63 9 9 64 4 53 55 26 57 60 61 26 65 4 26 26 26 26 26 26 26 26 2 10 10 2 2 2 2 2 2 2 2 10 2 29 2 2 2 2 3 11 68 9 69 9 9 9 9 2 29 2 2 2 2 2 2 2 3 30 28 9 71 9 9 9 9 4 70 26 26 72 26 26 26 26 2 4 21 2 2 2 2 2 2 2 12 12 2 2 12 2 2 2 3 74 75 9 9 36 9 9 9 2 7 2 2 2 12 7 2 38 3 77 9 9 9 23 23 9 9 2 2 7 2 2 35 2 2 2 2 35 2 2 2 2 2 2 2 3 79 59 9 9 80 9 9 9 2 5 33 2 2 2 2 2 2 3 82 9 9 9 9 9 9 9 4 76 78 26 26 81 83 26 26 2 5 7 2 2 2 2 2 2 2 2 2 2 2 7 2 2 2 3 85 86 9 9 41 9 9 9 2 33 2 2 2 2 2 2 2 3 9 9 9 9 88 9 9 9 3 37 9 9 9 9 9 9 9 4 87 89 26 26 90 26 26 26 2 15 0 2 2 38 2 2 45 2 16 2 2 2 2 2 2 2 3 9 92 9 9 9 9 9 93 2 0 2 2 2 2 2 2 45 2 2 2 2 2 2 2 2 7 3 95 9 9 9 9 9 9 96 3 93 96 9 9 9 9 9 37 4 94 97 26 26 26 26 26 98 5 48 66 67 73 84 91 67 99 @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Worm-1042015.rule���������������������������������������������������������������0000644�0001750�0001750�00000011272�12536111364�013744� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Worm-1042015 Paterson's worms (by Dean Hickerson, 11/20/2008) Pattern #061 Sven Kahrkling's notation 1042015 Gardner's notation 1a2c3caca4a Final outcome unknown; doesn't finish within 1.3*10^18 steps. Very chaotic. Points and lines of hexagonal grid are mapped to points of square grid as below. "*" is a point of the hex grid, "-", "/", and "\" are lines of the hex grid. +--+--+--+--+ |- |* |- |* | +--+--+--+--+ | /| \| /| \| +--+--+--+--+ |* |- |* |- | +--+--+--+--+ Each step of the worm is simulated by 2 gens in the rule. In even gens, there's an arrow at one point of the hex grid showing which way the worm will move next. In odd gens, there's an arrow on one line of the hex grid. The transitions from even to odd gens are the same for all worms. Those from odd to even depend on the specific type of worm: If a point (state 0 or 1) has a line with an arrow pointing at it, it becomes a 'point with arrow'; the direction depends on the 6 neighboring lines, which are the NW, N, E, S, SW, and W neighbors in the square grid. Gen 0 consists of a single point in state 1, a 'point with arrow' pointing east. (Starting with a point in state 2, 3, 4, 5, or 6 would also work, rotating the whole pattern.) States are: 0 empty (unvisited point or line) 1-6 'point with arrow', showing direction of next movement (1=E; 2=SE; 3=SW; 4=W; 5=NW; 6=NE) 7 point that's been visited 8,9,10 edge - (8=line; 9=E arrow; 10=W arrow) 11,12,13 edge / (11=line; 12=NE arrow; 13=SW arrow) 14,15,16 edge \ (14=line; 15=SE arrow; 16=NW arrow) @TABLE n_states:17 neighborhood:Moore symmetries:none var point={1,2,3,4,5,6} var a0={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a1={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a2={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a3={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a4={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a5={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a6={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a7={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var n={8,11,14} var o={8,11,14} var p={8,11,14} var q={8,11,14} var b={0,7} # point with arrow becomes point that's been visited point,a0,a1,a2,a3,a4,a5,a6,a7,7 # line with arrow becomes line without arrow 9,a0,a1,a2,a3,a4,a5,a6,a7,8 10,a0,a1,a2,a3,a4,a5,a6,a7,8 12,a0,a1,a2,a3,a4,a5,a6,a7,11 13,a0,a1,a2,a3,a4,a5,a6,a7,11 15,a0,a1,a2,a3,a4,a5,a6,a7,14 16,a0,a1,a2,a3,a4,a5,a6,a7,14 # point with arrow creates line with arrow next to it 0,a0,a1,a2,a3,a4,a5,1,a6,9 0,2,a0,a1,a2,a3,a4,a5,a6,15 0,a0,3,a1,a2,a3,a4,a5,a6,13 0,a0,a1,4,a2,a3,a4,a5,a6,10 0,a0,a1,a2,5,a3,a4,a5,a6,16 0,a0,a1,a2,a3,6,a4,a5,a6,12 # 4 eaten: use only remaining direction # 0 (straight): b,0,a0,n,a1,o,12,p,q,6 b,n,a0,0,a1,o,p,9,q,1 b,n,a0,o,a1,0,p,q,15,2 b,13,a0,n,a1,o,0,p,q,3 b,n,a0,10,a1,o,p,0,q,4 b,n,a0,o,a1,16,p,q,0,5 # 1 (gentle right): b,n,a0,0,a1,o,12,p,q,1 b,n,a0,o,a1,0,p,9,q,2 b,n,a0,o,a1,p,0,q,15,3 b,13,a0,n,a1,o,p,0,q,4 b,n,a0,10,a1,o,p,q,0,5 b,0,a0,n,a1,16,o,p,q,6 # 2 (sharp right): b,n,a0,o,a1,0,12,p,q,2 b,n,a0,o,a1,p,0,9,q,3 b,n,a0,o,a1,p,q,0,15,4 b,13,a0,n,a1,o,p,q,0,5 b,0,a0,10,a1,n,o,p,q,6 b,n,a0,0,a1,16,o,p,q,1 # 4 (sharp left): b,n,a0,o,a1,p,12,0,q,4 b,n,a0,o,a1,p,q,9,0,5 b,0,a0,n,a1,o,p,q,15,6 b,13,a0,0,a1,n,o,p,q,1 b,n,a0,10,a1,0,o,p,q,2 b,n,a0,o,a1,16,0,p,q,3 # 5 (gentle left): b,n,a0,o,a1,p,12,q,0,5 b,0,a0,n,a1,o,p,9,q,6 b,n,a0,0,a1,o,p,q,15,1 b,13,a0,n,a1,0,o,p,q,2 b,n,a0,10,a1,o,0,p,q,3 b,n,a0,o,a1,16,p,0,q,4 # rule-specific transitions at point with arrow coming in # rule 1042015 # none eaten: 1 = gentle right b,0,a0,0,a1,0,12,0,0,1 b,0,a0,0,a1,0,0,9,0,2 b,0,a0,0,a1,0,0,0,15,3 b,13,a0,0,a1,0,0,0,0,4 b,0,a0,10,a1,0,0,0,0,5 b,0,a0,0,a1,16,0,0,0,6 # 1 eaten(1): 0 = straight b,0,a0,n,a1,0,12,0,0,6 b,0,a0,0,a1,n,0,9,0,1 b,0,a0,0,a1,0,n,0,15,2 b,13,a0,0,a1,0,0,n,0,3 b,0,a0,10,a1,0,0,0,n,4 b,n,a0,0,a1,16,0,0,0,5 # 2 eaten(02): 4 = sharp left b,n,a0,0,a1,o,12,0,0,4 b,0,a0,n,a1,0,o,9,0,5 b,0,a0,0,a1,n,0,o,15,6 b,13,a0,0,a1,0,n,0,o,1 b,o,a0,10,a1,0,0,n,0,2 b,0,a0,o,a1,16,0,0,n,3 # 2 eaten(15): 2 = sharp right b,0,a0,o,a1,0,12,0,n,2 b,n,a0,0,a1,o,0,9,0,3 b,0,a0,n,a1,0,o,0,15,4 b,13,a0,0,a1,n,0,o,0,5 b,0,a0,10,a1,0,n,0,o,6 b,o,a0,0,a1,16,0,n,0,1 # 2 eaten(24): 0 = straight b,0,a0,0,a1,n,12,o,0,6 b,0,a0,0,a1,0,n,9,o,1 b,o,a0,0,a1,0,0,n,15,2 b,13,a0,o,a1,0,0,0,n,3 b,n,a0,10,a1,o,0,0,0,4 b,0,a0,n,a1,16,o,0,0,5 # 2 eaten(04): 1 = gentle right b,n,a0,0,a1,0,12,o,0,1 b,0,a0,n,a1,0,0,9,o,2 b,o,a0,0,a1,n,0,0,15,3 b,13,a0,o,a1,0,n,0,0,4 b,0,a0,10,a1,o,0,n,0,5 b,0,a0,0,a1,16,o,0,n,6 # 3 eaten(124): 5 = gentle left b,0,a0,n,a1,o,12,p,0,5 b,0,a0,0,a1,n,o,9,p,6 b,p,a0,0,a1,0,n,o,15,1 b,13,a0,p,a1,0,0,n,o,2 b,o,a0,10,a1,p,0,0,n,3 b,n,a0,o,a1,16,p,0,0,4 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/LifeOnTheSlope.rule�������������������������������������������������������������0000644�0001750�0001750�00000010104�12536111364�015017� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE LifeOnTheSlope @TREE num_states=3 num_neighbors=8 num_nodes=78 1 0 0 0 1 0 0 2 1 0 1 0 2 0 1 2 1 2 2 0 1 0 1 2 2 1 4 5 1 1 0 1 2 2 5 7 3 3 6 8 1 2 0 0 2 4 0 10 1 1 0 0 2 5 10 12 3 6 11 13 2 7 12 0 3 8 13 15 4 9 14 16 2 0 0 2 1 0 2 1 2 10 2 19 3 11 18 20 2 12 19 1 3 13 20 22 4 14 21 23 2 0 1 0 3 15 22 25 4 16 23 26 5 17 24 27 2 2 2 7 2 19 7 4 3 20 29 30 2 1 4 1 3 22 30 32 4 23 31 33 3 25 32 25 4 26 33 35 5 27 34 36 6 28 37 28 3 18 18 29 4 21 39 31 5 24 40 34 2 7 7 0 3 29 29 42 2 4 0 4 3 30 42 44 4 31 43 45 3 32 44 32 4 33 45 47 5 34 46 48 6 41 49 41 7 38 38 50 4 39 39 43 5 40 52 46 2 0 0 0 3 42 42 54 4 43 43 55 3 44 54 44 4 45 55 57 5 46 56 58 6 53 59 53 7 50 50 60 8 51 51 61 4 35 47 35 5 36 48 63 6 37 64 37 4 47 57 47 5 48 58 66 6 49 67 49 7 65 65 68 3 54 54 54 4 55 55 70 4 57 70 57 5 58 71 72 6 59 73 59 7 68 68 74 8 69 69 75 9 62 76 62 @COLORS 1 200 200 255 pale blue 2 200 200 255 pale blue @ICONS XPM /* width height num_colors chars_per_pixel */ "31 62 2 1" /* colors */ "A c #FFFFFF" ". c #000000" /* icon for state 1 */ "AAA............................" "AAAA..........................." "AAAAA.........................." ".AAAAA........................." "..AAAAA........................" "...AAAAA......................." "....AAAAA......................" ".....AAAAA....................." "......AAAAA...................." ".......AAAAA..................." "........AAAAA.................." ".........AAAAA................." "..........AAAAA................" "...........AAAAA..............." "............AAAAA.............." ".............AAAAA............." "..............AAAAA............" "...............AAAAA..........." "................AAAAA.........." ".................AAAAA........." "..................AAAAA........" "...................AAAAA......." "....................AAAAA......" ".....................AAAAA....." "......................AAAAA...." ".......................AAAAA..." "........................AAAAA.." ".........................AAAAA." "..........................AAAAA" "...........................AAAA" "............................AAA" /* icon for state 2 */ "............................AAA" "...........................AAAA" "..........................AAAAA" ".........................AAAAA." "........................AAAAA.." ".......................AAAAA..." "......................AAAAA...." ".....................AAAAA....." "....................AAAAA......" "...................AAAAA......." "..................AAAAA........" ".................AAAAA........." "................AAAAA.........." "...............AAAAA..........." "..............AAAAA............" ".............AAAAA............." "............AAAAA.............." "...........AAAAA..............." "..........AAAAA................" ".........AAAAA................." "........AAAAA.................." ".......AAAAA..................." "......AAAAA...................." ".....AAAAA....................." "....AAAAA......................" "...AAAAA......................." "..AAAAA........................" ".AAAAA........................." "AAAAA.........................." "AAAA..........................." "AAA............................" XPM /* width height num_colors chars_per_pixel */ "15 30 2 1" /* colors */ "A c #FFFFFF" ". c #000000" /* icon for state 1 */ "AA............." "AAA............" ".AAA..........." "..AAA.........." "...AAA........." "....AAA........" ".....AAA......." "......AAA......" ".......AAA....." "........AAA...." ".........AAA..." "..........AAA.." "...........AAA." "............AAA" ".............AA" /* icon for state 2 */ ".............AA" "............AAA" "...........AAA." "..........AAA.." ".........AAA..." "........AAA...." ".......AAA....." "......AAA......" ".....AAA......." "....AAA........" "...AAA........." "..AAA.........." ".AAA..........." "AAA............" "AA............." XPM /* width height num_colors chars_per_pixel */ "7 14 2 1" /* colors */ "A c #FFFFFF" ". c #000000" /* icon for state 1 */ "A......" ".A....." "..A...." "...A..." "....A.." ".....A." "......A" /* icon for state 2 */ "......A" ".....A." "....A.." "...A..." "..A...." ".A....." "A......" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Worm-complement.rule������������������������������������������������������������0000644�0001750�0001750�00000002565�12536111364�015300� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Worm-complement Paterson's worms - Erase solid regions, leaving only points with at least one uneaten edge, and the single point or line with an arrow. Use this with rules like 1252121 and 1525115, which fill regions with density near 100%, to see the uneaten paths within the regions: After running such a rule for a while, switch to this rule and run for 1 generation. (by Dean Hickerson, 11/20/2008) States: 0 empty (unvisited point or line) 1-6 'point with arrow', showing direction of next movement (1=E; 2=SE; 3=SW; 4=W; 5=NW; 6=NE) 7 point that's been visited 8,9,10 edge - (8=line; 9=E arrow; 10=W arrow) 11,12,13 edge / (11=line; 12=NE arrow; 13=SW arrow) 14,15,16 edge \ (14=line; 15=SE arrow; 16=NW arrow) @TABLE n_states:17 neighborhood:Moore symmetries:none var a0={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a1={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a2={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a3={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a4={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a5={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a6={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var a7={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16} var line={8,11,14} # visited point dies if it has 6 lines out from it 7,11,a0,8,a1,14,11,8,14,0 # undirected lines die line,a0,a1,a2,a3,a4,a5,a6,a7,0 �������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/TripATronMargolus_emulated.rule�������������������������������������������������0000644�0001750�0001750�00000003577�12536111364�017473� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE TripATronMargolus_emulated @TREE num_states=5 num_neighbors=8 num_nodes=114 1 0 2 2 4 4 1 0 1 2 3 4 2 0 1 0 1 0 2 1 1 1 1 1 1 0 2 1 4 3 2 0 1 4 1 4 3 2 3 5 3 5 3 3 3 3 3 3 3 5 3 5 3 5 4 6 7 8 7 8 4 7 7 7 7 7 2 4 1 4 1 4 3 2 3 11 3 11 3 11 3 11 3 11 4 12 7 13 7 13 5 9 10 14 10 14 1 0 1 1 3 3 2 16 1 16 1 16 3 17 3 17 3 17 4 18 7 18 7 18 5 19 10 19 10 19 1 0 4 2 4 4 2 0 1 21 1 0 3 2 3 22 3 2 4 23 7 23 7 23 5 24 10 24 10 24 1 0 2 2 2 4 2 0 1 0 1 26 3 2 3 2 3 27 4 28 7 28 7 28 5 29 10 29 10 29 6 15 20 25 20 30 5 10 10 10 10 10 6 20 20 32 20 32 3 2 3 2 3 2 1 0 1 4 3 4 2 1 1 35 1 1 3 36 36 3 36 3 4 34 37 34 7 34 5 38 10 38 10 38 4 23 37 23 7 23 5 40 10 40 10 40 4 28 37 28 7 28 5 42 10 42 10 42 6 39 32 41 32 43 1 0 1 2 3 2 2 1 1 1 1 45 3 46 46 3 46 3 4 34 7 34 47 34 5 48 10 48 10 48 4 23 7 23 47 23 5 50 10 50 10 50 4 28 7 28 47 28 5 52 10 52 10 52 6 49 32 51 32 53 7 31 33 44 33 54 6 32 32 32 32 32 7 33 33 56 33 56 4 34 7 34 7 34 2 35 35 1 35 1 3 3 3 59 3 3 4 60 7 60 7 60 5 58 61 58 10 58 5 24 61 24 10 24 5 29 61 29 10 29 6 62 32 63 32 64 5 38 61 38 10 38 5 40 61 40 10 40 5 42 61 42 10 42 6 66 32 67 32 68 5 48 61 48 10 48 5 50 61 50 10 50 5 52 61 52 10 52 6 70 32 71 32 72 7 65 56 69 56 73 2 45 45 1 45 1 3 3 3 3 3 75 4 76 7 76 7 76 5 58 10 58 77 58 5 24 10 24 77 24 5 29 10 29 77 29 6 78 32 79 32 80 5 38 10 38 77 38 5 40 10 40 77 40 5 42 10 42 77 42 6 82 32 83 32 84 5 48 10 48 77 48 5 50 10 50 77 50 5 52 10 52 77 52 6 86 32 87 32 88 7 81 56 85 56 89 8 55 57 74 57 90 1 0 1 3 3 3 2 92 1 92 1 92 3 93 3 93 3 93 4 18 7 94 7 18 5 19 10 95 10 19 6 96 96 32 96 32 7 97 97 56 97 56 7 56 56 56 56 56 8 98 98 99 98 99 5 58 10 58 10 58 6 101 32 25 32 30 7 102 56 44 56 54 8 103 99 74 99 90 1 0 1 1 3 1 2 105 1 105 1 105 3 106 3 106 3 106 4 18 7 18 7 107 5 19 10 19 10 108 6 109 109 32 109 32 7 110 110 56 110 56 8 111 111 99 111 99 9 91 100 104 112 104 @COLORS 1 90 90 90 2 62 62 62 3 0 255 127 4 0 178 88 ���������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/LangtonsAnt_LLRR.rule�����������������������������������������������������������0000644�0001750�0001750�00000071753�12536111364�015303� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE LangtonsAnt_LLRR @TREE num_states=20 num_neighbors=4 num_nodes=17 1 0 1 2 3 1 1 1 1 2 2 2 2 3 3 3 3 0 0 0 0 1 4 8 12 16 8 8 8 8 12 12 12 12 16 16 16 16 4 4 4 4 2 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 7 11 15 19 11 11 11 11 15 15 15 15 19 19 19 19 7 7 7 7 2 3 3 3 3 3 0 3 3 3 0 3 3 3 3 3 0 3 3 3 0 3 2 2 2 2 4 2 2 2 4 2 2 2 2 2 4 2 2 2 4 2 1 5 9 13 17 9 9 9 9 13 13 13 13 17 17 17 17 5 5 5 5 2 6 6 6 6 6 0 6 6 6 0 6 6 6 6 6 0 6 6 6 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 7 7 7 7 8 7 7 7 8 7 7 7 7 7 8 7 7 7 8 7 4 5 5 5 5 5 5 9 5 5 5 9 5 9 5 5 5 9 5 5 5 1 6 10 14 18 10 10 10 10 14 14 14 14 18 18 18 18 6 6 6 6 2 11 11 11 11 11 0 11 11 11 0 11 11 11 11 11 0 11 11 11 0 3 12 12 12 12 8 12 12 12 8 12 12 12 12 12 8 12 12 12 8 12 3 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 4 13 13 13 13 13 13 14 13 13 13 14 13 14 13 13 13 14 13 13 13 5 10 10 10 10 10 10 10 15 10 10 10 15 10 15 10 10 10 15 10 10 @COLORS 0 0 0 0 1 0 155 67 2 127 0 255 3 128 128 128 4 186 185 102 5 186 185 102 6 186 185 102 7 186 185 102 8 32 160 73 9 32 160 73 10 32 160 73 11 32 160 73 12 137 32 228 13 137 32 228 14 137 32 228 15 137 32 228 16 138 138 123 17 138 138 123 18 138 138 123 19 138 138 123 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 589 10 1" /* colors */ "A c #009B43" "B c #7F00FF" "C c #808080" ". c #000000" "E c #B9B860" "F c #5C5C30" "G c #5CA951" "H c #9C5CAF" "I c #9C9C70" "J c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 3 */ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" /* icon for state 4 */ "..............................." ".......E...............E......." ".......E...............E......." "........E.............E........" "........E.............E........" ".........EEEJJEEEJJEEE........." "............JJEEEJJ............" ".............EEEEE............." "........EE....EEE....EE........" ".........EE...EEE...EE........." "..........EE..EEE..EE.........." "...........EEEEEEEEE..........." "............EEEEEEE............" "..............EEE.............." "..............EEE.............." "...........EEEEEEEEE..........." "..........EEEEEEEEEEE.........." ".........EE...EEE...EE........." "........EE....EEE....EE........" ".............EEEEE............." "............EEEEEEE............" "...........EE.EEE.EE..........." "..........EE..EEE..EE.........." ".........EE...EEE...EE........." "........EE...FEEEF...EE........" ".............EEEEE............." ".............EEEEE............." ".............FEEEF............." "..............EEE.............." "..............................." "..............................." /* icon for state 5 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................EE." "......E.....E.........E...EE..." "......EE....EE.......EE..E....." ".......EE....EE.....EE...E....." "........EE....EE...EE....E....." ".........EE...EE..EE....JJ....." "...FEEF...EE..EE..EE...EJJ....." "..EEEEEEEEEEEEEEEEEEEEEEEE....." "..EEEEEEEEEEEEEEEEEEEEEEEE....." "..EEEEEEEEEEEEEEEEEEEEEEEE....." "...FEEF...EE..EE..EE...EJJ....." ".........EE...EE..EE....JJ....." "........EE....EE...EE....E....." ".......EE....EE.....EE...E....." "......EE....EE.......EE..E....." "......E.....E.........E...EE..." "............................EE." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 6 */ "..............................." "..............................." "..............EEE.............." ".............FEEEF............." ".............EEEEE............." ".............EEEEE............." "........EE...FEEEF...EE........" ".........EE...EEE...EE........." "..........EE..EEE..EE.........." "...........EE.EEE.EE..........." "............EEEEEEE............" ".............EEEEE............." "........EE....EEE....EE........" ".........EE...EEE...EE........." "..........EEEEEEEEEEE.........." "...........EEEEEEEEE..........." "..............EEE.............." "..............EEE.............." "............EEEEEEE............" "...........EEEEEEEEE..........." "..........EE..EEE..EE.........." ".........EE...EEE...EE........." "........EE....EEE....EE........" ".............EEEEE............." "............JJEEEJJ............" ".........EEEJJEEEJJEEE........." "........E.............E........" "........E.............E........" ".......E...............E......." ".......E...............E......." "..............................." /* icon for state 7 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".EE............................" "...EE...E.........E.....E......" ".....E..EE.......EE....EE......" ".....E...EE.....EE....EE......." ".....E....EE...EE....EE........" ".....JJ....EE..EE...EE........." ".....JJE...EE..EE..EE...FEEF..." ".....EEEEEEEEEEEEEEEEEEEEEEEE.." ".....EEEEEEEEEEEEEEEEEEEEEEEE.." ".....EEEEEEEEEEEEEEEEEEEEEEEE.." ".....JJE...EE..EE..EE...FEEF..." ".....JJ....EE..EE...EE........." ".....E....EE...EE....EE........" ".....E...EE.....EE....EE......." ".....E..EE.......EE....EE......" "...EE...E.........E.....E......" ".EE............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 8 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAEAAAAAAAAAAAAAAAEAAAAAAA" "AAAAAAAEAAAAAAAAAAAAAAAEAAAAAAA" "AAAAAAAAEAAAAAAAAAAAAAEAAAAAAAA" "AAAAAAAAEAAAAAAAAAAAAAEAAAAAAAA" "AAAAAAAAAEEEJJEEEJJEEEAAAAAAAAA" "AAAAAAAAAAAAJJEEEJJAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAEEAAAAEEEAAAAEEAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAAAEEAAEEEAAEEAAAAAAAAAA" "AAAAAAAAAAAEEEEEEEEEAAAAAAAAAAA" "AAAAAAAAAAAAEEEEEEEAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAEEEEEEEEEAAAAAAAAAAA" "AAAAAAAAAAEEEEEEEEEEEAAAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAEEAAAAEEEAAAAEEAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAEEEEEEEAAAAAAAAAAAA" "AAAAAAAAAAAEEAEEEAEEAAAAAAAAAAA" "AAAAAAAAAAEEAAEEEAAEEAAAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAEEAAAGEEEGAAAEEAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAAGEEEGAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 9 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAEEA" "AAAAAAEAAAAAEAAAAAAAAAEAAAEEAAA" "AAAAAAEEAAAAEEAAAAAAAEEAAEAAAAA" "AAAAAAAEEAAAAEEAAAAAEEAAAEAAAAA" "AAAAAAAAEEAAAAEEAAAEEAAAAEAAAAA" "AAAAAAAAAEEAAAEEAAEEAAAAJJAAAAA" "AAAGEEGAAAEEAAEEAAEEAAAEJJAAAAA" "AAEEEEEEEEEEEEEEEEEEEEEEEEAAAAA" "AAEEEEEEEEEEEEEEEEEEEEEEEEAAAAA" "AAEEEEEEEEEEEEEEEEEEEEEEEEAAAAA" "AAAGEEGAAAEEAAEEAAEEAAAEJJAAAAA" "AAAAAAAAAEEAAAEEAAEEAAAAJJAAAAA" "AAAAAAAAEEAAAAEEAAAEEAAAAEAAAAA" "AAAAAAAEEAAAAEEAAAAAEEAAAEAAAAA" "AAAAAAEEAAAAEEAAAAAAAEEAAEAAAAA" "AAAAAAEAAAAAEAAAAAAAAAEAAAEEAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAEEA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 10 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAAGEEEGAAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAEEAAAGEEEGAAAEEAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAAAEEAAEEEAAEEAAAAAAAAAA" "AAAAAAAAAAAEEAEEEAEEAAAAAAAAAAA" "AAAAAAAAAAAAEEEEEEEAAAAAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAEEAAAAEEEAAAAEEAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAAAEEEEEEEEEEEAAAAAAAAAA" "AAAAAAAAAAAEEEEEEEEEAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAEEEAAAAAAAAAAAAAA" "AAAAAAAAAAAAEEEEEEEAAAAAAAAAAAA" "AAAAAAAAAAAEEEEEEEEEAAAAAAAAAAA" "AAAAAAAAAAEEAAEEEAAEEAAAAAAAAAA" "AAAAAAAAAEEAAAEEEAAAEEAAAAAAAAA" "AAAAAAAAEEAAAAEEEAAAAEEAAAAAAAA" "AAAAAAAAAAAAAEEEEEAAAAAAAAAAAAA" "AAAAAAAAAAAAJJEEEJJAAAAAAAAAAAA" "AAAAAAAAAEEEJJEEEJJEEEAAAAAAAAA" "AAAAAAAAEAAAAAAAAAAAAAEAAAAAAAA" "AAAAAAAAEAAAAAAAAAAAAAEAAAAAAAA" "AAAAAAAEAAAAAAAAAAAAAAAEAAAAAAA" "AAAAAAAEAAAAAAAAAAAAAAAEAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 11 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AEEAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAEEAAAEAAAAAAAAAEAAAAAEAAAAAA" "AAAAAEAAEEAAAAAAAEEAAAAEEAAAAAA" "AAAAAEAAAEEAAAAAEEAAAAEEAAAAAAA" "AAAAAEAAAAEEAAAEEAAAAEEAAAAAAAA" "AAAAAJJAAAAEEAAEEAAAEEAAAAAAAAA" "AAAAAJJEAAAEEAAEEAAEEAAAGEEGAAA" "AAAAAEEEEEEEEEEEEEEEEEEEEEEEEAA" "AAAAAEEEEEEEEEEEEEEEEEEEEEEEEAA" "AAAAAEEEEEEEEEEEEEEEEEEEEEEEEAA" "AAAAAJJEAAAEEAAEEAAEEAAAGEEGAAA" "AAAAAJJAAAAEEAAEEAAAEEAAAAAAAAA" "AAAAAEAAAAEEAAAEEAAAAEEAAAAAAAA" "AAAAAEAAAEEAAAAAEEAAAAEEAAAAAAA" "AAAAAEAAEEAAAAAAAEEAAAAEEAAAAAA" "AAAEEAAAEAAAAAAAAAEAAAAAEAAAAAA" "AEEAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 12 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBEBBBBBBBBBBBBBBBEBBBBBBB" "BBBBBBBEBBBBBBBBBBBBBBBEBBBBBBB" "BBBBBBBBEBBBBBBBBBBBBBEBBBBBBBB" "BBBBBBBBEBBBBBBBBBBBBBEBBBBBBBB" "BBBBBBBBBEEEJJEEEJJEEEBBBBBBBBB" "BBBBBBBBBBBBJJEEEJJBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBEEBBBBEEEBBBBEEBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBBBEEBBEEEBBEEBBBBBBBBBB" "BBBBBBBBBBBEEEEEEEEEBBBBBBBBBBB" "BBBBBBBBBBBBEEEEEEEBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBEEEEEEEEEBBBBBBBBBBB" "BBBBBBBBBBEEEEEEEEEEEBBBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBEEBBBBEEEBBBBEEBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBEEEEEEEBBBBBBBBBBBB" "BBBBBBBBBBBEEBEEEBEEBBBBBBBBBBB" "BBBBBBBBBBEEBBEEEBBEEBBBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBEEBBBHEEEHBBBEEBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBBHEEEHBBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 13 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBEEB" "BBBBBBEBBBBBEBBBBBBBBBEBBBEEBBB" "BBBBBBEEBBBBEEBBBBBBBEEBBEBBBBB" "BBBBBBBEEBBBBEEBBBBBEEBBBEBBBBB" "BBBBBBBBEEBBBBEEBBBEEBBBBEBBBBB" "BBBBBBBBBEEBBBEEBBEEBBBBJJBBBBB" "BBBHEEHBBBEEBBEEBBEEBBBEJJBBBBB" "BBEEEEEEEEEEEEEEEEEEEEEEEEBBBBB" "BBEEEEEEEEEEEEEEEEEEEEEEEEBBBBB" "BBEEEEEEEEEEEEEEEEEEEEEEEEBBBBB" "BBBHEEHBBBEEBBEEBBEEBBBEJJBBBBB" "BBBBBBBBBEEBBBEEBBEEBBBBJJBBBBB" "BBBBBBBBEEBBBBEEBBBEEBBBBEBBBBB" "BBBBBBBEEBBBBEEBBBBBEEBBBEBBBBB" "BBBBBBEEBBBBEEBBBBBBBEEBBEBBBBB" "BBBBBBEBBBBBEBBBBBBBBBEBBBEEBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBEEB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 14 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBBHEEEHBBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBEEBBBHEEEHBBBEEBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBBBEEBBEEEBBEEBBBBBBBBBB" "BBBBBBBBBBBEEBEEEBEEBBBBBBBBBBB" "BBBBBBBBBBBBEEEEEEEBBBBBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBEEBBBBEEEBBBBEEBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBBBEEEEEEEEEEEBBBBBBBBBB" "BBBBBBBBBBBEEEEEEEEEBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBEEEBBBBBBBBBBBBBB" "BBBBBBBBBBBBEEEEEEEBBBBBBBBBBBB" "BBBBBBBBBBBEEEEEEEEEBBBBBBBBBBB" "BBBBBBBBBBEEBBEEEBBEEBBBBBBBBBB" "BBBBBBBBBEEBBBEEEBBBEEBBBBBBBBB" "BBBBBBBBEEBBBBEEEBBBBEEBBBBBBBB" "BBBBBBBBBBBBBEEEEEBBBBBBBBBBBBB" "BBBBBBBBBBBBJJEEEJJBBBBBBBBBBBB" "BBBBBBBBBEEEJJEEEJJEEEBBBBBBBBB" "BBBBBBBBEBBBBBBBBBBBBBEBBBBBBBB" "BBBBBBBBEBBBBBBBBBBBBBEBBBBBBBB" "BBBBBBBEBBBBBBBBBBBBBBBEBBBBBBB" "BBBBBBBEBBBBBBBBBBBBBBBEBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 15 */ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BEEBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBEEBBBEBBBBBBBBBEBBBBBEBBBBBB" "BBBBBEBBEEBBBBBBBEEBBBBEEBBBBBB" "BBBBBEBBBEEBBBBBEEBBBBEEBBBBBBB" "BBBBBEBBBBEEBBBEEBBBBEEBBBBBBBB" "BBBBBJJBBBBEEBBEEBBBEEBBBBBBBBB" "BBBBBJJEBBBEEBBEEBBEEBBBHEEHBBB" "BBBBBEEEEEEEEEEEEEEEEEEEEEEEEBB" "BBBBBEEEEEEEEEEEEEEEEEEEEEEEEBB" "BBBBBEEEEEEEEEEEEEEEEEEEEEEEEBB" "BBBBBJJEBBBEEBBEEBBEEBBBHEEHBBB" "BBBBBJJBBBBEEBBEEBBBEEBBBBBBBBB" "BBBBBEBBBBEEBBBEEBBBBEEBBBBBBBB" "BBBBBEBBBEEBBBBBEEBBBBEEBBBBBBB" "BBBBBEBBEEBBBBBBBEEBBBBEEBBBBBB" "BBBEEBBBEBBBBBBBBBEBBBBBEBBBBBB" "BEEBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" /* icon for state 16 */ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCECCCCCCCCCCCCCCCECCCCCCC" "CCCCCCCECCCCCCCCCCCCCCCECCCCCCC" "CCCCCCCCECCCCCCCCCCCCCECCCCCCCC" "CCCCCCCCECCCCCCCCCCCCCECCCCCCCC" "CCCCCCCCCEEEJJEEEJJEEECCCCCCCCC" "CCCCCCCCCCCCJJEEEJJCCCCCCCCCCCC" "CCCCCCCCCCCCCEEEEECCCCCCCCCCCCC" "CCCCCCCCEECCCCEEECCCCEECCCCCCCC" "CCCCCCCCCEECCCEEECCCEECCCCCCCCC" "CCCCCCCCCCEECCEEECCEECCCCCCCCCC" "CCCCCCCCCCCEEEEEEEEECCCCCCCCCCC" "CCCCCCCCCCCCEEEEEEECCCCCCCCCCCC" "CCCCCCCCCCCCCCEEECCCCCCCCCCCCCC" "CCCCCCCCCCCCCCEEECCCCCCCCCCCCCC" "CCCCCCCCCCCEEEEEEEEECCCCCCCCCCC" "CCCCCCCCCCEEEEEEEEEEECCCCCCCCCC" "CCCCCCCCCEECCCEEECCCEECCCCCCCCC" "CCCCCCCCEECCCCEEECCCCEECCCCCCCC" "CCCCCCCCCCCCCEEEEECCCCCCCCCCCCC" "CCCCCCCCCCCCEEEEEEECCCCCCCCCCCC" "CCCCCCCCCCCEECEEECEECCCCCCCCCCC" "CCCCCCCCCCEECCEEECCEECCCCCCCCCC" "CCCCCCCCCEECCCEEECCCEECCCCCCCCC" "CCCCCCCCEECCCIEEEICCCEECCCCCCCC" "CCCCCCCCCCCCCEEEEECCCCCCCCCCCCC" "CCCCCCCCCCCCCEEEEECCCCCCCCCCCCC" "CCCCCCCCCCCCCIEEEICCCCCCCCCCCCC" "CCCCCCCCCCCCCCEEECCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" /* icon for state 17 */ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCEEC" "CCCCCCECCCCCECCCCCCCCCECCCEECCC" "CCCCCCEECCCCEECCCCCCCEECCECCCCC" "CCCCCCCEECCCCEECCCCCEECCCECCCCC" "CCCCCCCCEECCCCEECCCEECCCCECCCCC" "CCCCCCCCCEECCCEECCEECCCCJJCCCCC" "CCCIEEICCCEECCEECCEECCCEJJCCCCC" "CCEEEEEEEEEEEEEEEEEEEEEEEECCCCC" "CCEEEEEEEEEEEEEEEEEEEEEEEECCCCC" "CCEEEEEEEEEEEEEEEEEEEEEEEECCCCC" "CCCIEEICCCEECCEECCEECCCEJJCCCCC" "CCCCCCCCCEECCCEECCEECCCCJJCCCCC" "CCCCCCCCEECCCCEECCCEECCCCECCCCC" "CCCCCCCEECCCCEECCCCCEECCCECCCCC" "CCCCCCEECCCCEECCCCCCCEECCECCCCC" "CCCCCCECCCCCECCCCCCCCCECCCEECCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCEEC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" /* icon for state 18 */ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCEEECCCCCCCCCCCCCC" "CCCCCCCCCCCCCIEEEICCCCCCCCCCCCC" "CCCCCCCCCCCCCEEEEECCCCCCCCCCCCC" "CCCCCCCCCCCCCEEEEECCCCCCCCCCCCC" "CCCCCCCCEECCCIEEEICCCEECCCCCCCC" "CCCCCCCCCEECCCEEECCCEECCCCCCCCC" "CCCCCCCCCCEECCEEECCEECCCCCCCCCC" "CCCCCCCCCCCEECEEECEECCCCCCCCCCC" "CCCCCCCCCCCCEEEEEEECCCCCCCCCCCC" "CCCCCCCCCCCCCEEEEECCCCCCCCCCCCC" "CCCCCCCCEECCCCEEECCCCEECCCCCCCC" "CCCCCCCCCEECCCEEECCCEECCCCCCCCC" "CCCCCCCCCCEEEEEEEEEEECCCCCCCCCC" "CCCCCCCCCCCEEEEEEEEECCCCCCCCCCC" "CCCCCCCCCCCCCCEEECCCCCCCCCCCCCC" "CCCCCCCCCCCCCCEEECCCCCCCCCCCCCC" "CCCCCCCCCCCCEEEEEEECCCCCCCCCCCC" "CCCCCCCCCCCEEEEEEEEECCCCCCCCCCC" "CCCCCCCCCCEECCEEECCEECCCCCCCCCC" "CCCCCCCCCEECCCEEECCCEECCCCCCCCC" "CCCCCCCCEECCCCEEECCCCEECCCCCCCC" "CCCCCCCCCCCCCEEEEECCCCCCCCCCCCC" "CCCCCCCCCCCCJJEEEJJCCCCCCCCCCCC" "CCCCCCCCCEEEJJEEEJJEEECCCCCCCCC" "CCCCCCCCECCCCCCCCCCCCCECCCCCCCC" "CCCCCCCCECCCCCCCCCCCCCECCCCCCCC" "CCCCCCCECCCCCCCCCCCCCCCECCCCCCC" "CCCCCCCECCCCCCCCCCCCCCCECCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" /* icon for state 19 */ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CEECCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCEECCCECCCCCCCCCECCCCCECCCCCC" "CCCCCECCEECCCCCCCEECCCCEECCCCCC" "CCCCCECCCEECCCCCEECCCCEECCCCCCC" "CCCCCECCCCEECCCEECCCCEECCCCCCCC" "CCCCCJJCCCCEECCEECCCEECCCCCCCCC" "CCCCCJJECCCEECCEECCEECCCIEEICCC" "CCCCCEEEEEEEEEEEEEEEEEEEEEEEECC" "CCCCCEEEEEEEEEEEEEEEEEEEEEEEECC" "CCCCCEEEEEEEEEEEEEEEEEEEEEEEECC" "CCCCCJJECCCEECCEECCEECCCIEEICCC" "CCCCCJJCCCCEECCEECCCEECCCCCCCCC" "CCCCCECCCCEECCCEECCCCEECCCCCCCC" "CCCCCECCCEECCCCCEECCCCEECCCCCCC" "CCCCCECCEECCCCCCCEECCCCEECCCCCC" "CCCEECCCECCCCCCCCCECCCCCECCCCCC" "CEECCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" XPM /* width height num_colors chars_per_pixel */ "15 285 10 1" /* colors */ "A c #009B43" "B c #7F00FF" "C c #808080" ". c #000000" "E c #B9B860" "F c #5C5C30" "G c #5CA951" "H c #9C5CAF" "I c #9C9C70" "J c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 3 */ "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" /* icon for state 4 */ "....E.....E...." ".....E...E....." "......JEJ......" "...E..EEE..E..." "....E..E..E...." ".....EEEEE....." ".......E......." "....EEEEEEE...." "...E...E...E..." ".....EEEEE....." "....E..E..E...." "...E..FEF..E..." "......EEE......" "......FEF......" "..............." /* icon for state 5 */ "..............." "..............." "..............." "...E..E....E..." "....E..E..E...E" ".....E.E.E...E." ".FEF.E.E.E.EJ.." ".EEEEEEEEEEEE.." ".FEF.E.E.E.EJ.." ".....E.E.E...E." "....E..E..E...E" "...E..E....E..." "..............." "..............." "..............." /* icon for state 6 */ "..............." "......FEF......" "......EEE......" "...E..FEF..E..." "....E..E..E...." ".....EEEEE....." "...E...E...E..." "....EEEEEEE...." ".......E......." ".....EEEEE....." "....E..E..E...." "...E..EEE..E..." "......JEJ......" ".....E...E....." "....E.....E...." /* icon for state 7 */ "..............." "..............." "..............." "...E....E..E..." "E...E..E..E...." ".E...E.E.E....." "..JE.E.E.E.FEF." "..EEEEEEEEEEEE." "..JE.E.E.E.FEF." ".E...E.E.E....." "E...E..E..E...." "...E....E..E..." "..............." "..............." "..............." /* icon for state 8 */ "AAAAEAAAAAEAAAA" "AAAAAEAAAEAAAAA" "AAAAAAJEJAAAAAA" "AAAEAAEEEAAEAAA" "AAAAEAAEAAEAAAA" "AAAAAEEEEEAAAAA" "AAAAAAAEAAAAAAA" "AAAAEEEEEEEAAAA" "AAAEAAAEAAAEAAA" "AAAAAEEEEEAAAAA" "AAAAEAAEAAEAAAA" "AAAEAAGEGAAEAAA" "AAAAAAEEEAAAAAA" "AAAAAAGEGAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 9 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAEAAEAAAAEAAA" "AAAAEAAEAAEAAAE" "AAAAAEAEAEAAAEA" "AGEGAEAEAEAEJAA" "AEEEEEEEEEEEEAA" "AGEGAEAEAEAEJAA" "AAAAAEAEAEAAAEA" "AAAAEAAEAAEAAAE" "AAAEAAEAAAAEAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 10 */ "AAAAAAAAAAAAAAA" "AAAAAAGEGAAAAAA" "AAAAAAEEEAAAAAA" "AAAEAAGEGAAEAAA" "AAAAEAAEAAEAAAA" "AAAAAEEEEEAAAAA" "AAAEAAAEAAAEAAA" "AAAAEEEEEEEAAAA" "AAAAAAAEAAAAAAA" "AAAAAEEEEEAAAAA" "AAAAEAAEAAEAAAA" "AAAEAAEEEAAEAAA" "AAAAAAJEJAAAAAA" "AAAAAEAAAEAAAAA" "AAAAEAAAAAEAAAA" /* icon for state 11 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAEAAAAEAAEAAA" "EAAAEAAEAAEAAAA" "AEAAAEAEAEAAAAA" "AAJEAEAEAEAGEGA" "AAEEEEEEEEEEEEA" "AAJEAEAEAEAGEGA" "AEAAAEAEAEAAAAA" "EAAAEAAEAAEAAAA" "AAAEAAAAEAAEAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 12 */ "BBBBEBBBBBEBBBB" "BBBBBEBBBEBBBBB" "BBBBBBJEJBBBBBB" "BBBEBBEEEBBEBBB" "BBBBEBBEBBEBBBB" "BBBBBEEEEEBBBBB" "BBBBBBBEBBBBBBB" "BBBBEEEEEEEBBBB" "BBBEBBBEBBBEBBB" "BBBBBEEEEEBBBBB" "BBBBEBBEBBEBBBB" "BBBEBBHEHBBEBBB" "BBBBBBEEEBBBBBB" "BBBBBBHEHBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 13 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBEBBEBBBBEBBB" "BBBBEBBEBBEBBBE" "BBBBBEBEBEBBBEB" "BHEHBEBEBEBEJBB" "BEEEEEEEEEEEEBB" "BHEHBEBEBEBEJBB" "BBBBBEBEBEBBBEB" "BBBBEBBEBBEBBBE" "BBBEBBEBBBBEBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 14 */ "BBBBBBBBBBBBBBB" "BBBBBBHEHBBBBBB" "BBBBBBEEEBBBBBB" "BBBEBBHEHBBEBBB" "BBBBEBBEBBEBBBB" "BBBBBEEEEEBBBBB" "BBBEBBBEBBBEBBB" "BBBBEEEEEEEBBBB" "BBBBBBBEBBBBBBB" "BBBBBEEEEEBBBBB" "BBBBEBBEBBEBBBB" "BBBEBBEEEBBEBBB" "BBBBBBJEJBBBBBB" "BBBBBEBBBEBBBBB" "BBBBEBBBBBEBBBB" /* icon for state 15 */ "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBEBBBBEBBEBBB" "EBBBEBBEBBEBBBB" "BEBBBEBEBEBBBBB" "BBJEBEBEBEBHEHB" "BBEEEEEEEEEEEEB" "BBJEBEBEBEBHEHB" "BEBBBEBEBEBBBBB" "EBBBEBBEBBEBBBB" "BBBEBBBBEBBEBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB" /* icon for state 16 */ "CCCCECCCCCECCCC" "CCCCCECCCECCCCC" "CCCCCCJEJCCCCCC" "CCCECCEEECCECCC" "CCCCECCECCECCCC" "CCCCCEEEEECCCCC" "CCCCCCCECCCCCCC" "CCCCEEEEEEECCCC" "CCCECCCECCCECCC" "CCCCCEEEEECCCCC" "CCCCECCECCECCCC" "CCCECCIEICCECCC" "CCCCCCEEECCCCCC" "CCCCCCIEICCCCCC" "CCCCCCCCCCCCCCC" /* icon for state 17 */ "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCECCECCCCECCC" "CCCCECCECCECCCE" "CCCCCECECECCCEC" "CIEICECECECEJCC" "CEEEEEEEEEEEECC" "CIEICECECECEJCC" "CCCCCECECECCCEC" "CCCCECCECCECCCE" "CCCECCECCCCECCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" /* icon for state 18 */ "CCCCCCCCCCCCCCC" "CCCCCCIEICCCCCC" "CCCCCCEEECCCCCC" "CCCECCIEICCECCC" "CCCCECCECCECCCC" "CCCCCEEEEECCCCC" "CCCECCCECCCECCC" "CCCCEEEEEEECCCC" "CCCCCCCECCCCCCC" "CCCCCEEEEECCCCC" "CCCCECCECCECCCC" "CCCECCEEECCECCC" "CCCCCCJEJCCCCCC" "CCCCCECCCECCCCC" "CCCCECCCCCECCCC" /* icon for state 19 */ "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCECCCCECCECCC" "ECCCECCECCECCCC" "CECCCECECECCCCC" "CCJECECECECIEIC" "CCEEEEEEEEEEEEC" "CCJECECECECIEIC" "CECCCECECECCCCC" "ECCCECCECCECCCC" "CCCECCCCECCECCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" "CCCCCCCCCCCCCCC" XPM /* width height num_colors chars_per_pixel */ "7 133 10 1" /* colors */ "A c #009B43" "B c #7F00FF" "C c #808080" ". c #000000" "E c #B9B860" "F c #5C5C30" "G c #5CA951" "H c #9C5CAF" "I c #9C9C70" "J c #FFFFFF" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" "BBBBBBB" /* icon for state 3 */ "CCCCCCC" "CCCCCCC" "CCCCCCC" "CCCCCCC" "CCCCCCC" "CCCCCCC" "CCCCCCC" /* icon for state 4 */ ".E...E." "..JEJ.." "...E..." ".EEEEE." "...E..." ".EEEEE." "...E..." /* icon for state 5 */ "......." ".E.E..E" ".E.E.J." "EEEEEE." ".E.E.J." ".E.E..E" "......." /* icon for state 6 */ "...E..." ".EEEEE." "...E..." ".EEEEE." "...E..." "..JEJ.." ".E...E." /* icon for state 7 */ "......." "E..E.E." ".J.E.E." ".EEEEEE" ".J.E.E." "E..E.E." "......." /* icon for state 8 */ "AEAAAEA" "AAJEJAA" "AAAEAAA" "AEEEEEA" "AAAEAAA" "AEEEEEA" "AAAEAAA" /* icon for state 9 */ "AAAAAAA" "AEAEAAE" "AEAEAJA" "EEEEEEA" "AEAEAJA" "AEAEAAE" "AAAAAAA" /* icon for state 10 */ "AAAEAAA" "AEEEEEA" "AAAEAAA" "AEEEEEA" "AAAEAAA" "AAJEJAA" "AEAAAEA" /* icon for state 11 */ "AAAAAAA" "EAAEAEA" "AJAEAEA" "AEEEEEE" "AJAEAEA" "EAAEAEA" "AAAAAAA" /* icon for state 12 */ "BEBBBEB" "BBJEJBB" "BBBEBBB" "BEEEEEB" "BBBEBBB" "BEEEEEB" "BBBEBBB" /* icon for state 13 */ "BBBBBBB" "BEBEBBE" "BEBEBJB" "EEEEEEB" "BEBEBJB" "BEBEBBE" "BBBBBBB" /* icon for state 14 */ "BBBEBBB" "BEEEEEB" "BBBEBBB" "BEEEEEB" "BBBEBBB" "BBJEJBB" "BEBBBEB" /* icon for state 15 */ "BBBBBBB" "EBBEBEB" "BJBEBEB" "BEEEEEE" "BJBEBEB" "EBBEBEB" "BBBBBBB" /* icon for state 16 */ "CECCCEC" "CCJEJCC" "CCCECCC" "CEEEEEC" "CCCECCC" "CEEEEEC" "CCCECCC" /* icon for state 17 */ "CCCCCCC" "CECECCE" "CECECJC" "EEEEEEC" "CECECJC" "CECECCE" "CCCCCCC" /* icon for state 18 */ "CCCECCC" "CEEEEEC" "CCCECCC" "CEEEEEC" "CCCECCC" "CCJEJCC" "CECCCEC" /* icon for state 19 */ "CCCCCCC" "ECCECEC" "CJCECEC" "CEEEEEE" "CJCECEC" "ECCECEC" "CCCCCCC" ���������������������golly-2.7-src/Rules/TMGasMargolus_emulated.rule�����������������������������������������������������0000644�0001750�0001750�00000024217�12536111364�016556� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE TMGasMargolus_emulated @TREE num_states=9 num_neighbors=8 num_nodes=340 1 0 2 2 4 4 6 6 8 8 1 0 1 2 3 4 5 6 7 8 2 0 1 0 1 0 1 0 1 0 2 1 1 1 1 1 1 1 1 1 1 0 2 1 4 3 6 5 8 7 2 0 1 4 1 4 1 4 1 4 3 2 3 5 3 5 3 5 3 5 3 3 3 3 3 3 3 3 3 3 3 5 3 5 3 5 3 5 3 5 4 6 7 8 7 8 7 8 7 8 4 7 7 7 7 7 7 7 7 7 2 4 1 4 1 4 1 4 1 4 3 2 3 11 3 11 3 11 3 11 3 11 3 11 3 11 3 11 3 11 4 12 7 13 7 13 7 13 7 13 5 9 10 14 10 14 10 14 10 14 1 0 1 1 3 3 5 5 7 7 2 16 1 16 1 16 1 16 1 16 3 17 3 17 3 17 3 17 3 17 4 18 7 18 7 18 7 18 7 18 5 19 10 19 10 19 10 19 10 19 1 0 2 2 4 4 2 6 2 8 1 0 2 2 4 4 8 6 6 8 1 0 8 2 4 4 8 6 8 8 1 0 2 2 4 4 6 6 2 8 2 0 1 21 1 22 1 23 1 24 1 0 2 2 4 4 8 6 8 8 1 0 2 2 4 4 6 6 6 8 2 0 1 22 1 22 1 26 1 27 1 0 2 2 4 4 2 6 8 8 2 0 1 29 1 26 1 26 1 0 1 0 6 2 4 4 6 6 6 8 2 0 1 31 1 27 1 0 1 27 3 2 3 25 3 28 3 30 3 32 4 33 7 33 7 33 7 33 7 33 5 34 10 34 10 34 10 34 10 34 2 0 1 26 1 26 1 26 1 0 2 0 1 27 1 27 1 0 1 27 3 2 3 28 3 28 3 36 3 37 4 38 7 38 7 38 7 38 7 38 5 39 10 39 10 39 10 39 10 39 2 0 1 26 1 26 1 23 1 0 2 0 1 29 1 26 1 23 1 0 3 2 3 41 3 36 3 42 3 2 4 43 7 43 7 43 7 43 7 43 5 44 10 44 10 44 10 44 10 44 2 0 1 27 1 27 1 0 1 24 2 0 1 31 1 27 1 0 1 31 3 2 3 46 3 37 3 2 3 47 4 48 7 48 7 48 7 48 7 48 5 49 10 49 10 49 10 49 10 49 6 15 20 35 20 40 20 45 20 50 5 10 10 10 10 10 10 10 10 10 6 20 20 52 20 52 20 52 20 52 3 2 3 2 3 2 3 2 3 2 1 0 1 2 3 4 5 2 7 2 1 0 1 2 3 4 5 8 7 6 1 0 1 2 3 4 5 2 7 8 1 0 1 6 3 4 5 6 7 6 2 1 1 55 1 56 1 57 1 58 3 59 59 3 59 3 59 3 59 3 1 0 1 2 3 4 5 8 7 8 1 0 1 2 3 4 5 6 7 6 2 1 1 56 1 56 1 61 1 62 3 63 63 3 63 3 63 3 63 3 1 0 1 8 3 4 5 8 7 8 2 1 1 65 1 61 1 61 1 1 3 66 66 3 66 3 66 3 66 3 1 0 1 2 3 4 5 6 7 2 2 1 1 68 1 62 1 1 1 62 3 69 69 3 69 3 69 3 69 3 4 54 60 54 64 54 67 54 70 54 5 71 10 71 10 71 10 71 10 71 4 33 60 33 64 33 67 33 70 33 5 73 10 73 10 73 10 73 10 73 4 38 60 38 64 38 67 38 70 38 5 75 10 75 10 75 10 75 10 75 4 43 60 43 64 43 67 43 70 43 5 77 10 77 10 77 10 77 10 77 4 48 60 48 64 48 67 48 70 48 5 79 10 79 10 79 10 79 10 79 6 72 52 74 52 76 52 78 52 80 2 1 1 61 1 61 1 61 1 1 3 82 82 3 82 3 82 3 82 3 2 1 1 62 1 62 1 1 1 62 3 84 84 3 84 3 84 3 84 3 4 54 64 54 64 54 83 54 85 54 5 86 10 86 10 86 10 86 10 86 4 33 64 33 64 33 83 33 85 33 5 88 10 88 10 88 10 88 10 88 4 38 64 38 64 38 83 38 85 38 5 90 10 90 10 90 10 90 10 90 4 43 64 43 64 43 83 43 85 43 5 92 10 92 10 92 10 92 10 92 4 48 64 48 64 48 83 48 85 48 5 94 10 94 10 94 10 94 10 94 6 87 52 89 52 91 52 93 52 95 2 1 1 61 1 61 1 57 1 1 3 97 97 3 97 3 97 3 97 3 2 1 1 65 1 61 1 65 1 1 3 99 99 3 99 3 99 3 99 3 4 54 98 54 83 54 100 54 7 54 5 101 10 101 10 101 10 101 10 101 4 33 98 33 83 33 100 33 7 33 5 103 10 103 10 103 10 103 10 103 4 38 98 38 83 38 100 38 7 38 5 105 10 105 10 105 10 105 10 105 4 43 98 43 83 43 100 43 7 43 5 107 10 107 10 107 10 107 10 107 4 48 98 48 83 48 100 48 7 48 5 109 10 109 10 109 10 109 10 109 6 102 52 104 52 106 52 108 52 110 2 1 1 62 1 62 1 1 1 58 3 112 112 3 112 3 112 3 112 3 2 1 1 68 1 62 1 1 1 58 3 114 114 3 114 3 114 3 114 3 4 54 113 54 85 54 7 54 115 54 5 116 10 116 10 116 10 116 10 116 4 33 113 33 85 33 7 33 115 33 5 118 10 118 10 118 10 118 10 118 4 38 113 38 85 38 7 38 115 38 5 120 10 120 10 120 10 120 10 120 4 43 113 43 85 43 7 43 115 43 5 122 10 122 10 122 10 122 10 122 4 48 113 48 85 48 7 48 115 48 5 124 10 124 10 124 10 124 10 124 6 117 52 119 52 121 52 123 52 125 7 51 53 81 53 96 53 111 53 126 6 52 52 52 52 52 52 52 52 52 7 53 53 128 53 128 53 128 53 128 4 54 7 54 7 54 7 54 7 54 2 55 55 1 55 1 55 1 55 1 2 56 56 1 56 1 56 1 56 1 2 65 65 1 65 1 65 1 65 1 2 68 68 1 68 1 68 1 68 1 3 3 3 131 3 132 3 133 3 134 4 135 7 135 7 135 7 135 7 135 2 61 61 1 61 1 61 1 61 1 2 62 62 1 62 1 62 1 62 1 3 3 3 132 3 132 3 137 3 138 4 139 7 139 7 139 7 139 7 139 2 57 57 1 57 1 57 1 57 1 3 3 3 141 3 137 3 137 3 3 4 142 7 142 7 142 7 142 7 142 2 58 58 1 58 1 58 1 58 1 3 3 3 144 3 138 3 3 3 138 4 145 7 145 7 145 7 145 7 145 5 130 136 130 140 130 143 130 146 130 5 34 136 34 140 34 143 34 146 34 5 39 136 39 140 39 143 39 146 39 5 44 136 44 140 44 143 44 146 44 5 49 136 49 140 49 143 49 146 49 6 147 52 148 52 149 52 150 52 151 5 71 136 71 140 71 143 71 146 71 5 73 136 73 140 73 143 73 146 73 5 75 136 75 140 75 143 75 146 75 5 77 136 77 140 77 143 77 146 77 5 79 136 79 140 79 143 79 146 79 6 153 52 154 52 155 52 156 52 157 5 86 136 86 140 86 143 86 146 86 5 88 136 88 140 88 143 88 146 88 5 90 136 90 140 90 143 90 146 90 5 92 136 92 140 92 143 92 146 92 5 94 136 94 140 94 143 94 146 94 6 159 52 160 52 161 52 162 52 163 5 101 136 101 140 101 143 101 146 101 5 103 136 103 140 103 143 103 146 103 5 105 136 105 140 105 143 105 146 105 5 107 136 107 140 107 143 107 146 107 5 109 136 109 140 109 143 109 146 109 6 165 52 166 52 167 52 168 52 169 5 116 136 116 140 116 143 116 146 116 5 118 136 118 140 118 143 118 146 118 5 120 136 120 140 120 143 120 146 120 5 122 136 122 140 122 143 122 146 122 5 124 136 124 140 124 143 124 146 124 6 171 52 172 52 173 52 174 52 175 7 152 128 158 128 164 128 170 128 176 3 3 3 137 3 137 3 137 3 3 4 178 7 178 7 178 7 178 7 178 3 3 3 138 3 138 3 3 3 138 4 180 7 180 7 180 7 180 7 180 5 130 140 130 140 130 179 130 181 130 5 34 140 34 140 34 179 34 181 34 5 39 140 39 140 39 179 39 181 39 5 44 140 44 140 44 179 44 181 44 5 49 140 49 140 49 179 49 181 49 6 182 52 183 52 184 52 185 52 186 5 71 140 71 140 71 179 71 181 71 5 73 140 73 140 73 179 73 181 73 5 75 140 75 140 75 179 75 181 75 5 77 140 77 140 77 179 77 181 77 5 79 140 79 140 79 179 79 181 79 6 188 52 189 52 190 52 191 52 192 5 86 140 86 140 86 179 86 181 86 5 88 140 88 140 88 179 88 181 88 5 90 140 90 140 90 179 90 181 90 5 92 140 92 140 92 179 92 181 92 5 94 140 94 140 94 179 94 181 94 6 194 52 195 52 196 52 197 52 198 5 101 140 101 140 101 179 101 181 101 5 103 140 103 140 103 179 103 181 103 5 105 140 105 140 105 179 105 181 105 5 107 140 107 140 107 179 107 181 107 5 109 140 109 140 109 179 109 181 109 6 200 52 201 52 202 52 203 52 204 5 116 140 116 140 116 179 116 181 116 5 118 140 118 140 118 179 118 181 118 5 120 140 120 140 120 179 120 181 120 5 122 140 122 140 122 179 122 181 122 5 124 140 124 140 124 179 124 181 124 6 206 52 207 52 208 52 209 52 210 7 187 128 193 128 199 128 205 128 211 3 3 3 137 3 137 3 133 3 3 4 213 7 213 7 213 7 213 7 213 3 3 3 141 3 137 3 133 3 3 4 215 7 215 7 215 7 215 7 215 5 130 214 130 179 130 216 130 10 130 5 34 214 34 179 34 216 34 10 34 5 39 214 39 179 39 216 39 10 39 5 44 214 44 179 44 216 44 10 44 5 49 214 49 179 49 216 49 10 49 6 217 52 218 52 219 52 220 52 221 5 71 214 71 179 71 216 71 10 71 5 73 214 73 179 73 216 73 10 73 5 75 214 75 179 75 216 75 10 75 5 77 214 77 179 77 216 77 10 77 5 79 214 79 179 79 216 79 10 79 6 223 52 224 52 225 52 226 52 227 5 86 214 86 179 86 216 86 10 86 5 88 214 88 179 88 216 88 10 88 5 90 214 90 179 90 216 90 10 90 5 92 214 92 179 92 216 92 10 92 5 94 214 94 179 94 216 94 10 94 6 229 52 230 52 231 52 232 52 233 5 101 214 101 179 101 216 101 10 101 5 103 214 103 179 103 216 103 10 103 5 105 214 105 179 105 216 105 10 105 5 107 214 107 179 107 216 107 10 107 5 109 214 109 179 109 216 109 10 109 6 235 52 236 52 237 52 238 52 239 5 116 214 116 179 116 216 116 10 116 5 118 214 118 179 118 216 118 10 118 5 120 214 120 179 120 216 120 10 120 5 122 214 122 179 122 216 122 10 122 5 124 214 124 179 124 216 124 10 124 6 241 52 242 52 243 52 244 52 245 7 222 128 228 128 234 128 240 128 246 3 3 3 138 3 138 3 3 3 134 4 248 7 248 7 248 7 248 7 248 3 3 3 144 3 138 3 3 3 144 4 250 7 250 7 250 7 250 7 250 5 130 249 130 181 130 10 130 251 130 5 34 249 34 181 34 10 34 251 34 5 39 249 39 181 39 10 39 251 39 5 44 249 44 181 44 10 44 251 44 5 49 249 49 181 49 10 49 251 49 6 252 52 253 52 254 52 255 52 256 5 71 249 71 181 71 10 71 251 71 5 73 249 73 181 73 10 73 251 73 5 75 249 75 181 75 10 75 251 75 5 77 249 77 181 77 10 77 251 77 5 79 249 79 181 79 10 79 251 79 6 258 52 259 52 260 52 261 52 262 5 86 249 86 181 86 10 86 251 86 5 88 249 88 181 88 10 88 251 88 5 90 249 90 181 90 10 90 251 90 5 92 249 92 181 92 10 92 251 92 5 94 249 94 181 94 10 94 251 94 6 264 52 265 52 266 52 267 52 268 5 101 249 101 181 101 10 101 251 101 5 103 249 103 181 103 10 103 251 103 5 105 249 105 181 105 10 105 251 105 5 107 249 107 181 107 10 107 251 107 5 109 249 109 181 109 10 109 251 109 6 270 52 271 52 272 52 273 52 274 5 116 249 116 181 116 10 116 251 116 5 118 249 118 181 118 10 118 251 118 5 120 249 120 181 120 10 120 251 120 5 122 249 122 181 122 10 122 251 122 5 124 249 124 181 124 10 124 251 124 6 276 52 277 52 278 52 279 52 280 7 257 128 263 128 269 128 275 128 281 8 127 129 177 129 212 129 247 129 282 1 0 1 1 3 3 5 1 7 1 2 284 1 284 1 284 1 284 1 284 3 285 3 285 3 285 3 285 3 285 1 0 1 1 3 3 5 7 7 5 2 287 1 287 1 287 1 287 1 287 3 288 3 288 3 288 3 288 3 288 1 0 1 1 3 3 5 1 7 7 2 290 1 290 1 290 1 290 1 290 3 291 3 291 3 291 3 291 3 291 1 0 1 5 3 3 5 5 7 5 2 293 1 293 1 293 1 293 1 293 3 294 3 294 3 294 3 294 3 294 4 18 7 286 7 289 7 292 7 295 1 0 1 1 3 3 5 7 7 7 2 297 1 297 1 297 1 297 1 297 3 298 3 298 3 298 3 298 3 298 1 0 1 1 3 3 5 5 7 5 2 300 1 300 1 300 1 300 1 300 3 301 3 301 3 301 3 301 3 301 4 18 7 289 7 289 7 299 7 302 1 0 1 7 3 3 5 7 7 7 2 304 1 304 1 304 1 304 1 304 3 305 3 305 3 305 3 305 3 305 4 18 7 306 7 299 7 299 7 18 1 0 1 1 3 3 5 5 7 1 2 308 1 308 1 308 1 308 1 308 3 309 3 309 3 309 3 309 3 309 4 18 7 310 7 302 7 18 7 302 5 19 10 296 10 303 10 307 10 311 6 312 312 52 312 52 312 52 312 52 7 313 313 128 313 128 313 128 313 128 7 128 128 128 128 128 128 128 128 128 8 314 314 315 314 315 314 315 314 315 5 130 10 130 10 130 10 130 10 130 6 317 52 35 52 40 52 45 52 50 7 318 128 81 128 96 128 111 128 126 8 319 315 177 315 212 315 247 315 282 4 18 7 299 7 299 7 299 7 18 4 18 7 302 7 302 7 18 7 302 5 19 10 303 10 303 10 321 10 322 6 323 323 52 323 52 323 52 323 52 7 324 324 128 324 128 324 128 324 128 8 325 325 315 325 315 325 315 325 315 4 18 7 299 7 299 7 292 7 18 4 18 7 306 7 299 7 306 7 18 5 19 10 327 10 321 10 328 10 19 6 329 329 52 329 52 329 52 329 52 7 330 330 128 330 128 330 128 330 128 8 331 331 315 331 315 331 315 331 315 4 18 7 302 7 302 7 18 7 295 4 18 7 310 7 302 7 18 7 295 5 19 10 333 10 322 10 19 10 334 6 335 335 52 335 52 335 52 335 52 7 336 336 128 336 128 336 128 336 128 8 337 337 315 337 315 337 315 337 315 9 283 316 320 326 320 332 320 338 320 @COLORS 1 90 90 90 2 62 62 62 3 0 255 127 4 0 178 88 5 255 255 255 6 220 220 220 7 255 255 0 8 220 220 0 ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Sand-square4cyclic_emulated.rule������������������������������������������������0000644�0001750�0001750�00000035032�12536111364�017524� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Sand-square4cyclic_emulated @TREE num_states=9 num_neighbors=8 num_nodes=460 1 0 1 1 3 3 5 5 7 7 1 0 1 2 3 4 5 6 7 8 2 0 1 0 1 0 1 0 1 0 1 0 2 1 4 3 6 5 8 7 1 0 2 2 4 4 6 6 8 8 2 3 4 3 4 3 4 3 4 3 2 1 1 0 1 0 1 0 1 0 3 2 5 6 5 6 5 6 5 6 2 1 1 1 1 1 1 1 1 1 3 5 5 8 5 8 5 8 5 8 3 6 8 6 8 6 8 6 8 6 4 7 9 10 9 10 9 10 9 10 2 4 4 1 4 1 4 1 4 1 3 8 12 8 12 8 12 8 12 8 3 12 12 8 12 8 12 8 12 8 3 8 8 8 8 8 8 8 8 8 4 13 14 15 14 15 14 15 14 15 2 3 1 3 1 3 1 3 1 3 3 2 17 2 17 2 17 2 17 2 3 17 17 8 17 8 17 8 17 8 3 2 8 2 8 2 8 2 8 2 4 18 19 20 19 20 19 20 19 20 5 11 16 21 16 21 16 21 16 21 2 0 1 3 1 3 1 3 1 3 1 0 1 2 3 2 5 6 7 8 2 4 24 4 24 4 24 4 24 4 2 4 24 4 1 4 1 4 1 4 3 23 25 2 26 2 26 2 26 2 2 4 1 4 1 4 1 4 1 4 3 28 25 8 26 8 26 8 26 8 4 27 29 20 29 20 29 20 29 20 2 1 24 1 24 1 24 1 24 1 2 1 24 1 1 1 1 1 1 1 3 8 31 8 32 8 32 8 32 8 4 33 33 15 33 15 33 15 33 15 3 17 28 2 28 2 28 2 28 2 3 28 28 8 28 8 28 8 28 8 4 35 36 20 36 20 36 20 36 20 5 30 34 37 34 37 34 37 34 37 2 0 4 0 4 0 4 0 4 0 2 3 4 0 4 0 4 0 4 0 1 0 1 2 1 4 5 6 7 8 2 1 1 41 1 41 1 41 1 41 2 1 1 41 1 1 1 1 1 1 3 39 40 42 40 43 40 43 40 43 3 40 40 8 40 8 40 8 40 8 3 8 8 42 8 43 8 43 8 43 4 44 45 46 45 46 45 46 45 46 4 14 14 15 14 15 14 15 14 15 3 2 2 42 2 43 2 43 2 43 3 2 2 8 2 8 2 8 2 8 4 49 50 46 50 46 50 46 50 46 5 47 48 51 48 51 48 51 48 51 3 23 26 2 26 2 26 2 26 2 3 28 26 8 26 8 26 8 26 8 4 53 54 20 54 20 54 20 54 20 3 8 32 8 32 8 32 8 32 8 4 56 56 15 56 15 56 15 56 15 5 55 57 37 57 37 57 37 57 37 3 39 40 43 40 43 40 43 40 43 3 8 8 43 8 43 8 43 8 43 4 59 45 60 45 60 45 60 45 60 3 2 2 43 2 43 2 43 2 43 4 62 50 60 50 60 50 60 50 60 5 61 48 63 48 63 48 63 48 63 6 22 38 52 58 64 58 64 58 64 3 23 28 2 28 2 28 2 28 2 2 0 41 0 41 0 41 0 41 0 3 67 8 67 8 67 8 67 8 67 2 0 41 0 1 0 1 0 1 0 3 69 8 69 8 69 8 69 8 69 4 66 36 68 36 70 36 70 36 70 2 1 41 1 41 1 41 1 41 1 3 72 8 72 8 72 8 72 8 72 2 1 41 1 1 1 1 1 1 1 3 74 8 74 8 74 8 74 8 74 4 15 15 73 15 75 15 75 15 75 5 71 76 37 76 37 76 37 76 37 4 27 29 68 29 70 29 70 29 70 4 33 33 73 33 75 33 75 33 75 5 78 79 37 79 37 79 37 79 37 4 15 15 15 15 15 15 15 15 15 5 81 81 81 81 81 81 81 81 81 4 53 54 68 54 70 54 70 54 70 4 56 56 73 56 75 56 75 56 75 5 83 84 37 84 37 84 37 84 37 6 77 80 82 85 82 85 82 85 82 3 39 40 8 40 8 40 8 40 8 1 0 1 1 3 1 5 5 7 7 2 3 4 88 4 88 4 88 4 88 3 89 89 8 89 8 89 8 89 8 2 3 4 88 4 0 4 0 4 0 3 91 91 8 91 8 91 8 91 8 4 87 90 15 92 15 92 15 92 15 2 0 1 88 1 88 1 88 1 88 3 94 94 8 94 8 94 8 94 8 2 0 1 88 1 0 1 0 1 0 3 96 96 8 96 8 96 8 96 8 4 50 95 15 97 15 97 15 97 15 5 93 48 98 48 98 48 98 48 98 4 44 90 46 92 46 92 46 92 46 4 49 95 46 97 46 97 46 97 46 5 100 48 101 48 101 48 101 48 101 4 59 90 60 92 60 92 60 92 60 4 62 95 60 97 60 97 60 97 60 5 103 48 104 48 104 48 104 48 104 6 99 82 102 82 105 82 105 82 105 4 66 36 70 36 70 36 70 36 70 4 15 15 75 15 75 15 75 15 75 5 107 108 37 108 37 108 37 108 37 4 27 29 70 29 70 29 70 29 70 4 33 33 75 33 75 33 75 33 75 5 110 111 37 111 37 111 37 111 37 4 53 54 70 54 70 54 70 54 70 4 56 56 75 56 75 56 75 56 75 5 113 114 37 114 37 114 37 114 37 6 109 112 82 115 82 115 82 115 82 4 87 92 15 92 15 92 15 92 15 4 50 97 15 97 15 97 15 97 15 5 117 48 118 48 118 48 118 48 118 4 44 92 46 92 46 92 46 92 46 4 49 97 46 97 46 97 46 97 46 5 120 48 121 48 121 48 121 48 121 4 59 92 60 92 60 92 60 92 60 4 62 97 60 97 60 97 60 97 60 5 123 48 124 48 124 48 124 48 124 6 119 82 122 82 125 82 125 82 125 7 65 86 106 116 126 116 126 116 126 4 66 36 20 36 20 36 20 36 20 1 0 4 2 4 4 6 6 8 8 2 129 1 129 1 129 1 129 1 129 3 17 130 2 130 2 130 2 130 2 3 28 130 8 130 8 130 8 130 8 4 131 132 20 132 20 132 20 132 20 5 128 81 37 81 133 81 37 81 133 5 30 34 37 34 133 34 37 34 133 5 55 57 37 57 133 57 37 57 133 6 134 135 82 136 82 136 82 136 82 5 71 76 37 76 133 76 37 76 133 5 78 79 37 79 133 79 37 79 133 5 83 84 37 84 133 84 37 84 133 6 138 139 82 140 82 140 82 140 82 6 82 82 82 82 82 82 82 82 82 5 107 108 37 108 133 108 37 108 133 5 110 111 37 111 133 111 37 111 133 5 113 114 37 114 133 114 37 114 133 6 143 144 82 145 82 145 82 145 82 7 137 141 142 146 142 146 142 146 142 4 87 45 15 45 15 45 15 45 15 4 50 50 15 50 15 50 15 50 15 1 0 1 4 3 4 5 6 7 8 2 150 150 1 150 1 150 1 150 1 3 12 12 151 12 151 12 151 12 151 3 8 8 151 8 151 8 151 8 151 4 152 14 153 14 153 14 153 14 153 5 148 48 149 154 149 48 149 154 149 5 47 48 51 154 51 48 51 154 51 5 61 48 63 154 63 48 63 154 63 6 155 82 156 82 157 82 157 82 157 5 93 48 98 154 98 48 98 154 98 5 100 48 101 154 101 48 101 154 101 5 103 48 104 154 104 48 104 154 104 6 159 82 160 82 161 82 161 82 161 5 117 48 118 154 118 48 118 154 118 5 120 48 121 154 121 48 121 154 121 5 123 48 124 154 124 48 124 154 124 6 163 82 164 82 165 82 165 82 165 7 158 142 162 142 166 142 166 142 166 3 17 28 2 130 2 130 2 130 2 3 28 28 8 130 8 130 8 130 8 4 168 169 20 169 20 169 20 169 20 5 128 81 170 81 133 81 37 81 170 5 30 34 170 34 133 34 37 34 170 5 55 57 170 57 133 57 37 57 170 6 171 172 82 173 82 173 82 173 82 5 71 76 170 76 133 76 37 76 170 5 78 79 170 79 133 79 37 79 170 5 83 84 170 84 133 84 37 84 170 6 175 176 82 177 82 177 82 177 82 5 107 108 170 108 133 108 37 108 170 5 110 111 170 111 133 111 37 111 170 5 113 114 170 114 133 114 37 114 170 6 179 180 82 181 82 181 82 181 82 7 174 178 142 182 142 182 142 182 142 3 12 12 8 12 151 12 151 12 151 3 8 8 8 8 151 8 151 8 151 4 184 14 185 14 185 14 185 14 185 5 148 186 149 154 149 48 149 186 149 5 47 186 51 154 51 48 51 186 51 5 61 186 63 154 63 48 63 186 63 6 187 82 188 82 189 82 189 82 189 5 93 186 98 154 98 48 98 186 98 5 100 186 101 154 101 48 101 186 101 5 103 186 104 154 104 48 104 186 104 6 191 82 192 82 193 82 193 82 193 5 117 186 118 154 118 48 118 186 118 5 120 186 121 154 121 48 121 186 121 5 123 186 124 154 124 48 124 186 124 6 195 82 196 82 197 82 197 82 197 7 190 142 194 142 198 142 198 142 198 8 127 147 167 183 199 147 167 147 167 1 0 1 3 3 3 5 5 7 7 2 201 1 201 1 201 1 201 1 201 3 202 8 202 8 202 8 202 8 202 4 35 36 203 36 203 36 203 36 203 5 128 81 37 81 204 81 37 81 204 5 30 34 37 34 204 34 37 34 204 5 55 57 37 57 204 57 37 57 204 6 205 206 82 207 82 207 82 207 82 5 71 76 37 76 204 76 37 76 204 5 78 79 37 79 204 79 37 79 204 5 83 84 37 84 204 84 37 84 204 6 209 210 82 211 82 211 82 211 82 5 107 108 37 108 204 108 37 108 204 5 110 111 37 111 204 111 37 111 204 5 113 114 37 114 204 114 37 114 204 6 213 214 82 215 82 215 82 215 82 7 208 212 142 216 142 216 142 216 142 4 131 132 203 132 203 132 203 132 203 5 128 81 37 81 218 81 37 81 218 5 30 34 37 34 218 34 37 34 218 5 55 57 37 57 218 57 37 57 218 6 219 220 82 221 82 221 82 221 82 5 71 76 37 76 218 76 37 76 218 5 78 79 37 79 218 79 37 79 218 5 83 84 37 84 218 84 37 84 218 6 223 224 82 225 82 225 82 225 82 5 107 108 37 108 218 108 37 108 218 5 110 111 37 111 218 111 37 111 218 5 113 114 37 114 218 114 37 114 218 6 227 228 82 229 82 229 82 229 82 7 222 226 142 230 142 230 142 230 142 7 142 142 142 142 142 142 142 142 142 4 168 169 203 169 203 169 203 169 203 5 128 81 170 81 218 81 37 81 233 5 30 34 170 34 218 34 37 34 233 5 55 57 170 57 218 57 37 57 233 6 234 235 82 236 82 236 82 236 82 5 71 76 170 76 218 76 37 76 233 5 78 79 170 79 218 79 37 79 233 5 83 84 170 84 218 84 37 84 233 6 238 239 82 240 82 240 82 240 82 5 107 108 170 108 218 108 37 108 233 5 110 111 170 111 218 111 37 111 233 5 113 114 170 114 218 114 37 114 233 6 242 243 82 244 82 244 82 244 82 7 237 241 142 245 142 245 142 245 142 8 217 231 232 246 232 231 232 231 232 2 129 129 1 129 1 129 1 129 1 3 248 248 8 248 8 248 8 248 8 4 14 249 15 249 15 249 15 249 15 5 148 48 149 250 149 48 149 250 149 5 47 48 51 250 51 48 51 250 51 5 61 48 63 250 63 48 63 250 63 6 251 82 252 82 253 82 253 82 253 5 93 48 98 250 98 48 98 250 98 5 100 48 101 250 101 48 101 250 101 5 103 48 104 250 104 48 104 250 104 6 255 82 256 82 257 82 257 82 257 5 117 48 118 250 118 48 118 250 118 5 120 48 121 250 121 48 121 250 121 5 123 48 124 250 124 48 124 250 124 6 259 82 260 82 261 82 261 82 261 7 254 142 258 142 262 142 262 142 262 4 152 249 153 249 153 249 153 249 153 5 148 48 149 264 149 48 149 264 149 5 47 48 51 264 51 48 51 264 51 5 61 48 63 264 63 48 63 264 63 6 265 82 266 82 267 82 267 82 267 5 93 48 98 264 98 48 98 264 98 5 100 48 101 264 101 48 101 264 101 5 103 48 104 264 104 48 104 264 104 6 269 82 270 82 271 82 271 82 271 5 117 48 118 264 118 48 118 264 118 5 120 48 121 264 121 48 121 264 121 5 123 48 124 264 124 48 124 264 124 6 273 82 274 82 275 82 275 82 275 7 268 142 272 142 276 142 276 142 276 4 184 249 185 249 185 249 185 249 185 5 148 186 149 264 149 48 149 278 149 5 47 186 51 264 51 48 51 278 51 5 61 186 63 264 63 48 63 278 63 6 279 82 280 82 281 82 281 82 281 5 93 186 98 264 98 48 98 278 98 5 100 186 101 264 101 48 101 278 101 5 103 186 104 264 104 48 104 278 104 6 283 82 284 82 285 82 285 82 285 5 117 186 118 264 118 48 118 278 118 5 120 186 121 264 121 48 121 278 121 5 123 186 124 264 124 48 124 278 124 6 287 82 288 82 289 82 289 82 289 7 282 142 286 142 290 142 290 142 290 8 263 232 277 232 291 232 277 232 277 4 35 36 20 36 203 36 203 36 203 5 128 81 293 81 204 81 37 81 293 5 30 34 293 34 204 34 37 34 293 5 55 57 293 57 204 57 37 57 293 6 294 295 82 296 82 296 82 296 82 5 71 76 293 76 204 76 37 76 293 5 78 79 293 79 204 79 37 79 293 5 83 84 293 84 204 84 37 84 293 6 298 299 82 300 82 300 82 300 82 5 107 108 293 108 204 108 37 108 293 5 110 111 293 111 204 111 37 111 293 5 113 114 293 114 204 114 37 114 293 6 302 303 82 304 82 304 82 304 82 7 297 301 142 305 142 305 142 305 142 4 131 132 20 132 203 132 203 132 203 5 128 81 293 81 218 81 37 81 307 5 30 34 293 34 218 34 37 34 307 5 55 57 293 57 218 57 37 57 307 6 308 309 82 310 82 310 82 310 82 5 71 76 293 76 218 76 37 76 307 5 78 79 293 79 218 79 37 79 307 5 83 84 293 84 218 84 37 84 307 6 312 313 82 314 82 314 82 314 82 5 107 108 293 108 218 108 37 108 307 5 110 111 293 111 218 111 37 111 307 5 113 114 293 114 218 114 37 114 307 6 316 317 82 318 82 318 82 318 82 7 311 315 142 319 142 319 142 319 142 4 168 169 20 169 203 169 203 169 203 5 128 81 321 81 218 81 37 81 321 5 30 34 321 34 218 34 37 34 321 5 55 57 321 57 218 57 37 57 321 6 322 323 82 324 82 324 82 324 82 5 71 76 321 76 218 76 37 76 321 5 78 79 321 79 218 79 37 79 321 5 83 84 321 84 218 84 37 84 321 6 326 327 82 328 82 328 82 328 82 5 107 108 321 108 218 108 37 108 321 5 110 111 321 111 218 111 37 111 321 5 113 114 321 114 218 114 37 114 321 6 330 331 82 332 82 332 82 332 82 7 325 329 142 333 142 333 142 333 142 8 306 320 232 334 232 320 232 320 232 4 14 14 15 249 15 249 15 249 15 5 148 336 149 250 149 48 149 336 149 5 47 336 51 250 51 48 51 336 51 5 61 336 63 250 63 48 63 336 63 6 337 82 338 82 339 82 339 82 339 5 93 336 98 250 98 48 98 336 98 5 100 336 101 250 101 48 101 336 101 5 103 336 104 250 104 48 104 336 104 6 341 82 342 82 343 82 343 82 343 5 117 336 118 250 118 48 118 336 118 5 120 336 121 250 121 48 121 336 121 5 123 336 124 250 124 48 124 336 124 6 345 82 346 82 347 82 347 82 347 7 340 142 344 142 348 142 348 142 348 4 152 14 153 249 153 249 153 249 153 5 148 336 149 264 149 48 149 350 149 5 47 336 51 264 51 48 51 350 51 5 61 336 63 264 63 48 63 350 63 6 351 82 352 82 353 82 353 82 353 5 93 336 98 264 98 48 98 350 98 5 100 336 101 264 101 48 101 350 101 5 103 336 104 264 104 48 104 350 104 6 355 82 356 82 357 82 357 82 357 5 117 336 118 264 118 48 118 350 118 5 120 336 121 264 121 48 121 350 121 5 123 336 124 264 124 48 124 350 124 6 359 82 360 82 361 82 361 82 361 7 354 142 358 142 362 142 362 142 362 4 184 14 185 249 185 249 185 249 185 5 148 364 149 264 149 48 149 364 149 5 47 364 51 264 51 48 51 364 51 5 61 364 63 264 63 48 63 364 63 6 365 82 366 82 367 82 367 82 367 5 93 364 98 264 98 48 98 364 98 5 100 364 101 264 101 48 101 364 101 5 103 364 104 264 104 48 104 364 104 6 369 82 370 82 371 82 371 82 371 5 117 364 118 264 118 48 118 364 118 5 120 364 121 264 121 48 121 364 121 5 123 364 124 264 124 48 124 364 124 6 373 82 374 82 375 82 375 82 375 7 368 142 372 142 376 142 376 142 376 8 349 232 363 232 377 232 363 232 363 5 128 81 37 81 204 81 37 81 293 5 30 34 37 34 204 34 37 34 293 5 55 57 37 57 204 57 37 57 293 6 379 380 82 381 82 381 82 381 82 5 71 76 37 76 204 76 37 76 293 5 78 79 37 79 204 79 37 79 293 5 83 84 37 84 204 84 37 84 293 6 383 384 82 385 82 385 82 385 82 5 107 108 37 108 204 108 37 108 293 5 110 111 37 111 204 111 37 111 293 5 113 114 37 114 204 114 37 114 293 6 387 388 82 389 82 389 82 389 82 7 382 386 142 390 142 390 142 390 142 5 128 81 37 81 218 81 37 81 307 5 30 34 37 34 218 34 37 34 307 5 55 57 37 57 218 57 37 57 307 6 392 393 82 394 82 394 82 394 82 5 71 76 37 76 218 76 37 76 307 5 78 79 37 79 218 79 37 79 307 5 83 84 37 84 218 84 37 84 307 6 396 397 82 398 82 398 82 398 82 5 107 108 37 108 218 108 37 108 307 5 110 111 37 111 218 111 37 111 307 5 113 114 37 114 218 114 37 114 307 6 400 401 82 402 82 402 82 402 82 7 395 399 142 403 142 403 142 403 142 5 128 81 170 81 218 81 37 81 321 5 30 34 170 34 218 34 37 34 321 5 55 57 170 57 218 57 37 57 321 6 405 406 82 407 82 407 82 407 82 5 71 76 170 76 218 76 37 76 321 5 78 79 170 79 218 79 37 79 321 5 83 84 170 84 218 84 37 84 321 6 409 410 82 411 82 411 82 411 82 5 107 108 170 108 218 108 37 108 321 5 110 111 170 111 218 111 37 111 321 5 113 114 170 114 218 114 37 114 321 6 413 414 82 415 82 415 82 415 82 7 408 412 142 416 142 416 142 416 142 8 391 404 232 417 232 404 232 404 232 5 148 48 149 250 149 48 149 336 149 5 47 48 51 250 51 48 51 336 51 5 61 48 63 250 63 48 63 336 63 6 419 82 420 82 421 82 421 82 421 5 93 48 98 250 98 48 98 336 98 5 100 48 101 250 101 48 101 336 101 5 103 48 104 250 104 48 104 336 104 6 423 82 424 82 425 82 425 82 425 5 117 48 118 250 118 48 118 336 118 5 120 48 121 250 121 48 121 336 121 5 123 48 124 250 124 48 124 336 124 6 427 82 428 82 429 82 429 82 429 7 422 142 426 142 430 142 430 142 430 5 148 48 149 264 149 48 149 350 149 5 47 48 51 264 51 48 51 350 51 5 61 48 63 264 63 48 63 350 63 6 432 82 433 82 434 82 434 82 434 5 93 48 98 264 98 48 98 350 98 5 100 48 101 264 101 48 101 350 101 5 103 48 104 264 104 48 104 350 104 6 436 82 437 82 438 82 438 82 438 5 117 48 118 264 118 48 118 350 118 5 120 48 121 264 121 48 121 350 121 5 123 48 124 264 124 48 124 350 124 6 440 82 441 82 442 82 442 82 442 7 435 142 439 142 443 142 443 142 443 5 148 186 149 264 149 48 149 364 149 5 47 186 51 264 51 48 51 364 51 5 61 186 63 264 63 48 63 364 63 6 445 82 446 82 447 82 447 82 447 5 93 186 98 264 98 48 98 364 98 5 100 186 101 264 101 48 101 364 101 5 103 186 104 264 104 48 104 364 104 6 449 82 450 82 451 82 451 82 451 5 117 186 118 264 118 48 118 364 118 5 120 186 121 264 121 48 121 364 121 5 123 186 124 264 124 48 124 364 124 6 453 82 454 82 455 82 455 82 455 7 448 142 452 142 456 142 456 142 456 8 431 232 444 232 457 232 444 232 444 9 200 247 292 335 378 247 292 418 458 @COLORS 1 90 90 90 2 62 62 62 3 255 255 0 4 220 220 0 5 120 100 0 6 100 80 0 7 148 148 148 8 103 103 103 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/StarWars.rule�������������������������������������������������������������������0000644�0001750�0001750�00000000767�12536111364�013763� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE StarWars @TREE num_states=4 num_neighbors=8 num_nodes=36 1 0 2 3 0 2 0 0 0 0 1 1 2 3 0 2 0 2 0 0 3 1 3 1 1 1 0 1 3 0 2 2 5 2 2 3 3 6 3 3 4 4 7 4 4 2 5 5 5 5 3 6 9 6 6 4 7 10 7 7 5 8 11 8 8 3 9 9 9 9 4 10 13 10 10 5 11 14 11 11 6 12 15 12 12 2 5 0 5 5 3 9 17 9 9 4 13 18 13 13 5 14 19 14 14 6 15 20 15 15 7 16 21 16 16 3 17 1 17 17 4 18 23 18 18 5 19 24 19 19 6 20 25 20 20 7 21 26 21 21 8 22 27 22 22 3 1 1 1 1 4 23 29 23 23 5 24 30 24 24 6 25 31 25 25 7 26 32 26 26 8 27 33 27 27 9 28 34 28 28 ���������golly-2.7-src/Rules/Perrier.rule��������������������������������������������������������������������0000644�0001750�0001750�00000024547�12536111364�013627� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Perrier J.-Y. Perrier, M. Sipper, and J. Zahnd "Toward a viable, self-reproducing universal computer" Physica D, vol. 97, pp. 335-352, 1996 Thanks to Gianluca Tempesti for the transition table and the pattern. Two small changes have been made. Firstly a conflicting rule has been removed. This only causes a problem in some packages, where the first applicable rule is used - other packages used the last applicable rule. Secondly a rule has been added to correct what appears to be a rare bug that shows up when trying to write to the first entry on the data tape. Other such cases might exist. Contact: tim.hutton@gmail.com @TABLE # rules: 637 n_states:64 neighborhood:vonNeumann symmetries:none var a={14,15,16} var b={11,12} var c={4,5,6,7,8,9,10} var d={32,33,34,35,36,37,38} var e={0,1,2,14,15,16} var f={32,33,34,35,36,37,38} var g={39,40} var h={39,40} var i={28,29,30,31,41} var j={28,29,30,31,41} var k={4,5,6,7,8} var l={9,10} var m={11,12} var n={2,28,29,30,31,41} var o={11,12} var p={47,48} 1,2,a,2,0,a 0,2,1,2,a,1 a,2,0,2,1,0 1,a,2,0,2,a a,0,2,1,2,0 0,1,2,a,2,1 1,2,0,2,a,a a,2,1,2,0,0 0,2,a,2,1,1 1,1,2,a,2,a 0,a,2,1,2,1 1,2,a,0,2,a 0,1,a,3,2,1 a,1,1,2,0,0 a,2,2,0,1,0 1,2,1,2,a,a a,2,0,1,2,0 1,a,0,3,2,a 0,a,a,2,1,1 a,1,2,0,2,0 0,2,2,1,a,1 0,2,1,a,2,1 a,0,1,3,2,0 1,0,0,2,a,a 1,0,2,a,2,a 1,2,2,2,a,a a,2,2,2,0,1 2,0,0,0,14,1 0,0,0,1,2,2 0,0,0,0,1,2 0,1,0,0,2,2 1,2,2,a,1,a 1,2,a,2,1,a 1,2,2,a,0,a 1,2,a,1,2,a 1,a,2,1,2,a 1,a,1,3,2,a 1,1,1,2,a,a 2,0,0,15,2,17 0,17,2,1,a,1 17,0,0,0,2,2 2,0,15,2,0,17 0,2,1,a,17,1 17,0,0,2,0,2 1,17,2,2,15,15 17,0,0,15,2,1 15,17,2,2,0,1 0,0,0,1,0,2 0,0,0,2,1,2 1,1,2,2,a,a 1,2,2,a,2,a a,1,2,2,0,0 2,0,0,14,0,1 14,2,2,0,2,1 0,a,2,2,1,1 0,0,1,2,0,2 1,0,2,2,a,a 15,2,2,0,2,1 1,2,2,15,17,15 17,0,15,2,0,1 15,2,2,0,17,1 0,0,2,1,0,2 0,0,1,0,0,2 1,2,a,2,2,a 2,0,14,0,0,1 14,2,0,2,2,1 0,1,2,0,0,2 2,15,2,0,0,17 15,2,0,2,2,1 1,2,15,17,2,15 17,15,2,0,0,1 15,2,0,17,2,1 0,2,1,0,0,2 0,1,0,0,0,2 1,a,2,2,2,a 2,14,0,0,0,1 14,0,2,2,2,1 0,2,0,0,1,2 0,1,0,2,0,2 2,14,0,2,0,17 2,17,2,0,2,1 17,1,0,2,0,1 0,2,1,2,0,2 1,1,0,2,14,0 1,2,0,2,0,16 0,2,0,2,1,18 18,2,0,2,1,2 1,14,18,1,2,19 1,19,2,0,2,19 19,0,2,1,2,0 0,1,2,19,2,1 18,2,0,2,14,2 14,2,18,2,0,18 0,1,16,2,18,1 1,19,0,2,2,19 2,0,2,18,2,0 18,2,2,2,1,0 1,2,18,2,14,18 2,19,2,0,2,20 1,2,0,2,19,14 19,0,1,2,2,0 0,14,18,2,1,1 2,18,2,2,2,18 18,2,0,2,0,2 0,1,a,20,2,1 2,1,18,b,2,18 18,2,2,2,2,2 a,1,2,18,0,0 18,15,2,b,2,2 2,0,18,2,2,18 2,18,0,2,b,21 1,2,0,18,a,a 18,1,2,2,2,2 2,a,18,0,2,18 0,2,a,18,1,1 18,0,2,0,2,2 2,1,18,0,2,18 2,16,0,0,2,20 18,1,2,0,2,2 0,a,2,20,1,1 1,a,0,20,2,a a,0,1,20,2,0 1,0,2,20,a,a a,1,2,20,0,0 a,2,1,18,0,0 18,a,2,0,2,2 2,0,18,2,3,18 18,1,2,2,3,2 2,18,0,2,c,18 18,2,0,2,4,32 18,2,0,2,5,33 18,2,0,2,6,34 18,2,0,2,7,35 18,2,0,2,8,36 18,2,0,2,9,37 18,2,0,2,10,38 18,d,0,2,6,34 18,d,0,2,5,33 18,d,0,2,7,35 18,d,0,2,8,36 18,d,0,2,9,37 18,d,0,2,10,38 d,2,0,18,c,2 2,e,2,d,3,d 1,2,0,d,a,a d,e,2,2,3,2 2,e,2,0,d,d 2,f,0,d,c,d d,e,2,0,2,2 2,e,f,d,3,d d,2,0,2,c,2 2,e,f,0,d,d 0,2,e,d,1,1 2,e,2,2,d,d a,2,1,d,0,0 1,a,1,20,2,a d,e,2,2,2,2 2,e,2,b,d,d 2,2,2,21,d,d d,e,2,b,2,2 1,0,2,d,a,a 2,e,f,2,d,d 2,18,0,0,c,18 d,2,2,21,2,2 2,e,f,b,d,d 18,f,0,0,6,34 18,f,0,0,4,32 18,f,0,0,5,33 18,f,0,0,7,35 18,f,0,0,8,36 18,f,0,0,9,37 18,f,0,0,10,38 2,2,f,21,d,d 0,20,0,0,0,22 2,2,20,0,d,d d,2,20,0,2,2 0,d,22,0,0,d 0,a,2,d,1,1 a,1,2,d,0,0 2,2,20,f,d,d 22,20,0,0,32,4 22,20,0,0,33,5 22,20,0,0,34,6 22,20,0,0,35,7 22,20,0,0,36,8 22,20,0,0,37,9 22,20,0,0,38,10 d,2,22,0,0,2 0,2,0,0,c,2 0,c,0,0,0,22 2,d,c,0,0,d d,2,20,2,2,2 d,2,c,0,0,2 22,c,0,0,34,6 22,c,0,0,33,5 22,c,0,0,32,4 22,c,0,0,35,7 22,c,0,0,36,8 22,c,0,0,37,9 22,c,0,0,38,10 2,d,c,f,0,d 1,1,2,20,14,14 d,2,c,2,0,2 d,2,0,0,c,23 d,2,0,23,c,23 23,d,0,0,c,2 23,d,0,2,c,2 d,e,2,23,3,23 23,e,d,2,3,2 d,e,2,0,23,23 23,e,d,0,2,2 d,e,2,2,23,23 23,e,d,2,2,2 d,e,2,b,23,23 23,e,d,b,2,2 d,2,2,21,23,23 23,2,d,21,2,2 d,2,20,2,23,23 d,23,c,2,0,23 23,2,20,d,2,2 23,2,c,d,0,2 d,23,c,0,0,23 d,23,22,0,0,23 0,23,22,0,0,23 23,2,c,23,0,2 23,23,22,0,0,0 22,c,0,0,23,2 21,23,0,2,b,24 24,2,0,2,12,40 24,2,0,2,11,39 2,24,0,2,b,24 2,2,2,g,2,g g,2,0,24,b,2 24,g,0,2,11,39 24,g,0,2,12,40 2,0,2,0,g,g g,2,2,2,2,2 2,h,0,g,b,g g,0,2,0,2,2 2,2,h,g,2,g g,2,0,2,b,2 1,14,1,2,2,14 2,e,2,c,g,g 2,0,h,0,g,g a,0,1,2,2,0 2,e,2,2,g,g g,0,2,c,2,2 2,2,h,2,g,g 0,1,a,g,2,1 2,24,0,0,b,24 2,e,2,0,g,g g,0,2,2,2,2 0,2,a,g,1,1 2,1,h,c,g,g 24,g,0,0,12,40 24,g,0,0,11,39 1,a,0,2,2,a 2,1,h,2,g,g g,a,2,c,2,2 40,2,0,0,12,13 39,2,0,0,11,13 2,1,h,0,g,g g,a,2,2,2,2 a,2,1,g,0,0 0,1,a,2,2,1 2,0,h,c,g,g g,2,0,13,b,13 13,g,0,0,b,2 g,a,2,0,2,2 2,0,h,2,g,g g,1,2,c,2,2 1,a,0,g,2,a 13,g,0,2,b,2 2,e,20,0,g,g g,1,2,2,2,2 1,2,0,g,a,a 2,a,h,c,g,g 0,g,22,0,0,g g,e,20,0,2,2 g,1,2,0,2,2 2,a,h,2,g,g 22,20,0,0,40,12 22,20,0,0,39,11 g,2,22,0,0,2 2,e,20,h,g,g 2,a,h,0,g,g a,0,1,g,2,0 0,0,0,0,b,2 0,b,0,0,0,22 2,g,b,0,0,g g,e,20,2,2,2 g,2,b,0,0,2 g,2,2,13,2,13 g,0,2,0,13,13 13,2,g,2,2,2 2,e,13,b,2,13 2,g,b,h,0,g 2,g,22,0,0,g g,2,b,2,0,2 g,2,2,2,13,13 13,0,g,0,2,0 22,b,0,0,39,11 22,b,0,0,40,12 0,2,0,0,b,2 13,e,2,b,2,2 2,e,13,2,2,13 0,a,2,13,1,1 13,2,g,2,0,2 a,2,1,13,0,0 13,e,2,2,2,2 2,e,13,0,2,13 2,13,b,2,0,25 g,e,2,2,3,3 13,e,2,0,2,2 1,2,0,13,a,a 25,2,b,2,0,26 g,e,2,0,3,3 3,e,g,2,3,2 0,2,26,0,0,25 26,2,b,2,0,2 0,2,a,13,1,1 3,e,g,0,2,2 2,e,13,2,3,13 13,e,2,2,3,2 2,13,0,2,c,25 g,e,20,2,3,3 1,2,0,3,a,a g,3,b,2,0,23 20,e,0,b,3,3 3,e,20,g,2,2 0,2,0,2,3,3 3,e,0,b,2,2 g,23,b,2,0,23 23,2,b,g,0,2 1,0,2,3,a,a 2,2,0,3,e,26 3,2,0,2,2,2 0,a,26,2,1,1 a,1,26,2,0,0 g,23,11,0,0,23 g,23,22,0,0,23 22,b,0,0,23,2 23,2,b,23,0,2 1,1,26,2,14,14 1,0,26,2,14,14 1,0,26,2,15,15 1,0,26,2,16,17 1,0,2,17,2,14 17,1,26,2,0,0 0,2,17,2,1,1 26,2,0,2,17,27 27,2,0,2,0,1 0,14,27,2,1,1 0,0,0,0,27,17 1,0,1,2,14,14 1,2,17,2,14,14 14,2,17,2,0,1 17,0,0,0,14,27 27,0,0,0,1,1 1,2,17,2,15,15 17,0,0,0,15,1 15,2,17,2,0,27 17,0,0,27,2,2 0,0,0,1,17,2 27,17,1,2,1,1 1,2,27,2,15,14 25,2,0,2,4,28 25,2,0,2,5,29 25,2,0,2,6,30 25,2,0,2,7,31 25,2,0,2,8,41 2,e,2,i,3,i i,2,0,25,c,2 25,i,0,2,4,28 25,i,0,2,5,29 25,i,0,2,6,30 25,i,0,2,7,31 25,i,0,2,8,41 a,2,1,i,0,0 2,e,2,0,i,i 2,j,0,i,c,i i,e,2,0,2,2 2,e,j,i,3,i i,2,0,2,c,2 1,2,0,i,a,a i,e,2,2,3,2 2,e,j,0,i,i 2,25,0,2,k,25 2,25,0,2,l,42 i,2,0,42,8,2 2,e,2,25,i,i 2,e,2,2,28,28 i,e,2,25,2,2 2,e,2,2,29,29 2,e,2,2,30,30 2,e,2,2,31,43 2,e,2,2,41,41 0,2,a,i,1,1 2,e,j,25,i,i i,e,2,2,2,2 43,e,2,2,2,2 2,28,b,2,25,44 44,2,b,2,25,2 b,2,2,m,44,11 2,e,2,44,30,30 2,e,2,44,28,28 2,e,2,44,29,29 2,e,2,44,31,43 2,e,2,44,41,41 2,30,b,2,25,45 25,n,45,0,0,45 45,2,b,2,25,2 2,e,2,45,29,29 2,e,2,45,28,28 2,e,2,45,30,30 2,e,2,45,31,43 2,e,2,45,41,41 2,e,j,45,i,i 2,i,b,2,45,i 45,n,2,0,0,0 0,45,2,0,0,25 2,e,2,j,28,28 2,e,2,j,29,29 2,e,2,j,30,30 2,e,2,j,31,43 2,e,2,j,41,41 i,2,b,2,0,2 2,29,b,2,25,46 a,2,1,43,0,0 b,m,2,o,46,12 46,2,b,2,25,2 2,e,43,0,i,i 2,43,b,46,0,31 2,28,b,46,0,28 2,29,b,46,0,29 2,30,b,46,0,30 2,41,b,46,0,41 0,n,31,25,0,25 25,25,2,0,0,0 2,41,12,2,25,48 2,41,11,2,25,47 47,2,11,2,25,2 48,2,11,2,25,2 2,e,2,p,2,p 0,2,a,p,1,1 p,e,2,2,2,2 2,e,p,25,2,p a,2,1,p,0,0 p,e,2,25,2,2 2,e,p,0,2,p 1,2,0,p,a,a p,e,2,0,2,2 2,e,p,2,3,p p,e,2,2,3,2 2,p,0,2,c,p p,2,0,2,c,2 2,p,0,42,c,p p,2,0,42,c,2 42,47,0,2,c,49 49,2,0,2,c,2 2,49,0,2,l,49 2,49,0,2,k,25 2,2,0,i,c,i 2,25,0,0,c,25 25,i,0,0,6,30 25,i,0,0,5,29 25,i,0,0,4,28 25,i,0,0,7,31 25,i,0,0,8,41 i,2,0,0,c,2 25,0,45,0,0,45 2,i,b,45,0,i 45,0,2,0,0,0 2,i,b,j,0,i 20,e,2,c,23,2 2,30,b,0,25,50 25,0,50,0,0,0 50,2,b,0,25,2 0,50,2,0,0,50 2,i,b,50,0,i 0,0,50,0,0,25 50,2,2,0,0,2 2,b,0,0,50,11 0,50,22,0,0,50 0,50,0,0,0,51 0,b,0,0,51,2 51,2,0,0,0,0 2,41,11,51,25,47 2,41,12,51,25,48 2,32,b,51,25,44 2,33,b,51,25,46 2,30,b,51,25,50 2,43,b,45,0,31 2,43,b,i,0,31 0,0,31,25,0,25 2,e,43,25,31,31 2,43,b,2,25,52 0,2,a,43,1,1 1,2,0,43,a,a 2,e,2,52,31,43 2,e,2,52,28,28 2,e,2,52,29,29 2,e,2,52,30,30 2,52,b,2,0,53 53,52,b,2,0,52 2,53,b,2,0,53 52,52,b,53,0,25 52,25,b,53,0,2 52,2,b,53,0,2 2,53,b,0,0,53 0,53,2,0,0,53 53,52,b,0,0,52 2,b,0,0,53,b 53,52,2,0,0,2 b,m,2,2,52,53 0,53,0,0,0,52 0,b,0,0,52,2 52,2,0,0,0,0 53,b,2,m,2,b b,m,2,53,2,53 b,m,2,53,25,53 53,b,2,m,25,b b,2,2,53,52,53 53,2,2,b,52,11 52,43,53,25,25,53 25,53,b,2,0,2 53,i,11,25,25,2 53,43,11,25,25,2 43,e,2,2,i,2 i,e,2,2,j,2 1,2,1,i,14,14 1,2,1,43,14,14 i,e,2,25,j,2 i,e,2,0,j,2 52,2,53,25,25,53 53,2,11,25,25,2 g,e,2,c,13,3 1,2,1,f,14,14 1,2,0,23,a,a 1,0,2,23,a,a 1,2,1,13,14,14 i,e,2,j,3,2 2,e,43,25,i,i i,2,0,j,c,2 52,i,53,25,25,53 1,14,1,g,2,14 1,2,1,g,14,14 1,0,2,13,a,a a,2,1,3,0,0 a,1,2,3,0,0 48,2,12,2,25,2 42,48,0,2,10,55 55,2,0,2,10,54 2,55,0,2,10,55 55,54,0,2,10,54 54,54,0,56,c,2 2,57,0,2,k,56 57,2,0,2,c,2 2,54,0,57,c,54 54,54,0,2,c,2 2,54,0,56,c,54 2,54,0,54,c,54 54,2,0,2,c,2 2,55,0,2,k,56 56,54,0,2,c,57 56,2,0,2,k,58 54,2,0,58,k,2 58,54,0,2,l,57 58,2,0,2,k,25 2,2,b,p,0,p p,2,b,2,0,2 42,48,0,2,9,59 2,2,0,59,8,59 60,2,0,2,c,2 2,59,0,60,c,60 2,60,0,60,c,60 61,2,0,2,c,2 #2,2,0,61,c,59 - this rule is overwritten by later rules 59,2,0,2,l,2 2,61,0,60,c,60 59,2,0,2,k,62 62,2,0,60,k,61 60,62,0,2,c,2 2,59,0,2,10,63 2,59,0,63,c,60 2,63,0,2,10,63 63,2,0,2,10,2 2,60,0,63,c,60 62,2,0,2,c,25 2,i,b,2,0,i 2,41,12,0,25,48 2,41,11,0,25,47 48,2,12,0,25,2 47,2,11,0,25,2 2,43,b,2,0,31 g,23,b,0,0,23 18,d,0,2,4,32 2,57,0,2,l,57 58,54,0,2,k,57 57,54,0,2,c,2 54,2,0,58,l,2 0,2,a,23,1,1 0,a,2,23,1,1 a,1,2,13,0,0 2,57,0,0,k,56 56,2,0,0,k,58 58,54,0,0,k,2 0,2,a,3,1,1 58,2,0,0,k,25 25,2,0,0,6,30 25,2,0,0,5,29 25,2,0,0,4,28 25,2,0,0,7,31 25,2,0,0,8,41 2,2,0,61,k,59 2,2,0,61,l,61 0,a,2,3,1,1 2,63,0,0,10,63 63,2,0,0,10,2 b,m,2,o,44,11 b,2,2,m,46,12 2,43,b,44,0,31 2,28,b,44,0,28 2,29,b,44,0,29 2,30,b,44,0,30 2,31,b,44,0,31 2,41,b,44,0,41 a,2,1,23,0,0 a,1,2,23,0,0 1,2,1,p,14,14 2,29,b,0,25,46 46,2,b,0,25,2 b,m,2,2,46,12 b,m,2,2,44,11 2,28,b,0,25,44 44,2,12,0,25,2 2,e,2,52,41,41 2,e,2,46,i,i # rule added by TJH to correct an apparent bug @COLORS 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 8 255 128 0 9 159 116 187 10 255 135 128 11 184 25 181 12 235 199 185 13 187 40 166 14 99 110 94 15 226 149 86 16 52 181 122 17 221 138 196 18 97 152 80 19 57 189 164 20 252 38 183 21 211 148 59 22 59 241 164 23 203 170 40 24 222 164 132 25 162 204 172 26 179 133 87 27 55 203 233 28 92 71 22 29 188 231 154 30 145 96 127 31 112 205 26 32 40 94 120 33 28 29 23 34 31 70 253 35 29 80 34 36 174 45 190 37 143 50 251 38 227 98 100 39 41 115 190 40 167 65 28 41 243 50 195 42 104 21 68 43 40 30 20 44 73 82 194 45 176 35 168 46 216 102 181 47 90 199 188 48 83 70 120 49 211 218 78 50 174 115 98 51 205 183 158 52 179 112 83 53 220 158 134 54 80 190 199 55 108 218 146 56 45 94 219 57 211 176 68 58 246 20 49 59 91 92 85 60 188 165 228 61 71 246 39 62 232 202 95 63 169 99 242 ���������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Banks-IV.rule�������������������������������������������������������������������0000644�0001750�0001750�00000001226�12536111364�013556� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Banks-IV Edwin Roger Banks, PhD Thesis 1971 Four-state, five-neighbor universal constructor (Appendix IV) http://www.bottomlayer.com/bottom/banks/banks_commentary.htm @TABLE # Format: C,N,E,S,W,C' n_states:4 neighborhood:vonNeumann symmetries:rotate4reflect 031301 132302 231300 013331 310002 220001 120002 123332 211103 213330 233300 311001 122002 211003 310301 100000 130000 011001 310002 020003 200000 012131 010303 033203 020303 023003 013102 230000 033331 331001 113000 121313 313132 230301 133333 130303 011301 321311 133000 013133 011132 320101 113330 133303 123003 120303 021332 020201 120202 210100 213300 210001 213130 320000 223230 010101 ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/BBM-Margolus-emulated.rule������������������������������������������������������0000644�0001750�0001750�00000006527�12536111364�016202� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE BBM-Margolus-emulated @TREE num_states=5 num_neighbors=8 num_nodes=126 1 0 2 2 4 4 1 0 1 2 3 4 2 0 1 0 1 0 2 1 1 1 1 1 1 0 2 1 4 3 2 0 1 4 1 4 3 2 3 5 3 5 3 3 3 3 3 3 3 5 3 5 3 5 4 6 7 8 7 8 4 7 7 7 7 7 2 4 1 4 1 4 3 2 3 11 3 11 3 11 3 11 3 11 4 12 7 13 7 13 5 9 10 14 10 14 1 0 1 1 3 3 2 16 1 16 1 16 3 17 3 17 3 17 4 18 7 18 7 18 5 19 10 19 10 19 1 0 2 2 2 4 2 0 1 21 1 0 1 0 4 2 4 4 2 0 1 0 1 23 3 2 3 22 3 24 4 25 7 25 7 25 5 26 10 26 10 26 1 0 4 2 2 4 2 0 1 28 1 0 3 2 3 29 3 2 4 30 7 30 7 30 5 31 10 31 10 31 6 15 20 27 20 32 5 10 10 10 10 10 6 20 20 34 20 34 3 2 3 2 3 2 1 0 1 2 3 2 2 1 1 37 1 1 3 38 38 3 38 3 1 0 1 4 3 4 2 1 1 1 1 40 3 41 41 3 41 3 4 36 39 36 42 36 5 43 10 43 10 43 4 25 39 25 42 25 5 45 10 45 10 45 4 30 39 30 42 30 5 47 10 47 10 47 6 44 34 46 34 48 1 0 1 4 3 2 2 1 1 50 1 1 3 51 51 3 51 3 4 36 52 36 7 36 5 53 10 53 10 53 4 25 52 25 7 25 5 55 10 55 10 55 4 30 52 30 7 30 5 57 10 57 10 57 6 54 34 56 34 58 7 33 35 49 35 59 6 34 34 34 34 34 7 35 35 61 35 61 4 36 7 36 7 36 2 37 37 1 37 1 3 3 3 64 3 3 4 65 7 65 7 65 2 40 40 1 40 1 3 3 3 3 3 67 4 68 7 68 7 68 5 63 66 63 69 63 5 26 66 26 69 26 5 31 66 31 69 31 6 70 34 71 34 72 5 43 66 43 69 43 5 45 66 45 69 45 5 47 66 47 69 47 6 74 34 75 34 76 5 53 66 53 69 53 5 55 66 55 69 55 5 57 66 57 69 57 6 78 34 79 34 80 7 73 61 77 61 81 2 50 50 1 50 1 3 3 3 83 3 3 4 84 7 84 7 84 5 63 85 63 10 63 5 26 85 26 10 26 5 31 85 31 10 31 6 86 34 87 34 88 5 43 85 43 10 43 5 45 85 45 10 45 5 47 85 47 10 47 6 90 34 91 34 92 5 53 85 53 10 53 5 55 85 55 10 55 5 57 85 57 10 57 6 94 34 95 34 96 7 89 61 93 61 97 8 60 62 82 62 98 1 0 1 1 3 1 2 100 1 100 1 100 3 101 3 101 3 101 4 18 7 102 7 18 1 0 1 3 3 3 2 104 1 104 1 104 3 105 3 105 3 105 4 18 7 18 7 106 5 19 10 103 10 107 6 108 108 34 108 34 7 109 109 61 109 61 7 61 61 61 61 61 8 110 110 111 110 111 5 63 10 63 10 63 6 113 34 27 34 32 7 114 61 49 61 59 8 115 111 82 111 98 1 0 1 3 3 1 2 117 1 117 1 117 3 118 3 118 3 118 4 18 7 119 7 18 5 19 10 120 10 19 6 121 121 34 121 34 7 122 122 61 122 61 8 123 123 111 123 111 9 99 112 116 124 116 @COLORS 1 90 90 90 2 62 62 62 3 0 255 127 4 0 178 88 5 127 0 255 6 88 0 178 7 148 148 148 8 103 103 103 9 128 255 0 10 89 178 0 11 255 0 128 12 178 0 89 13 0 128 255 14 0 89 178 15 1 159 0 16 0 111 0 17 159 0 1 18 111 0 0 19 255 254 96 20 178 177 67 21 0 1 159 22 0 0 111 23 96 255 254 24 67 178 177 25 254 96 255 26 177 67 178 27 126 125 21 28 88 87 14 29 21 126 125 30 14 88 87 31 125 21 126 32 87 14 88 33 255 116 116 34 178 81 81 35 116 255 116 36 81 178 81 37 116 116 255 38 81 81 178 39 228 227 0 40 159 158 0 41 28 255 27 42 19 178 18 43 255 27 28 44 178 18 19 45 0 228 227 46 0 159 158 47 227 0 228 48 158 0 159 49 27 28 255 50 18 19 178 51 59 59 59 52 41 41 41 53 234 195 176 54 163 136 123 55 175 196 255 56 122 137 178 57 171 194 68 58 119 135 47 59 194 68 171 60 135 47 119 61 68 171 194 62 47 119 135 63 72 184 71 64 50 128 49 65 184 71 72 66 128 49 50 67 71 72 184 68 49 50 128 69 169 255 188 70 118 178 131 71 252 179 63 72 176 125 44 73 63 252 179 74 44 176 125 75 179 63 252 76 125 44 176 77 80 9 0 78 56 6 0 79 0 80 9 80 0 56 6 81 9 0 80 82 6 0 56 83 255 175 250 84 178 122 175 85 199 134 213 86 139 93 149 87 115 100 95 88 80 70 66 89 188 163 0 90 131 114 0 91 0 188 163 92 0 131 114 93 163 0 188 94 114 0 131 95 203 73 0 96 142 51 0 97 0 203 73 98 0 142 51 99 73 0 203 100 51 0 142 101 94 189 0 102 65 132 0 103 189 0 94 104 132 0 65 �������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/AbsoluteTurmite_1N10S11S30N21W01N11S20E1.rule�����������������������������������0000644�0001750�0001750�00000034676�12536111364�020331� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE AbsoluteTurmite_1N10S11S30N21W01N11S20E1 @TREE num_states=10 num_neighbors=4 num_nodes=21 1 0 1 1 1 1 1 0 0 1 0 1 3 7 7 7 7 7 3 3 7 3 1 4 8 8 8 8 8 4 4 8 4 2 0 0 1 0 0 0 0 2 1 0 1 2 6 6 6 6 6 2 2 6 2 2 4 4 0 4 4 4 4 0 0 4 3 3 3 3 3 5 3 3 3 3 3 2 1 1 0 1 1 1 1 0 0 1 2 0 0 0 0 0 0 0 0 0 0 3 7 7 7 7 8 7 7 7 7 7 4 6 6 6 6 6 6 6 6 6 9 1 5 9 9 9 9 9 5 5 9 5 2 11 11 0 11 11 11 11 0 0 11 3 12 12 12 12 8 12 12 12 12 12 3 8 8 8 8 8 8 8 8 8 8 4 13 13 13 13 13 13 13 13 13 14 2 2 2 0 2 2 2 2 0 0 2 3 16 16 16 16 8 16 16 16 16 16 4 17 17 17 17 17 17 17 17 17 14 4 9 9 9 9 9 9 9 9 9 14 5 10 10 10 15 10 18 19 10 10 10 @COLORS 0 0 0 0 1 0 155 67 2 123 4 243 3 124 124 124 4 178 177 94 5 4 98 243 6 71 72 170 7 71 141 101 8 102 171 84 9 2 126 170 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 279 15 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #00327F" "G c #3F4DA1" "H c #408D61" "I c #5CA951" "J c #007FA1" "K c #7F00FF" "L c #808080" "M c #B9B860" "N c #0064FF" "O c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ "..............................." "..............................." ".............CCCCC............." "..........CKKKKKKKKKC.........." "........CKKKKKKKKKKKKKC........" ".......CKKKKKKKKKKKKKKKC......." "......CKKKKKKKKKKKKKKKKKC......" ".....CKKKKKKKKKKKKKKKKKKKC....." "....CKKKKKOOKKKKKKKKKKKKKKC...." "....KKKKKOOKKKKKKKKKKKKKKKK...." "...CKKKKOOKKKKKKKKKKKKKKKKKC..." "...KKKKKOOKKKKKKKKKKKKKKKKKK..." "...KKKKKOKKKKKKKKKKKKKKKKKKK..." "..CKKKKKKKKKKKKKKKKKKKKKKKKKC.." "..CKKKKKKKKKKKKKKKKKKKKKKKKKC.." "..CKKKKKKKKKKKKKKKKKKKKKKKKKC.." "..CKKKKKKKKKKKKKKKKKKKKKKKKKC.." "..CKKKKKKKKKKKKKKKKKKKKKKKKKC.." "...KKKKKKKKKKKKKKKKKKKKKKKKK..." "...KKKKKKKKKKKKKKKKKKKKKKKKK..." "...CKKKKKKKKKKKKKKKKKKKKKKKC..." "....KKKKKKKKKKKKKKKKKKKKKKK...." "....CKKKKKKKKKKKKKKKKKKKKKC...." ".....CKKKKKKKKKKKKKKKKKKKC....." "......CKKKKKKKKKKKKKKKKKC......" ".......CKKKKKKKKKKKKKKKC......." "........CKKKKKKKKKKKKKC........" "..........CKKKKKKKKKC.........." ".............CCCCC............." "..............................." "..............................." /* icon for state 3 */ "..............................." "..............................." ".............DDDDD............." "..........DLLLLLLLLLD.........." "........DLLLLLLLLLLLLLD........" ".......DLLLLLLLLLLLLLLLD......." "......DLLLLLLLLLLLLLLLLLD......" ".....DLLLLLLLLLLLLLLLLLLLD....." "....DLLLLLOOLLLLLLLLLLLLLLD...." "....LLLLLOOLLLLLLLLLLLLLLLL...." "...DLLLLOOLLLLLLLLLLLLLLLLLD..." "...LLLLLOOLLLLLLLLLLLLLLLLLL..." "...LLLLLOLLLLLLLLLLLLLLLLLLL..." "..DLLLLLLLLLLLLLLLLLLLLLLLLLD.." "..DLLLLLLLLLLLLLLLLLLLLLLLLLD.." "..DLLLLLLLLLLLLLLLLLLLLLLLLLD.." "..DLLLLLLLLLLLLLLLLLLLLLLLLLD.." "..DLLLLLLLLLLLLLLLLLLLLLLLLLD.." "...LLLLLLLLLLLLLLLLLLLLLLLLL..." "...LLLLLLLLLLLLLLLLLLLLLLLLL..." "...DLLLLLLLLLLLLLLLLLLLLLLLD..." "....LLLLLLLLLLLLLLLLLLLLLLL...." "....DLLLLLLLLLLLLLLLLLLLLLD...." ".....DLLLLLLLLLLLLLLLLLLLD....." "......DLLLLLLLLLLLLLLLLLD......" ".......DLLLLLLLLLLLLLLLD......." "........DLLLLLLLLLLLLLD........" "..........DLLLLLLLLLD.........." ".............DDDDD............." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." ".............EEEEE............." "..........EMMMMMMMMME.........." "........EMMMMMMMMMMMMME........" ".......EMMMMMMMMMMMMMMME......." "......EMMMMMMMMMMMMMMMMME......" ".....EMMMMMMMMMMMMMMMMMMME....." "....EMMMMMOOMMMMMMMMMMMMMME...." "....MMMMMOOMMMMMMMMMMMMMMMM...." "...EMMMMOOMMMMMMMMMMMMMMMMME..." "...MMMMMOOMMMMMMMMMMMMMMMMMM..." "...MMMMMOMMMMMMMMMMMMMMMMMMM..." "..EMMMMMMMMMMMMMMMMMMMMMMMMME.." "..EMMMMMMMMMMMMMMMMMMMMMMMMME.." "..EMMMMMMMMMMMMMMMMMMMMMMMMME.." "..EMMMMMMMMMMMMMMMMMMMMMMMMME.." "..EMMMMMMMMMMMMMMMMMMMMMMMMME.." "...MMMMMMMMMMMMMMMMMMMMMMMMM..." "...MMMMMMMMMMMMMMMMMMMMMMMMM..." "...EMMMMMMMMMMMMMMMMMMMMMMME..." "....MMMMMMMMMMMMMMMMMMMMMMM...." "....EMMMMMMMMMMMMMMMMMMMMME...." ".....EMMMMMMMMMMMMMMMMMMME....." "......EMMMMMMMMMMMMMMMMME......" ".......EMMMMMMMMMMMMMMME......." "........EMMMMMMMMMMMMME........" "..........EMMMMMMMMME.........." ".............EEEEE............." "..............................." "..............................." /* icon for state 5 */ "..............................." "..............................." ".............FFFFF............." "..........FNNNNNNNNNF.........." "........FNNNNNNNNNNNNNF........" ".......FNNNNNNNNNNNNNNNF......." "......FNNNNNNNNNNNNNNNNNF......" ".....FNNNNNNNNNNNNNNNNNNNF....." "....FNNNNNOONNNNNNNNNNNNNNF...." "....NNNNNOONNNNNNNNNNNNNNNN...." "...FNNNNOONNNNNNNNNNNNNNNNNF..." "...NNNNNOONNNNNNNNNNNNNNNNNN..." "...NNNNNONNNNNNNNNNNNNNNNNNN..." "..FNNNNNNNNNNNNNNNNNNNNNNNNNF.." "..FNNNNNNNNNNNNNNNNNNNNNNNNNF.." "..FNNNNNNNNNNNNNNNNNNNNNNNNNF.." "..FNNNNNNNNNNNNNNNNNNNNNNNNNF.." "..FNNNNNNNNNNNNNNNNNNNNNNNNNF.." "...NNNNNNNNNNNNNNNNNNNNNNNNN..." "...NNNNNNNNNNNNNNNNNNNNNNNNN..." "...FNNNNNNNNNNNNNNNNNNNNNNNF..." "....NNNNNNNNNNNNNNNNNNNNNNN...." "....FNNNNNNNNNNNNNNNNNNNNNF...." ".....FNNNNNNNNNNNNNNNNNNNF....." "......FNNNNNNNNNNNNNNNNNF......" ".......FNNNNNNNNNNNNNNNF......." "........FNNNNNNNNNNNNNF........" "..........FNNNNNNNNNF.........." ".............FFFFF............." "..............................." "..............................." /* icon for state 6 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAGGGGGAAAAAAAAAAAAA" "AAAAAAAAAAGKKKKKKKKKGAAAAAAAAAA" "AAAAAAAAGKKKKKKKKKKKKKGAAAAAAAA" "AAAAAAAGKKKKKKKKKKKKKKKGAAAAAAA" "AAAAAAGKKKKKKKKKKKKKKKKKGAAAAAA" "AAAAAGKKKKKKKKKKKKKKKKKKKGAAAAA" "AAAAGKKKKKOOKKKKKKKKKKKKKKGAAAA" "AAAAKKKKKOOKKKKKKKKKKKKKKKKAAAA" "AAAGKKKKOOKKKKKKKKKKKKKKKKKGAAA" "AAAKKKKKOOKKKKKKKKKKKKKKKKKKAAA" "AAAKKKKKOKKKKKKKKKKKKKKKKKKKAAA" "AAGKKKKKKKKKKKKKKKKKKKKKKKKKGAA" "AAGKKKKKKKKKKKKKKKKKKKKKKKKKGAA" "AAGKKKKKKKKKKKKKKKKKKKKKKKKKGAA" "AAGKKKKKKKKKKKKKKKKKKKKKKKKKGAA" "AAGKKKKKKKKKKKKKKKKKKKKKKKKKGAA" "AAAKKKKKKKKKKKKKKKKKKKKKKKKKAAA" "AAAKKKKKKKKKKKKKKKKKKKKKKKKKAAA" "AAAGKKKKKKKKKKKKKKKKKKKKKKKGAAA" "AAAAKKKKKKKKKKKKKKKKKKKKKKKAAAA" "AAAAGKKKKKKKKKKKKKKKKKKKKKGAAAA" "AAAAAGKKKKKKKKKKKKKKKKKKKGAAAAA" "AAAAAAGKKKKKKKKKKKKKKKKKGAAAAAA" "AAAAAAAGKKKKKKKKKKKKKKKGAAAAAAA" "AAAAAAAAGKKKKKKKKKKKKKGAAAAAAAA" "AAAAAAAAAAGKKKKKKKKKGAAAAAAAAAA" "AAAAAAAAAAAAAGGGGGAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 7 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAHHHHHAAAAAAAAAAAAA" "AAAAAAAAAAHLLLLLLLLLHAAAAAAAAAA" "AAAAAAAAHLLLLLLLLLLLLLHAAAAAAAA" "AAAAAAAHLLLLLLLLLLLLLLLHAAAAAAA" "AAAAAAHLLLLLLLLLLLLLLLLLHAAAAAA" "AAAAAHLLLLLLLLLLLLLLLLLLLHAAAAA" "AAAAHLLLLLOOLLLLLLLLLLLLLLHAAAA" "AAAALLLLLOOLLLLLLLLLLLLLLLLAAAA" "AAAHLLLLOOLLLLLLLLLLLLLLLLLHAAA" "AAALLLLLOOLLLLLLLLLLLLLLLLLLAAA" "AAALLLLLOLLLLLLLLLLLLLLLLLLLAAA" "AAHLLLLLLLLLLLLLLLLLLLLLLLLLHAA" "AAHLLLLLLLLLLLLLLLLLLLLLLLLLHAA" "AAHLLLLLLLLLLLLLLLLLLLLLLLLLHAA" "AAHLLLLLLLLLLLLLLLLLLLLLLLLLHAA" "AAHLLLLLLLLLLLLLLLLLLLLLLLLLHAA" "AAALLLLLLLLLLLLLLLLLLLLLLLLLAAA" "AAALLLLLLLLLLLLLLLLLLLLLLLLLAAA" "AAAHLLLLLLLLLLLLLLLLLLLLLLLHAAA" "AAAALLLLLLLLLLLLLLLLLLLLLLLAAAA" "AAAAHLLLLLLLLLLLLLLLLLLLLLHAAAA" "AAAAAHLLLLLLLLLLLLLLLLLLLHAAAAA" "AAAAAAHLLLLLLLLLLLLLLLLLHAAAAAA" "AAAAAAAHLLLLLLLLLLLLLLLHAAAAAAA" "AAAAAAAAHLLLLLLLLLLLLLHAAAAAAAA" "AAAAAAAAAAHLLLLLLLLLHAAAAAAAAAA" "AAAAAAAAAAAAAHHHHHAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 8 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAIIIIIAAAAAAAAAAAAA" "AAAAAAAAAAIMMMMMMMMMIAAAAAAAAAA" "AAAAAAAAIMMMMMMMMMMMMMIAAAAAAAA" "AAAAAAAIMMMMMMMMMMMMMMMIAAAAAAA" "AAAAAAIMMMMMMMMMMMMMMMMMIAAAAAA" "AAAAAIMMMMMMMMMMMMMMMMMMMIAAAAA" "AAAAIMMMMMOOMMMMMMMMMMMMMMIAAAA" "AAAAMMMMMOOMMMMMMMMMMMMMMMMAAAA" "AAAIMMMMOOMMMMMMMMMMMMMMMMMIAAA" "AAAMMMMMOOMMMMMMMMMMMMMMMMMMAAA" "AAAMMMMMOMMMMMMMMMMMMMMMMMMMAAA" "AAIMMMMMMMMMMMMMMMMMMMMMMMMMIAA" "AAIMMMMMMMMMMMMMMMMMMMMMMMMMIAA" "AAIMMMMMMMMMMMMMMMMMMMMMMMMMIAA" "AAIMMMMMMMMMMMMMMMMMMMMMMMMMIAA" "AAIMMMMMMMMMMMMMMMMMMMMMMMMMIAA" "AAAMMMMMMMMMMMMMMMMMMMMMMMMMAAA" "AAAMMMMMMMMMMMMMMMMMMMMMMMMMAAA" "AAAIMMMMMMMMMMMMMMMMMMMMMMMIAAA" "AAAAMMMMMMMMMMMMMMMMMMMMMMMAAAA" "AAAAIMMMMMMMMMMMMMMMMMMMMMIAAAA" "AAAAAIMMMMMMMMMMMMMMMMMMMIAAAAA" "AAAAAAIMMMMMMMMMMMMMMMMMIAAAAAA" "AAAAAAAIMMMMMMMMMMMMMMMIAAAAAAA" "AAAAAAAAIMMMMMMMMMMMMMIAAAAAAAA" "AAAAAAAAAAIMMMMMMMMMIAAAAAAAAAA" "AAAAAAAAAAAAAIIIIIAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 9 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAJJJJJAAAAAAAAAAAAA" "AAAAAAAAAAJNNNNNNNNNJAAAAAAAAAA" "AAAAAAAAJNNNNNNNNNNNNNJAAAAAAAA" "AAAAAAAJNNNNNNNNNNNNNNNJAAAAAAA" "AAAAAAJNNNNNNNNNNNNNNNNNJAAAAAA" "AAAAAJNNNNNNNNNNNNNNNNNNNJAAAAA" "AAAAJNNNNNOONNNNNNNNNNNNNNJAAAA" "AAAANNNNNOONNNNNNNNNNNNNNNNAAAA" "AAAJNNNNOONNNNNNNNNNNNNNNNNJAAA" "AAANNNNNOONNNNNNNNNNNNNNNNNNAAA" "AAANNNNNONNNNNNNNNNNNNNNNNNNAAA" "AAJNNNNNNNNNNNNNNNNNNNNNNNNNJAA" "AAJNNNNNNNNNNNNNNNNNNNNNNNNNJAA" "AAJNNNNNNNNNNNNNNNNNNNNNNNNNJAA" "AAJNNNNNNNNNNNNNNNNNNNNNNNNNJAA" "AAJNNNNNNNNNNNNNNNNNNNNNNNNNJAA" "AAANNNNNNNNNNNNNNNNNNNNNNNNNAAA" "AAANNNNNNNNNNNNNNNNNNNNNNNNNAAA" "AAAJNNNNNNNNNNNNNNNNNNNNNNNJAAA" "AAAANNNNNNNNNNNNNNNNNNNNNNNAAAA" "AAAAJNNNNNNNNNNNNNNNNNNNNNJAAAA" "AAAAAJNNNNNNNNNNNNNNNNNNNJAAAAA" "AAAAAAJNNNNNNNNNNNNNNNNNJAAAAAA" "AAAAAAAJNNNNNNNNNNNNNNNJAAAAAAA" "AAAAAAAAJNNNNNNNNNNNNNJAAAAAAAA" "AAAAAAAAAAJNNNNNNNNNJAAAAAAAAAA" "AAAAAAAAAAAAAJJJJJAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "15 135 15 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #00327F" "G c #3F4DA1" "H c #408D61" "I c #5CA951" "J c #007FA1" "K c #7F00FF" "L c #808080" "M c #B9B860" "N c #0064FF" "O c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "..............." "......CCC......" "....CKKKKKC...." "...CKKKKKKKC..." "..CKKOKKKKKKC.." "..KKOKKKKKKKK.." ".CKKOKKKKKKKKC." ".CKKKKKKKKKKKC." ".CKKKKKKKKKKKC." "..KKKKKKKKKKK.." "..CKKKKKKKKKC.." "...CKKKKKKKC..." "....CKKKKKC...." "......CCC......" "..............." /* icon for state 3 */ "..............." "......DDD......" "....DLLLLLD...." "...DLLLLLLLD..." "..DLLOLLLLLLD.." "..LLOLLLLLLLL.." ".DLLOLLLLLLLLD." ".DLLLLLLLLLLLD." ".DLLLLLLLLLLLD." "..LLLLLLLLLLL.." "..DLLLLLLLLLD.." "...DLLLLLLLD..." "....DLLLLLD...." "......DDD......" "..............." /* icon for state 4 */ "..............." "......EEE......" "....EMMMMME...." "...EMMMMMMME..." "..EMMOMMMMMME.." "..MMOMMMMMMMM.." ".EMMOMMMMMMMME." ".EMMMMMMMMMMME." ".EMMMMMMMMMMME." "..MMMMMMMMMMM.." "..EMMMMMMMMME.." "...EMMMMMMME..." "....EMMMMME...." "......EEE......" "..............." /* icon for state 5 */ "..............." "......FFF......" "....FNNNNNF...." "...FNNNNNNNF..." "..FNNONNNNNNF.." "..NNONNNNNNNN.." ".FNNONNNNNNNNF." ".FNNNNNNNNNNNF." ".FNNNNNNNNNNNF." "..NNNNNNNNNNN.." "..FNNNNNNNNNF.." "...FNNNNNNNF..." "....FNNNNNF...." "......FFF......" "..............." /* icon for state 6 */ "AAAAAAAAAAAAAAA" "AAAAAAGGGAAAAAA" "AAAAGKKKKKGAAAA" "AAAGKKKKKKKGAAA" "AAGKKOKKKKKKGAA" "AAKKOKKKKKKKKAA" "AGKKOKKKKKKKKGA" "AGKKKKKKKKKKKGA" "AGKKKKKKKKKKKGA" "AAKKKKKKKKKKKAA" "AAGKKKKKKKKKGAA" "AAAGKKKKKKKGAAA" "AAAAGKKKKKGAAAA" "AAAAAAGGGAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 7 */ "AAAAAAAAAAAAAAA" "AAAAAAHHHAAAAAA" "AAAAHLLLLLHAAAA" "AAAHLLLLLLLHAAA" "AAHLLOLLLLLLHAA" "AALLOLLLLLLLLAA" "AHLLOLLLLLLLLHA" "AHLLLLLLLLLLLHA" "AHLLLLLLLLLLLHA" "AALLLLLLLLLLLAA" "AAHLLLLLLLLLHAA" "AAAHLLLLLLLHAAA" "AAAAHLLLLLHAAAA" "AAAAAAHHHAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 8 */ "AAAAAAAAAAAAAAA" "AAAAAAIIIAAAAAA" "AAAAIMMMMMIAAAA" "AAAIMMMMMMMIAAA" "AAIMMOMMMMMMIAA" "AAMMOMMMMMMMMAA" "AIMMOMMMMMMMMIA" "AIMMMMMMMMMMMIA" "AIMMMMMMMMMMMIA" "AAMMMMMMMMMMMAA" "AAIMMMMMMMMMIAA" "AAAIMMMMMMMIAAA" "AAAAIMMMMMIAAAA" "AAAAAAIIIAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 9 */ "AAAAAAAAAAAAAAA" "AAAAAAJJJAAAAAA" "AAAAJNNNNNJAAAA" "AAAJNNNNNNNJAAA" "AAJNNONNNNNNJAA" "AANNONNNNNNNNAA" "AJNNONNNNNNNNJA" "AJNNNNNNNNNNNJA" "AJNNNNNNNNNNNJA" "AANNNNNNNNNNNAA" "AAJNNNNNNNNNJAA" "AAAJNNNNNNNJAAA" "AAAAJNNNNNJAAAA" "AAAAAAJJJAAAAAA" "AAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "7 63 15 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #00327F" "G c #3F4DA1" "H c #408D61" "I c #5CA951" "J c #007FA1" "K c #7F00FF" "L c #808080" "M c #B9B860" "N c #0064FF" "O c #FFFFFF" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ "..CCC.." ".CKKKC." "CKOKKKC" "CKKKKKC" "CKKKKKC" ".CKKKC." "..CCC.." /* icon for state 3 */ "..DDD.." ".DLLLD." "DLOLLLD" "DLLLLLD" "DLLLLLD" ".DLLLD." "..DDD.." /* icon for state 4 */ "..EEE.." ".EMMME." "EMOMMME" "EMMMMME" "EMMMMME" ".EMMME." "..EEE.." /* icon for state 5 */ "..FFF.." ".FNNNF." "FNONNNF" "FNNNNNF" "FNNNNNF" ".FNNNF." "..FFF.." /* icon for state 6 */ "AAGGGAA" "AGKKKGA" "GKOKKKG" "GKKKKKG" "GKKKKKG" "AGKKKGA" "AAGGGAA" /* icon for state 7 */ "AAHHHAA" "AHLLLHA" "HLOLLLH" "HLLLLLH" "HLLLLLH" "AHLLLHA" "AAHHHAA" /* icon for state 8 */ "AAIIIAA" "AIMMMIA" "IMOMMMI" "IMMMMMI" "IMMMMMI" "AIMMMIA" "AAIIIAA" /* icon for state 9 */ "AAJJJAA" "AJNNNJA" "JNONNNJ" "JNNNNNJ" "JNNNNNJ" "AJNNNJA" "AAJJJAA" ������������������������������������������������������������������golly-2.7-src/Rules/CrittersMargolus_emulated.rule��������������������������������������������������0000644�0001750�0001750�00000006707�12536111364�017406� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE CrittersMargolus_emulated @TREE num_states=5 num_neighbors=8 num_nodes=132 1 0 2 2 4 4 1 0 1 2 3 4 2 0 1 0 1 0 2 1 1 1 1 1 1 0 2 1 4 3 2 0 1 4 1 4 3 2 3 5 3 5 3 3 3 3 3 3 3 5 3 5 3 5 4 6 7 8 7 8 4 7 7 7 7 7 2 4 1 4 1 4 3 2 3 11 3 11 3 11 3 11 3 11 4 12 7 13 7 13 5 9 10 14 10 14 1 0 1 1 3 3 2 16 1 16 1 16 3 17 3 17 3 17 4 18 7 18 7 18 5 19 10 19 10 19 1 0 4 2 2 4 1 0 4 2 4 4 2 0 1 21 1 22 2 0 1 22 1 0 3 2 3 23 3 24 4 25 7 25 7 25 5 26 10 26 10 26 1 0 2 2 2 4 2 0 1 22 1 28 2 0 1 28 1 28 3 2 3 29 3 30 4 31 7 31 7 31 5 32 10 32 10 32 6 15 20 27 20 33 5 10 10 10 10 10 6 20 20 35 20 35 3 2 3 2 3 2 1 0 1 4 3 2 1 0 1 4 3 4 2 1 1 38 1 39 3 40 40 3 40 3 2 1 1 39 1 1 3 42 42 3 42 3 4 37 41 37 43 37 5 44 10 44 10 44 4 25 41 25 43 25 5 46 10 46 10 46 4 31 41 31 43 31 5 48 10 48 10 48 6 45 35 47 35 49 1 0 1 2 3 2 2 1 1 39 1 51 3 52 52 3 52 3 2 1 1 51 1 51 3 54 54 3 54 3 4 37 53 37 55 37 5 56 10 56 10 56 4 25 53 25 55 25 5 58 10 58 10 58 4 31 53 31 55 31 5 60 10 60 10 60 6 57 35 59 35 61 7 34 36 50 36 62 6 35 35 35 35 35 7 36 36 64 36 64 4 37 7 37 7 37 2 38 38 1 38 1 2 39 39 1 39 1 3 3 3 67 3 68 4 69 7 69 7 69 3 3 3 68 3 3 4 71 7 71 7 71 5 66 70 66 72 66 5 26 70 26 72 26 5 32 70 32 72 32 6 73 35 74 35 75 5 44 70 44 72 44 5 46 70 46 72 46 5 48 70 48 72 48 6 77 35 78 35 79 5 56 70 56 72 56 5 58 70 58 72 58 5 60 70 60 72 60 6 81 35 82 35 83 7 76 64 80 64 84 2 51 51 1 51 1 3 3 3 68 3 86 4 87 7 87 7 87 3 3 3 86 3 86 4 89 7 89 7 89 5 66 88 66 90 66 5 26 88 26 90 26 5 32 88 32 90 32 6 91 35 92 35 93 5 44 88 44 90 44 5 46 88 46 90 46 5 48 88 48 90 48 6 95 35 96 35 97 5 56 88 56 90 56 5 58 88 58 90 58 5 60 88 60 90 60 6 99 35 100 35 101 7 94 64 98 64 102 8 63 65 85 65 103 1 0 1 3 3 1 2 105 1 105 1 105 3 106 3 106 3 106 1 0 1 3 3 3 2 108 1 108 1 108 3 109 3 109 3 109 4 18 7 107 7 110 4 18 7 110 7 18 5 19 10 111 10 112 6 113 113 35 113 35 7 114 114 64 114 64 7 64 64 64 64 64 8 115 115 116 115 116 5 66 10 66 10 66 6 118 35 27 35 33 7 119 64 50 64 62 8 120 116 85 116 103 1 0 1 1 3 1 2 122 1 122 1 122 3 123 3 123 3 123 4 18 7 110 7 124 4 18 7 124 7 124 5 19 10 125 10 126 6 127 127 35 127 35 7 128 128 64 128 64 8 129 129 116 129 116 9 104 117 121 130 121 @COLORS 1 90 90 90 2 62 62 62 3 0 255 127 4 0 178 88 5 127 0 255 6 88 0 178 7 148 148 148 8 103 103 103 9 128 255 0 10 89 178 0 11 255 0 128 12 178 0 89 13 0 128 255 14 0 89 178 15 1 159 0 16 0 111 0 17 159 0 1 18 111 0 0 19 255 254 96 20 178 177 67 21 0 1 159 22 0 0 111 23 96 255 254 24 67 178 177 25 254 96 255 26 177 67 178 27 126 125 21 28 88 87 14 29 21 126 125 30 14 88 87 31 125 21 126 32 87 14 88 33 255 116 116 34 178 81 81 35 116 255 116 36 81 178 81 37 116 116 255 38 81 81 178 39 228 227 0 40 159 158 0 41 28 255 27 42 19 178 18 43 255 27 28 44 178 18 19 45 0 228 227 46 0 159 158 47 227 0 228 48 158 0 159 49 27 28 255 50 18 19 178 51 59 59 59 52 41 41 41 53 234 195 176 54 163 136 123 55 175 196 255 56 122 137 178 57 171 194 68 58 119 135 47 59 194 68 171 60 135 47 119 61 68 171 194 62 47 119 135 63 72 184 71 64 50 128 49 65 184 71 72 66 128 49 50 67 71 72 184 68 49 50 128 69 169 255 188 70 118 178 131 71 252 179 63 72 176 125 44 73 63 252 179 74 44 176 125 75 179 63 252 76 125 44 176 77 80 9 0 78 56 6 0 79 0 80 9 80 0 56 6 81 9 0 80 82 6 0 56 83 255 175 250 84 178 122 175 85 199 134 213 86 139 93 149 87 115 100 95 88 80 70 66 89 188 163 0 90 131 114 0 91 0 188 163 92 0 131 114 93 163 0 188 94 114 0 131 95 203 73 0 96 142 51 0 97 0 203 73 98 0 142 51 99 73 0 203 100 51 0 142 101 94 189 0 102 65 132 0 103 189 0 94 104 132 0 65 ���������������������������������������������������������golly-2.7-src/Rules/Langtons-Ant.rule���������������������������������������������������������������0000644�0001750�0001750�00000033360�12536111364�014515� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Langtons-Ant @TREE num_states=10 num_neighbors=4 num_nodes=17 1 0 1 1 1 1 1 0 0 0 0 1 2 6 6 6 6 6 2 2 2 2 2 0 0 0 0 0 1 0 1 0 0 1 5 9 9 9 9 9 5 5 5 5 2 3 3 3 3 3 0 3 0 3 3 3 2 2 2 2 4 2 4 2 2 2 1 3 7 7 7 7 7 3 3 3 3 2 6 6 6 6 6 0 6 0 6 6 2 0 0 0 0 0 0 0 0 0 0 3 7 7 7 7 8 7 8 7 7 7 4 5 5 9 5 5 5 5 5 9 5 1 4 8 8 8 8 8 4 4 4 4 2 11 11 11 11 11 0 11 0 11 11 3 12 12 12 12 8 12 8 12 12 12 3 8 8 8 8 8 8 8 8 8 8 4 13 13 14 13 13 13 13 13 14 13 5 10 10 10 15 10 10 10 10 10 15 @COLORS 0 255 255 255 1 0 0 0 2 0 0 0 3 0 0 0 4 0 0 0 5 0 0 0 6 0 0 0 7 0 0 0 8 0 0 0 9 0 0 0 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 279 2 1" /* colors */ "A c #FFFFFF" ". c #000000" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ ".........A...........A........." ".........A...........A........." "..........A.........A.........." "...........A.......A..........." "............AAAAAAA............" "............A.AAA.A............" ".......A....AAAAAAA....A......." ".......A.....AAAAA.....A......." "........A.....AAA.....A........" ".........A....AAA....A........." "..........AAAAAAAAAAA.........." "...........AAAAAAAAA..........." "..............AAA.............." "..............AAA.............." "..........AAAAAAAAAAA.........." ".........AAAAAAAAAAAAA........." "........AA....AAA....AA........" ".......A......AAA......A......." "......A.......AAA.......A......" "...........AAAAAAAAA..........." "..........AAAAAAAAAAA.........." ".........AA...AAA...AA........." "........A.....AAA.....A........" ".......A.....AAAAA.....A......." "......A.....AAAAAAA.....A......" "............AAAAAAA............" "............AAAAAAA............" "............AAAAAAA............" ".............AAAAA............." "..............................." "..............................." /* icon for state 3 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "......A.....A.................." ".......A.....A.........AA......" "........A.....A.......A........" ".........A....AA.....A.......AA" ".........AA....AA...A.......A.." "..........AA...AA..AA......A..." "...AAAA...AA...AA..AA...AAA...." "..AAAAAA..AA...AA..AA..AA.A...." "..AAAAAAAAAAAAAAAAAAAAAAAAA...." "..AAAAAAAAAAAAAAAAAAAAAAAAA...." "..AAAAAAAAAAAAAAAAAAAAAAAAA...." "..AAAAAA..AA...AA..AA..AA.A...." "...AAAA...AA...AA..AA...AAA...." "..........AA...AA..AA......A..." ".........AA....AA...A.......A.." ".........A....AA.....A.......AA" "........A.....A.......A........" ".......A.....A.........AA......" "......A.....A.................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." ".............AAAAA............." "............AAAAAAA............" "............AAAAAAA............" "............AAAAAAA............" "......A.....AAAAAAA.....A......" ".......A.....AAAAA.....A......." "........A.....AAA.....A........" ".........AA...AAA...AA........." "..........AAAAAAAAAAA.........." "...........AAAAAAAAA..........." "......A.......AAA.......A......" ".......A......AAA......A......." "........AA....AAA....AA........" ".........AAAAAAAAAAAAA........." "..........AAAAAAAAAAA.........." "..............AAA.............." "..............AAA.............." "...........AAAAAAAAA..........." "..........AAAAAAAAAAA.........." ".........A....AAA....A........." "........A.....AAA.....A........" ".......A.....AAAAA.....A......." ".......A....AAAAAAA....A......." "............A.AAA.A............" "............AAAAAAA............" "...........A.......A..........." "..........A.........A.........." ".........A...........A........." ".........A...........A........." /* icon for state 5 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..................A.....A......" "......AA.........A.....A......." "........A.......A.....A........" "AA.......A.....AA....A........." "..A.......A...AA....AA........." "...A......AA..AA...AA.........." "....AAA...AA..AA...AA...AAAA..." "....A.AA..AA..AA...AA..AAAAAA.." "....AAAAAAAAAAAAAAAAAAAAAAAAA.." "....AAAAAAAAAAAAAAAAAAAAAAAAA.." "....AAAAAAAAAAAAAAAAAAAAAAAAA.." "....A.AA..AA..AA...AA..AAAAAA.." "....AAA...AA..AA...AA...AAAA..." "...A......AA..AA...AA.........." "..A.......A...AA....AA........." "AA.......A.....AA....A........." "........A.......A.....A........" "......AA.........A.....A......." "..................A.....A......" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 6 */ "AAAAAAAAA.AAAAAAAAAAA.AAAAAAAAA" "AAAAAAAAA.AAAAAAAAAAA.AAAAAAAAA" "AAAAAAAAAA.AAAAAAAAA.AAAAAAAAAA" "AAAAAAAAAAA.AAAAAAA.AAAAAAAAAAA" "AAAAAAAAAAAA.......AAAAAAAAAAAA" "AAAAAAAAAAAA.A...A.AAAAAAAAAAAA" "AAAAAAA.AAAA.......AAAA.AAAAAAA" "AAAAAAA.AAAAA.....AAAAA.AAAAAAA" "AAAAAAAA.AAAAA...AAAAA.AAAAAAAA" "AAAAAAAAA.AAAA...AAAA.AAAAAAAAA" "AAAAAAAAAA...........AAAAAAAAAA" "AAAAAAAAAAA.........AAAAAAAAAAA" "AAAAAAAAAAAAAA...AAAAAAAAAAAAAA" "AAAAAAAAAAAAAA...AAAAAAAAAAAAAA" "AAAAAAAAAA...........AAAAAAAAAA" "AAAAAAAAA.............AAAAAAAAA" "AAAAAAAA..AAAA...AAAA..AAAAAAAA" "AAAAAAA.AAAAAA...AAAAAA.AAAAAAA" "AAAAAA.AAAAAAA...AAAAAAA.AAAAAA" "AAAAAAAAAAA.........AAAAAAAAAAA" "AAAAAAAAAA...........AAAAAAAAAA" "AAAAAAAAA..AAA...AAA..AAAAAAAAA" "AAAAAAAA.AAAAA...AAAAA.AAAAAAAA" "AAAAAAA.AAAAA.....AAAAA.AAAAAAA" "AAAAAA.AAAAA.......AAAAA.AAAAAA" "AAAAAAAAAAAA.......AAAAAAAAAAAA" "AAAAAAAAAAAA.......AAAAAAAAAAAA" "AAAAAAAAAAAA.......AAAAAAAAAAAA" "AAAAAAAAAAAAA.....AAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 7 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAA.AAAAA.AAAAAAAAAAAAAAAAAA" "AAAAAAA.AAAAA.AAAAAAAAA..AAAAAA" "AAAAAAAA.AAAAA.AAAAAAA.AAAAAAAA" "AAAAAAAAA.AAAA..AAAAA.AAAAAAA.." "AAAAAAAAA..AAAA..AAA.AAAAAAA.AA" "AAAAAAAAAA..AAA..AA..AAAAAA.AAA" "AAA....AAA..AAA..AA..AAA...AAAA" "AA......AA..AAA..AA..AA..A.AAAA" "AA.........................AAAA" "AA.........................AAAA" "AA.........................AAAA" "AA......AA..AAA..AA..AA..A.AAAA" "AAA....AAA..AAA..AA..AAA...AAAA" "AAAAAAAAAA..AAA..AA..AAAAAA.AAA" "AAAAAAAAA..AAAA..AAA.AAAAAAA.AA" "AAAAAAAAA.AAAA..AAAAA.AAAAAAA.." "AAAAAAAA.AAAAA.AAAAAAA.AAAAAAAA" "AAAAAAA.AAAAA.AAAAAAAAA..AAAAAA" "AAAAAA.AAAAA.AAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 8 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAA.....AAAAAAAAAAAAA" "AAAAAAAAAAAA.......AAAAAAAAAAAA" "AAAAAAAAAAAA.......AAAAAAAAAAAA" "AAAAAAAAAAAA.......AAAAAAAAAAAA" "AAAAAA.AAAAA.......AAAAA.AAAAAA" "AAAAAAA.AAAAA.....AAAAA.AAAAAAA" "AAAAAAAA.AAAAA...AAAAA.AAAAAAAA" "AAAAAAAAA..AAA...AAA..AAAAAAAAA" "AAAAAAAAAA...........AAAAAAAAAA" "AAAAAAAAAAA.........AAAAAAAAAAA" "AAAAAA.AAAAAAA...AAAAAAA.AAAAAA" "AAAAAAA.AAAAAA...AAAAAA.AAAAAAA" "AAAAAAAA..AAAA...AAAA..AAAAAAAA" "AAAAAAAAA.............AAAAAAAAA" "AAAAAAAAAA...........AAAAAAAAAA" "AAAAAAAAAAAAAA...AAAAAAAAAAAAAA" "AAAAAAAAAAAAAA...AAAAAAAAAAAAAA" "AAAAAAAAAAA.........AAAAAAAAAAA" "AAAAAAAAAA...........AAAAAAAAAA" "AAAAAAAAA.AAAA...AAAA.AAAAAAAAA" "AAAAAAAA.AAAAA...AAAAA.AAAAAAAA" "AAAAAAA.AAAAA.....AAAAA.AAAAAAA" "AAAAAAA.AAAA.......AAAA.AAAAAAA" "AAAAAAAAAAAA.A...A.AAAAAAAAAAAA" "AAAAAAAAAAAA.......AAAAAAAAAAAA" "AAAAAAAAAAA.AAAAAAA.AAAAAAAAAAA" "AAAAAAAAAA.AAAAAAAAA.AAAAAAAAAA" "AAAAAAAAA.AAAAAAAAAAA.AAAAAAAAA" "AAAAAAAAA.AAAAAAAAAAA.AAAAAAAAA" /* icon for state 9 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAA.AAAAA.AAAAAA" "AAAAAA..AAAAAAAAA.AAAAA.AAAAAAA" "AAAAAAAA.AAAAAAA.AAAAA.AAAAAAAA" "..AAAAAAA.AAAAA..AAAA.AAAAAAAAA" "AA.AAAAAAA.AAA..AAAA..AAAAAAAAA" "AAA.AAAAAA..AA..AAA..AAAAAAAAAA" "AAAA...AAA..AA..AAA..AAA....AAA" "AAAA.A..AA..AA..AAA..AA......AA" "AAAA.........................AA" "AAAA.........................AA" "AAAA.........................AA" "AAAA.A..AA..AA..AAA..AA......AA" "AAAA...AAA..AA..AAA..AAA....AAA" "AAA.AAAAAA..AA..AAA..AAAAAAAAAA" "AA.AAAAAAA.AAA..AAAA..AAAAAAAAA" "..AAAAAAA.AAAAA..AAAA.AAAAAAAAA" "AAAAAAAA.AAAAAAA.AAAAA.AAAAAAAA" "AAAAAA..AAAAAAAAA.AAAAA.AAAAAAA" "AAAAAAAAAAAAAAAAAA.AAAAA.AAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "15 135 2 1" /* colors */ "A c #FFFFFF" ". c #000000" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "....A.....A...." ".....A...A....." "......AAA......" "...A..AAA..A..." "....A..A..A...." ".....AAAAA....." ".......A......." "....AAAAAAA...." "...A...A...A..." ".....AAAAA....." "....A..A..A...." "...A..AAA..A..." "......AAA......" "......AAA......" "..............." /* icon for state 3 */ "..............." "..............." "..............." "...A..A....A..." "....A..A..A...A" ".....A.A.A...A." ".AAA.A.A.A.AA.." ".AAAAAAAAAAAA.." ".AAA.A.A.A.AA.." ".....A.A.A...A." "....A..A..A...A" "...A..A....A..." "..............." "..............." "..............." /* icon for state 4 */ "..............." "......AAA......" "......AAA......" "...A..AAA..A..." "....A..A..A...." ".....AAAAA....." "...A...A...A..." "....AAAAAAA...." ".......A......." ".....AAAAA....." "....A..A..A...." "...A..AAA..A..." "......AAA......" ".....A...A....." "....A.....A...." /* icon for state 5 */ "..............." "..............." "..............." "...A....A..A..." "A...A..A..A...." ".A...A.A.A....." "..AA.A.A.A.AAA." "..AAAAAAAAAAAA." "..AA.A.A.A.AAA." ".A...A.A.A....." "A...A..A..A...." "...A....A..A..." "..............." "..............." "..............." /* icon for state 6 */ "AAAA.AAAAA.AAAA" "AAAAA.AAA.AAAAA" "AAAAAA...AAAAAA" "AAA.AA...AA.AAA" "AAAA.AA.AA.AAAA" "AAAAA.....AAAAA" "AAAAAAA.AAAAAAA" "AAAA.......AAAA" "AAA.AAA.AAA.AAA" "AAAAA.....AAAAA" "AAAA.AA.AA.AAAA" "AAA.AA...AA.AAA" "AAAAAA...AAAAAA" "AAAAAA...AAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 7 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAA.AA.AAAA.AAA" "AAAA.AA.AA.AAA." "AAAAA.A.A.AAA.A" "A...A.A.A.A..AA" "A............AA" "A...A.A.A.A..AA" "AAAAA.A.A.AAA.A" "AAAA.AA.AA.AAA." "AAA.AA.AAAA.AAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 8 */ "AAAAAAAAAAAAAAA" "AAAAAA...AAAAAA" "AAAAAA...AAAAAA" "AAA.AA...AA.AAA" "AAAA.AA.AA.AAAA" "AAAAA.....AAAAA" "AAA.AAA.AAA.AAA" "AAAA.......AAAA" "AAAAAAA.AAAAAAA" "AAAAA.....AAAAA" "AAAA.AA.AA.AAAA" "AAA.AA...AA.AAA" "AAAAAA...AAAAAA" "AAAAA.AAA.AAAAA" "AAAA.AAAAA.AAAA" /* icon for state 9 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAA.AAAA.AA.AAA" ".AAA.AA.AA.AAAA" "A.AAA.A.A.AAAAA" "AA..A.A.A.A...A" "AA............A" "AA..A.A.A.A...A" "A.AAA.A.A.AAAAA" ".AAA.AA.AA.AAAA" "AAA.AAAA.AA.AAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "7 63 2 1" /* colors */ "A c #FFFFFF" ". c #000000" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ ".A...A." "..AAA.." "...A..." ".AAAAA." "...A..." ".AAAAA." "...A..." /* icon for state 3 */ "......." ".A.A..A" ".A.A.A." "AAAAAA." ".A.A.A." ".A.A..A" "......." /* icon for state 4 */ "...A..." ".AAAAA." "...A..." ".AAAAA." "...A..." "..AAA.." ".A...A." /* icon for state 5 */ "......." "A..A.A." ".A.A.A." ".AAAAAA" ".A.A.A." "A..A.A." "......." /* icon for state 6 */ "A.AAA.A" "AA...AA" "AAA.AAA" "A.....A" "AAA.AAA" "A.....A" "AAA.AAA" /* icon for state 7 */ "AAAAAAA" "A.A.AA." "A.A.A.A" "......A" "A.A.A.A" "A.A.AA." "AAAAAAA" /* icon for state 8 */ "AAA.AAA" "A.....A" "AAA.AAA" "A.....A" "AAA.AAA" "AA...AA" "A.AAA.A" /* icon for state 9 */ "AAAAAAA" ".AA.A.A" "A.A.A.A" "A......" "A.A.A.A" ".AA.A.A" "AAAAAAA" ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Caterpillars.rule���������������������������������������������������������������0000644�0001750�0001750�00000001024�12536111364�014625� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Caterpillars @TREE num_states=4 num_neighbors=8 num_nodes=38 1 0 2 3 0 1 0 1 3 0 2 0 1 0 0 2 1 1 1 1 3 2 3 2 2 1 1 2 3 0 2 1 5 1 1 3 3 6 3 3 4 4 7 4 4 2 5 1 5 5 3 6 9 6 6 4 7 10 7 7 5 8 11 8 8 3 9 3 9 9 4 10 13 10 10 5 11 14 11 11 6 12 15 12 12 3 3 3 3 3 4 13 17 13 13 5 14 18 14 14 6 15 19 15 15 7 16 20 16 16 1 1 1 3 0 2 1 22 1 1 3 3 23 3 3 4 17 24 17 17 5 18 25 18 18 6 19 26 19 19 7 20 27 20 20 8 21 28 21 21 2 22 5 22 22 3 23 30 23 23 4 24 31 24 24 5 25 32 25 25 6 26 33 26 26 7 27 34 27 27 8 28 35 28 28 9 29 36 29 29 ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Evoloop.rule��������������������������������������������������������������������0000644�0001750�0001750�00000037607�12536111364�013643� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Evoloop Hiroki Sayama "Toward the Realization of an Evolving Ecosystem on Cellular Automata", Proceedings of the Fourth International Symposium on Artificial Life and Robotics (AROB 4th '99), M. Sugisaka and H. Tanaka, eds., pp.254-257, Beppu, Oita, Japan, 1999. Transition rules from: http://necsi.org/postdocs/sayama/sdsr/java/loops.java Credits: "Self-Replicating Loops & Ant, Programmed by Eli Bachmutsky, Copyleft Feb.1999" Note that the transition table given in the above link is incomplete, and is patched by the function set_undefined_rule(). The table below has these changes incorporated, and was produced automatically by a bottom-up merging procedure from the full 9^5 rule table. See Rules/TableGenerators/make_ruletable.cpp @TABLE # rules: 132 # variables: 123 # format: C,N,E,S,W,C' # # Variables are bound within each transition. # For example, if a={1,2} then 4,a,0->a represents # two transitions: 4,1,0->1 and 4,2,0->2 n_states:9 neighborhood:vonNeumann symmetries:rotate4 var a={0,2,5} var b={0,1,2,3,4,5,6,7} var c={0,1,2,3,4,5,6,7} var d={1,4,6,7} var e={1,4} var f={0,1} var g={0,1,2,3,4,5,6,7,8} var h={0,1,2,3,4,5,6,7,8} var i={2,3,4,5,6,7} var j={0,2,3,5} var k={0,2,3,4,5,6,7} var l={4,6,7} var m={2,5} var n={0,1,8} var o={0,3,5} var p={2,3,5} var q={3,5} var r={2,4,6,7} var s={0,1} var t={0,1} var u={0,1,2,3,4,7} var v={5,6} var w={1,6,7} var x={0,3,5} var y={0,3,5} var z={1,3,5} var A={0,1,3,5} var B={0,1,3,5} var C={1,3,5} var D={1,3,5} var E={0,1,2,3,4,5} var F={0,1,2,4,5} var G={1,2,4} var H={0,1,3,4,5,6} var I={0,1,2,3,4,5,6} var J={1,2,4,6} var K={0,1,2,4,5,6,7} var L={0,1,2,3,4,5,7} var M={1,2,4,6,7} var N={0,3} var O={0,1,2,3,5} var P={0,1,2,3,4} var Q={0,2,3,5,6} var R={0,1,3,4,5,6,7} var S={1,3} var T={1,2,3,5} var U={0,1,3,4,5} var V={0,1,4,5,6} var W={1,4,6} var X={2,3,5} var Y={0,5} var Z={1,2} var aa={0,1,5} var ab={0,2} var ac={2,3,4,5} var ad={2,3,4,5,6} var ae={0,3} var af={0,3} var ag={3,7} var ah={2,8} var ai={0,2,8} var aj={0,8} var ak={0,2,8} var al={6,8} var am={0,1,4,5,6,7} var an={0,1,4,5,6,7} var ao={1,4,6,7} var ap={1,3,4,5,6,7} var aq={2,3,5,8} var ar={0,1,2,3,4,5,6,7,8} var as={0,1,4,6,7} var at={1,5,6} var au={4,7} var av={1,3,4,5,7} var aw={0,4,5,7} var ax={1,4,5,6,7} var ay={0,4,5,7} var az={1,4,5,6,7} var aA={0,1,3,5,6,7} var aB={1,2,3,4,5,7} var aC={0,1,4,7} var aD={2,4,6,7,8} var aE={3,5,6} var aF={2,3,5,6} var aG={2,3,5,6} var aH={2,3} var aI={0,1,3,4,7} var aJ={2,5,6,7} var aK={1,2,3,4,6,7} var aL={1,3,4,7} var aM={0,2,3} var aN={1,2,4,7} var aO={3,6} var aP={1,2,3,4,7} var aQ={3,4,7} var aR={1,2,3,4,5,6,7} var aS={3,4,6,7,8} var aT={0,3,6} var aU={3,4,5,7} var aV={2,3,6} var aW={1,2,3,4,5,6,7} var aX={0,8} var aY={0,8} var aZ={4,5,6,7} var ba={4,6,7,8} var bb={1,2,4,6,7} var bc={4,5} var bd={4,7,8} var be={0,1,4,5,7} var bf={4,5,7} var bg={1,2,4,5,7} var bh={1,2,4,5,7} var bi={0,1,2,3,4,6,7} var bj={2,5,6} var bk={1,3,4,6,7} var bl={0,4,6,7} var bm={6,7,8} var bn={1,3,4,5,6,7} var bo={1,4,7} var bp={2,3,5,6} var bq={2,3,5,6} var br={0,1,2,3,4,5,6,7} var bs={0,1,2,3,4,5,6,7} 0,a,0,0,1,2 0,0,0,0,4,3 0,b,c,1,d,1 0,0,0,2,e,2 f,g,h,i,8,8 0,j,k,l,1,1 0,0,0,4,m,2 0,0,0,7,5,2 f,b,n,8,i,8 0,o,1,j,d,1 0,0,1,0,2,2 0,o,1,2,p,1 0,j,1,q,r,1 f,s,i,t,8,8 0,u,2,1,p,1 0,0,r,p,1,1 0,0,2,3,2,2 0,0,q,1,2,1 0,o,q,2,1,1 0,1,2,v,2,6 w,o,x,y,k,8 z,A,B,C,D,8 1,E,F,G,4,4 1,H,I,J,6,6 1,K,L,M,7,7 1,N,A,j,p,8 1,O,P,4,G,4 1,Q,I,6,J,6 1,b,R,7,M,7 1,N,S,f,T,8 1,O,e,o,4,4 1,U,J,o,6,6 1,V,M,I,7,7 1,I,W,7,3,7 1,o,2,N,4,4 S,j,p,O,5,8 C,j,p,2,X,8 1,0,2,3,2,4 1,f,2,5,2,7 1,f,2,5,4,3 1,f,2,7,3,5 1,Y,3,Z,4,4 C,aa,q,ab,D,8 1,o,5,4,Z,4 1,f,6,2,4,4 1,o,7,3,M,7 C,f,2,X,q,8 1,e,ac,6,2,6 C,f,A,5,ab,8 1,1,4,3,3,4 1,X,2,5,4,4 1,ad,2,7,3,7 1,2,4,3,3,3 1,2,6,2,7,6 X,0,0,0,0,8 2,N,ae,af,ag,1 ah,ai,aj,ak,al,0 X,am,an,d,ao,8 2,b,R,ap,3,1 aq,g,h,ar,8,0 2,as,ab,3,ap,1 2,0,0,3,2,4 2,0,0,4,2,3 X,am,an,v,at,8 2,ab,0,5,au,5 2,0,0,8,av,0 X,aw,ax,ay,az,8 2,aA,ap,ab,3,1 2,0,aB,0,8,0 2,aC,2,0,6,5 2,0,2,0,7,3 2,am,2,ax,3,1 2,aC,2,3,2,3 2,0,2,5,2,5 aD,0,2,6,Y,0 2,0,3,2,ax,1 2,ab,3,aE,2,1 2,2,aF,aG,3,1 2,2,3,4,5,1 3,0,0,0,aH,2 3,R,k,b,v,8 3,0,0,0,7,4 3,aI,R,aJ,aK,8 3,0,0,3,2,2 3,u,U,aL,ao,8 3,0,0,4,2,1 3,aM,b,aN,aO,8 3,0,1,0,2,1 3,f,aP,s,aQ,8 q,R,ax,aR,aK,8 aS,0,1,2,5,0 3,0,2,aT,2,8 3,aC,2,5,2,1 3,0,3,3,2,1 aU,ap,aR,aV,aW,8 4,aj,aX,aY,ai,1 aZ,o,x,y,ap,8 ba,0,am,M,bb,0 l,ar,g,h,8,1 4,o,x,2,q,8 bc,0,o,q,2,8 4,0,0,8,ap,1 ba,0,ao,o,M,0 4,0,ap,0,8,1 ba,0,M,bb,ap,0 bd,0,2,be,M,0 4,0,2,0,q,8 ba,0,2,C,ao,0 4,0,2,aH,2,1 au,0,2,6,2,6 ba,0,3,ao,M,0 ba,0,3,2,ao,0 4,0,3,2,2,1 bf,bg,bh,aR,aW,8 5,b,bi,aF,bj,8 5,0,0,2,3,2 5,aI,bk,bl,bi,8 5,0,1,2,1,8 5,0,2,0,m,2 5,0,2,1,5,2 5,0,2,au,5,8 5,0,3,1,2,0 6,0,2,aC,2,2 al,0,2,aF,2,0 bm,0,3,2,2,0 6,ap,bn,aR,aW,8 6,ap,2,bn,2,8 al,bo,2,2,2,0 6,aF,aG,bp,bq,8 7,0,2,2,2,1 7,0,2,3,2,0 8,b,c,br,bs,0 @TREE num_states=9 num_neighbors=4 num_nodes=377 1 0 8 8 8 1 8 8 8 0 1 2 1 2 3 8 8 8 8 0 1 0 8 2 2 1 5 8 8 0 1 0 8 1 2 8 8 8 8 0 1 3 8 2 3 8 8 8 8 0 1 0 8 2 8 8 8 8 8 0 1 0 8 0 8 8 8 8 8 0 1 0 8 1 4 8 8 8 8 0 1 0 1 0 0 1 0 1 1 0 2 0 1 2 3 4 5 6 7 8 1 1 8 8 8 0 8 0 0 0 1 2 1 2 3 0 5 0 0 0 1 0 8 1 8 8 8 8 8 0 1 1 4 8 8 0 8 0 0 0 1 2 8 2 8 8 8 8 8 0 1 1 6 8 8 0 8 0 0 0 1 1 7 8 8 0 8 0 0 0 2 1 10 11 12 13 14 15 16 8 1 2 1 2 8 0 5 0 0 0 1 0 8 2 8 0 8 0 0 0 1 0 8 2 8 8 2 8 8 0 1 2 4 2 8 0 5 0 0 0 1 0 6 0 8 0 8 0 0 0 1 0 7 2 8 0 5 0 0 0 1 8 8 0 0 1 0 1 1 0 2 2 18 19 20 21 5 22 23 24 1 0 8 4 2 8 8 8 8 0 2 3 12 26 12 12 12 12 12 24 1 2 4 3 1 0 5 0 0 0 1 0 4 8 8 0 8 0 0 0 1 0 6 8 8 0 8 0 0 0 1 0 7 8 8 0 8 0 0 0 2 4 13 28 12 29 14 30 31 24 1 0 8 8 8 8 8 8 8 0 1 0 8 5 8 8 8 8 8 0 2 5 33 5 12 34 33 33 34 24 2 6 15 22 12 30 33 30 31 24 2 7 16 23 12 31 14 31 31 24 2 8 8 24 24 24 24 24 24 8 3 9 17 25 27 32 35 36 37 38 2 1 10 18 12 13 33 15 16 8 1 1 1 2 8 0 8 0 0 0 1 1 8 1 8 0 8 0 0 0 2 10 10 41 42 13 10 15 16 8 1 2 8 2 1 0 8 0 0 0 1 1 4 2 8 0 8 0 0 0 1 1 6 2 8 0 8 0 0 0 1 1 7 2 8 0 8 0 0 0 2 44 41 41 42 45 41 46 47 24 1 1 4 1 8 0 8 0 0 0 1 1 6 1 8 0 8 0 0 0 1 1 7 1 8 0 8 0 0 0 2 12 42 42 12 49 12 50 51 24 2 13 13 45 49 13 13 15 16 24 1 1 8 2 8 0 8 0 0 0 2 33 10 54 12 13 33 15 16 24 2 15 15 41 50 15 15 15 16 24 2 16 16 47 51 16 16 16 16 24 3 40 43 48 52 53 55 56 57 38 2 2 11 19 26 28 5 22 23 24 2 44 54 54 42 45 54 46 47 24 1 0 1 2 8 0 2 2 0 0 1 1 1 2 3 0 5 2 0 0 1 0 8 2 8 1 8 0 1 0 1 2 4 3 8 1 8 0 0 0 1 0 4 2 3 0 5 2 0 0 1 0 7 5 1 0 8 0 0 0 1 0 6 0 8 6 8 0 6 0 1 0 7 2 3 0 5 2 0 0 2 61 62 63 64 65 66 67 68 24 1 1 8 2 8 0 0 0 0 0 1 0 8 2 8 1 8 0 0 0 1 0 8 1 1 8 8 8 8 0 1 0 4 2 8 0 8 0 0 0 1 0 6 1 8 0 8 0 0 0 1 0 7 2 8 0 8 0 0 0 2 5 70 71 72 73 12 74 75 24 1 0 4 1 8 0 8 0 0 0 1 0 6 2 8 0 8 0 0 0 2 73 45 73 77 73 73 78 75 24 1 0 4 5 8 0 8 0 0 0 1 0 7 5 8 0 8 0 0 0 2 20 41 19 12 80 5 78 81 24 1 0 6 5 8 0 8 0 0 0 1 1 6 5 8 0 8 0 0 0 2 83 84 78 74 83 78 78 81 24 1 0 7 3 8 0 8 0 0 0 1 0 7 1 8 0 8 0 0 0 2 86 47 75 87 75 75 75 75 24 2 24 24 24 24 24 24 24 24 24 3 59 60 69 76 79 82 85 88 89 2 3 12 20 12 12 12 12 12 24 1 1 1 1 8 0 8 0 0 0 1 0 5 1 8 0 8 0 0 0 2 5 92 19 12 77 12 74 93 24 2 12 12 12 12 12 12 12 12 24 2 12 49 77 12 77 12 74 87 24 2 12 50 74 12 74 12 74 87 24 2 12 51 87 12 87 12 87 87 24 3 91 52 94 95 96 95 97 98 89 2 4 13 21 12 29 34 30 31 24 1 0 3 2 8 0 8 0 0 0 2 73 45 73 77 73 101 78 75 24 2 29 13 73 77 29 29 30 31 24 2 33 13 73 12 29 33 30 31 24 2 30 15 73 74 30 30 30 31 24 2 31 16 75 87 31 31 31 31 24 3 100 53 102 96 103 104 105 106 89 2 5 14 5 12 14 33 33 14 24 1 1 8 2 0 0 8 0 0 0 2 33 10 109 12 13 33 15 16 24 1 1 8 2 8 0 2 0 0 0 2 20 111 19 12 73 5 22 75 24 2 12 12 12 12 5 12 12 12 24 2 33 33 5 12 33 33 33 33 24 2 33 15 78 12 30 33 30 31 24 2 33 16 75 12 31 33 31 31 24 3 108 110 112 113 104 114 115 116 89 2 15 15 46 50 15 15 15 16 24 2 83 46 78 74 78 78 78 75 24 2 30 15 78 74 30 30 30 31 24 3 36 118 119 97 120 115 120 106 89 2 7 16 23 12 31 34 31 31 24 3 122 57 88 98 106 116 106 106 89 3 38 38 89 89 89 89 89 89 38 4 39 58 90 99 107 117 121 123 124 2 1 10 44 12 13 33 15 16 8 2 10 10 54 42 13 10 15 16 8 2 11 41 54 42 45 109 46 47 24 2 14 10 54 12 13 33 15 16 24 3 126 127 128 52 53 129 118 57 38 1 1 8 8 8 8 8 8 8 0 1 1 1 2 8 8 8 8 8 0 1 1 8 1 8 8 8 8 8 0 1 1 4 8 8 8 8 8 8 0 1 1 6 8 8 8 8 8 8 0 1 1 7 8 8 8 8 8 8 0 2 10 131 132 133 134 131 135 136 8 1 1 4 2 8 8 8 8 8 0 1 1 6 2 8 8 8 8 8 0 1 1 7 2 8 8 8 8 8 0 2 54 132 132 133 138 132 139 140 24 1 1 4 1 8 8 8 8 8 0 1 1 6 1 8 8 8 8 8 0 1 1 7 1 8 8 8 8 8 0 2 42 133 133 133 142 133 143 144 24 2 13 134 138 142 134 134 135 136 24 1 1 8 2 8 8 8 8 8 0 2 10 131 147 133 134 131 135 136 24 2 15 135 132 143 135 135 135 136 24 2 16 136 140 144 136 136 136 136 24 3 43 137 141 145 146 148 149 150 38 2 18 41 41 42 45 54 41 47 24 2 41 132 132 133 138 147 132 140 24 1 1 1 2 3 8 8 8 8 0 1 1 1 2 8 8 8 0 8 0 1 1 1 3 8 8 8 8 8 0 1 1 4 2 3 8 8 8 8 0 1 6 7 2 1 8 8 8 8 0 1 6 6 2 8 8 8 8 8 0 1 1 7 2 3 8 8 8 8 0 2 62 154 155 156 157 158 159 160 24 1 1 1 1 8 8 8 8 8 0 2 92 162 132 162 142 133 143 144 24 2 45 138 138 142 138 138 139 140 24 2 111 132 147 133 138 147 139 140 24 2 46 139 139 143 139 139 139 140 24 2 47 140 140 144 140 140 140 140 24 3 152 153 161 163 164 165 166 167 89 1 1 5 1 8 8 8 8 8 0 2 70 162 147 133 142 133 143 169 24 2 12 133 133 12 142 12 143 144 24 2 49 142 142 142 142 142 143 144 24 2 50 143 143 143 143 143 143 144 24 2 51 144 144 144 144 144 144 144 24 3 52 145 170 171 172 171 173 174 89 1 1 3 2 8 8 8 8 8 0 2 45 138 138 142 138 176 139 140 24 2 15 135 138 143 135 135 135 136 24 3 53 146 177 172 146 146 178 150 89 2 33 10 41 12 13 33 15 16 24 2 10 131 132 133 134 131 135 136 24 2 41 132 147 133 138 147 139 140 24 2 33 131 147 12 134 33 135 136 24 2 15 135 139 143 135 135 135 136 24 3 180 181 182 171 146 183 184 150 89 2 84 139 139 143 139 139 139 140 24 3 118 184 186 173 184 184 184 150 89 3 57 150 167 174 150 150 150 150 89 4 130 151 168 175 179 185 187 188 124 2 2 44 61 5 73 20 83 86 24 2 18 41 62 92 45 111 46 47 24 2 19 41 63 19 73 19 78 75 24 2 20 42 64 12 77 12 74 87 24 2 21 45 65 77 73 73 78 75 24 2 5 41 66 12 101 5 78 75 24 2 22 46 67 74 78 22 78 75 24 2 23 47 68 93 75 75 75 75 24 3 190 191 192 193 194 195 196 197 89 2 11 54 62 70 45 41 84 47 24 2 41 132 154 162 138 132 139 140 24 2 54 132 155 147 138 147 139 140 24 2 42 133 156 133 142 133 143 144 24 2 45 138 157 142 138 138 139 140 24 2 109 132 158 133 176 147 139 140 24 2 46 139 159 143 139 139 139 140 24 2 47 140 160 169 140 140 140 140 24 3 199 200 201 202 203 204 205 206 89 2 19 54 63 71 73 19 78 75 24 2 41 132 155 132 138 147 139 140 24 1 0 4 2 8 8 8 0 8 0 1 0 6 2 8 8 8 8 8 0 1 0 7 2 8 8 8 0 8 0 2 63 155 5 12 210 5 211 212 24 1 0 4 2 8 8 8 8 8 0 1 0 6 1 8 8 8 8 8 0 1 0 7 2 8 8 8 8 8 0 2 19 147 12 12 214 12 215 216 24 2 73 138 210 214 214 214 211 216 24 2 19 147 5 12 214 5 211 216 24 2 78 139 211 215 211 211 211 216 24 2 75 140 212 216 216 216 216 216 24 3 208 209 213 217 218 219 220 221 89 2 26 42 64 72 77 12 74 87 24 2 42 133 156 162 142 133 143 144 24 2 71 132 12 12 214 12 215 216 24 1 0 4 1 8 8 8 8 8 0 1 0 7 1 8 8 8 8 8 0 2 12 133 12 12 226 12 215 227 24 1 0 4 3 8 8 8 8 8 0 1 0 3 1 8 8 8 8 8 0 2 77 142 229 230 226 226 215 227 24 2 74 143 215 215 215 215 215 227 24 1 0 7 3 8 8 8 8 8 0 2 87 144 233 227 227 227 227 227 24 3 223 224 225 228 231 228 232 234 89 2 28 45 65 73 73 80 83 75 24 2 77 142 229 226 226 226 215 227 24 1 0 4 2 3 8 8 8 8 0 2 73 138 238 226 214 214 211 216 24 1 0 4 2 1 8 8 8 8 0 2 73 138 240 226 214 214 211 216 24 1 0 7 2 3 8 8 8 8 0 2 75 140 242 227 216 216 216 216 24 3 236 203 218 237 239 241 220 243 89 2 5 54 66 12 73 5 78 75 24 2 54 147 158 133 138 147 139 140 24 2 5 147 5 12 214 5 211 216 24 1 0 7 2 1 8 8 8 8 0 2 75 140 248 227 216 216 216 216 24 3 245 246 219 228 241 247 220 249 89 2 22 46 67 74 78 78 78 75 24 2 41 132 159 143 139 139 139 140 24 2 73 138 211 215 211 211 211 216 24 2 75 140 211 227 216 216 216 216 24 3 251 252 220 232 253 220 220 254 89 2 23 47 68 75 75 81 81 75 24 2 47 140 160 144 140 140 140 140 24 3 256 257 221 234 243 249 254 243 89 3 89 89 89 89 89 89 89 89 89 4 198 207 222 235 244 250 255 258 259 2 3 12 5 12 12 12 12 12 24 2 12 42 70 12 49 12 50 51 24 2 26 42 71 12 77 12 74 87 24 2 12 12 72 12 12 12 12 12 24 2 12 49 73 12 77 5 74 87 24 2 12 51 75 12 87 12 87 87 24 3 261 262 263 264 265 95 97 266 89 2 12 42 92 12 49 12 50 51 24 2 42 133 162 133 142 133 143 144 24 2 42 133 132 133 142 133 143 144 24 2 12 133 162 12 142 12 143 144 24 3 268 269 270 271 172 171 173 174 89 2 20 42 19 12 77 12 74 87 24 2 42 133 147 133 142 133 143 144 24 2 64 156 12 12 229 12 215 233 24 2 77 142 214 226 226 226 215 227 24 2 87 144 216 227 227 227 227 227 24 3 273 274 275 228 276 228 232 277 89 2 72 162 12 12 230 12 215 227 24 2 12 142 226 12 226 12 215 227 24 2 12 143 215 12 215 12 215 227 24 2 12 144 227 12 227 12 227 227 24 3 95 171 279 95 280 95 281 282 89 2 12 142 230 12 226 12 215 227 24 2 77 142 226 226 226 226 215 227 24 2 87 144 227 227 227 227 227 227 24 3 96 172 276 284 285 280 232 286 89 3 95 171 228 95 280 95 281 282 89 3 97 173 232 281 232 281 232 286 89 2 12 51 93 12 87 12 87 87 24 2 51 144 169 144 144 144 144 144 24 3 290 291 277 282 286 282 286 286 89 4 267 272 278 283 287 288 289 292 259 2 4 13 73 12 29 33 30 31 24 2 28 45 73 77 73 73 78 75 24 2 14 13 73 12 29 33 30 31 24 3 294 53 295 96 103 296 120 106 89 3 53 146 164 172 146 146 184 150 89 2 21 45 73 77 73 73 73 75 24 2 45 138 138 142 138 138 138 140 24 2 65 157 210 229 238 240 211 242 24 2 77 142 214 230 226 226 215 227 24 2 73 138 214 226 214 214 211 216 24 2 75 140 216 227 216 216 216 216 24 3 299 300 301 302 303 303 220 304 89 2 73 142 214 226 226 226 215 227 24 2 5 142 226 12 226 12 215 227 24 3 96 172 306 280 285 307 232 286 89 1 0 4 8 8 8 8 8 8 0 1 0 6 8 8 8 8 8 8 0 1 0 7 8 8 8 8 8 8 0 2 29 134 214 226 309 309 310 311 24 2 30 135 211 215 310 310 310 311 24 2 31 136 216 227 311 311 311 311 24 3 103 146 303 285 312 312 313 314 89 2 34 13 101 12 29 33 30 31 24 2 13 134 176 142 134 134 135 136 24 2 80 138 214 226 214 214 211 216 24 2 33 134 214 12 309 33 310 311 24 3 316 317 318 280 312 319 313 314 89 2 83 139 211 215 211 211 211 216 24 3 120 184 321 232 313 313 313 314 89 3 106 150 304 286 314 314 314 314 89 4 297 298 305 308 315 320 322 323 259 2 5 33 20 12 33 33 33 33 24 2 5 54 19 12 73 5 78 75 24 2 34 13 80 12 29 33 30 31 24 2 34 16 81 12 31 33 31 31 24 3 325 180 326 95 327 114 115 328 89 2 14 10 111 12 13 33 15 16 24 2 54 147 147 133 138 147 139 140 24 3 330 181 331 171 146 183 184 150 89 2 5 109 19 12 73 5 78 75 24 2 66 158 5 12 240 5 211 248 24 2 101 176 214 226 214 214 211 216 24 3 333 182 334 228 335 247 220 304 89 2 14 13 73 5 29 33 30 31 24 3 337 146 303 280 312 319 313 314 89 2 33 135 211 12 310 33 310 311 24 2 33 136 216 12 311 33 311 311 24 3 114 183 247 95 319 114 339 340 89 2 33 15 22 12 30 33 30 31 24 3 342 184 220 281 313 339 313 314 89 2 14 16 75 12 31 33 31 31 24 3 344 150 304 282 314 340 314 314 89 4 329 332 336 288 338 341 343 345 259 2 6 15 83 12 30 33 30 31 24 2 15 15 84 50 15 15 15 16 24 2 22 41 78 74 73 78 78 75 24 2 30 15 83 74 30 30 30 31 24 2 31 16 81 87 31 31 31 31 24 3 347 348 349 97 350 115 120 351 89 2 46 132 139 143 138 139 139 140 24 3 118 184 353 173 184 184 184 150 89 2 22 46 78 74 78 78 78 75 24 2 67 159 211 215 211 211 211 211 24 2 22 139 211 215 211 211 211 216 24 3 355 166 356 232 220 357 220 304 89 3 120 184 220 232 313 313 313 314 89 3 115 184 220 281 313 339 313 314 89 4 352 354 358 289 359 360 359 323 259 2 7 16 86 12 31 33 31 31 24 2 23 47 75 87 75 75 75 75 24 3 362 57 363 98 106 344 106 106 89 2 68 160 212 233 242 248 211 242 24 2 93 169 216 227 227 227 227 227 24 3 363 167 365 366 304 304 304 304 89 2 75 144 216 227 227 227 227 227 24 3 98 174 368 282 286 282 286 286 89 2 34 16 75 12 31 33 31 31 24 2 81 140 216 227 216 216 216 216 24 3 370 150 371 282 314 340 314 314 89 3 106 150 371 286 314 314 314 314 89 4 364 188 367 369 323 372 373 323 259 4 124 124 259 259 259 259 259 259 124 5 125 189 260 293 324 346 361 374 375 @COLORS # colors from # http://necsi.org/postdocs/sayama/sdsr/java/loops.java # Color.black,Color.blue,Color.red,Color.green, # Color.yellow,Color.magenta,Color.white,Color.cyan,Color.orange 1 0 0 255 2 255 0 0 3 0 255 0 4 255 255 0 5 255 0 255 6 255 255 255 7 0 255 255 8 255 128 0 # this is the background state for Evoloop-finite 9 0 0 0 �������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/AbsoluteTurmite_0S11W11E21S21W00N0.rule�����������������������������������������0000644�0001750�0001750�00000026371�12536111364�017564� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE AbsoluteTurmite_0S11W11E21S21W00N0 @TREE num_states=8 num_neighbors=4 num_nodes=17 1 0 1 0 1 1 1 1 0 1 2 5 2 5 5 5 5 2 2 0 0 0 0 0 0 0 1 2 1 1 1 1 1 1 1 0 1 3 6 3 6 6 6 6 3 2 4 4 4 4 4 4 4 0 3 2 2 2 2 3 5 2 2 1 4 7 4 7 7 7 7 4 2 7 7 7 7 7 7 7 0 2 0 0 0 0 0 0 0 0 3 8 8 8 8 9 9 8 8 4 6 6 6 10 6 6 6 6 3 5 5 5 5 9 9 5 5 3 9 9 9 9 9 9 9 9 4 12 12 12 13 12 12 12 12 4 10 10 10 13 10 10 10 10 5 11 11 14 11 11 11 15 11 @COLORS 0 0 0 0 1 0 155 67 2 123 4 243 3 124 124 124 4 178 177 94 5 71 72 170 6 71 141 101 7 102 171 84 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 217 12 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #3F4DA1" "G c #408D61" "H c #5CA951" "I c #7F00FF" "J c #808080" "K c #B9B860" "L c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ "..............................." "..............................." ".............CCCCC............." "..........CIIIIIIIIIC.........." "........CIIIIIIIIIIIIIC........" ".......CIIIIIIIIIIIIIIIC......." "......CIIIIIIIIIIIIIIIIIC......" ".....CIIIIIIIIIIIIIIIIIIIC....." "....CIIIIILLIIIIIIIIIIIIIIC...." "....IIIIILLIIIIIIIIIIIIIIII...." "...CIIIILLIIIIIIIIIIIIIIIIIC..." "...IIIIILLIIIIIIIIIIIIIIIIII..." "...IIIIILIIIIIIIIIIIIIIIIIII..." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "..CIIIIIIIIIIIIIIIIIIIIIIIIIC.." "...IIIIIIIIIIIIIIIIIIIIIIIII..." "...IIIIIIIIIIIIIIIIIIIIIIIII..." "...CIIIIIIIIIIIIIIIIIIIIIIIC..." "....IIIIIIIIIIIIIIIIIIIIIII...." "....CIIIIIIIIIIIIIIIIIIIIIC...." ".....CIIIIIIIIIIIIIIIIIIIC....." "......CIIIIIIIIIIIIIIIIIC......" ".......CIIIIIIIIIIIIIIIC......." "........CIIIIIIIIIIIIIC........" "..........CIIIIIIIIIC.........." ".............CCCCC............." "..............................." "..............................." /* icon for state 3 */ "..............................." "..............................." ".............DDDDD............." "..........DJJJJJJJJJD.........." "........DJJJJJJJJJJJJJD........" ".......DJJJJJJJJJJJJJJJD......." "......DJJJJJJJJJJJJJJJJJD......" ".....DJJJJJJJJJJJJJJJJJJJD....." "....DJJJJJLLJJJJJJJJJJJJJJD...." "....JJJJJLLJJJJJJJJJJJJJJJJ...." "...DJJJJLLJJJJJJJJJJJJJJJJJD..." "...JJJJJLLJJJJJJJJJJJJJJJJJJ..." "...JJJJJLJJJJJJJJJJJJJJJJJJJ..." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "..DJJJJJJJJJJJJJJJJJJJJJJJJJD.." "...JJJJJJJJJJJJJJJJJJJJJJJJJ..." "...JJJJJJJJJJJJJJJJJJJJJJJJJ..." "...DJJJJJJJJJJJJJJJJJJJJJJJD..." "....JJJJJJJJJJJJJJJJJJJJJJJ...." "....DJJJJJJJJJJJJJJJJJJJJJD...." ".....DJJJJJJJJJJJJJJJJJJJD....." "......DJJJJJJJJJJJJJJJJJD......" ".......DJJJJJJJJJJJJJJJD......." "........DJJJJJJJJJJJJJD........" "..........DJJJJJJJJJD.........." ".............DDDDD............." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." ".............EEEEE............." "..........EKKKKKKKKKE.........." "........EKKKKKKKKKKKKKE........" ".......EKKKKKKKKKKKKKKKE......." "......EKKKKKKKKKKKKKKKKKE......" ".....EKKKKKKKKKKKKKKKKKKKE....." "....EKKKKKLLKKKKKKKKKKKKKKE...." "....KKKKKLLKKKKKKKKKKKKKKKK...." "...EKKKKLLKKKKKKKKKKKKKKKKKE..." "...KKKKKLLKKKKKKKKKKKKKKKKKK..." "...KKKKKLKKKKKKKKKKKKKKKKKKK..." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "..EKKKKKKKKKKKKKKKKKKKKKKKKKE.." "...KKKKKKKKKKKKKKKKKKKKKKKKK..." "...KKKKKKKKKKKKKKKKKKKKKKKKK..." "...EKKKKKKKKKKKKKKKKKKKKKKKE..." "....KKKKKKKKKKKKKKKKKKKKKKK...." "....EKKKKKKKKKKKKKKKKKKKKKE...." ".....EKKKKKKKKKKKKKKKKKKKE....." "......EKKKKKKKKKKKKKKKKKE......" ".......EKKKKKKKKKKKKKKKE......." "........EKKKKKKKKKKKKKE........" "..........EKKKKKKKKKE.........." ".............EEEEE............." "..............................." "..............................." /* icon for state 5 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAFIIIIIIIIIFAAAAAAAAAA" "AAAAAAAAFIIIIIIIIIIIIIFAAAAAAAA" "AAAAAAAFIIIIIIIIIIIIIIIFAAAAAAA" "AAAAAAFIIIIIIIIIIIIIIIIIFAAAAAA" "AAAAAFIIIIIIIIIIIIIIIIIIIFAAAAA" "AAAAFIIIIILLIIIIIIIIIIIIIIFAAAA" "AAAAIIIIILLIIIIIIIIIIIIIIIIAAAA" "AAAFIIIILLIIIIIIIIIIIIIIIIIFAAA" "AAAIIIIILLIIIIIIIIIIIIIIIIIIAAA" "AAAIIIIILIIIIIIIIIIIIIIIIIIIAAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAFIIIIIIIIIIIIIIIIIIIIIIIIIFAA" "AAAIIIIIIIIIIIIIIIIIIIIIIIIIAAA" "AAAIIIIIIIIIIIIIIIIIIIIIIIIIAAA" "AAAFIIIIIIIIIIIIIIIIIIIIIIIFAAA" "AAAAIIIIIIIIIIIIIIIIIIIIIIIAAAA" "AAAAFIIIIIIIIIIIIIIIIIIIIIFAAAA" "AAAAAFIIIIIIIIIIIIIIIIIIIFAAAAA" "AAAAAAFIIIIIIIIIIIIIIIIIFAAAAAA" "AAAAAAAFIIIIIIIIIIIIIIIFAAAAAAA" "AAAAAAAAFIIIIIIIIIIIIIFAAAAAAAA" "AAAAAAAAAAFIIIIIIIIIFAAAAAAAAAA" "AAAAAAAAAAAAAFFFFFAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 6 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAGGGGGAAAAAAAAAAAAA" "AAAAAAAAAAGJJJJJJJJJGAAAAAAAAAA" "AAAAAAAAGJJJJJJJJJJJJJGAAAAAAAA" "AAAAAAAGJJJJJJJJJJJJJJJGAAAAAAA" "AAAAAAGJJJJJJJJJJJJJJJJJGAAAAAA" "AAAAAGJJJJJJJJJJJJJJJJJJJGAAAAA" "AAAAGJJJJJLLJJJJJJJJJJJJJJGAAAA" "AAAAJJJJJLLJJJJJJJJJJJJJJJJAAAA" "AAAGJJJJLLJJJJJJJJJJJJJJJJJGAAA" "AAAJJJJJLLJJJJJJJJJJJJJJJJJJAAA" "AAAJJJJJLJJJJJJJJJJJJJJJJJJJAAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAGJJJJJJJJJJJJJJJJJJJJJJJJJGAA" "AAAJJJJJJJJJJJJJJJJJJJJJJJJJAAA" "AAAJJJJJJJJJJJJJJJJJJJJJJJJJAAA" "AAAGJJJJJJJJJJJJJJJJJJJJJJJGAAA" "AAAAJJJJJJJJJJJJJJJJJJJJJJJAAAA" "AAAAGJJJJJJJJJJJJJJJJJJJJJGAAAA" "AAAAAGJJJJJJJJJJJJJJJJJJJGAAAAA" "AAAAAAGJJJJJJJJJJJJJJJJJGAAAAAA" "AAAAAAAGJJJJJJJJJJJJJJJGAAAAAAA" "AAAAAAAAGJJJJJJJJJJJJJGAAAAAAAA" "AAAAAAAAAAGJJJJJJJJJGAAAAAAAAAA" "AAAAAAAAAAAAAGGGGGAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 7 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAHHHHHAAAAAAAAAAAAA" "AAAAAAAAAAHKKKKKKKKKHAAAAAAAAAA" "AAAAAAAAHKKKKKKKKKKKKKHAAAAAAAA" "AAAAAAAHKKKKKKKKKKKKKKKHAAAAAAA" "AAAAAAHKKKKKKKKKKKKKKKKKHAAAAAA" "AAAAAHKKKKKKKKKKKKKKKKKKKHAAAAA" "AAAAHKKKKKLLKKKKKKKKKKKKKKHAAAA" "AAAAKKKKKLLKKKKKKKKKKKKKKKKAAAA" "AAAHKKKKLLKKKKKKKKKKKKKKKKKHAAA" "AAAKKKKKLLKKKKKKKKKKKKKKKKKKAAA" "AAAKKKKKLKKKKKKKKKKKKKKKKKKKAAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAHKKKKKKKKKKKKKKKKKKKKKKKKKHAA" "AAAKKKKKKKKKKKKKKKKKKKKKKKKKAAA" "AAAKKKKKKKKKKKKKKKKKKKKKKKKKAAA" "AAAHKKKKKKKKKKKKKKKKKKKKKKKHAAA" "AAAAKKKKKKKKKKKKKKKKKKKKKKKAAAA" "AAAAHKKKKKKKKKKKKKKKKKKKKKHAAAA" "AAAAAHKKKKKKKKKKKKKKKKKKKHAAAAA" "AAAAAAHKKKKKKKKKKKKKKKKKHAAAAAA" "AAAAAAAHKKKKKKKKKKKKKKKHAAAAAAA" "AAAAAAAAHKKKKKKKKKKKKKHAAAAAAAA" "AAAAAAAAAAHKKKKKKKKKHAAAAAAAAAA" "AAAAAAAAAAAAAHHHHHAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "15 105 12 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #3F4DA1" "G c #408D61" "H c #5CA951" "I c #7F00FF" "J c #808080" "K c #B9B860" "L c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "..............." "......CCC......" "....CIIIIIC...." "...CIIIIIIIC..." "..CIILIIIIIIC.." "..IILIIIIIIII.." ".CIILIIIIIIIIC." ".CIIIIIIIIIIIC." ".CIIIIIIIIIIIC." "..IIIIIIIIIII.." "..CIIIIIIIIIC.." "...CIIIIIIIC..." "....CIIIIIC...." "......CCC......" "..............." /* icon for state 3 */ "..............." "......DDD......" "....DJJJJJD...." "...DJJJJJJJD..." "..DJJLJJJJJJD.." "..JJLJJJJJJJJ.." ".DJJLJJJJJJJJD." ".DJJJJJJJJJJJD." ".DJJJJJJJJJJJD." "..JJJJJJJJJJJ.." "..DJJJJJJJJJD.." "...DJJJJJJJD..." "....DJJJJJD...." "......DDD......" "..............." /* icon for state 4 */ "..............." "......EEE......" "....EKKKKKE...." "...EKKKKKKKE..." "..EKKLKKKKKKE.." "..KKLKKKKKKKK.." ".EKKLKKKKKKKKE." ".EKKKKKKKKKKKE." ".EKKKKKKKKKKKE." "..KKKKKKKKKKK.." "..EKKKKKKKKKE.." "...EKKKKKKKE..." "....EKKKKKE...." "......EEE......" "..............." /* icon for state 5 */ "AAAAAAAAAAAAAAA" "AAAAAAFFFAAAAAA" "AAAAFIIIIIFAAAA" "AAAFIIIIIIIFAAA" "AAFIILIIIIIIFAA" "AAIILIIIIIIIIAA" "AFIILIIIIIIIIFA" "AFIIIIIIIIIIIFA" "AFIIIIIIIIIIIFA" "AAIIIIIIIIIIIAA" "AAFIIIIIIIIIFAA" "AAAFIIIIIIIFAAA" "AAAAFIIIIIFAAAA" "AAAAAAFFFAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 6 */ "AAAAAAAAAAAAAAA" "AAAAAAGGGAAAAAA" "AAAAGJJJJJGAAAA" "AAAGJJJJJJJGAAA" "AAGJJLJJJJJJGAA" "AAJJLJJJJJJJJAA" "AGJJLJJJJJJJJGA" "AGJJJJJJJJJJJGA" "AGJJJJJJJJJJJGA" "AAJJJJJJJJJJJAA" "AAGJJJJJJJJJGAA" "AAAGJJJJJJJGAAA" "AAAAGJJJJJGAAAA" "AAAAAAGGGAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 7 */ "AAAAAAAAAAAAAAA" "AAAAAAHHHAAAAAA" "AAAAHKKKKKHAAAA" "AAAHKKKKKKKHAAA" "AAHKKLKKKKKKHAA" "AAKKLKKKKKKKKAA" "AHKKLKKKKKKKKHA" "AHKKKKKKKKKKKHA" "AHKKKKKKKKKKKHA" "AAKKKKKKKKKKKAA" "AAHKKKKKKKKKHAA" "AAAHKKKKKKKHAAA" "AAAAHKKKKKHAAAA" "AAAAAAHHHAAAAAA" "AAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "7 49 12 1" /* colors */ "A c #009B43" ". c #000000" "C c #3F007F" "D c #404040" "E c #5C5C30" "F c #3F4DA1" "G c #408D61" "H c #5CA951" "I c #7F00FF" "J c #808080" "K c #B9B860" "L c #FFFFFF" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ "..CCC.." ".CIIIC." "CILIIIC" "CIIIIIC" "CIIIIIC" ".CIIIC." "..CCC.." /* icon for state 3 */ "..DDD.." ".DJJJD." "DJLJJJD" "DJJJJJD" "DJJJJJD" ".DJJJD." "..DDD.." /* icon for state 4 */ "..EEE.." ".EKKKE." "EKLKKKE" "EKKKKKE" "EKKKKKE" ".EKKKE." "..EEE.." /* icon for state 5 */ "AAFFFAA" "AFIIIFA" "FILIIIF" "FIIIIIF" "FIIIIIF" "AFIIIFA" "AAFFFAA" /* icon for state 6 */ "AAGGGAA" "AGJJJGA" "GJLJJJG" "GJJJJJG" "GJJJJJG" "AGJJJGA" "AAGGGAA" /* icon for state 7 */ "AAHHHAA" "AHKKKHA" "HKLKKKH" "HKKKKKH" "HKKKKKH" "AHKKKHA" "AAHHHAA" �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Rules/Turmite_180121020081.rule�������������������������������������������������������0000644�0001750�0001750�00000064756�12536111364�015145� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@RULE Turmite_180121020081 @TREE num_states=18 num_neighbors=4 num_nodes=27 1 0 1 1 1 1 1 0 0 0 0 1 1 1 1 0 0 0 0 1 2 10 10 10 10 10 2 2 2 2 10 10 10 10 2 2 2 2 1 6 14 14 14 14 14 6 6 6 6 14 14 14 14 6 6 6 6 2 0 0 0 1 0 0 0 0 0 1 0 0 0 2 0 2 0 0 1 5 13 13 13 13 13 5 5 5 5 13 13 13 13 5 5 5 5 2 4 4 4 0 4 4 4 4 4 0 4 4 4 0 4 0 4 4 1 9 17 17 17 17 17 9 9 9 9 17 17 17 17 9 9 9 9 2 6 6 6 0 6 6 6 6 6 0 6 6 6 0 6 0 6 6 3 3 3 5 3 3 3 3 3 5 3 3 3 7 3 7 3 3 3 1 3 11 11 11 11 11 3 3 3 3 11 11 11 11 3 3 3 3 2 9 9 9 0 9 9 9 9 9 0 9 9 9 0 9 0 9 9 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 10 10 11 10 10 10 10 10 11 10 10 10 11 10 11 10 10 10 1 7 15 15 15 15 15 7 7 7 7 15 15 15 15 7 7 7 7 2 13 13 13 0 13 13 13 13 13 0 13 13 13 0 13 0 13 13 3 14 14 11 14 14 14 14 14 11 14 14 14 11 14 11 14 14 14 4 8 8 8 8 12 8 12 8 8 8 15 8 8 8 8 8 15 8 1 4 12 12 12 12 12 4 4 4 4 12 12 12 12 4 4 4 4 2 17 17 17 0 17 17 17 17 17 0 17 17 17 0 17 0 17 17 3 18 18 11 18 18 18 18 18 11 18 18 18 11 18 11 18 18 18 3 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 4 19 19 19 19 20 19 20 19 19 19 20 19 19 19 19 19 20 19 1 8 16 16 16 16 16 8 8 8 8 16 16 16 16 8 8 8 8 2 22 22 22 0 22 22 22 22 22 0 22 22 22 0 22 0 22 22 3 23 23 11 23 23 23 23 23 11 23 23 23 11 23 11 23 23 23 4 24 24 24 24 20 24 20 24 24 24 20 24 24 24 24 24 20 24 5 16 16 16 16 16 21 16 21 16 16 16 25 16 16 16 16 16 25 @COLORS 0 0 0 0 1 0 155 67 2 131 12 251 3 131 12 251 4 131 12 251 5 131 12 251 6 132 132 132 7 132 132 132 8 132 132 132 9 132 132 132 10 23 130 99 11 23 130 99 12 23 130 99 13 23 130 99 14 23 151 78 15 23 151 78 16 23 151 78 17 23 151 78 @ICONS XPM /* width height num_colors chars_per_pixel */ "31 527 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 2 */ "..............................." ".......C...............C......." ".......C...............C......." "........C.............C........" "........C.............C........" ".........CCCIICCCIICCC........." "............IICCCII............" ".............CCCCC............." "........CC....CCC....CC........" ".........CC...CCC...CC........." "..........CC..CCC..CC.........." "...........CCCCCCCCC..........." "............CCCCCCC............" "..............CCC.............." "..............CCC.............." "...........CCCCCCCCC..........." "..........CCCCCCCCCCC.........." ".........CC...CCC...CC........." "........CC....CCC....CC........" ".............CCCCC............." "............CCCCCCC............" "...........CC.CCC.CC..........." "..........CC..CCC..CC.........." ".........CC...CCC...CC........." "........CC...ECCCE...CC........" ".............CCCCC............." ".............CCCCC............." ".............ECCCE............." "..............CCC.............." "..............................." "..............................." /* icon for state 3 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................CC." "......C.....C.........C...CC..." "......CC....CC.......CC..C....." ".......CC....CC.....CC...C....." "........CC....CC...CC....C....." ".........CC...CC..CC....II....." "...ECCE...CC..CC..CC...CII....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "..CCCCCCCCCCCCCCCCCCCCCCCC....." "...ECCE...CC..CC..CC...CII....." ".........CC...CC..CC....II....." "........CC....CC...CC....C....." ".......CC....CC.....CC...C....." "......CC....CC.......CC..C....." "......C.....C.........C...CC..." "............................CC." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 4 */ "..............................." "..............................." "..............CCC.............." ".............ECCCE............." ".............CCCCC............." ".............CCCCC............." "........CC...ECCCE...CC........" ".........CC...CCC...CC........." "..........CC..CCC..CC.........." "...........CC.CCC.CC..........." "............CCCCCCC............" ".............CCCCC............." "........CC....CCC....CC........" ".........CC...CCC...CC........." "..........CCCCCCCCCCC.........." "...........CCCCCCCCC..........." "..............CCC.............." "..............CCC.............." "............CCCCCCC............" "...........CCCCCCCCC..........." "..........CC..CCC..CC.........." ".........CC...CCC...CC........." "........CC....CCC....CC........" ".............CCCCC............." "............IICCCII............" ".........CCCIICCCIICCC........." "........C.............C........" "........C.............C........" ".......C...............C......." ".......C...............C......." "..............................." /* icon for state 5 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".CC............................" "...CC...C.........C.....C......" ".....C..CC.......CC....CC......" ".....C...CC.....CC....CC......." ".....C....CC...CC....CC........" ".....II....CC..CC...CC........." ".....IIC...CC..CC..CC...ECCE..." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....CCCCCCCCCCCCCCCCCCCCCCCC.." ".....IIC...CC..CC..CC...ECCE..." ".....II....CC..CC...CC........." ".....C....CC...CC....CC........" ".....C...CC.....CC....CC......." ".....C..CC.......CC....CC......" "...CC...C.........C.....C......" ".CC............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 6 */ "..............................." ".......D...............D......." ".......D...............D......." "........D.............D........" "........D.............D........" ".........DDDIIDDDIIDDD........." "............IIDDDII............" ".............DDDDD............." "........DD....DDD....DD........" ".........DD...DDD...DD........." "..........DD..DDD..DD.........." "...........DDDDDDDDD..........." "............DDDDDDD............" "..............DDD.............." "..............DDD.............." "...........DDDDDDDDD..........." "..........DDDDDDDDDDD.........." ".........DD...DDD...DD........." "........DD....DDD....DD........" ".............DDDDD............." "............DDDDDDD............" "...........DD.DDD.DD..........." "..........DD..DDD..DD.........." ".........DD...DDD...DD........." "........DD...FDDDF...DD........" ".............DDDDD............." ".............DDDDD............." ".............FDDDF............." "..............DDD.............." "..............................." "..............................." /* icon for state 7 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "............................DD." "......D.....D.........D...DD..." "......DD....DD.......DD..D....." ".......DD....DD.....DD...D....." "........DD....DD...DD....D....." ".........DD...DD..DD....II....." "...FDDF...DD..DD..DD...DII....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "..DDDDDDDDDDDDDDDDDDDDDDDD....." "...FDDF...DD..DD..DD...DII....." ".........DD...DD..DD....II....." "........DD....DD...DD....D....." ".......DD....DD.....DD...D....." "......DD....DD.......DD..D....." "......D.....D.........D...DD..." "............................DD." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 8 */ "..............................." "..............................." "..............DDD.............." ".............FDDDF............." ".............DDDDD............." ".............DDDDD............." "........DD...FDDDF...DD........" ".........DD...DDD...DD........." "..........DD..DDD..DD.........." "...........DD.DDD.DD..........." "............DDDDDDD............" ".............DDDDD............." "........DD....DDD....DD........" ".........DD...DDD...DD........." "..........DDDDDDDDDDD.........." "...........DDDDDDDDD..........." "..............DDD.............." "..............DDD.............." "............DDDDDDD............" "...........DDDDDDDDD..........." "..........DD..DDD..DD.........." ".........DD...DDD...DD........." "........DD....DDD....DD........" ".............DDDDD............." "............IIDDDII............" ".........DDDIIDDDIIDDD........." "........D.............D........" "........D.............D........" ".......D...............D......." ".......D...............D......." "..............................." /* icon for state 9 */ "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." ".DD............................" "...DD...D.........D.....D......" ".....D..DD.......DD....DD......" ".....D...DD.....DD....DD......." ".....D....DD...DD....DD........" ".....II....DD..DD...DD........." ".....IID...DD..DD..DD...FDDF..." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....DDDDDDDDDDDDDDDDDDDDDDDD.." ".....IID...DD..DD..DD...FDDF..." ".....II....DD..DD...DD........." ".....D....DD...DD....DD........" ".....D...DD.....DD....DD......." ".....D..DD.......DD....DD......" "...DD...D.........D.....D......" ".DD............................" "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." "..............................." /* icon for state 10 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAAACCCIICCCIICCCAAAAAAAAA" "AAAAAAAAAAAAIICCCIIAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAACCCCCCCCCCCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAACCACCCACCAAAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAGCCCGAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAAGCCCGAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 11 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAACCA" "AAAAAACAAAAACAAAAAAAAACAAACCAAA" "AAAAAACCAAAACCAAAAAAACCAACAAAAA" "AAAAAAACCAAAACCAAAAACCAAACAAAAA" "AAAAAAAACCAAAACCAAACCAAAACAAAAA" "AAAAAAAAACCAAACCAACCAAAAIIAAAAA" "AAAGCCGAAACCAACCAACCAAACIIAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AACCCCCCCCCCCCCCCCCCCCCCCCAAAAA" "AAAGCCGAAACCAACCAACCAAACIIAAAAA" "AAAAAAAAACCAAACCAACCAAAAIIAAAAA" "AAAAAAAACCAAAACCAAACCAAAACAAAAA" "AAAAAAACCAAAACCAAAAACCAAACAAAAA" "AAAAAACCAAAACCAAAAAAACCAACAAAAA" "AAAAAACAAAAACAAAAAAAAACAAACCAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAACCA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 12 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAGCCCGAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAGCCCGAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAAAACCACCCACCAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAAAACCCCCCCCCCCAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAAAACCCAAAAAAAAAAAAAA" "AAAAAAAAAAAACCCCCCCAAAAAAAAAAAA" "AAAAAAAAAAACCCCCCCCCAAAAAAAAAAA" "AAAAAAAAAACCAACCCAACCAAAAAAAAAA" "AAAAAAAAACCAAACCCAAACCAAAAAAAAA" "AAAAAAAACCAAAACCCAAAACCAAAAAAAA" "AAAAAAAAAAAAACCCCCAAAAAAAAAAAAA" "AAAAAAAAAAAAIICCCIIAAAAAAAAAAAA" "AAAAAAAAACCCIICCCIICCCAAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAAACAAAAAAAAAAAAACAAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAACAAAAAAAAAAAAAAACAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 13 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "ACCAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAACCAAACAAAAAAAAACAAAAACAAAAAA" "AAAAACAACCAAAAAAACCAAAACCAAAAAA" "AAAAACAAACCAAAAACCAAAACCAAAAAAA" "AAAAACAAAACCAAACCAAAACCAAAAAAAA" "AAAAAIIAAAACCAACCAAACCAAAAAAAAA" "AAAAAIICAAACCAACCAACCAAAGCCGAAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAACCCCCCCCCCCCCCCCCCCCCCCCAA" "AAAAAIICAAACCAACCAACCAAAGCCGAAA" "AAAAAIIAAAACCAACCAAACCAAAAAAAAA" "AAAAACAAAACCAAACCAAAACCAAAAAAAA" "AAAAACAAACCAAAAACCAAAACCAAAAAAA" "AAAAACAACCAAAAAAACCAAAACCAAAAAA" "AAACCAAACAAAAAAAAACAAAAACAAAAAA" "ACCAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 14 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAAADDDIIDDDIIDDDAAAAAAAAA" "AAAAAAAAAAAAIIDDDIIAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAADDDDDDDDDDDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAADDADDDADDAAAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAHDDDHAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAAHDDDHAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 15 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAADDA" "AAAAAADAAAAADAAAAAAAAADAAADDAAA" "AAAAAADDAAAADDAAAAAAADDAADAAAAA" "AAAAAAADDAAAADDAAAAADDAAADAAAAA" "AAAAAAAADDAAAADDAAADDAAAADAAAAA" "AAAAAAAAADDAAADDAADDAAAAIIAAAAA" "AAAHDDHAAADDAADDAADDAAADIIAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AADDDDDDDDDDDDDDDDDDDDDDDDAAAAA" "AAAHDDHAAADDAADDAADDAAADIIAAAAA" "AAAAAAAAADDAAADDAADDAAAAIIAAAAA" "AAAAAAAADDAAAADDAAADDAAAADAAAAA" "AAAAAAADDAAAADDAAAAADDAAADAAAAA" "AAAAAADDAAAADDAAAAAAADDAADAAAAA" "AAAAAADAAAAADAAAAAAAAADAAADDAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAADDA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 16 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAHDDDHAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAHDDDHAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAAAADDADDDADDAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAAAADDDDDDDDDDDAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAAAADDDAAAAAAAAAAAAAA" "AAAAAAAAAAAADDDDDDDAAAAAAAAAAAA" "AAAAAAAAAAADDDDDDDDDAAAAAAAAAAA" "AAAAAAAAAADDAADDDAADDAAAAAAAAAA" "AAAAAAAAADDAAADDDAAADDAAAAAAAAA" "AAAAAAAADDAAAADDDAAAADDAAAAAAAA" "AAAAAAAAAAAAADDDDDAAAAAAAAAAAAA" "AAAAAAAAAAAAIIDDDIIAAAAAAAAAAAA" "AAAAAAAAADDDIIDDDIIDDDAAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAAADAAAAAAAAAAAAADAAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAADAAAAAAAAAAAAAAADAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" /* icon for state 17 */ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "ADDAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAADDAAADAAAAAAAAADAAAAADAAAAAA" "AAAAADAADDAAAAAAADDAAAADDAAAAAA" "AAAAADAAADDAAAAADDAAAADDAAAAAAA" "AAAAADAAAADDAAADDAAAADDAAAAAAAA" "AAAAAIIAAAADDAADDAAADDAAAAAAAAA" "AAAAAIIDAAADDAADDAADDAAAHDDHAAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAADDDDDDDDDDDDDDDDDDDDDDDDAA" "AAAAAIIDAAADDAADDAADDAAAHDDHAAA" "AAAAAIIAAAADDAADDAAADDAAAAAAAAA" "AAAAADAAAADDAAADDAAAADDAAAAAAAA" "AAAAADAAADDAAAAADDAAAADDAAAAAAA" "AAAAADAADDAAAAAAADDAAAADDAAAAAA" "AAADDAAADAAAAAAAAADAAAAADAAAAAA" "ADDAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "15 255 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 2 */ "....C.....C...." ".....C...C....." "......ICI......" "...C..CCC..C..." "....C..C..C...." ".....CCCCC....." ".......C......." "....CCCCCCC...." "...C...C...C..." ".....CCCCC....." "....C..C..C...." "...C..ECE..C..." "......CCC......" "......ECE......" "..............." /* icon for state 3 */ "..............." "..............." "..............." "...C..C....C..." "....C..C..C...C" ".....C.C.C...C." ".ECE.C.C.C.CI.." ".CCCCCCCCCCCC.." ".ECE.C.C.C.CI.." ".....C.C.C...C." "....C..C..C...C" "...C..C....C..." "..............." "..............." "..............." /* icon for state 4 */ "..............." "......ECE......" "......CCC......" "...C..ECE..C..." "....C..C..C...." ".....CCCCC....." "...C...C...C..." "....CCCCCCC...." ".......C......." ".....CCCCC....." "....C..C..C...." "...C..CCC..C..." "......ICI......" ".....C...C....." "....C.....C...." /* icon for state 5 */ "..............." "..............." "..............." "...C....C..C..." "C...C..C..C...." ".C...C.C.C....." "..IC.C.C.C.ECE." "..CCCCCCCCCCCC." "..IC.C.C.C.ECE." ".C...C.C.C....." "C...C..C..C...." "...C....C..C..." "..............." "..............." "..............." /* icon for state 6 */ "....D.....D...." ".....D...D....." "......IDI......" "...D..DDD..D..." "....D..D..D...." ".....DDDDD....." ".......D......." "....DDDDDDD...." "...D...D...D..." ".....DDDDD....." "....D..D..D...." "...D..FDF..D..." "......DDD......" "......FDF......" "..............." /* icon for state 7 */ "..............." "..............." "..............." "...D..D....D..." "....D..D..D...D" ".....D.D.D...D." ".FDF.D.D.D.DI.." ".DDDDDDDDDDDD.." ".FDF.D.D.D.DI.." ".....D.D.D...D." "....D..D..D...D" "...D..D....D..." "..............." "..............." "..............." /* icon for state 8 */ "..............." "......FDF......" "......DDD......" "...D..FDF..D..." "....D..D..D...." ".....DDDDD....." "...D...D...D..." "....DDDDDDD...." ".......D......." ".....DDDDD....." "....D..D..D...." "...D..DDD..D..." "......IDI......" ".....D...D....." "....D.....D...." /* icon for state 9 */ "..............." "..............." "..............." "...D....D..D..." "D...D..D..D...." ".D...D.D.D....." "..ID.D.D.D.FDF." "..DDDDDDDDDDDD." "..ID.D.D.D.FDF." ".D...D.D.D....." "D...D..D..D...." "...D....D..D..." "..............." "..............." "..............." /* icon for state 10 */ "AAAACAAAAACAAAA" "AAAAACAAACAAAAA" "AAAAAAICIAAAAAA" "AAACAACCCAACAAA" "AAAACAACAACAAAA" "AAAAACCCCCAAAAA" "AAAAAAACAAAAAAA" "AAAACCCCCCCAAAA" "AAACAAACAAACAAA" "AAAAACCCCCAAAAA" "AAAACAACAACAAAA" "AAACAAGCGAACAAA" "AAAAAACCCAAAAAA" "AAAAAAGCGAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 11 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAACAACAAAACAAA" "AAAACAACAACAAAC" "AAAAACACACAAACA" "AGCGACACACACIAA" "ACCCCCCCCCCCCAA" "AGCGACACACACIAA" "AAAAACACACAAACA" "AAAACAACAACAAAC" "AAACAACAAAACAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 12 */ "AAAAAAAAAAAAAAA" "AAAAAAGCGAAAAAA" "AAAAAACCCAAAAAA" "AAACAAGCGAACAAA" "AAAACAACAACAAAA" "AAAAACCCCCAAAAA" "AAACAAACAAACAAA" "AAAACCCCCCCAAAA" "AAAAAAACAAAAAAA" "AAAAACCCCCAAAAA" "AAAACAACAACAAAA" "AAACAACCCAACAAA" "AAAAAAICIAAAAAA" "AAAAACAAACAAAAA" "AAAACAAAAACAAAA" /* icon for state 13 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAACAAAACAACAAA" "CAAACAACAACAAAA" "ACAAACACACAAAAA" "AAICACACACAGCGA" "AACCCCCCCCCCCCA" "AAICACACACAGCGA" "ACAAACACACAAAAA" "CAAACAACAACAAAA" "AAACAAAACAACAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 14 */ "AAAADAAAAADAAAA" "AAAAADAAADAAAAA" "AAAAAAIDIAAAAAA" "AAADAADDDAADAAA" "AAAADAADAADAAAA" "AAAAADDDDDAAAAA" "AAAAAAADAAAAAAA" "AAAADDDDDDDAAAA" "AAADAAADAAADAAA" "AAAAADDDDDAAAAA" "AAAADAADAADAAAA" "AAADAAHDHAADAAA" "AAAAAADDDAAAAAA" "AAAAAAHDHAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 15 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAADAADAAAADAAA" "AAAADAADAADAAAD" "AAAAADADADAAADA" "AHDHADADADADIAA" "ADDDDDDDDDDDDAA" "AHDHADADADADIAA" "AAAAADADADAAADA" "AAAADAADAADAAAD" "AAADAADAAAADAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" /* icon for state 16 */ "AAAAAAAAAAAAAAA" "AAAAAAHDHAAAAAA" "AAAAAADDDAAAAAA" "AAADAAHDHAADAAA" "AAAADAADAADAAAA" "AAAAADDDDDAAAAA" "AAADAAADAAADAAA" "AAAADDDDDDDAAAA" "AAAAAAADAAAAAAA" "AAAAADDDDDAAAAA" "AAAADAADAADAAAA" "AAADAADDDAADAAA" "AAAAAAIDIAAAAAA" "AAAAADAAADAAAAA" "AAAADAAAAADAAAA" /* icon for state 17 */ "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAADAAAADAADAAA" "DAAADAADAADAAAA" "ADAAADADADAAAAA" "AAIDADADADAHDHA" "AADDDDDDDDDDDDA" "AAIDADADADAHDHA" "ADAAADADADAAAAA" "DAAADAADAADAAAA" "AAADAAAADAADAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAA" XPM /* width height num_colors chars_per_pixel */ "7 119 9 1" /* colors */ "A c #009B43" ". c #000000" "C c #7F00FF" "D c #808080" "E c #3F007F" "F c #404040" "G c #3F4DA1" "H c #408D61" "I c #FFFFFF" /* icon for state 1 */ "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" "AAAAAAA" /* icon for state 2 */ ".C...C." "..ICI.." "...C..." ".CCCCC." "...C..." ".CCCCC." "...C..." /* icon for state 3 */ "......." ".C.C..C" ".C.C.I." "CCCCCC." ".C.C.I." ".C.C..C" "......." /* icon for state 4 */ "...C..." ".CCCCC." "...C..." ".CCCCC." "...C..." "..ICI.." ".C...C." /* icon for state 5 */ "......." "C..C.C." ".I.C.C." ".CCCCCC" ".I.C.C." "C..C.C." "......." /* icon for state 6 */ ".D...D." "..IDI.." "...D..." ".DDDDD." "...D..." ".DDDDD." "...D..." /* icon for state 7 */ "......." ".D.D..D" ".D.D.I." "DDDDDD." ".D.D.I." ".D.D..D" "......." /* icon for state 8 */ "...D..." ".DDDDD." "...D..." ".DDDDD." "...D..." "..IDI.." ".D...D." /* icon for state 9 */ "......." "D..D.D." ".I.D.D." ".DDDDDD" ".I.D.D." "D..D.D." "......." /* icon for state 10 */ "ACAAACA" "AAICIAA" "AAACAAA" "ACCCCCA" "AAACAAA" "ACCCCCA" "AAACAAA" /* icon for state 11 */ "AAAAAAA" "ACACAAC" "ACACAIA" "CCCCCCA" "ACACAIA" "ACACAAC" "AAAAAAA" /* icon for state 12 */ "AAACAAA" "ACCCCCA" "AAACAAA" "ACCCCCA" "AAACAAA" "AAICIAA" "ACAAACA" /* icon for state 13 */ "AAAAAAA" "CAACACA" "AIACACA" "ACCCCCC" "AIACACA" "CAACACA" "AAAAAAA" /* icon for state 14 */ "ADAAADA" "AAIDIAA" "AAADAAA" "ADDDDDA" "AAADAAA" "ADDDDDA" "AAADAAA" /* icon for state 15 */ "AAAAAAA" "ADADAAD" "ADADAIA" "DDDDDDA" "ADADAIA" "ADADAAD" "AAAAAAA" /* icon for state 16 */ "AAADAAA" "ADDDDDA" "AAADAAA" "ADDDDDA" "AAADAAA" "AAIDIAA" "ADAAADA" /* icon for state 17 */ "AAAAAAA" "DAADADA" "AIADADA" "ADDDDDD" "AIADADA" "DAADADA" "AAAAAAA" ������������������golly-2.7-src/Help/���������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�12536111546�011172� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Help/about.gif������������������������������������������������������������������������0000644�0001750�0001750�00000136171�12536111364�012722� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89aya�ð1ÿÿÿ333!ÿ NETSCAPE2.0�}�!þGifBuilder 1.1�!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷¾xÃý†Ä¢ñØ ‘̦óù»5”ЪõŠÚ"K„´› ‹ÇÌ­JhfHÉì¶ÛØM×`úúÏë=ñ©á^¸7HXø!˜@ågÈØèøW9‡øhyé3©ò€&è‰*Ê¢éP¸4ºÊz±ª’kGÛz‹›Hq:ÇË›,ü×2Ù9Œ|kKÌœºœMXê¬Û[]-­}I½íý­–!.A~fŽÎ®žÒÝï¸._?LMo¯¿Ï‘ÏÿïÎÔ8N� š€öb<ƒ gó×ÁĆ +%zÕkFŠÿm‚ôŽÏÆŽ$+¨šf!„‘%[æPB–JY.kºR„ÊÂ9®ÚüirÅ12ùÛ 4i3f‘2õ"Ž¥Ò©ã^y:ÉtM$„N­˜XN(3°{p˜}*Ê—Z¯[ŽšfUYª¸®ú²#É–™­FñJ aUÛ±:¹@Íû±¯¦¶uÎ^û Ùq¸•qaIy²e´> ]œRJÏ^òÆÜ x.]p Ð ®%ö §ÖZ(#™ókŸ“éè\xsæà±I[>µ¬ÏðE‹?'^Jú/ã³s:¿Èó6RÕ¢«OÞøWaßË5n·ñð¶‘_þ°pÅ„¥_÷:>– äŸ¹ÿþ MWØì"Uuaav {=e0 J.•`9»°uTrtÂvÞsÖçÝy<)š€¿á—ÛJ'j‡^ˆš¸SÇiNW«ÝÈ ­)'>»Y04¦è¢f­ˆ—ò}XZ“ð5÷ã{Ðip™ƒÙã;‚‘’8~)áà})^&\ob"ItÎacæz‡]Z“RªØ!vê¸ÜYA‚Dçäù–ežµ˜æ¥š`.ZL¢²mè$—iŠh }é½Éç…„]xä¥-bF"‘SFúg”lަߓ£šÉ`™ZÖW ²Í7*¤¸¨inœRGi¤x†Ze‘›ÆÙ©°¥j)N­ÿú˜‘_aáhrT­3»FHеqÅj¥svE·žúq-AŽ’pk¦½rkª\±>:(•2Ê‘]ïZÈݘ,î)ª´íykŸ–Åq™dT˜ž)ðƒVzûÝFrG&—˫‚Ǫ¢¬i(¢ à¼ô¢3løR6¯¾Kl¤ùùúfe°Îº¿Á.©ò¤¶Ì2–ìÅô²¿<>¸”?öñO·9èvç>KƒŸâæ‚óÒ…”šÕ\5#ÙÐ28Ý.Ôûj}Å^X/Õ²~òØE³#önŒù'ô‚€®}ãI÷'¯GtÓS±AÌYjïÍÓs[`?„×=3¢Pž­øâ_†œŠä–ª o×&q¹Ñ)ñ¦ùkùÞy+3*l1é¥—Þ ƒ«/šáC‰¿®”Ô±LKûäåλa½ÿŽ‚í¸ûKÄ<ð÷æ|ç±WÞüT* ­zô “.¼õ�e3{vÙk¿ý@‚O·DWŸJ~E›ÿ«Sõé׺Ɇ"ý¾ÑybØ~ý{‰œtúïßùýOz3ù„ûx=”¬/×8ô=^œàï2fÁ Ê ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±õ[ÔhǦó %&É`ôŠÍjCÌG—Ê´nÇäòsÚø‚Íì¶«N„ÅrôûŽÏoâq%±¤'8Hè ö'ˆhÐÕWøɶ¨¤8y`w¹ÉéäHé¥ÈPÕYjªcIe¸æ5©y ;ô÷):”*«» ”™S „É;,{H’úØšKÜì|ùÁœ&ý\mJ­êq(lÝ+ ¬í=NŒaNž®Þ»ÞNžì/ŽR?g<‚œï¯w/Ø¿ÕÂ!!ˆ°DÀ1 :œc_‰+j0È.ÛD+ÿ¹Züˆ¥€¡<‰¢FJBè‡2&WSV¦œ&3gHnùñirÔ9Dúb„Œ¨Œ\Š:m©R$7žK›"}ŠU(Ò>Ê2äS5¤U¯pu3ËÎ¥ •j¸Ò¤¨Ñ‚ÚžYr…Ö–îO½G[e:Øœ´@oEØÆ(³W†¡aí㽆;.¼ pÄ„[*ö)øðHÄ›o%sÈÇܺíh™å#˜ccÙ\ .û™U(œ&G®Ìy2NÜ„w™H3¨ÑÁ1Ï9zXü_åhŽª6㉠¿úxoÑÊ}].¿Ù;h¶/‘§Fÿžùyß_K[=¬[¼ÆbÛÿãîY€½7`Z8 aÃ\ RƒÑ_á˜\_æýáE¶Ý§ƒÖQÖ™_òÙŸyÈebfãM8âräµèFtpè`%ëU²k:¦ÀÒyîÁŠéâw?Á˜}BŠB~Ffƒd|/^ô¡nö"c•ÔmÍ’;~ Q\Ú=È^^õÙR!ˆ>™Þ‹Ò1H£dzù¨¦slJÙ^wZ™dw¤¥i¥„4Ö¨dn]‚‰è s}2ØŠ“Ñ9‰…æyÛƒs~Ö‰"JzØž&¦HiŸ‚hcBeYâu†–$̨g2él.†Jé›–šišWÊ e§©ú ªˆ¢Æ©)p¶qÖ+­eÿ± `˜¤ú*„—ÏâWAŽÛáŸyF”Ÿ´¥­¬‹yê‚«†–i§Þó›\íò:í‘Ön¹m¼ôÌ›(H®éšÉºÓ”ië«öþXç™®ª§œ¹n¾J¬Šâ ¬£7‚{/ÃLnyonü/¿o„o¾­-'TøRUi°LÂE¯Ä·+'¸$Ál(Ÿ»œëÁÐ÷.=;‡;#´ßZxi8]©&²S¹èÕ˜GóÃ-–ƒ6ñ¿„ܶŸÔu0ʘ±yä²$ÀZ=Ö¨a†r†d')yñ´D³{° ¦T[oÈò¯5fL7JS÷ÛóÇÔÊEtßEM*†?e´Rƒë­à͋뫶ä}µå¸öäî$ž&8–kz¬Cü9è;»7á©Cez]IÎtì­n´X³ßïNVé¼ÿ^­ïÀ'öð®³k<îØE“üï05ýNÑO?t©»o=õY…½MæÚ§ó<äSü÷9©]¾ù#ß›­úˆî[Ùqé»¶ª|5&ýMÕ¯iúÓÞ8®îD)V-~à=:ä€ÛÊü(ò ‚" ø(˜/š`°uùÛ ŸæÁº ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf°Ö@:§ÔªU…$Ðíõ /irÔ,N«×L´"éEãìºýî±¹å†ìâ‡(8è°7aÈçG¸È¸¶…x��yØx‰9$YÈ7C)•*Z÷Hé99šªúaJAwzÖº:K˲éùŠÚWÛëË{¡Û!Iü{LhœW¨ü׌ ñl++}}IA¬íÝØlý=.ÍM~Ž~Ó œÞ.(þF²îNß–_ŸŸ:‚«ÿÿ…Ÿ � žùskÁ(Þâ°AD‡Æñ‚!'ÿ;–04‘™«HKÞòjN'¥LºüHÒÙ®™Åb²ë÷ äKŠ–$¶¢£³ÒΡÓôÔìÃͨHšƒmTÑcfüA´ù4ëÆIRAùˆ‹Â•Ã,îBYÚhz.¢\Ë•iN·WY9ÕZË«8m—l¹a”}× ³Ö\°`ÞԢ԰߃5?–x9°e¹%›R†F1ÆDèÞ š¯AY~z:KzWìÔ¸*ÏfF<yñ߯‚AVËK4ä­Àµd®ì˜ólɨæ$ŸÛ)È‹_cÅ.†±päâ²SæÎøorß´‹÷ ]cLÐǑƧ\6sí‚ÓcNtؽûÏ×±wÿŸ1’PX Ë}֌ԖŸ€e,à€¶ø÷ßi'-× „ñ¶Þƒ:×›‡Ÿ½à†êvƒ$vBžŠøœ—S5䩇]jªÝx_¦I¨à µ¢O2u8œ‹ã‰ÈOmö‘e›wF†X¤‚íq8!I¸Å'“H…c—X<ÇUH]ÁØäb› ‰x»ù›PnxX•CÊÙdŒ&î·›ÒW}>F¦F-gãw^úB¡hjV™Tj)Ófƒ²Yž›¢õ&˜âAig‹yž2Zsdž^<WNjfDc®8ߣ~Êwd””*‰$‹ÁÅ )†œF7ë”ËíI®¯j†Ù©"‚§è^ÙÿE¤O$Ùà4š@ë`³†&úL²þ˜¢«Ýæh-t#fZF¸1Ъç¦êʹ‹úz ¢òN¦_½5Þµ*ˆ­®;ìºp²š'ŠÁZ ¯y�w-¡|,j¤Á|ëÁ4Nl%}¡EEg¥_ö7/9¤*Òl±q‰§£êÂkí¿äî ë6¨T¿öv¨ï¥ ;¼Á#2ÅÞk¦aŒ˜¶ wü’ŽË6úB;ÛnÄK¿3ðÓxÔlnÃ5Ò;t˜ú‹Å‡Q3—=%FX%_íÑÅa¦¢´h£­W°áìèöo»äZšeg¬ÓÙw_Ã5Â(/Ãïß&ý3 |™5¸áO…6l¨09¾k)°1må†Çm`iLW«ùá—gíÅ¡Sž9Á§¯^zçâøÍúPRg\Vì¶«€ôíº´û#{ïi%(¸ðÆÓ~|ò¦©|ó¹6½ÌÎwÉqðÓ—­<Ë_ϽXÖw¿Jêv{ëÓ÷àî2³çSO¾²¾™¿>ú¾v'ºñý .yßã²ï–?>þÉ®pH€Ÿ�½ñ“¹Ìî€PÑßþˆ:¶-‚•ûW÷À ÚŽ[ì  ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~xà~Ä¢ñˆtUB[ò JËšS8Íj·ÜÙÕºvÇärôÛ¨ZÍì¶ÛD'nâ·ýŽ©ç89‚ž(88QWsà÷甈HèøHXg¨Ây‰I5ĸ±‡x5™):Ê"Úxöv Hú «qzˆ*Âi›«+cª×´ l2AlÀ)œ¬LaÌ@ܼ-}D-}=ÖƒŒÝí=¢ý-.´:Žþ ýÅîmÿN8ŸZŸ¯ó|oÑñOŸÀå| <˜%TÀ9x!|ø¢„…… ZŒ(g’ÂUÿv¼²jÖ>Ò ‰r7‰ž‘0™òâ¢4íî±<– f̃ž>©rv“IK :w>”´©ç1¥ …v(h4*GE¦”º¢¹æ)T©\ùl–ÓZ|&šò³9œXÚ.Së–ª¢¬”ú¹$Ë!h×q‘6ËT"»j¥e ´ØÜDp§Î2,´äá¶dYqÜ5Œk†‹9Èʼn?ÑÓCï^ˆ†.ó©¼Y. P˜gRöl`Km`&î›Ò/Ð8[~Ì08-ØÀ{ß¾ ùäî¡Tû´ö»Ô÷뢨!Û&~Z4VTΙkÄý{²Zã©“ÿ<½ùhðµÏ·ßhpÙ¹ù[ÿÕšY²Õx£áw WTÒtÞ— fâ%ZR^õ’u¿ˆ× rû±U^|ö•‡\P¹"|XÉמyÌlxÎ_`÷Ùq·ZŽÙ˜…²x÷Ot~øœc"fÖbÚØÔ{ºy8܈óÉ‚žpÒa!X•¦±çÓÿ馗§}I`}M·”SVyâŠóÕÆL€ÏÉ \iÉ9#‰ENyf”<úØc“ÅÍå–)ªf¢;ÀDŒszVç‘Ëñéœ:JœkW¦‡džoîÙbrf hYeYhšhnšÓ¨‡žéŠR†šäpqbš¢¦wJ*ªŠ•‚jdŸB:Z*iL b‘UÿQG‡iH„j¤îê& ’TÕ¥©1IæT~rø§‚8^Kì§f«›´ˆÚ´¤©èò ÃM—1;®¢)!µžFmèçw‡>« ·½bI§zU;‘¥™¾«&“ïÙ'tú¦*}ßÜpÀ A<ÒÁßùWT·öît]2B‰¡®ù‹2:骭r¦äÌÌQk§°1[̃¯–q±€ÖW2rÖ5®º#dÝ-b¼[½Z‚3(ÐÀ˜©´#o’UÊ)w9uír‘¯Õ»`-u[C-óÊ41üaÚK TX/NsÞÜz_Ëð×`LåÞs]rã\AÖ‚ËTIa*þäâ{­”‘SÀ ¹äQ} «˜þX¨¹QœjÒBr‡~µM˜ J5ê1©¾zì®Ïvà¶Ð&Ž!ãžûK¼ÿ®±š,ñ<ê+cñÊ'®Äò³Cþ¢óšÇ;ÅÒ'zù‚×ã.õéÛóåý÷Ó'_Šø‚‡½ùïü“é«o‘³/¾: :ÇQøõ_}«„5‰¼?ž ..V¡_�I&’SY W— È@™¼Íl~‹ààüS; O!¶Ñ ðÇ:Ò€"ä+ôWÂJ ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf°Ö@:§ÔªÕ—\�³(÷ ‹•´H™ñ«×ì& °}åyûŽÏwäóú[û§'8HÈqgg UÈØ8x¨•�e·èx‰i”¨ˆ(™–* 39± eæ9ÊÚZq*™K—héz‹›:³Rç› l2Yª°*œ¬üÊ»ì<J¼ëóù\]­‚m½ý(ûq¨Í->®¸NŽ.z.’´žþ^ElÌ_âîþ oßÿ‹“¿wÌ­H0!cóÞS‘T$SûR4ü1#¾/ÿ\æ™ HO£Èl°¶‰ÌEDfЬL ó„—/á8ÜC'¦NSÈhí éÔÁDUQsÈfŸŠ:u0 (@VÍù4«Ír'§bôz¬d%¨YbõPG YA[Ô>kë«”§v|ÈþìQS+9¹GYVý;\‰7~~ÁE3«l]™ídÉ[ZÃ7Ãî²8`âÊÔr†ê6.Ó»>c)º’سXô:UŠðçž!Ò†kÚçL»XËqÜç³åɸ!÷¥º‹pÍÀ'ú¦L¹0cÒ[9åÈQwÒµdoÿ†¾´%òÞF{nŒœ¸Û¤—u‘ß¾sðø¨Š‹6®¼}õûº©Ûÿú”—,´M$Í eQàU<%×”7·uú‰Wàrræ•bô}ãS’YØtw™7ßsW("ƒ¡U´a9ø½7bsÕÔÑ‹6ñÝi\¡èZ:\§\TIw‘긢c22w§=7]’ºè\y䆨…ü±H¥\5rÈb†ÈÚ€¯t˜Ÿ}.FiY›Rfib]’e~çeÉ&–U6ùÝœèµeä¨äiãž1¦HæNŽÉ¨!ÜÙv`‰¶ød‰Vòé‚t$›pZ _œˆJ^ ó‘ º¨æ Š¢ùži‚¦*ª´fº`Pëièi}µ&'ªžé1gª–p¡*¥¥ÿIÉë«(6K!^ùŒVä‹®iÔ¤xî൱Ñ’ÀJ[èˆuZ‘·$Lv&¥Åš{ƒTJ®šm£ön«^(k¤¸¶ª „±ú¥¡}á9y[h›R{d©rFÊéÁEö¹« GhÝÃvfV«¬†ÉÕ½zÍ*•™ˆ{å Zi~+Lð“07­¤æ¡ÖpÅÂÌž>—Ël´AâèåÇ´˜l²€"EWŽ‘ È8¯Ë±ºŒhl5!ÞYÜæÂ²é'5 €‚+ Öa¯±5ºd>­ÚÔG/ 7„Fv/¶¨·=s勘`Çõ‹wÞ{õmw8g-xd«xÖ‡‰?õÉ_N°¦¬ÃAŽÒJ*Ÿô { b>l8讜39¥›ÎJÖŽ×v9ëc¾þìO…½ºí:]ܹ«ºÃ-ÔçÿΨŸîåN|èkù|ó ] òÎë}BêÓÛøÓ×ç-ýövï}V•[~ø¸”T½Ëæ‹I{äâ®â¾÷-?üÖOùûT•o뱫2è §âK-’F@¦ý pßI`ñèÒú90# ÙÂ%8A ^ƒdšjØÁ{5ÐX!LáJø»ÿ p…0(��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5@ë ‡Ä¢±õ[ؒǦó 2I[ôŠÍjYK UQ nÇärTì˜RÑæ¶û]þ²©^¸ýŽ'©â9Ÿ(8ØðÅ`èw–HØèøÈƸfø×õx‰G9Ãø#™ Ú³IA fêõ)ºÊ‚º!'éÙJ[û ªòúg€k뛉x»¢ËKü{ìhÌ›¢«Œü $|á¼}¶›ÍÝR]ªè=n>JŽÞÔœ›fnOæ±oß6¯Ä“ï¯× ' ÿd7¡Þ‰^.<”0œ6j+Æ`¸ÍBA‹ÿwô’3cÇ‘JDJÔ$É•!˜ì·QË™¥Ö!Ú‹ZL4{œ&íe;}:œƒQq'¾3 µÐÍIRû "²hÔ­Å*bZç–1•8 bµ¦õŽ•µO‘±•öiVX¯%Éf<é#-×ZHAF+´mW:kðdéí¡±»)ntñÜ}‘é%F Ylã«‚e¾Âʹ²KÌp?[n<píM@©¿0¹÷hàbSQ%•¬wÛÙ 1–Jy¬%Ü¡…×yËÖ1±¸„^Rü4òe ejþºï¶o¡V··ƒ­±útц– .²ãÎÜ/óžì=3Dô£Éoöœþ}iøì cÿ'Ëlå '°æ=5QöÓiÿ98_KTóœy.9“^öý·w˜×4öwWo¸©Ý…8↠ê'"Šø©Xa†Ñq£}”L±c±ý˜E+FV‚4.wU0.¢ÜzKn^WÆñÄ”s2òdL$ÆÇ uV6™ey d™c HfMJŽ'&‰ÊѧY–Ð=YØ_ïEZ/š8cœî¥ÖÜqSQy¡ûÕ&Œ¹äff£ ~€iƒ¾H\ŸêI7'…sVéå]€i)vr*Jc Õqùé‰úä˜(ŸjÀ£¤žn)eŠqbzÜ‚v&7i— bù訮ªÊé©mÒ™ëª_ÿÞJ*ƒ>Â’ã±òåÈNëQ>ᙣ°¸˜Tš*NÔ«¨£lª«iÜŽV-@×Öy¥´÷éP…,‰mÔ®£\õX®¼cŠ'+ª”è~ÜŽ—¤µ•"<s㚚隘½éÎnÓkío‰‡®~ûÖok‡å«oC8Åb§erA p³óÒjàÅ[LZÚº7l²©ŒÇôñzž–gÜ–Æ8F,²§;Òùì» –ìžH ŒmZŒMò HgˆÏú'f\ ­|ÖÞâ#¨Â¬xÝ›¯fÛ»ÝAMwÒ ÃÕ$puï­Ó¤Sµ3Ygó=c‡m]Ⱦ/‚Mëé«¡Œ3®Ô–¦Â >yÔO ¹sæžëô¨u×¹Òùç&ÔbJ‘›.Û·Ù²ÞèÒä‹9ìäØU¶Ôn{: 9Ý{ÝEæ¼ç1É®{îÅÓ´“’ª/ß“¦NéÅ;ô|åV½õÂs¡=áÙgß=<g㾾ο*aùê›ÇõúÜ(îoäÒ»Ï|éÀ7%.ý?NùþšS -vÏkC^ÿêBÀ½åä;À[K?Ä<P:Eû&X8Û<ƒ¬ëÄ9hº ‚0v"¡£ 3@ª��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡Ä¢ ÈøÙŒÌ¦ó)¬5”ЪõŠ!RÀ’ üfÇä²s›£Ó]³û o¶bö:ŽÏë?¶»ág@µGXhرè5xØèøÈÅ6µÈy‰i¥Qg·™ šóI× ¸85'ºÊJbêóJIÚJ[ûGç*ÉiËk;‹òÕgšÛkìXyœÁ¬{ é,ˆñQg­}<­Ñ½ Þûí^Ž5¢ÆwjÞœë.ZŒ¾Ìg?¯_” £¾ð…dù*l*0a‰nÌ४¦0âUZØI¼˜§0`ÿ1z\@ŠØÆŠKz ¨«ã•ILºäðéš™ÕXR»÷2ç…ØÀÜä8C§P –|–62èÐ¥±#8³“F¦TUD}ŠRPLœ>ªz5(¥4˼úÁµ¬EÃÜ´Ih‰ÜŸÜÞ¢Rk‡šHEs¤ÎMÛbêWpáíí“Dî°aaj‘ò·ž35H•MFüÐÏߘ#—âDù.Ù[6ƒ¬<ú›ç?¯…^|š´:ÉÿÂj5!xpÄÖW%—ÎÝÔí-ÓxKÆy™tlÍt3w¶«¹a½ÔךKb®<³]Ö¨×>œtjMèëc¶žJøêg¸¾oÿý:ãøËŸm>xäÕé«ÿÅžÜjHa§_Káù–jaÄ‚\`4PSÞZ{œY¸9+gà…*¢ufçWOZ ÷xª‰hÔ{Ÿù køE’ qº¨â‹ó¨c„³ôô£ˆªt¡ Zº)GlÅq'[:S-Xa‹÷UãŽ2æ†"‡ÞÙ‹·ÅH¥†É)sOþ}Y¢QÝÁ„’nFI]V;™µÝx£%¦$Žx8 „4ÝU—îmé%;|Ny¡‰Ú9a~wê5Y¡ÿé™'"¾‰)Q\jÊ¢3JЦ <RÙçJÝy(™=ZÖß¡›îç©óÁwÖ§¢^Ié ÍÐ9%£€íie˜¤¢¢Ú©Ðù *±Áÿw¦mêù+~¾Ø’™£¾JW›caXãXN׌·Y“ªŒQ܆'w*ñ•m¤Í¾�¥Ak’U..Ú:ù.¬Î9º/ê1hâ÷fÊTaÈÊÉæ³ž¶§¡Jk—ñúñÃKªªë±Ê: (lö(<×Ķþ*(‹J«±Lõ¢yé¶#9­h"§ç d¹†J²”ž<i¯õíês³YækkÈ<×i1yáúÌpÀ#–yòÌ3Zm–¾<£ó>ÅÙŸétt]P¬ÇØóò‹®¬rþ™cü<LvÙLJÙ(7Šâlþ‘K7ÖTQMówîúMx^å½ÊS²:óÙ'b¶¸Så1Nùi|Í'UÉæV^¹yæÝÈyèV QW¢ÿ-èGœŽ:LÆÃºIO6ºéDÅ.»†DoèM˸c®U¿UÎë uð’~Œ|Uº}|óG¿{„ÒOOÒõ¿k¡ïÚ —Õß;nƓ銣Ï~ˆ·¼„…²ä=üÐLÓßö{Õ·âþïŸñm.c‹`N¾Õjp)X‘Àú·@…H®C¬^us9#]x©K 7x‘ ~„C©„Iˆ»µÕ…B9! ¿W”ÊP��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡Ä¢ ȰՌ̦ó9\.~�ôŠÍjYK¤âgÝŠÇä§÷k~Õå¶û G”òŽÏë?õê¼@µ7HX8rff¸ÈØ8…Ö†(èhy©5™„ÀÆ©ˆ *ÈIQGê—æp'Úêj¢ÒI „úz‹k*Ibë™û <Ñ9l÷WœìŠlÁl¬ mÛ‚|6 Õëìüì“ N¸»ŠÑý`ž„>w®þŽ{]ž o_Æ Â~M￲-)^ÿ æ¡×/‘Á… ½U×0b†„í.P,¥J¢F}ÿÝýÁøm£H€Ilíëi¤Êrò4¡¬÷°ÚÊ™°XíÈG3§.w-§¼Ô 4¿*&kåøt#"/¥™4ê k§¦U*é´¢Ô­–“ÔT¡Ã±$c¦²‚ÚŒiá¬õ6 UJ0ÑlW[®ËªÊ±6BQ¡FëŠõ(—¨Ó¯JVÙÄÈ­ñÙŒXÏý},ÐðbÇŠ!á|‹™¬O_¤èLšK‹\Ë>qgìå Ž5ت‚-KÖÜ4e_µ‰Aþ8Øånß…u»6ôwïàx‡cÕ 74îÃYUYMM½³öçPùw¾=çÌŒ§+nžî÷ÉÇ›|ö¼úæéC¿ƒÞ2¹RMoÓÿíî߯ÉEß ;eæš0ï)¸_9àTÙ& &(L`juXh¨5 GðVyÀq†^yCµöblUÄÜfî™WK>ý3#Œ²áWk°í¨ŽñyÇLŒ/®¡œ~-zBF |GŸ‰:ÉÛXÒ! ¥‹DþçA‡<~ÉÇ–r$YŠáQÙžˆ/šˆßN€±wYub6Yßdk–鿇BrÙ]vÃ]ù¤‘+*ø’Ž`ª‡vÆùT–X zçynþµâ†}ŽV"‹IÚ™à)Ö=–‰›Ô(%§š^ÔÅ ‰5ú\”#FZX§”ÂYå¥DfºÜ¦f®©'¨Šú©¯îJ Z^êò+ŠqÿL´ ƒBʧ~ÑŽ·Žœ�¢ê)LÂò°ç¤ª1ÊÓ€Í,ùj«µšË-ç’舾«â˜Óv†Tª¦&'í“øÅy¦æÙ¯¥¬Ž†$À³‡¹¼.z¸Ö>]ÃÛ!¬W­{âÂŽlÔy¦Þ:k¾ÊíKÚ  ŸÉ`¿Ä‰6§ˆŸü)¦S2œ\¶ñ 43`ß«°'Lɲ1ÇÁ0uh`õ€ÒZÝ&ƒrÆŒôäœ^áÖ.v0ãàtÖËH,õ"T3™ôYüæ5äÐF#ê#X‹†DBE¯NÛ£ôªtï]¡kiîÌwàâ­ÆÊ*Ì-¸2Ðþj+Ä'žSÞò®+!…¸sŒÜ…Q{9æèìxç`R„¶è¦'ê˨Ÿþn³TÖ™⬫Sú!”Ï›ë¶kŽûŽÔûè*ʼF…ò^<äÇ¿îlò35Ý8óÎK™!M¯¾¡‰}ç2qA|÷ð†-þ;sƒ~ù¡d\}¸é«¿þÍ&ûD>üð\¼5磾oÿ+’«K?þõï~Û VýH“cuA€ŒM×À½Å ŒàB&2 z¯v\;<Ó€p„;(��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR�µŒçúÎ÷!m¸ù†Ä¢ñÈ¢ J ò J‰JFÕ6Íj·Ü‘SQý2Ë®ùŒ†^™ñ8 ËÕírû`ǯçü¾Ÿãæ¶ ¨Gøwˆ˜ˆ§‘Ö¨)é±WWó8©¹©“™9X×àôÉYjšcF)jóHv ‹²ôiG(dŠ%ËÛ»‘ú�¼ê ìk|¬;KZŒÜÌKê’ë<m=a ÊŠÑDÝø…]±<îmþäIA{ÎÞT{ïN?^¼_ÏOÿo%þ~Í1° B Q5\ÑÄÃÁöMŒˆQ[‘tÿÛ2zôl 3Š‹>š­Ñ¸#‡å; S ´+©‹‰óÂL=Œæü™…1 Dáìl•*¶šE›2zó.éÑ Ijtе-1BµLÆ2«X@—\îBê)eÕ÷0Q=Ûì†Ü·Îæb i‹k^Q_wôëM)TªxÓ²ÄÅóÃÃ6yÞ¢KÌ-ßVÙÚî²Ë8r¨Çpµæ|ïí܇75h«W+S×*f Ø ½ƒYKµ…qçwa'—L)™5eU»SSÆL8O1ÒwŠÿ¬òdäw1E×:ôŽ0É#ˤýka±tÞ…ÿ. ½2z×6ïúrïôÏÑ·¯î¾yÅ싘ÉÿÝ –u|½B‚%¡]³‚ ^…ƒâ<qjFÎM:W•Je½‡K%€3^vÀ57"}l`¸Y:_ÙõÒy™H¢}Ó…æ5¢HF ´^l>ª œjkÁÖÚqË#v0º¸_Ç•F“"jšŒ¡˜Ø‰ý©…£€õåG^T¯Áöc™Yê‡Ô˜÷…‰¦Yl²HåzO*ÈU{;j)!žò½('œJž(àm¾'—/•¸æ|D’if£Pz�"\œ5y¢JªŽ¡{j:)••Î×gˆÓj$X%5y—–úyè©=QǦ«3ª÷ç¥sVX§|‚Ê*\•|ÚÊjœ1æhª¨ohxãªÆÿ÷MËH 1wåN¶´+…Ö·JE*d«=+ަªd Š“—i—ù-g.*¢…KI³(9Šï€.ÝÂh!‰R«m’ªF’[ð»íW "Ç/–½Þ70´¼fsnŹޯi^ôŽÁh‘ùÆ4)§`Ú&qx¨Íz±››–êÅÌNËÞžšç°»È1³BÌ‘w½e\êÆ�â·¥VýÆ:rFžÙŸ~]œòƒdá§.$/‡Ã'S=œ¹GH)=g­ÈÖÓx ð×t}\o…7íãuâÅ´ÛáÑ]¦ÝH¦– žò=V¼þ:wãà„Çv›Å@.Îx-ÏF yå*¾/…ó„YrmùB‰ŸÕ]yhwþÑèÑrNzN¨»·zêM/l•…®ó½°éh¶>;?>…œyî€á.·ïfÂ>‹ðî~ðÆŸ³RÕV/¯:ºE ½£Kó^ýOÄ3Œcöù6ŸTïy‘í‚ç¦<ù±¤Ÿ)ûêŸb>Øú¾Tëþ±K?N&× üù¿~¤Zý+SC·H;x©„l¤[ãâ×@“HEoŒà÷\, vÎÒ ðÜçÁúA0„Ç« Oˆƒ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇQ@Óòçú·uÝ ‡Ä¢ËÆøŒÌ¦ó9D.~€%ôŠÍjYÖj7¡ÜŠÇä«TÑ=#¨å¶û]<«§_°ŽÏë?õê¬À¶7HXØöð5fèøˆ·(ˆF险)d ÑY™Ô¸9Jº‡9è XÊÚzò‰†!Iëj{K![²¤‹û;X;!l ¨º«ê ¼LÚ©|ÈKÌ<%ˆ˜cM½Íô<œ¢Í-^&ý>³v>¾^œúÍ÷ÊNOX¾VŸ¯=™Í¸6ê„S§à±ƒ ¡xëWL!>y +ò’E1ÆC‰ÿ;ÒÆ‘ƒ”{Kòñ&ñ!:“,oôºv!ä™-k 7NF›<³){é®Xb4{7S¥<¥E:M—.Í*Œ3ŸZ!G‘(|?›^ýª!kB w"žJµ¬X6¬¸åöÖ\jq{«•ÑY;9ÿ…õáì-5„ EúñO{¡z‚º(.LgvQÍU\÷0âÄÿ"k^HYíD’™}ÕÊz™kŸ9¨õ¦NeNéÐÀ‚é­3öu®¶;; „2èáÓduzÖ Š·Ü·‘Ù:³ƒzèãÄ—¿s&?ØÄG®®+U4䉀‹ûM$ܺ'ó¸Å__ý}ePÚ^9øçÄ™ý´ÿÕßvBwÙwÐÁÝå%ˆŒb½qæ }“<‡V…mÖ`€®tá~èýány™ÕØI‚¶¡dîägYu¦¹‡âc÷ÉÈâ..®xÜá‡#yfùx ƒµ IÄY¬…x’%ÿièØ{“õh#fê(W*òS£t˜ý%$Œ Á%�ØÞ’I‰& dyæˆ Ò×Þ;7·d9óÉ'Zv:ex¥}.egjÌÝéezŠå–êA$•L²¥ )AŒ©¨§˜-*:YeÊq]koÎCtº› Z)¨‹8gŸ1"(•…Žz)RÆwSžº $¨cŠšé¢˜îš'€O¢Âª¢®ÿbéÝ£•ÇTSR˜VÎF”ëyLòpš€`Vð[“¯ê`f©/zz̵Ñt™”ØË­‡è–‰¨,´EÊ^½¾Û¼fˆ!žåâÚ½Ô)ð¿Ÿî©e†•{Ê;ïÂ�ŸŠªëW˜ÂJô«.¾&­©1YK«’o›p±ê¹:0¸¤ Ûî¾pÞçðŒƒÇ%ÄãvI‰¦Bë|¤‚ÿu{bX÷Š,N³7«s‡kU8ô6C‡lHÎêè–VÔ‚ÆXgñ·¶h]¸Ø¬#Ëì2}a|ÅÊ%ÜpÙ(z±Õ´Ýq¯××»Úö“ßDN5£n©ª}°áµu¥™±à:Ny,±À­iYåšc%aÀ›þtãÞšó`æ ç›µÊxzë öëzìÞÊN»Ô׎»íäýaîh²UzÝKû^éðÌFüï2–¼UÌ#öuµÍ;¸•ÓØð×¼PáÛkš÷&hÿý#À Þûºå3ôâño9ùëõLÔó‹œöG¼ßßSýÎíÏ¿}ü/h%  ò‚78ÕÈÏ€�)à%ÈÀÃ1Ke�Œ Kf± ‚ƒÔàݺf(Rq"¬]XÂ. ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰*Aʶî Çò¼öJçúÎ÷~xà~Ä¢ñˆtk·aò JK•Íàœj·Üîçú�[WY¯ùŒ~VN±5 Ë¡íò›Ñœë÷üïl—à&¸Ögxˆ¨¢(t5xð˜(99ŨIdIéùI“9ÑÙ¸ F šªZ‚ê‘yʘ·:KY×ÀY»»Ûá‹ÅF!êÌ{¼Ú)*(\±ŒeŒ,Ûl-Q9Ímø<ªíìüÝ]®¬nήê«| Ô>O_¿¡^¯¯GŽÒ*ÖoŸ@5Ã0äÃ60¡™wBº§0â–€þ8´'1ãÄ/ÿ ÿiüØâ"Ç ð‚<I¤E”,Ï¡ú³ceË™$ Õ†¦NÏd†cè@äΡ„äúÖ&›Å‚D›ú# ™BZEm[Pr0¯z¥’Ŭ18L…¬úeX³Á •Åã"yGÚE˯í[s{qÐUT\¼vÛº"œöØ ÅI+v%ô 1›[/'fVxkæ7· G¾«Ws\7ãñÌÙÎÞl¡.{Iú4EGY!6(Bfâ™eÄ®µuÌ%¯*×5 Û´åÒÉiƒv­šÔkÌÆû½Ô¼µßÒ£ƒ2ãZ[óÒڦϰyÙûñÖÝ­§GþÙyß÷á×Ëe¯Þ=óøÚ‹rÿ}š0à™ÖLæAUaèaåD�6È`w2…Nö ÷™Rþ‚këX`a gÌjšX—~ª¡}¢Ãâ}Ïå¤Ü6û5¨bA>4`Žº¢[ºíFdJ¸„(zÅ@h~)Š·b é_†?Θ”e×PŒw\y>R7ÌT.v$Y‘jbHÞˆ$ù&c“Abù$ŽÛ•™Þ|p²)§IðUäå”f¢c&|KjueŸ¨…™%ŽNŠ™(>i®I醭'.¢Øbsw®ch{FšÚ–J¹Ü xÆ]žQ¶'[uüÑ é‹­ñ_ŠQrÙÞ§†úÖ¨–ŠÝ©žÒ*™‡ÿÖçg²öô8+§ºVJ¸ÂX•Óu™íOïi%jZ •ˆ2à¤ãœ©¥5º«îªo¢º,»6Æk![Ñš‹n¥þžŠ ¸“ñ{Û¹|’Kf«pΧ\½¿ª*ªÀÙÌvŒ2̨óbìŸÄ¤’jqÇãð£Õ&xáaøþ[Ï«õ56XÆ—F—g¸†¬ñs4k ±´97›rÄ"ßLòÎsél/ŠÆ)²d½z>ÂØ‹£’ÛÊ,w¬Ë†W0ÐÖ’T´½½ˆLð!MË,ŽmcÙµu½ÅvÙf“mõD!Ϧ¨°=ÄõÕ~<'ÚSœv y­`]Oxxã¬!è ýî8âÅÑ…ÊdˆVžØÞ¬vóMœå¦zAŽúƒŒCù¸©[ÅoI¬¼Nú_4þqî´ûÝ¡»ÿ~4îÀo»×Ä0ã#!ÿ7pƒë.9ó•bKܰÒÃnýäãyýn¡COW÷jR/ºøµ¯¼ù‡§¶ú´ËÞúyî³ä¼ëhy<D¾'¯¡˜uço6q¯]�¬R¤#·:倎I [¦(áHå©{ÍÚ†* bC›×4È}Ѐ±ðÙ+Xž žsPY!ðJçBâ5á1¬! ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó ›KªôŠÍjAJHWnÇä2ô[ƒÕæ¶ûíD«Ø&ŽÏë1ì;  ·GXhx1øôàwøy¤(áXçgW©¹9“Ù¸6É9Júé5á9áÈXêúšñ•j1+È ›[Êû&j©+L Ì#Æ´<¼ YËKQ»èpÍl5[);Ý }ý .ø×ˆn~NY}RŒÞþȾ ¾êN¿Û TŸ,ϯðÊ6BD ˆ0г :ŒSÎ�¼òZü·£âÅÿ5ÒâV‡£H…ž<RwäÈ•1–˜(‘¥Ì$Ú…lYp¦N0§õL´3(Mg}”ä$¨L¨RTÔ f»)ÍÔ&—²üÕ4ÓÑU#ZýÚ¨)Wj–jŠ›óGѳ8ºj›Öí¸â~–EÔÖ©Ý5äJ»RŽ,@v¢J4[ƒo<.ƒçSD7ìYUÓ¦c×§²•'ƒ¼õ7±çS˜ë>“üXEè9kŠõ6Öòh{sìÃ5·æÃ¡t36¬2Þ1ÙUfKë\²0]¸µžÎL4òU6—KíŒZõ8x‘¯½ËÛXcÒªn&7þ˜NdÍF¡V¼[»yÇÒÕ§ìþºýÍÁMÓÿï¿VèÉG;D¡tY‚ò— F4TÞ‚Ù1˜R…÷¸Û6‚ x.¿EGJçÕ·Ø€ÇñÒÓz ÎbqÓñGb9Ü%6£‰®-¶a\zùe[8éßj´5f zÙ˜š‹ûXQ{"96¾'Úˆ¨!”þµHÙ’O†Gå'µùHæG¾µ"¦‡ ‰¥pHòvã¿dÆ¡hY¢Õ&^!:)g•ú‡–oZ†Ù •¥¥¤&cYf£ü†{^¸§rЄi]ZvYbIòÅ祣1‡é~’ÝA¨v†æ©*ŠšF‰§Nzj¥×‰:'fšêæ‹R2yèž~Þ˜Ô¦½ªV㪟ÿ¶ºˆk>ˆ¦cCŒéƒâÅ’ Y ªÔ‚‹¦÷ŸÄ⊢¶ä| „MÐN sBêÀjR϶+¦£ö>[‡Â–fµ²¨gùZMœùíjg|"þ™k¦F¾ylišðŠ®2|$©ï;ÈrF΋-÷"ô]±Ñ¢/DùïÁ¥J|ḴTeļ2JçÄ�ÇÔÄ…æüYÅò<qÃDÛÒ±¹·Â+òÈí Œ•Sfn|eD:StÓnÄ™ªÊˆ˜œ¢t7ót4º†d ×Tÿ›4p{]bªÓ÷ F£Ïœ.‹¡Ü>¶ã¢.é ø<·˜¥ ï r‚f~x1‰×,-lx3n›š*Â-¥Ö”'„ª”“wûùæ}«¹èN£ë¯éª¿äùê®SEÞS¾®·¿ZK{îøÂ®ûÜ¢â]zïJm%«ðÆïþ%>ÇÆrä-Ï<ñLCVó9Oý5Öm·WÝg?„† ¾>M‹üZù|ˆêNÂÛ¾Ïy쩤:Òôo„y¾ ³†½ý 7åÙãبIH YýC Lw@öè¸ÛN�%ȹÁ]ƒLC9øn„á! —‚‰ª°��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±EkԒǦó 2?`ôŠÍj_¶ibÜŠÇd¨WVTËì¶»ÝM×ïºý>’3Έ%þè çñÃ'ˆ˜ÈF83xp”ĨHY‰2i� B×Ç„i z’ö™Ñ¡é'ºÊêèŠÚG’*ÙZ[«ÙSš¹kë{÷I 3Ź×û‹ 7qlUûš-­ôõÀL!w=½M‰û<ªÍ-.ÈŒ>®œÞ쳈ëm,ow~ÙÛŽïŸÕZ¹±Ð£°ª„rÁæ0b¨tÇ„5úÀP¢Æÿ=Z¶1äbT.u‚(2%—ƒ%1¢³¦2¦oždÚEË1=„:æ²Àò¦P„“Hvâ Ê¡Lf3ŒNO“›Z]FÊ‹*5FÅùv5ìÊ£\Fš·+¡Ow¹‚¸åö¶ÙÚ|™êÅšµ¬NkS“š+ö×™*_?¢å«FobŒ’Òž<1¦Æ-Ë’[ ­…:f[ræ‹q;·Dì´áÏŠÏz•waˆ»UòtË©ëO4—KxbðYÚÞÁE«.~¹ô÷x†u<µñá˜1S^Üü´ÝÏHyÝž#·ÅÙ×aj®J}²iô²s*‡\jÞóÍ£‘WnŸùmy°çÇÿ:Q­-·YàL†Íx²q¤TvØ]ÐÏ@ýi·YE^T† fèx©yÝ_æQÇ^…!¶ÕWzÞ 5ÂA§Þr%J6HŽ�X Ž'îÇÞS±yG[mB Q“Ž}E|/šãtíµ““ƒõU7b2懟)SÖó :6™"t­éV™Cžé’‡guDRŒcnYÜ“m%H –œQ¨&-ú§"•Yöhšq\šµŒYîéJ6(’‡f£9øIŸ‹¥'g”r–h_’…I߉Ò%G§¢^fŠgœ%}y(œ.*J™™ ij¥“LVJ“é÷#õÈZ¥­~Îúâ~‚ÆêªÀ"ºjŽ~ÿle ‹Dù¡/I¥…Ìm¨‹–ƒv¨KÈÆÀã¥ÅæJ ´&XŠÕޤnš­§ÑvåCæ:Ц…¸‰|&NZèÊ®¯ÿ®+­•ü¶z«=ÕÊàÀ‹F[j—«-ª•ÂWþºĆÉ2/½¶ X1€¸‘‡¤‚bú0/Õ!pÃXª ‰Ï!¼$®¦Nû‚1‹©,Å ºÛw×]#1Œz\¹[Bå×¹†¶ìKÉG-uÇxr–UQAña5„ýöFÕ`Ã!v·yªŒÓZït²»H )•0 ƒh°É<¿íè`L‡h&¬Mã}¦t+©/à†£©«në*æØ‡¯C“‘Ž/þ¸Md»B;¹¨•3Õ·‹ûú¶ySVë£jš¡ ¥–y§¯¾êö°:éwÃN{ƒ¶|{íõ­—ì]ë>$?„OüëÅ_ðäÈŸ^1¶y,7‡‚½XvÿŽÆÕ[?’ôÛ‡u¡éS?Tøy(O~%`kcYú!ɾÔLî¿o̼Í/’ïnZË×ïø#CFd-cÿ‹ƒNE¹‚wdñŸ-ç¼£ ï)72 ƒµ+a§¸vpƒ",! ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰6Aʶî ÇòŒöJçúÎ÷¾xÃý†Ä¢ñ販�7¤ó ›*ªôŠÍjAÖ*#(ÜŠÇd¨rqf†ݲû w¦½ßvüŽÏ‡ÖµÃ<¤'8(È÷ñè`HØè¨Å¸ô`ç§ùˆ™Ùry99Aéª9JÊÕÙ™±†˜¸(Zú Û×Z™ãª‹›Ë´(+Šáj°ªK¬û+Ü;ò;\ÜLÊ,í<Ýx¼qjÝ—MÍÝÆû™ì=þȼ-$M¶MÞ.†í›zÌî^—m½®nϯ™–Þ/ @4ôì§/ÞÁ…ä î’„Œ¡Ä�Ù8ütJ\‹ÿ;b´¢ ŽK^[¦Qä ’&[Ê#¨ÜH–.]J«¨PÊ4kÚdI)£²>‹úJ-„žF›R…nÎ:¦ÒrеBR¥KÙ…ŒÀ4«Ç9mʆ’ÊiZOWy*Á×[܇añÌEë¡,Ÿ¨Á¶ÂËÔªX„PY5¯k ¥ëð²‰8Iê¬UsÒÈ YÇ:²Í¬æ›g°˜‘%¼q´6lqýi,8‘¡°±›ÜkX˜-Ö‹QÒ)­4eÈ“%_ÞEY3§Î¾…Ï&îå®iÎDS«¤.)R0¹¯ ®«[ó,ZËŒS®ú¼qéÉ_‡þ~jôå·Æ.ߢÌé¤ÓÏÿ·ã—rùq� :_¹‡ZNãÅ—Šø,(šeÆÔ_[KX_²uf ô%\dþ…Úc#²rÚT•íwÜgʼnVŸsû�¤J‰.F÷Üh¯eV›m>N±™~ÕtËoÖ…8Ù‹&ÆèÐ[ гbvJ2‡ÚEQReb%4Ú‡"‡’öøc™ vÇÕQè@H"yUV‰>Ô±×X„q(&ƒL¶ø¦,qÖ™åPÚNŒyªwÜåž™Ž:hʺêfppv‰!Y¥(Ž0ö·ç•IúÙ% xFß–'Îw¨”«•ÚæIk—£¡´bú‘¦—qzªzŸ~*—úÕ&¡è‰¸–ª¶ÿŠêª–hQ‘fdâÑãigQm>¦"øƒ•”J Ìr«Æð–Wø½+/d*c^¦S~;l£gšË–†ûh¾×†wäFëfØ©½¤¤tþ•K$®tö° n"¬ëÂÃVµÞ¦sŠËÖcÏi1¼Ìvèo¯‹îñ¯¾%íUØa]É;ò¸“.É_ÁÀÍv®e ׫Ã#\é}0yk¼•Þkç«ü§E)Ÿ·CÉ&ôkaÂ*"ÃJÉ37I;­ÇÑ\wÍ7•7µ‡1ËûÆÖh—á5PK§«c´Ò>M7·Još[uÓm¿cz7°{‹Õò†£*(¸Žƒ?Zä—†8Ñ‹g5öÛBÂOŽù r'~Hæ„+GÏÚžÿø5ƒ%8zK%c|Ó5©{þàà¾nê`#N{îYš£{ïCù< ¶ãÞpð°GE¡ÝÆùòΛ^¡Ë =_·èŽS¯ï<u =åûŒÔ½™Öc4~øÅpCéæÛ{8j®ú6ÊIšúðÇÒSBõ­|ÿÉ«µ²òõ/“œ¿x4@Òˆ7©²_ë¼9ðcP†HA¨ñƒ´I6×Á½á-„¾› ²ª°��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋uÝ ‡Äb ¸øÙŒÌ¦ó)D*K¨õŠÍ¾h .W ‹¡ßG9á«×lãyVÞíºýîˆÏ"ôÃ(8¡'çWxø7¸Èˆ…ØÑçg …¦Øx‰éÉB‰ ô˜* iæi:9j³9êúšš'IXjÑ陫»›‡*+sË+üêS<œZ<kK¬ Øúmk-­GÑÚÝ¥-ž‰ ÂZU>¾>]¡ÛÀÍ>ïúõMŸ¿G»¯ï¯|ÆÚ»‰ X0ᨃØ*|øŒƒ/‡µàA¼L8ÿÐ6büè­ß¹_srx‰Ò µ2›A h¨dÊ™_œ˜&Í™+e’¤ GçΡ>Ðñ9iÑœK¢LMg) ŸšüšZ…ƒ«R0E}ªZZñªØ^¸˜AhÖåF¯²–¸ÕöV¦Ð@qYÍ%›U2V*/Üòwl²7„å%-»Ê죿È,zA·/:»R}•k²Í¬]WÖÜÙòËÌ©îm>$ZoZŸtrŒjê˜ ¶‚1z])5ê^AGôŒgX±nÔ¡…»&Ýõ˜QSÃÑx&ùy)ÇÄ.öêÉTn?Ý < oÓ]‚_½9g¾˜K&?}Öv²ÅÏ“voÝ9üʪ§ªÿ Va±ýtŠx„†U‚ñ]5„ Nè_?ÒI¸`¹m8ÉY´)x__òÙÜW†gÔI‘¸bƒÿåÇœqôANo5^à‰š˜TcµýHÆH£UÓÍ{#n†Þgç9”‹ˆúYK’:"éà…à1×ßRê7_„&ñ%b¥a‡a–õ"˜1’(e ÁHnוùdˆ¿ ØV½áÇcŸ`åU'ŸZ’Øb”ÎhcÉhHDZÙ¡Ÿv–ˆg“K®)h¤s–'ižw^Z(}\~%g œ.Öé”’Mj¨v¤Ê#xª**’n:ÕgœBšªf}ƒÚê)•kæ¨)¯¢z£zÄÿ±ú©« y=|(­3Q0)Юîð –t¦êªÊj£ž)jÛà™!Xz`š¥Rºè¡ÚÄRb€:o£Lywïn‹R"Ü”nŽDnĶ{fïnª¦Žˆš§0dì…ÛÞ[W» ³cº1­¸^i¦º€å«ï?üÞ›-É�SxdÇ‘,1¸Â|ª±ërÅÕõZ¥Î¦í–Ưr<´'/ew*“\ò:õv”H²§(y0@C‹ŒÇÃ2“r³€ÈÂqt —;ØÕL¡5Ö¢µ¦­ád»cÓ ¨o"¾s¶Ü Ñ­ N²e€®Þ?®V«‹ßž·àóÀ†˜“€[«xmE2œŽ£îÂD.ØÄå…Í0æžø·_'Tþù¾gCXºç‰nsê@Ý0Æ»Þ4éŸN;æ«çλej÷<»ïºíI|îcùæñÉïðÏóäÃôzKo}éáž}æþ öÝ[Ííïãûád‚-þùÂ,÷=§£™ï>>4²<rûõ/‚“è ¾­¿ý ¢ŠYŒØÔ*ICàë@ž­9pL,Vþ&¨½Uô ƒÓc Ù8H;·ô„½« “×Àªp��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷¾xÃý†Ä¢ñØ ‘̦óù»5”ЪõŠÚ"K„´› ‹ÇÇÕrfHÉì¶Û¹~€Á·ýާÌ{oº—'8x÷ˆa˜@5EØèˆÔ§R‘héø¨¹)cyÉ÷ÉXI9šÉyŠZeÙE:Q— Ë–Öº({‹‹–â©Ø÷• ¬H²Ä:Õ*¬¼Ik<éü ½<íV¼“|)M½Mæ¬}ýÍ=~…­&Nž®Žb®þ>î-§_+m-±jÏêŽé‡^¿Žö¹:H‡ Â{ì: óO¤3 =D|ˆŠ|ÿ\ˆeü8ÂÔ! -f¨2¥!OÎã‚R¥Ì^«ÌL23ç‘’*¸ñ¥ODÁñu¬T/¡“n}ª‡K{ÜQ<i¬%T¨É^éSAÕãÖ±FýHý3µ&”1‘¥hÛ<qÍÄ<KS\½oaŽÔr.Ùe† Oå‹lè!µ5B˜*f·'¯-#7î»VîÐÊ™éX†Yb°ˆA‡Û쳫_Ï¡SOVp©æ„6±–Ýðà‰X–ÖKùœÝÏz /9¹¶pJ{%ò­ëšôpPŸ^·fÍ÷rÔ�)ÏIN¶uÎ^ƒ9Ìã±sä~É×N:øìϱ׋®Þñ:ÒìúBÿïNßmö.ýyˆTð!˜Ø ^­_ƒØÙ}ˆhpš„N§O†_%ÅT…Æ–W(kæ_„²q7{’µ7ÑoZÇÞŒÎñž‹Y5 È¢t¬!CÜnFFÖyqÌÅsùäxã{ýa‡Ž|‚VãK:šÖ†*Ö—/&†c~ʹæ”Ñɦ JšõA“ß=Ùef†CtIn˜&n͉’cmxbƒh‚Ø'¡2Þål²òœ]¾µŠm^ŠH‘+’)e£-F6(Z¨íyÙ§cj ££u²gè¢j>'šþ‰j6 räj¥j•igªV¦ZcžRšzÙx¾~¹—­ÿò×b¬Æöªª¶Fz ¥žWqª¹D„¶Þ@报¹yù(šJk­v˜k‡2r®cg†ûão欫Cº3R ¤Ä‹én†› ¥j,µØq7g»œÎç®ÃàK­¨;ùj² ^ÇÓÞI'€®êÚÀˆ½)®µ“õ&˜¶œ#.ps)òžÿ5ì-Äõú{%~ ã§ÆìÜ,±Ÿù5ö³Å…й´‚­ýŠPœ1¯¼Á)ÞFQeS+¶´Ã¸Üêµ,Io=$¢fyâÌÈšT3Ùc€ 0]pìtšàFäËUTï}\ÙøÂ‰°SqóQ&èEUîN„ür‰d†¸xä;V”6 ƒÉKn6*[\œ™˜G˜‡›ýùL÷V%–k—^¸6V 9ë„ë–Õ nËŽ{>Ãí»¿ÃyÏ!ýNuåG§N|›¸òÙNò˜_¾’ó «+ýôQ«^ýïÿ š=îâøÞ½ìà‡¿Õò‰;8>ùÓø’è¿e«?˜èž ù¤ÿ‹¶€õÇß”ˆDîÏ&ƒÀ&vKI� £ªPJeÔ >8c®Ñ5Ðtô"ô&¨Jä‚Ì`¿4ØAÉuå`!ÜÉ$XÂÅ‘0…ák _èƒ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷>x»ý†Ä¢ñ³5‚8¤ó …‹  )Íj·\ö¡¬Z»ä²YvPã³û §}ÁsÄ*;Öãü¾_µ·W³öwˆØXEAhǤ–(9é´˜¶È†i`øÈIù gÙ ØzŠ ¥iW#¸é˜*;ûÓ´z«§tKÛëÛby{§÷[lÌŠËÛ¨|µt—{}j „]È,­-š}¢|½®hÝ-n~®2QŽÎÞ¾Yλî>O)ߨFM¯¿Ÿ‰œÎ/à™Q÷.`²'0!p¸:,v-Ÿ¿AäZ$Î?ÿ]ü¤£³†:D‚üȰ™Á &Oº 1 ßÊð^ÚD±Kb’€6Þü©îà+ž<mµ$Ê¨Ò ‰©ÄöÔDÓwK«%E•#–::­z•³5,4Sb¢JýŠvd²9_.¥|ê¨&F³Ñpغín³·,ÛîʪkTWÀÖ`Mû‹Û<Z‘R¸Ç¤¡°N[Ñ-¬2²o1õfÖ˜L3ÉUz{Æ*MQåÝ© §K‰ºP¿Ðka;<ñW¶XiO,u9¤åž£Å4ͯ̿ª_ÖÄz(iåýNS7-Ýù3­¹kO9Œ[¶«ããÛw«ÌâÃ'.›¹gÑ„‰dæú#úÍÛgÿß»cÝ ø]RðcyÃ9§–c^ð…gW¹"AtÈóÍz÷7a…9H!‡!V`m¾y"‚x"þ§‘{‘V"#èŶaù˜Ó‹º¨ÞrïM×›f(ê†ä“)èÓž<·ÙŽBêØÞ:Ì HT"·årh™›O1ºÂ£eD×vèi…[’n^·&Si–…Ÿ—U"¸Œ‘ÙEøž}bêÇŒxX™Rö£l?Ž  óõh–š1%Rœo^údeFéßWî¨^s|z7’u„²8%˜ØE™£oMböÚ™RÚ$+9FH*9h2Jk© Zá¤{"º`©CÖÚbgyÿ¶õݨ‰Â*£¬ªÚ%­¾C)B“ai}Å2Å­•ñÛþVl·ŠRõW5ål~êbtܲSºÊ¥ì6êêXäö…iÀ©™xä¼t@w¬µ”=ʯÉöWÞ~#úYÜ­¡Îe7ò k$A7æa±ž¢òºo˜º¨FžÁδ)ð<L ¢m)±¡ ïÇ0fâB ¨k¯šÌ±»9güå£zjp’ÊéÒ6©â¨']QËVÅ‹ïböÌÒÈ>BĴʈ„,ö‡ýú¥4\»Ö;×Íá,]ödÏŒ¶¢„A"ã·´±lµCе"˜ƒqõM¸qÄÒ\ Å_ò]8:]9x¦§EV'Ð ÓäºÅùÄrj¾Û™0Žï}¤ƒ^—T{[c6§£Þ‹¥sý±Ù°Ÿ¤íë·ß®;¸»_÷ïÂ<ÅðI2KaðÊõn<;[gN{ó^1¯·ôn*o½ôÔgßòì¹zÎýäoI~ãä¯^~ùÈC}ú/mOö>–µ7*ÿüÎÛn|ðëï ¡TÏn¥ø�Á¾þYö È@ÍAækÏ0`c—'àäï‚KéÖbA:/2x¡ð V9JÐ]@Sá 7èÂã,†4ôA��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä" Øø!̦óÙ«%ЪõŠIÈ%BêÍŠÇä"BslËì¶V§ÑS@üÏë“Û\´(¸Whxò·à§ˆèø)·¡YiiIøuvÉÙyt’Y‘êizÚWJ±Ô(9ÕŠ+»ø š`{À kàg7û L‚K ¸Œœl7q|{ˬ,M­£è<]V[Û­ ŽíÁÌ~Þfn1þ…îÙå¢þ^_ÅnŸ¯ï›;L¿hß¾VÊÉ›ñ Â,^TýSÓn¡ÄD›ù{61£™yÿ«ú`¨¨1ä¸]¥jˆ2¤Êƒ€\™ìèq¥Ì ØZ9Lïå̶FÆKÈ!åΡhDõ»yÂ+¢LSAëÇ‹K/WO›ZBIª3›‰€^ýJëhÕˆËNª©ƒP~Á¡]«Ç­/ÃpåubtÁf» ï29%qý«é£°†óÜ’­E~r M K®<Ë™Ñ"¤uëd¨wÓ‘<(sÃvû®CìW\ÏÃFñšLõXЗ9ÇÑ,‰ÔÛпgëýfØ3@ÈóvKê÷h.ÏØÜy®]»¤‹ÁNmùdߌÇO­Ì<m­’Í›)Ç.]÷rôÚÓ{•zœ¸{ùÝË[ÿïbšVIÕ´”S3°g uüƒUa˜à~ŸÝ—ße|\hÛcdñŠqâõ\|ΉfÒu ~¸YˆåXG‰ö¨ßiäE–Ü‹ëÕ[ŽF(¦!… ΡZD#ªH£y?r¨F(ê5c{,~ô~¸Å˜b‹"îWãnH¾öŽ^Ú¨‹P[¹d‹F çÔ5Ãñ8eòVåzƒ™\{Ñ%ù¦–ïÈäxÃÅ´ÚjB³–k_:I¡Ûå|g:&ç Ðéò ‘NÆ©"f 9'¥mâWšE²¨©‚.6hK†Š…Ù•Of ©¥Ï¥—]¤®bj%œ~rzg`JÖILCê*cu¨(Þª¶ÿu™è‘Ò„=±9]'É*gP±ÊÐë*|ªê©7Êv¸%¨²ú$j ¥ö _m€4.¢MÙîQñ*¥“ÇbögqéæJŸ¢Yhç¾Nêèk³ÖGm¥Ï²¶¯¤úe˜«=õŽòUkY›u/¾Ëj°`Ï'íyš›çÈwÊ)hA2Øï¿×ei,Ì3|+ž‚ɇfQ3»ñ4abL……Œò¿¨DL45PÃáá²^]BÉÈLŒ ßf­ç»­æ+´ÃEŸM›Í[-zvÛÕz6íÏ>ûø©Û~mâò¦Q"µÝ}½Î õúÍñm·ý<ðµ„Ë{Ø„‹?a¶;ö ù):¯õýå•›BÓ0:¾ù—?imè‡þ«¦¯ÞÂ謿Þì²ã4»è‘ƒ];X®Ÿ†{î±iî;Ús|ñ&U¼— ‚þpòL¡þ¹äzîüD°|õà {û‰ÔkÿK£ôD7ø+!…÷^7šRò®7ûÏsˆý+ÙË/Žž¾¾R.þ9£„ûù5¹‘�¾÷iå€ÔÂ�¢± o[’ áÒgAÙu+ƒ”A��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú·uÝ ‡Äb ÈøÙŒÌ¦óü%•ЪõŠõÑ"Û5 ‹¶®×°œšÇì¶;–† “€u¢ë÷|QÞkwðÕGXhØ(8xØèøøð§07)y‰yI‰ $™ù ʢȱ è`šªZaæ):Ú¹*;{”QÊYçJ»Ë;¹9ñçªÛ[lÌJ’H|̼º,ù\çÛ\M(MmÍ}ˆŒöýÝMîÖš3^®.–¾îþŽ~ 3 Õ>=“Œïo¤o"}ÿd7OÛÁ…& rç‡É7³wLJÿ;b”H޼„AÊ鈅"]=´™2¦…/ï¤á(3狚іàô¡3è ž €d)4é‰5s¶5²èP“J«Vâ¤ÌiÑ‹’~Fµ ö×¢<Za2²Yrf ¯o|¢y{Ìí´§‘½y íÖtÃV³8Q®x¿†=ë;³ž3O•q<˜š¸ÇûäN‘£,rÆÆR9£] —_å·gö´ø¤g¬¹ìfë‰`ˆýú¦Wì^Çlw_¦gzuᮡ!—•›:·oÆÀK²L/8rÒЩB í¥eS+›ÆŠW3{L‹ï}.¾9æÁÓçv]VzóaóŸ‰ ÿ ×­SûÛ:gÿŸ{öÍÆšnì˜B^âM R ’tAAâ@æØ5!aiYáu¨¨˜‚-·ÝyÆ Èa|ÒÇ\~ÎȘt0j£]F5¸_Œ/Ú•Û‡¶ýHS¼æ’0¶z !(Omeõ·™zÀàX‹IjPâoQR÷ây(ªváÙfR%¤Wg™%w).Æ`y£ ÙâU_µ)Ù›HNE—t~¥œIUêxåž]þ' †à©Y晎nHÊi_n#œA7ÝŸ[zI蔕Zhs9hÝU¨¥'’Œ zj#œFYxÃujœžOꩦüÍ(ß¡0âyYŸî-¸«‰gܨ*°´ÿ;*}Þq$âx¶8ˆA£#Fæ˜ë !!…,š+©õ J)RšÎ®”±².wDrʃ²†yïNûh¾SŽ¥(l#”²¤~º"Ùf³çâ¹€^]¢rfú“nœ¨¸ýÖ‰hŽû9éFá¸VÙÑV›®¾·ÙÙš`rÚÔî�é*kíEì$eí»©– k<ÄWk%¹V–š3Ç}tÃ:4ð…kYk23iª_÷sÉ×d µhŠN­½ - ×q™­ÂwÊ¥©µÖQǘÛF¬Ñ·oW¥vkúÞÝ~Í2”GÚ àß~¹pçTصá Ñtë²*5î¸:#¿{ÛOåfÞ¤yçE&6„Ûžó‚åOQ>ºå­šÝ©žyZ¨¿¾ŽèjÑŽ{Ú¹ïÎ{ï³GØûÒØžxðp_<fã¿W‡±3øòÅC/Ó«;Q/üêB(=ö³Äç:ÊÜwïý_ÈWˆñåŸ~ [‘¿¾*MOtàñ+E-âîW¢þýŨì%X\ÎÑóyôF@“å¥ðK 1„Å›÷5ÐÜßÇúGÁ”ø„^Ì Jº@jN"|]½JˆÂ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡ÄâÊfsü’Ʀó Õ1keôŠÍj}@F—™ ‚·ä²ÙÙ}¤¿³û ®Ã‡1hë÷|ÍxnXGÕgxˆè!˜h•øy8XÅX0驹iTˆQ¸ÉIZj8yéÙˆjÚêjÂêW9úZk+¡z»K[5¡ËÆ8åËk|<C—LŒìÜÚüÙ¨¤ìýœ ‡ ÁmI­.þQ|9~ŽVîMžTŽªöí_ö^-ÃŽïÓÏBÀßD8aÁ…(åÀ¦¡DJþ̈8MÚ²‰ÿA(Ä(ðŽ'bK¶ëÆÎ"8{&[zÔÕo .;Æ*¦Ž¡•5{²€©RdÆ }­J”ª/1IÐ<ÊqŽÃ¡"o>…Š5„TbI¯±J™5lê–ÚÔk3 è‹%®’q'Ím¸æô½F—ä×¥ïŠ5 hJªf…i¼†R°S1yèªA¢IãÃ(ÍYv¬´2áÉ–éuÎ<s·¸Ÿ¾æRYÔàÑŸ ¯i´.¦ØTaÉý{Î×k1^{M8gëÞÃ…†¦LiÙ™ó¼œ ¹qÎÁ”Cg~\³µµ8¥oV}½ö`á«‹n»umqב˫¯.ù:ÜÐj½¾~ZvøòKÇÿgsÚsÿy6Ò€÷¦-dÐÕkÌ4ÒƒÏU0DíÙÇV†áW‡bèápç‘w[p:W {ßðgš>¢m·"~)îàŒvÇ]uÞéGŒ ÅÜ*váF¤»åØM Çb{4V6$aî86‚×d/6G¥ö] `~'Jˆ˜zŠDYdšq¶J;0YcñAd`^îeG\˜1²Æbjt¶6_lri¦>B¹Ü2áQ'Œ*n€¦š’úu&£XÆ åœ:Ý‘z:Ù#ŸrV‰è}–îô)EÃ<zi©[~I‡¥œ¦*R§*“%ŠšÓh§¨§k«Žújr¸Ž÷+­ ÿYƒc–Å kè­ëaé8Djš–C` !SöPá…ežöÑm›z#-€žÒSmB©Qø.hÉ‚ îŽVÒ[«”öò:i¿dzû(oOò䜿Úiž—Ä.'è„„Æ(+œ¾.»fØÍ ¬Ã#{ ÁÐCZp´qÌ…¹þƒçP ⵯ­µÚ)­u#Æ­Å3R™ç±wl({Úö—íÈ#¹óž‡É_™·®üÛb'ã6²u­Óî·Çx\µ$X›Ìï¸wžçµ¸%rmÆÖÏìœuEa«ÈdZbBöÓ5-Â*ªn¯}XÜrÿÓ Ý”L¤Þ{ûÄt*{Ñ–v˃^·N ¾8CVYõ°g‘Ã_Nyã–³vù⺑.ä»ÈùúQèè.%Îê®?ðë²kÉè³OŠîíþú¦•Úº?ÍúïÂ+Ž*pëN¶íÇcŽóòP ]9 ;O¤…,½MýQK1˜ýî‚w÷Úsn¼ømß!»Ýšþ÷Ø[û·òìCó¯ÂFüüQ5½¹±úC­¹6õ&ÿG@PÑ–ɯ€ôëšæ ÇÀê…ÏpL`q»ªð‚ã+žW6ÈÁçÕEc!DžK¸<¢p…1(��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Äb XkؒƦó Ý!™‹0ŠÍj·›+€ªô"¬Ü²ùŒ¥)ê° ËmG]±|Ï÷ü>Hopu—çgxˆø øå5HØÈ˜8I'Ù8ȘwYù zFøjzú´XñÈf7Š+»¥êæ9‹››qÛJÁJª,ÌÂûe ñ;¬\™üÑŒg7ö¼LXŒ¼»Z½­|]ìÍŽ:ÝíÃv-®>ù­Èë¸?—žùRG/Ÿ/„¯ÿ¯‹Ü~� ÆðwœÁ…MVAGB!É%+'C EŠÿWÑ#HOÈŽ$ÿÜ)Bâ±’,UlÄØ¢”-k^ÔéÕŒz)múÔð’Á=_<b ù³$,À‚&}:Ðѽw’œB½ºBÌRŠ\‰Ä 6È ±[kýš6ôè\Hz!5ÔÖ˜Õ™dݪ²¨'-²·_ò¬‹­qûÝt„kΓKt²*ܯñ1Ȇq"~ Shfi˜ ­Œ9¹U3ÆœÂöù+Ù7jZK• ú"ßÊ~ò¾iiçÍs}I­GºêéÅ‘1ÅmûØÓh⨅ï^ü¸èᇅV…DŽrÓ¼åÊöí$3Ç`ÁsOmݸÛéU”_‡ÞܼÑò¡åR÷êΜ«ì›!bÿFžLÔµ¶WŒWSÅ­1ÁrÙ<¸“eFÍðJ¨áÛ‚š5X`œÑo^Ñ—ÞÁ]·‘v®Ÿ&&F'_ƒÏ1¸ßIwž�6…4³Õ¤=S±¦•Iµ°˜Ÿs/8z6"hJæヤAÉ^‹%R©¥2c½I&Q¸IÊ‘õ%]!Þ ¸žwXÒ“Šž¸f•QºöaNéÍy߆ôÙ)(vn:Tn Yf£ðÅçzÊç$…ÏI'§Ÿ12×€ªIöfjÈ x›ñçiSHJi(Ž ¦Ê(’2Ù¦z^§ˆšºÈe§xÚž¨ìeúªª§ê8è³ÿÖè*†<•…’¢Ä€ôžZûP{+ˆ ö’s4B é…É$ŠºFèI©:¶)¹Ûq«l¡¼¶¨€ñjèh¾z¨mn?ÊÊÜ¡¥±˜W½I‚škŸ+J¸§ÀQ†–ܺ.Ü,bß^Ì,Ÿ[%¼¤6õ¬ð&•:“®¾ØkˆŠ|¯GKaJêǼL«Ì2ÇpÊq·;Xä…­jLÞ°½>ùaÌøÌV²Éù+òjúj‚¸rÜ4D» ×gFì^V«ƒõØplµo¸YÌvg41a¶Ó5°·K,wÞîèêÚ%*F¬wành*m˜· Žxdhå7gO‰ƒõ Ø÷ãO»é¥¶Œ–o~“JídÈùOi»0uèsWžó8›Îzë®›1úëúTþê²;úÑíA®¼ö¾fê^f2¨Û¼å¼Ÿñ #ϼ—«7ïSµi}ò¶ü;ÞÕ·¤Ü´Ûcå KÊÐõ‹fN¾MÔ³]a…éƒÏ |Û¾2þû³£å^ìö3Ô¼ÂÕ¿¿q ¯pŠO�­§9®ù뀸Ûp„§@B®w) &ëî‚ÓwgÁF/",á ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡ÄâÊ�2~H£ó êšµSŠÍj·œæAùð"ªb®ùŒŠÁ /»]MËçôVyö^Zãõ¾ÿïA•t·Çˆ˜¨’7ö³)©gðÖ8x8¹É9…GáæpÕIZZFX)ˆéh˜j ›óê–:*‹›»ñ*J[Á«+l\²Ì:¬¼,”Ìüœèü5« mí'MQ<!xý­ì›Â ^Hž4& jÞ^ŽÎ^é>Oÿº®N¿µö9 ¿P¼ÂmÁ…§ìÉcñ\Â6gF¼Ø a7„ÿ1zd! •ÁÃ|<Ù¡Ú¯’ñ–Xd‰¥³<l&j@3¦N…—€!—sAÐ2-¹¼dC 6¢L›­¡Í‘&56½Ú­T•ª’ÝŠ5l­Ó4mMzT_+¡1ÀfùùÐ-¶¸<qL­õ%©­š ÉÍ*öcµ§y嚉Vm¦qoàúL·§®>œ‰ÓB†×ïê—%Oƒ<ƒn:¯Û2ëÉæø¨f¿‰AîåõçßÂk“®ÉUÒ¾>¥ÎØY³ëÈ@,þŠ9ßçb¿ûêe;\µèçÂ{Z¡ˆz³Ðç¼£o\*ÒÙŽøzw~^·pæÔ§{Öm})dæÚѯ/=Ÿnñ¯ø¯«ÿËžžB÷=¶wîE^^æýÓŸ|ñAgU„Ûd䃆¶‘bÀ€"†ŸÁWE]¡`T~Ç_€…݆S}ò5G ŠÐ±à~ì�X}58Ù„;>…WW¹ÕF¤Û­uœˆøæâ‘2vG£M…ÐØÝr>>)b”75‰^•In¸ã{&r¶%xH¦$e‘jrábKš§å‰íç— jø‹’¢‘)ç˜øù3Õée Wþ¹ç¡ÿQJ›].¹f¤vÁxM\Nù真Ôi(mz—¢ŽQVÆáppÙè)žNž&*¢~‚é ~šÖ.]Úʨ–Ê© )ö4 ŸÀ’Jg–žù!p¬ÿ* l¢°bǨªçik‚V@ÚXC¤™êƒq;Ζ‘]Ø¥^0k«˜Ã®ƒÛ„è’P\¥­9I-¨=Pú¬½©²rkÖJz’™Ý.ö—Yúùj"¥¨òJì©õZk²6jk*J—ð±KKk’÷hh°ñTÌãˆ/ÌÈ»�c´ž(o¿KoÆöuT³qÄuü¨ÄÑZ™ŸÅ%é\²±K-Ê$‹‰ïµ<-üòvBº²mg}–O³$LÒÿVäõ¶áͬ ¿Cš|ôBa3ó±Ê÷t\³kTmìÒ×Uë$’ºwêáÝ~;èÓã&»÷߆Ӊà¼Èšj÷áL•GÞp—êxå…ÇGU²r5nù3ˆuáÇçz§=º`Ûdzêà¸m†®K:´Ø³ßÞsè¸ÓNùî¾›ðµx¿On…­¿ŒÝ:âŠ<V³‘3wóekŒô®[;µõ†¯½ß¦sß½.Â[ø§­TÌæ‹Õ!›®ßùŽVÿ>/][zñõÓC™èå§•ðí¯-’6r¹âMv—3LzÈ ÀøõÎl Œ`‘S7 ЂïHÜ9ÈLÜ„·CàI8 ¢px#\¡ oP��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó ú„JGPŠÍj·! i­*‚^®ùŒ–¿ëX%NËçôV[…x/ïìxý¸ÀAxà—§'¸ÈØ8x¡8™çXiyyhȶԇéùi楙IxzŠ 3º9!Šèöš:K"+™ÙZ:YÛë;&ãªyû[l <²6J|ÜŒÉ|h í\Ý»úEÂdÍ]mòÝ-žEÍn5ž®np¹þþgø-úPŸ¶ÊÜž/à–~æ¨ðq%0¡‚7”S1GÃ'&F¼gЇÿ;ÒàÈŽR2mKz v¯P‹xLº¬ˆC È—4¹ðÛ¦cfÍtJjÃ2d+žD§»‡I€E›Ú+#s«Œþ„:½ªj´*@c2mi«Ø•PËB%5V µÈb%'Ô«·¸iwøAd—.°/|޵v·l"½7 ½pÎŒ¯äJP"×ñ a‡åTur]ºCýy=j8QfJ(/à üYYäÁ*÷�µuø¯:¼Ñ’êíäÚïã{ŠGŸ~í[3dÎLºB�-r™iÑ–ƒãZ 2ð§C–vήø#ì\#ÑÎÞãä=Ø75ï=ܳuãÔ1'n½k³úã8WKßÞžotååï#ÿSŽW|òèf<„ÜnÕYÐÐ<a,˜}N(Òc–B¡h} ¶VvãÔrÏ=x^h qô!~œÙ#"x%J( ƒ×ÕÆ_ŒÛÕH¢`¹ÉÆ#9¶ýdàâµÈ\Ž7šÈÐb¶µâ?6þg¢)âÂä~ð åqDji%[[Vp[bJI%xBÊô¥yHª¹WˆêýX¥—_ÍÇby¹¤7’oj—KœvHã•06ÉåY÷¹g^‡8f£™\”0j—gZö!äçsÀá8)’¾çŸ™€’ˆÇuèZ§¡”¦4*'aøÞ ¦§ ›©ýY!–rJžŽv+œ­2V*¯¤zZèZ‡ÿ²š«Zd›‚=a¸R~!ˆihD4¸¤¶*ÊÇ`´½žê#¢Ã(lvKÞ¹Œ‰KæºG¶+L¶e¦)¡£ú.¨Gc¯ëªEÎgÜL‡g)µ‚*pÀë §t ‹ú­~.©•/‚I\ϲ֬yâþ»/Mª‘Rï€ðâF°ÈC÷Y-÷§goPbìp—§Å{©“ÃVü0Η룸j*-+—ìM^#2EôO™Vë‹Àé.‚ñÕÚ(3§‡ø"ö3DV/­ÏØáéx4¦,MB6Óðõ±fݺM·.gyH2UuïË-`Üñ]È|Žw¾ì1Ûáb!%gsIשx£y[lNäEºmÅ(Ùm[>‹ÖêrΣOí zéT·fz䕲àyê&}R×®Ïîí¡O»í³—3¥î’Ÿ^Ýæ¾s#OOÊ><QJ%Ïüñ¬7¯¯ðÐ_þ«ÒO_µ{àžy=ö´8˜!—Þ¿müÜÕ§:þ;«oO¹U(µžþ3VK˜Ãÿ%ô†Ÿ“áŸ?c¬/L„‰N�k>öÅí€c’…AvÄÀèÄTÜ'WÁùh¤;è¶ât„$4@��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR�µŒçúÎ÷!m¸ù†Ä¢ñÈ¢ J ò J‰JFÕ6Íj·Ü‘SQý2Ë®ùŒ¦ŽË ñ8 Ëa쉛l4çü¾ßQGqhsõ‡˜(W–1ˆPó¨8IyÄ"t¸†Uéù‰tÙ±ùÖ zŠÊ#ªñVH–+ë² (*éT;»ËkŠ+tëȸ×[lŒñ5 l‘©yü -ø¡KH}}j ÈÚŒý .ÍNî©í%^®ŽX뜾–¬“ |.ŸŸ6¬ßïŸg' @€ÿ ¢º7Í B-ø \rg*â‰?.4¬p±”DŠÿé€!cÇ‘IV!$‰2)nïRºä²²”®“8D¾¼Yí!›8{î´S›™èù<*¢L² †– ÄïcQ¤Tí8C,çÀqzªz 鎛{°Úxã‰ÉÀhÿ°Í²…X¬C[lØ6îWr+•:Ýf¶¨É¶zr…ŒdËP‚‡;½ÝÖáUÅ WVFe+káFjf–˜Ÿ2†\vnaÂÝöRUe,PÁ¬Ÿ¶‚¸ðh©›Cç~©ÎÙÏÞö½¸÷ÇßÉoÜu›»Ç¸wͶ!ÜX½–ÜÛyòÁŠ{¶8:o“Ç—[wÜØ|ìàÉA«?o<<ýË`×ÿÕ8ßjµ…EÍ]ÄwW-ÍgV=¸U~¼1¡ƒ w{B è^{o”öœrÎØó^t®×ˆãÅ—X\ûM%†*ò—ŸŠ¤lBS®í˜†‘I8Êwص"yz…f(ÖHäŠà]D]ƒ€I5‡å™"+§Á&Ô4Gòf’€5ÖFÆG_/Â`‡J¢7åu¤¡Éæ ¹¡(ž›qnW•2²Xg–1^¹ç„p~©[˜ŠÊ•×2OÒY–£™GW}MÒ£‘Ì=¨Ôy•öÙ"gUŠXžœLšg{ZiU”ºiZ*§Á÷雯by*v›JÚi€µ˜h£žh®ž®)Ú£%ÿb„¨ExˆQÍø£˜=@)e…|v¹A³‚¬É+?¿vå­w¤n7£3ºúàê…—n9YuÙ¹h½«ñ ®ºÞQŠì¦íÊl¬üVki¢š¥‰lqùư| j‚~Ú­ ÿ{ê[⥺Üo¯”k‡öªc~ž5#¤—Wêp°Ï²‰ñˆ¶VÇ߯³Œ®–0/[ì‰xØ<is³šé&·i ‡ üM²úJÓC"=ÉÃK³cõÔ^â»›ŽFLRÖØ�}uR�*/ØúYÈôŽ8þ5[¶Ž´ æÛp,¶†Ò]ÕÂÜBåó‚|»öKÚ/h=8_R÷:3Õ‰'®#K>NùÝl»Ó£¤•+Zv›~Žš{›ý9èÂL^zêg.¹êaâ¡Ä®Ï^ÑÓ´·¹³ÞÎ÷Ôˆó>Òï<Ï#>z Oü?°G›üQ»ÓÌ|ôÍ¿öŠGÓ_/YçØƒ2 öömèè¬~™÷૵Õg(“Ï òç÷AÔèo­'ôïë#þ¹õ[žóýýØ1§1Å|þSH†Ld—;°nìkÊðøÎ}”Ç/WA{%PÔ`‰¹–ŽL",! ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf樒ΪõŠý@I*BêÍŠÇdåVq>/¤å¶ûÝ OÔ‰.×&‡ë÷ü¯†ŽxðÓWh—'"h�Åvø锈ö79õ€©¹ùbÉU²8EÈIZŠãé:ƒgÚꪈz©Õ•˜ùz‹«è7SÊ›\«f ¼á(¼ÌŒILuL¡ÚL]­…m½ÝfL-Í-Îù b77žþ¨íS®þ~Ë?Ï<ý´KŸŸ -¯ï_è #Láþ;Ø \*|~ë7b{ZDA±Ž•Œÿ;^ ¨ÐB@$ßÐú(qaÉ•¦5J‘’¥Ìv¼î bHPàÌ ”šä“£¬1yµùåä"ŸkØ; Õ…-¢MEŒŠU§(/A#Éó©Õ›×Öüº í%¡RÃte”-Y”¢³²’ÄܨŸs‡2`‹iU q)ùMÆJ–Ú¿žŠÖxøoÅÁrSU<P*Ç‘3ožH²ÎxÕòK 8°]»šE{% Ú«as‰uŽèò渦=Wµýi×çÛps 'š¸w£ÊÈ£h;©q²Ã¿î-ÙujÚ kS½[tﵕÕ}¶ Ë6ÇófŽØ¹èÄÅïî;~qÁ[1fÿäØÚçMôÇU¿I&`‚ZÉ…SN«ÈWc~¥ -ÁRnêÝ×\kB±‡ uéõµ^t¡m}7ч¢aøµÇO/×­FãF1Öá][…×"zñm'^s³5"ŒàuX`†Øe—_N=Ç D ’Æw5^yB‰²¥ÂŽJÚd‚OaÆÙ¡™9¥‹&'wd^¨¥„hN‡ D TårÆÕWR:‰e �z"’?òÖæžD–ɤ‘jF¹&fb¢§'nfJÈ'‹†¦Yçsï5h¢KVÒÝ—z†õà˜h1 ê‰Bz¨¤©R '|¶eúâ­wÖ”ç§d]zä–¤ÂÔO€Ø $€7ÿ yb‰ôY— öDg¬Ÿ°z­Žƒº9«££bª-œÊ÷dyžùk%‚®û —ä55£¸løºßævª½{­`Šøæ`(Iºj­<ß§ªú¦¥SúžzŽ…¹Å-—Ძ­ý½&d¸£Ðæx^&˦¬·ê®¿•êûn¡Î*7`• R±¢7œä…ߎüQ„bì…yͦ,F®(|±IHK¯Ÿ°¥ ¬EKWSóÏ& -1C.É /Ð^3»ÜRš¹a¨_GõÖÆRJtÎÙ«MÅ×mxE­UÒn«£³ƒ(ßÍ7´Î`miß‚÷´Ø1v~”=KˆxãøJ‡”á‡7NÕ¦_<9åYy¼·æh{™ç¢C^6£ÒÌzŸŽøä˲~·uYÂÞwæ´;΂å·Ï#ùÀŒïޱ”cÏÚ7=<cçn;ò†ôîÃñÕ:ÿŽá ®îRàÔçŒõ¥+¾óöÕ' u{ÌÎÕ¼ø‡xŸái¡›¯>Oz>\ºÇß‘ûæÿ?cKÛ¿+e}ü `Æj/Òn Ô\˜¸ûAp] œ eP��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰*Aʶî Çò¼öJçúÎ÷~xà~Ä¢ñˆtk·aò JK•Íàœj·Üîçú�[WY¯ùŒ~VN±5 Ë¡íòçN4çü¾ÿ›•džeG(ø‡˜ˆVÁˆ¥×t(ä¨hyIS iÈ ‰  £I*tÇt7¹d*êújÑÚª2A¦9I‰ »Ë;›áKYÃÆøÉk|\|1‹‹§Œ Í’wX'}ýèðœ¦Ç¾8è9¤{ºL±'ÎîZy®ŠOØ^ßi¯¿ïIÂÏ/ »w "ØoBƒ -¤Õ0¢1ór<”ˆñÌÅŒÿ-¢hãM³Ž$ùœÛˆ*eÉ•›½xg %Ë™Dþª¥.ŒLš,OâYFP¥KžD[\!¶FØË¢LS$FÝ·2;›ZöMU³5vª&¼ Vd :«X• ‹¶ÈسÚrµÍ:4˜¯sµýdw×–™b‚¶ÊÊénZcÔÖ¢Òµ.9¸Rsx:ÌqÖjoEEw—í6k”%+ut´kåyå~ݹޡ WçSv”ÞÔrÖdTÌ“ª³Âž !lúlëà)I…Æl—¸lÔœÈZtïÉÉO‡¨s¤y™Su~Ž9j5ù~ƒ9Þð¶Þõè×í¡«—nüréëù²7ÿ? ÞzøÕ‡|º1_)Î6œXÚÕ2ßMÚTʃ^Ha†öf™…jVY_hõLÓÃ^‡ˆ)÷ xÅ(àgí]&ÜHÜm j)’¦#1³%¨p¸ y®©'ÔcˆÑèÝ€*þÃd…ØUÇc…;ê¨AwRö÷È'òçŒYnˆ%‹¿ÜFdšXéÑ“ŠQfçÆ~µqùÆ”VI§~êDù˜˜ä‘ÍÅù…#ºwžž&Ù’š’z©p3Êyâu&W§t}ÊÈÚ¥±eJ]˜‚zZ&-^"J¥˜ƒ0ºž ŇЛ(Šª3GÚ™£M‚Êg{ŠJß©JÑÙϪÄÿ꫹6*+°æ ©` ÔöÊa7jA !¶ª5æ–±˜#e�]‹ë¸fvy§vèš0j2sFçmTy¨°Ne(‚¶b8iÀºÏ2I²«ŸÌ Œ{Õ%졸/Âú"rã‘êÝØœí±8bº©Åý.ìj ÏÆ:F½*wð¯À`¡ÜÈ?*D1œkÊí{ëE›g±'WlrÆòš/Ê'Xs?Ó74»lr ¤‚U½ë2GAXQR( yoÒØÀJu]p%æmb1É5"'‡m Øi‡ õr1Ï[Ó¥øV­&W -éÏ~ã-©ÞÏüŸÑ€.Œ_}G¼ï‡ˆã–Ùo3þøU>Ëè+ÆpWnùmÐ*ÆyèÝÆõ¨áè‰Û#zêé4~ôæ­WžõŸÏŽû[[çÎ{¬»ÃÞ;â°M|ZÓV|ò§ý¥<êºE|óµ«ôÖ_?éNlÛŽ½DÏW/w‹Ý[<餻¸îøû0/ûšS¯~@ß§¿¦,ÑÇ/ÇêŽË[ßöø¯_¾ð®Zÿ³ 8àÀ–&-‹œÿØ[™Ël÷ƒ 4P¥¸ZHYÙ6Xµ­Ü „ÂSM¼Hˆ;¢pv \a ?èÂÊ ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"@—̦SXkآϪõŠ)@E´› ‹ÇͭÜø‘×ìvœ„3ä$ÝÏë3Ý齇¶GXh˜¸�x¦vèøX†1ˆÐø“¹É©•¢ ˆÙØIZê¡ù‘ˆ6Iagú ë5z:«J›KJ{${–¤,œV—ã7WÇ:¼üÊ«l±¥ŠÈL ú)m0ZÍíè vÝ->®õýIŽž>-¥Þ.Í%éN?_Á[¯Oô¼ïÿ0 À~ì^äˆÏAÏòI1•Ãx³Šýª1c‚ÿ/ÉÓÖê£Æ‘+:2 )¥RA’,‚šådË™ó¸À¹Î×Jš<qdbtÏâ‰=Y®ªtÌ‹:&‹:e±ŠÒ6DJ˜>½ÚK*UpÉ^BhZR±8«‘Ö§œ/g-¥Uª­í o±’„tQC¹ZÁÁ‰V×´[–|t,1a›}­&þHx_È8“"ûê÷1±Ž“+*{1'h?Dã õQÚ…ã"† T§Ä”šáJMñYËZïTì±ö`Ç´tWvëØ÷åbœqÿ,únAxo–µógiê”Ù£'kMɹ¢cÓÑ2EÅ:¼wbë‘K¿ts:vèÊéƒlÞ~¾áàòyÓÿv­Œ`$øÝ ÙÚ©&ÓrðÙ‚Ò\êIˆào"gŸpr…B€Öax[{ß±Vg²÷•x#÷`d âÇ\q*š¢Œùù'nÑL¥ZNì¸Ö_t±òˆ,b>þÇžE6ºø’ ÎØ[“÷=yRüi`b•½u©`]>ŽY!{8rIä’s§f–’¥]†9êH¥“-Æ×Ê’pòâšž¹Ÿ”Ça$ä|K9[“¢If£0ˆé§ŸÅ±)âsvšçåi¹I™”xB($¦qž()2øMŠ"ƒµQz¨œQZºÁ¢nÝ9+¨o^™i4rzªÆj¦{Z™›©X Š¢„…ÿRªi³¯^)«’ÛEf‚iS£>ÓCLB“™ÓB*©Cú›ëgä¢V)ˆn¦ «`¥³¶µ9¬®Ü:ÊoƒùV-šçÖZ^¼þº'¼újiè­ÀI†/cå1kš…®ŠJqªÂKQ¯ªT¨} ¸n¿ý G%sÇç§ ¬¤Æ7‚Œä~ «ç±m\ è ö£{­&¬¥·{¸WÀùn4­Éõ„¢óÏ@5m­!¬R½ÇÍ+Ç ²T{•©=Ws£5Öçä•P݉;šÓn ó:f¿M÷†KcXß„tï  (_ç-5ßüòx­·… >S?Sýµˆ s#nW¤êÝîµ¾Cnz …yO…ûhç4•¬êF¢ó}Ïã—ŸžQz•W|!묇-{ítQî‰íˆµµîžç {p¾¯i>«|ÍɯFrð>,Ða«}B¥§ˆQ„IVïŽñÚ_cÏÜ‹#ýÙy?þ!¥U‘IJ§èïËÎûðG«æ˜õ~ÿH0Û¿§LÊoè  >Ç›DÌ€viÜxÇÀ1)NŒàjXA ’$MöÓ ÛäAȉ/„¢‹ OØ‚��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±EkԒǦó 2?`ôŠÍjcÓÄ2¸ ‹ÇÐ.£J5“×ìöZ}Xºçô: ­„äö¾ÿ¯„¡·—4xˆ(±hˆ ÷³˜8IÉãèu÷È$YéùÉÑé!:Aêeʪºú(bê ¹iËjëWûK»K¥Kë{;Ì&ܘ#›F¼ü'¬á¬Ë,==sÕM­Í›W½ý Z‹½÷~Þç{Ùj>2Žÿd¸ô¿aŸÏßÌÞ±¯Ÿ@\1eˆpUÁ„ a,¤` bÉ7èmÊä,b,ŠÿÝ­{¸1ÈŽ$#$3­] o,KºÔçÈâ™”>þ½¼ ‘Vžk D¤7gÉ“õÀøT´TR¡ÍLùræ£J¦TwtÁ“êTÌ}ЖVExuÑ8[ š=å°Mµä²±µ"³I$n³¢Šó*ï×[N9Õ³Ù­-ZF¤~†µÒ ÎÛ:/Vì¢bÁ!aòI™Q[¶óLò,üW3⨡ f$MÖ(ѬJCÄÝÛ±ÓẉG×Õ[š—å`¿l'nü–wÏ\Ùíz<<w»ãÀ7ÿL8¤9©¾ÑB?î®Y—鲞…»¨ä^ʳG.”]ø`ò+—£¬.3üäÁÉuïéYº}ìóuËÿç__wÜuUy©¡€•1–够\IØL­1aKýõFa{ï¡Öžzd9¦Zx}]xŸiùu&rº'Únª¨Œ‹)ˆ_+ÔÉøß{8–¢ÕE©…[*ÌæãT¡¶cÌÑxb~5²˜R’&F÷à…>¹ŸŽä]§¥H™q! %d™î$wà(HžÈ[FÈ–hžåX—ç5ך$œ½)˜Fz¸Ò’õñè[›o®¦M%ªif£V½¢gcw>Ç`u i\¶Èfyš¸(tçÍtc“žz£çs‡bXYŒcùY§èåyÌ¥qÒ©iŽœR‰'…©j—›¨[’  ©0Љ€µÿÊ)áQUÉØ˜öçŠÓ*XdtR<ÃF®'L�Úi ˜š d¥ÞJÉ䇯pl”[.;ï­s¶;¡£úV©½Wz«§GáëªÀYþËj„Æ©lz/Jª®Á¡.(~Ê6lë‹_v¹'ÃFã¯}w¼»ïPsú´‚¬i0}×¶,#®‰ºw1‹ÓÇ­ÄÿJS²†bÜñ¦Õýj¶ oE²“%Ãruª / ?'}ÈÅT÷ Û5Zï”/?S§»…Õ`».]áRjW×K¯=œ½:V@l/=¢\le…s›Iîón<öÞLô¢Z(xHoè%ã‰37êÈüøP—¾ RÞ•“tµ8™†òùæ±Þ`M¢ŸŽoà¨ î¹æ«¿~~ªÃ.dÓWºI{îPo¬{ïà6»ïˆxõîÕÂ'„»ƒ­óÎìñ ÖÒò“;Ïùî_¿»ñÔ“<¿ÀoÏôŽ#>Uâß‘fù8I~ùZÁ«ßhßð¯8È„½?¿*¶›a/ÚçžÑ ÿàठ¸pnû‹þˆT,J+„`%¨2 >Ž€Ô`â¨åÁÕu0„°ƒ Oȃ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~x³ý†Ä¢ñé‚Ȧó - AeôŠÍjASΊ¸ÀÛ²ùÜì:Ô &ú ?ÅÔù ¼Ë÷üþ‡ÝF·$èWhxÈ¥7Vµ†èø¨¥ضè噩I$Y‰!ɸ):*ÓÕ9–A‰gy©JúJzJÕhàºá «ûÉõ‰‹*»;,'Ìj¼ä…—Lì\fÜ<dû\m&}b‹ÍlÝ=ª´ ®²êm~žº& 6Žîž¥½ÓþNµž<_¯onª¾ÿP5 áò<xd['ƒö‰&®œÃ‰=¡fCŠÿomÌñ±£È •ÕG°ÔÈ•%b|�ŠEH–KªaE J˜SÒü™H;œËh‰˜ te.“¨ˆšx‰4éO6ýNz k-©\5è4… çB‰ø¢v=+qÊ<O~¹¤Õ‡Yo›ÎES×Îݧdèèå¦-§S¯AÑN´Ü_=Ô\Rz)p Û:¬<•µ»µ)\˜9ÿÖÈÌS³²Ç 'e~/®%Æ•i!k]l«m·¾®Í-dÃ@‡±É ×îTŠE%mîä¼³›ßœÕVV]åw¦ûc̳'ÎFmK/}¼:ø¢Ìó,îÛ77cà‰¾Ø¹.>ùè÷˜³3¥ =¶iù€ãKÿ§_žv¸áWÔ*Y9üYvÚjçÁ×_ÃYàW41ita/éôD ‚‘aè“@Ûí÷a~$Þg"bTwQq¯!÷ŸsÞùô]tû½èß$ôQ—Ò•ø¸ ƒ Öˆ#†ìHVÙR¼-ùÆW­ø‡d;Î7¤Ž2bãg6F¤yUbIX¹h—EjId˜YŽÛFì1 '_ª¥{bZååe:5褖›‘‰ yV.GД˜y9æ€Ïz¥~`Ö'¢qî9ç`¸åéæ^qnJR¦€ ºX¡­ø[¥<¢y#¨Ê ¢´‘©Ü2@ƈ]¤Caª(›¨&˜(qvÒ*ˆ”¢Ö™©Tî°«ÿ>ªŸ«ÍÑ*kšêÚ¦•+²¥öéQ>ö kˆ?|ûªj‘{Q˜Rx›Žó ‹§4Î~Æm#ðŽ0Y§] èÛ½Géš,„ØòHéºwZÉiÂÄYª¢¡TXµóªŠ¿úƒ*®Ž;Ú„jqw&>9©` ? pµ';Û.‹ŠšÒ› /‰Ü˜‹…Äë1€ R6”jÍ^û3ÇÇ©Éç…A‡FoÉ[½¥†×[n’¶Ò’¦3£bàb!N{ƒ«¿r¡Wjp-c|ÐØÝ”­5¾áæk2ÛBŽuo.®m)—yÿÍÙÒH¶Â÷†€+|³[ºZtä1ÎdXœÑçݘÌf×xy™ÓÅaçpú汆~§,ºR\,÷ã©Óä/å®ÿñ:WU{î-¤¦{ï–Ïþ*Þ¾ÿͺðÃo •¨ÇOBUËYé"GzðóÉF=‰@Z/D¡óŽzøÜO=…¡Ï)ö'¶ˆþè!š=¢äíÛ~v¶ó£ Ì÷/¯¿^Æï?ŒòU Eƒø�‰±“}ÍQ×9 ç€±@µÐûhœWòEÁËEúË òa'ÂyPwÂéàs§ %‹à {'¿îO…2¬! ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋uÝ ‡Äb ¸øÙŒÌ¦ó)D*K¨õŠÍ®€4F·« ‹ÇPpò`N|Éì¶ûmK«ò·ýŽU§Ë:Zš(8¨·§¦D˜¨8hшÐçG÷³Xiéô˜”i°‰x* Ói²7Ù·9Úê:3Q:"9‰úz‹ë@{&õ› ìÆª1¬Z<ç¼xÌëQå ËÉ\m'm*ÛщmíM$Íý=NmÕ]žžˆNý®/øK1ߎ_ùþî•ïÏæ,Ͱhôþ¼f—ÀX:„„ì¡Düîé‚hn¢Æÿõ>Tœ‚áãÆ‘%›F2%O|žE©2&EG«,)Sæ/[œ±ÛWgΑ #~âùÒf¿?‡:Ý ÇL=CÎzŠ5ƒ@ª´(éªú¥½¬dÃþ9m'ÚÊ<†éÓNh¸tRÍ¥»RM.È-»,*Á…4Lý›lï!»È°­© Yo±­Œ1®…|ÒÝix+ƒ,Ì4SM“˜ùjK:’Oqg/NVѰÊÕ­?¶z1ßÒ-OóÎl«³æÉz'ýmÛ7ÚàqSù¾ÝôÞTÔ‹•^PÁL‘×ÒÛ{OÏÍ ?ƾÛìR‹—%“ü’9ü/`A¯§6]¼óúí›Óÿ'O›mÒIá ‚!S1ÑÅ—`ƒbé÷Ù wR„=m\Z,PXÖ™W\lð‘ÆÞu"ò¡{&ŽfØù¹Èbj+FøXr¨"[ZP†â69šV#t&Va…åŨߟ-G!“P*Y׌7>©¢VÔ¥WÒbÝAs¤bjéå† éàŽÁx"›Ïq©Ô‰R¶(Ÿ…¼ÁåäxT–Ùe•ý™·d–î×gœ|*•§ž`ŽÉhr…H¢sô¸ékF¥YdSPž7éø¹YŸ‘ýX ¨œ‚~J¨¡[bÙÛ)B*F¤¤8Ê‚§¥…ÆÊ꜑nÖ¢q‰¾™æ¨Šjª©©Í¥KÿU5P…ù¥E‘´ŠÚ÷^†Õ2è [ i›mP?±igQκV ·ã6 j¤<ðú-·¶ÊgWÙÁdm£cxmwˆqQ³ábÚ&ªÑî g¥©l0’ÒÊWkeÓ2 ²+<bP [¬êÁ-yÌ#ˆùêK¿×X ÀÓ«.ÃÁÎ{(Æ”<\”š*¬ÊŽÊxïÅ󑨴2ç|(UQzes§$&UGiIXBº1ô<2!W]„ÉÜåÖ¡P-õW‡ [ÌçqÓUÒ/ÍöÖø}5PEd³}ÛHŸñµt/½Ðk¯úíÞúÞ[Ü[t,øSóøôL²ž¸N~H±nsÀGþ å0 5æmK ”炇ºÐ¢Ómt·)\~zCª½`둳.ûàÞª^{î«îÅë.yàm;äÀøÀ¸Ý—ßñ9­»óµ÷.èÒ‹IýÃ;_ýí‚Ë}îáD~ù×f¾âJIÜwé“1¾Ÿ8ãë©å5ýþ€‡Êâë_²ÔÝF4š ÉžFÑÔ€³CŸþÇ@FMIù‹ SÒV@ ÊŽ@~Óàûµ;ž.ƒ"äÞ*hWÂZ ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR�µŒçúÎ÷!m¸ù†Ä¢ñÈ¢ J ò J‰Ê†s9Íj·ÜSqŪâ®ùŒFVÁˆ/¸œŽËçÃ¥›9¶®éü¾Ÿt·8¶÷gxˆGØæp3˜)É·ÈTÈpIXS9ÙéÉÃYa·xõizºU)¦gƒ «š2êú*›«û@„ilÓ»[ÜùJÜ(Z†¬l ­õ<1çáMW=ìh©~ÆýCÎ+Ž.GLnžîŽÚlÁþn߯’ß?·ÎKˆ*O TÐQÁ…hzÍcó‹¡ÄCœ9â71cŽLÿ'0ÖÓP¼y÷…<éãa7A0âB Ç6ÍbÚ4Xq—òDÝü9+ÙŠtCU9Y.ó•4*••Œ‚ä|hѦ–O¥z•7êàÌaµþ¨ú5­>MÖîT$íÑo© >w÷•Ê)ܾ6Öê…½ƒyª-–©$6’ŒáÔxPÞ›ìBÅ—‘äË _B¦º ¡e½s/ÒôÜhïäÏ›QŸÃµ©™­<Lí¼QAø°M•Cg½Âwl§´€=¸iam{º>ݺxeؾŒ×„Û™vqη£;Ï;Ü:羫Ðb~ü†)èæØS'ý9`öѯÕ{o¼[kùÌ«oÿ®Ùuÿ§_ràhÕ_¤”"’tóa×=³puËVÔ¬#5xhxჯa6ØJY5aƒ#·}¦‘”bgÿ±Wߊ‚ `¹Á·–vßÉHÜŽ®ä&^bw9C¢nFF!›]•äEd3¶ÇÎtüm£‹<Bä 9«UØŽ1þøä—Õx–D±uÍG®™Á~d5™ex-øn*×å–Æùe¨ içu B¤ãZYªh(AÚæÔ T_šlNºmªž”4ºA §‚^¹á€›NgÔŸJzÚèŠ[©Æˆr¸¤œZ(&tê…©¬s‚Öél‚Ùc¢Pö¹i¨šgÖ«ÿŠŠ±Âê(^²Ò Ž[e*¥¦`¿”&!QvˆìruLÈ%3»º®æfí²×*”mGšvhŸ¯Àö §®2*ŸdöV;-=èQ ”ïjòدV;Mù¡¡£¡ÉÊh¯¬Vç©ÿþJ«¢™òjY»wk±È·j‹`‹(ï/Á»}Ú›Ê4å‹í«I¶¬_~Êv)qs‹Ž èÅm>|T¬9zL1ÐÇ;4u"ã¹2UOC60Î.÷GX…>EØ%† ÃÇV'òóØjœèX@‚í‡Øl7äö?¯·qÊ’y5¥~(nÏæ xÔ/™˜Þ”!~õÔh–iÓˆOZ$ÕoQÉöÛÑ߃oL–Àïå^Öb2{ãùç™u‹wéª ~Ö˜«»o©¨¿®w-ŽûDûã–Ï{TÜ4Õjë½ÿ${ê?<RÊlüè'O<‡Á/é¡sÐ+nóÓ_ïùò,nß8÷ª/¯½ôâ³ùËΟ/¾ÙìwO~„ ¿Sñ Ý]>ý!9„-e»ëÏÉɯX�üJ;ܤ¹êg¬ØÜΘ–eA,iDµüUpMµaÞaW›¹ïƒR ÍHػΠ…×£ ¹7Â^.]2¬á ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷>x»ý†Ä¢ñ³5‚8¤ó …‹  )Íj·Ü$ÁìŠÇä¬rVXËì¶û˜¦:Òêë÷Ïë5_ºÊ&·7HX¨rpW¸¶døi�XEi'(™©©eù€‰Ø¸):Š÷Y5gGªºÊ‘˜Ñäú÷§Ëj{KÒ7W[׉û»‰å[rÇ;i œlˆ<¹#̬ý6¬ØìU-Ý]Ë «-Îõ‹4žNÎRGÁ[®.ŸŸ:Q?¯_f?£»°P8|2ú<(Æ` fÿ:Œâk` …+Z°'±Oÿ;&T!E$'"sEmDÆ#Kº¼s×)Tà-z‰ÓGJšZæüùΦ±‘>±=”箢v"} *·aÔ(Ú„Šõâ3©±Ö0Š™5¬:ŸúL­ÊÑš¦!ZÃÁ¶ÔÛ{yüŠcê\ÄDWUÆkËn_™2Ý-Të·Ø Jp“6ŽÙnèVƈÕHù2š¹0#²œ|(åcY™¹=^ŒÙgy{:ãT+àÙÅ/2ˆ).cÔ3Oò>Ýl7švÕNV>\ú3ä¹´ø*·¬×¸fäΧ÷fþÛ¬75¬£.–˜;ݶ¾SïÌW²Òå›­GM>œ}ãæ3_¯çÝ>òøsî‹cÿ7_Ýqv)ÒUC!䵟QñAWïv>õ˜ö`[k%Å`{²`›v7]‚‚pðÙçYl£ÝwÜu_XXaŠF tú±hÙŒ&¨Ù]ÝÍÆã6°•e`+ªáç_|±!÷œ‚'Ö袊$:Øß‡'c“uDÉn)Šwå1CÎ_=Ž9å1ü…¹âoŽ·ÜjõiÔ%gi•GË–¤ùGŸw Ú¦$ŽWÒ)'K•e7JN™'#>If£"µ˜¦)_¡ZYäœÊÕ‰%’ä©g™wžc§æš_Œ nY¥x0Õ }œ®E)pnÆ™¦“4Ñéš©ïáYë¥+†Öê“ì]˜£¤lÿâaz~âÅ(w7rHÜ+EDk&­RÚG„–_Qkm„¡¾Â«l%nµ¶ÄôÚ »˜¡‹)K"k£¨ïr›-œùò!¦£?yx&Ÿrê,£²rìz»j¥èaVS¯¶&œ¡¸ªÊÊæ|”fÙ`¥Û;î¶:Jû‚þf¥˜ÀŠ)ļ ·ëðŒ{êûéÇ·Y0”ï:3³T*ûéÃ4vóŸgq™°z,÷{²6·Š¼Ñv†;¡ê>òñÕf¸º¯ŸÁÑên2V3MFÖd›$°™pÁš„ˆÝ4@nDÜJ]KwÜ#{ÉQ¤Tçío99+Œ7àdzErÀzÂmxZ[Èx々--—ÊKŽùENÚB䙯¢uµŠ?úùQ‘{^:P%c”zÞœ«4zÅ­«^¡ M]&곋’ȸû®”î»kòº¯¿o üð™Pˆ{òÊÓ¶mÏM=ò²¶ƒC½ëµgÏý¡„›V÷Žch¼Ûâýñüžo8ó^ƒÏ>R‰~w—ǯ¶úñ=§óø“â-|ÍÂÿ ¸’¤(ð¾A‰É¨7ÆH”G¬UÁöAç‚÷Ë üˆ8*Ï¡áìZ¶?î.„*d_jZC#��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±õ[ÔhǦó %&É`ôŠÍjCÌG—Ê´nÇäòsÊ@'¾æ¶û}fSⵎÏë5_›\Y‡°´GXhè8ñwеxøi–˜fqgð3¹ÉùxI¤Ù9JŠä%Úà‡J—êWú ë¤j©Ù{‹Káx±ÚšŠÙ›+<œ \yjL¼¬§¼öáŒÌ<½ilµ{"6HÍmˆ=gíÛM^&¡­¨{ZÞ®u®‹š>ãånòÈïßdMк…åSçÞÁ‚ ]\ ¶°XÉc”E<†Ž¢F‡ÿä常1$‰‡ãè…«�R¤JŒõ”°Cw-ÞÊ™÷u�™’¦Îpò¢)ìÇk§PŸ¢gs¨R0¢¾%M¸4j6iN!J½*E›mL?býŠRM’É,Q‚‘³D(Ll©­ªÚÖ@ŸŠ‚kûkdZ°¹þÔÙ “«X˜ŒÔÎû ®"WŠß¦Yux‘ã~Mg³Øv-¶^‘)Å ±QÌYmÖ ¦UÒyúöòµGµØÊ´§•&Ñd_a2³• ¹ibΠSK.þ¸téÜ.kç-üYqòãÒ)ûf¼6ÙŬ[£¦ÎyÖ[ͺƒõm¶ºqÝÈCÿm9ñ˳Љ«¯>£rññúÿgôW:§•Ýs„x’D%‡à|Ιa{ ""Ü‚¡a`Ë`Ò€öT1ŠVØ}î ×ánô¡×mùiG!ˆõDWŸ~*²'âe->Å܉ hL‡¯ý(ÄawIˆad4†çâb5nbˆöÍØ’ù˜x¡|ðÉxã‘X*ˆä9nhJ>IfP— ¶Á%Ø16Cï iejC*—"a½-éÞp¦É'“Åõ——”(nã—5Òæ% :väZ™ŽZÈètâÉØr|þÇ›–éIɘEl^ç&ìL¢h”vºé3kbÚ¤uëÉ‘šüáùª“WØÜ¨šÖ©]§”êi(u£zöä©tze°‹ÿšZë/¡Ä:–Bb˜•‡JâÚ¦|´Xdš%%É“®án&Úgcfó©’Pb›eT¦š)«#H/¸b>Š/¤å–w.-Tšío^:'ƒÀÎj«¥yŽ‹Â,åzž@«VJ^’ïòZ±²ß¶I0Þå[¦¨nÚ `£UÌÛí{xÞÙêÆ î9ÚËÆm»É»Ù7ÇÄód¼«™<»znöÔo½ KUqÁÛ%Ó(‘gÀ\´'³FEl·–¬šºò–2uÓ’tMȇsjU™51öŽìÂuÚ.Ew—6hÛUËN§÷£¥>Ìà´yÿØcE xá2q+ïÙ†/x„2¹œ-I^pä–»Sí®å4)â^{­ù-žšI¸~¡Ešéªã|ºPék U­»~8QÔήRê+³�:îÝÀí¥[û®ðHôNü=˜'ï»îP1ÿšñ<Þ†<ôn­måè·[¯÷ðw7ÎýN?Mˆ·Úá‹¿Waz|¾ø¼˜mvûÅKTUpÕË?Ñ>ú¯¿Nû“º¼þ-å‚£•�Q1·ì€ørßfs?Dß“`Ü‘ ž®Ô`HøçÁÈ-¡ƒ!,á ��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú·uÝ ‡Ä¢‹ÖøÙŒÌ¦ó).”K¨õŠÍ‚IW¡ÔŠÇdë·›”–×ìöó À¶¹ûŽÏoÑòj"¬(88bçH˜¨èöåá8eا¶XiÙYhHuÙé)S%)§‘—&ú™ªŠµ‰¸ú ÛÑX‚Ú{‹KZê±{Л \ºçû+ŒÛë÷;Kqœ]ùìÀ,­<Aͱ¬ .è|íûR޾Ó=L3ž¯Žq>ú°nŸ™±¾|Ï­/ ¼íLöï¹rø:$‘°žDϾ=¼h‚¯ÿô"büøZDMy‰RÅ»kýPhL ³K GƼ鲤1xâü9ãå >§�=šâŒš—3/C u ³©Beò‹Š•Õ?Ž¡‚34HQˆ'ëÕ³$­-B”ʦ ÕÖi§Ïf½¶+6¥\'öíYêl;j¹Õq[–A-¥u2¶—¸áÈ=%rªßrçKvL²Y[C!!9Mõ+KÏv™Þ½hú¯±µ`š>švÁ̤-7¶š†ÜîG¡éü6Å»°ÚÜ&›*þ£¿è–E+'}ºÂ²'Í>f7QЛ?M¼E†"‹'ŸÜ7v£€…sn_þ=}ü×sOÿæ3[€ —\ö…t M¤4\sõÅ`edX‚¢)F’^;™¦Ù!áÕ6rbFpø±G\~Â7âLUuŒ*†¨.vÜs øÃk>fAIiÆI5Þ~#f8£€VgâFÖW’gÁ9˜]“ÁýgãUIn§ÝŠJrY"?®ýHf„ºÅ%¦þUt&bŒÑ‡!œLJwäyvuRŽ%NGe˜5¶hgŠxú‡œ 6§§thÎóa™ŽR¨ÕkVÈzv餈&wØ–’þ©çöt‡ŒñºiŒ¿Uêàså%êªÞx5_?Uöwé’W²˜*”Úê×r·’7j~UÒ åœÖÿ©J£±‚š˜W<-ê烮Î3Ę`û¥Ž<Dé-›]»-£Ð²I⛕iK ©èfZ.ˆì’婦q² /„Ý*9ï¾þK%¾Æõ‹!‡ÕÞû«›¹¶Ú ÂÍ^w™cîR*_¨ëY˜çª·:Œ¥Sk¬kw§Ü­+u5 p:${ØŽÀ,¬Ÿ7žÖGèp–J¶ ÍÕJy"³9£ñžîQ(ìÏ‘õØÝ›8¶›2TŒi8d¼ÂJ­(¯‘3ÁZÄVõËÓÞ†—ÖÈt½µ:T‡}&Ó³5™`Åxó¡ÞÄíh^ÜÕ-2Þ~K¸Z±ÍówTn(ÓJ…/Îí)Ï2¹¢FN¹–ˆ¿ïgåš'®sm“âö‘; ÿôté)š÷éÛ:¦X»RK¦Mû¶{ xî>â^¯×¾nÓ𿃲ñ8:e½¯|0t}õVÇž¼õ)3¿:õÝk”è—³-ø7ÉÚ;ßê››å"Èþö¯}üú¨TýöÃsx_‹Q»¿‡€~Ó_�ÃÁ½æ•JxDI+LÖÀ2ñ¦€Œš$ XÁÅ탌TÓAÆõ/„®kŒIˆB��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~xà~Ä¢ñˆtUB[ò JËšS8Íj·Ü×ê;LÃݲù ½>ÔV´û ‡_ÙâjüŽÏȈ9ÿpó§7HXÈ 81†ˆeèøiÀˆc×çÄ™©£FçQ 8·9J ƒ rÚÔXÚꊑ*ÙGâúõŠ› »§ªû ,Q Á›H\œœË[Œ¬ü º6+<Mm,æ¬ý-wá}nîÊ,®¤~ÞžÕ‰I)3ì^ŸCÏÎBoß–¿4ÈùâÀo1}öª¶ …„+žbp⇌ÿ;ÞKÁQ\HA1ñAQ–4’,3˜ì0r¡ƒ˜-Y¾\+eÄš<\ZÅÆÆœ4{EEï¦$�w}ÐÒJ AOVè5ë.KÝ^²šÉ'aQ­d#‚¢34^ªcÇnT)ïY\0­ìE¤ôíF·eq¡Åx ¿N*ÖvªaÑÉf·Å=t*(Ý*­Mš,¦ò8¸²ëÚˆrÊÇ…kÆùc©uåU·ﷰ”*ý„ÚJã~V5·óŠž©­Õܦi ŽScfXgfæÑÈ£+¯î»¹jÓÕA[¯m+7ר\¹7?œ³àá‘'e_¾Ôëò“«§KûYÔë/ÿ5¿\|Ám—ŸBѱ&Uä-õeŠì×T„›1g 7j¤È{YXᄸÁâÚ`Ù² /ôf^"LgÍi^ vö1·bƒñ©xœÀ 'ã{02µÝBdØÕÕŠ²‰’wöxb¢hä|¿9è¢L?ò¨£4X• Z9â‰/&ÆäT"ÙØ%ƒ{•ˆ$’´•÷ øMôÜ€JB£qc¢wÛjC&(™Uiªƒæ“¿—¡xøÕyã fê#-l¶Ii‹0G Ù¹$bÉa™#”ùiÿyIc9ýA©DÊÉP¨¥­Š*ˆ‹¦waUÚÝééwÙYv訚þ¹Þ¦XêW¤zÿòÙêž8ó…Z$BÊTœ„IºÄ ¯#±å·M¶E¡šü•b˜î*ä¤ÃŽ«£©éjén¢ÞpI/žùZ�dµçÖ[©EC²{ [D΋[ŸÎuª¡¸zÂZ¥<×f™ð}КY« üݪ«Ähâ ì®3ÙdÞ†· Àcóæ’Ê2ÛÁQjiqªúžZê­i™ç)»\Ž¢qŒ•Èbº´pqJ¶læË_í¡òÊÀœ|*<ÜÌŒ¡D˵5)L›ötkWS I×ÉÀŠ5·ÑôM¯a,uÜ(ã\¬É·‰(wÞãÞ¶Ø–ž«·›éöík‡~Œko“âP‰UrÃŽOn²LW¾EMyM¯ us¢We~”(žçãyé kÞkƆKÇïékJ·ë²oè¡å ÍÞfÑÜ9î<áµïÂ>|ñŸÐn|Y«µ>e™É“¤»ê¼=/éer„9õèô^»éÚ?eõ¥ßO~òzêÒljþã9ÑImûy“—¶ü=íæpåöß/ÐËMÔ¿?sK?ŠË^�ÛqÂu†qT^äÕÀ€¡ÈnœßWA V΀ôÐ:ºÅ0s`ààO€��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Äb‹Ö°ÕŒÌ¦ó9\&¥ÐªõŠQ§Œ0 ‹ŸÈî¡ÜE×ì¶ð ئ“q¸ûŽÏ‹ìs³Z(øð‡ V¨ 7¸ÈØxÇ÷h€8Y鈙If8¡hè©*uy–@É9…:ÊÚê°êQº°úãj{k†!{Jú‰ ¼›Z×ÛG79ÌÜ|²¬ í<·‹&ýL­=]Ò½ kJHòŽ.nœ<sžþÞ ã_?öE‹2,oß_u á6Tãü\A¯9:ô–ƒ_‰+î’ðCC ÿø2Zü8 ã±AšÔ¥D᎒'[>Ã'ÉK—4‹½šÉ »š<5l¼¹™•=‹rGKÉÀ˜F›Ê8t ZReúœZ`êÏ>ë.à¼úðX¨1KÊ S—"…~­V ÙV6rÆJÚIç¹`ÃÙýeêÐ)kËøåÓ¶Û¸²BR:+®ÂÆIÆÊ¸R¾€…Z.˜8¤M^ž1/F’ïlçGÝò¾Ý·/âÁŸ¦½û2ri.¨3ËuÍùé—UŽ5åâߣ‰ÝÉ<`qÚˆB'k u^.–‹¤RæuEÖçô^~ðó\äˆï¦¾ý½hìšÓßæª;°{ÊÍÛ›ÿ¦¯]Ó…¤Z}¿(‡ŸõÒ˜OŽ” iŠM8CWBGHƒÂæa¬¡µZ4†%§[aöñòSyùù6PÕ]H‹K†â~2–øßŠÑÈUn=†`lBþCÖ`åtŒÒs^†+.×"oñ™(ßHTZÆ ü½X%r¨hÜŠFˆ–#‰æ†>®9Q-M’(Øi!:&–þI×å’P‰ܘlÞ§'â}VÖXLœvr蜟½çËQiNº—™‰Y(?ßÍ h˜\ژ鞅ö™—N^2(–TZánÙ•ÊÞ£ÀiÉÝ^$Ê`s�rªä]Sæ*˜æ‘ªk|§úê±¢ÿF©ß¥tvê%|ÀëxLj¨Ö×vÂk­$=!·±‡S€s9úY·é’„éŽ:þ9Ÿx_öšË–Gš—Q‘° ›+¥þ¶ÊZ ¾uë¹ÙùV*¶ë¥òª® ˆ«¤†6Üã¢h®¦ÿÊÑÃ?+p¬3*â™iÈû/<Þ}XÛ½–@l«›ÛN좄 û÷ñ›Î÷லÚ|1s9{<(¿xFG•4á…`rÊýèËòËð u GÈÇ\ß3[ KDi#[£ ¶³_I[ÛlÞŠ$ÚR$Öy>]çÜz£bxÖ ¸öÞiÖrÞ÷É-¸QµÄ|µ9‰ƒõ¦´vLùã²ÂñG/´Oš–¹å ažç¢ «éyO‘;Yzêmj.ú䪿žȲkû܈‹[ûÞçÎû³÷®øï£œð±I%¼ñÊsÎüíˇå8ëÒ?ÏÓîkºã<õÂ$öN¹Œu,ÞˆƒºãÓdý—ÙŸËRÇ~õÜk^&…ñ×ÔQ«f5nÜú÷£$øÝ$}ÿ ”’â¿Ú¾PJ¨2Ê” ‚BºRdHA‹ ðÔ *0ØÁ¢€0„ä ñgµªð��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5@ë ‡Ä¢±õ[ؒǦó 2I[ôŠÍjaAeͺ ‹ÇЮcJ5“×ìv<QSp·ýŽßÀÑ 9â›(8Hâw`ÅG¨¸ÈH÷W×gH·ÔXiÖ%i`–8éx j9¡ (ªºÊBúw‡äÊZk«yF«7£kû êË%ü l¼ æ»ÇuÜìÌ‹ƒû<ˆ›IB «íýmÁ]:"nž% Ý»YQ~þγLþ°ç%.ïbï“îÕ…~^þ;¨‚ … 21DñL7€”E¼XbVŽ€ÿ1zôAI"»C?š¼ÒéÁ“,M»ÖqžÈ–4+Z|ÉÁ·’5[¦S†hãÄžDOÕá”ÒΑ'x½¨FNÊT fíÛö4+½zÄ’½<º‹)E¡¦Ê:­6rÉY6SütJúi­ŽZÍI=º–4˜e¥h+vaÈ } nõkˆ0½ÀiŠ ,G8¨5£ˆû8®Ê1)ŧÒ:šœË/I]häR [×#¤¨¬g¾\láªjÍzNüu¦ç…¯7ÕVÀ™¶mÛVú¶ü*`ðƉ{?¾]»ùVD«ñ’œnxTç×5ÿÝø¸ñÝ‹g3ßÌÝ÷wvÅSÆœ¼«óöṡüüJáŒ99ÿÉj§I·|ÍuZh¾Ç`gꤷŸxî=¨]yåÖ`\ewÝs‚Á_‚öMØ|#ª']W�„š~ *e"i.’'’Œ Frc}(¦qÕ$¦d<’é5TNÛ¨™…+ò§#ðÙ˜"e -gX“0:%zH–ˆà–ꑘß@6ôcf†SáhüàÝ:G)š•áYIå„*~awõEWÏxiÒ™£‡‡á XÅ æŸ+ÑWcBž )…zPçe’\^Ù¡œ,j£”ƒ 8œ­%Š£+3Þ'¥“åÊg„RÉ蓼¨o²×'©›¢:ëÞA¶¤¨¹jZ¡©^:¨ªÿ†È¨±½îú¬ŽT)yjÈ8D™_6H—¶(L© ˜M19­MÛÆ¨~ÊËÏ’n†6*¼bÛO(öX*Oñ{®’‘þKa[›ÙK-»Å~Jܰ~âhg˜·&Ì¢¸„¶šéÂ_y¨<ÂòÚÎn­"Z¥n«9²op‰9/ÀàT7¾´±¹M¬¶z /±s>—±‡pòk!Í ÉVž{9?Lñž]n,kÉE†ª—TÉå­Êø°f*¥ý†›§ˆ*åìÌÐ)cÁòÈå’,Ø×M|l6&h‡bsç~a¬>iK}ÀÉ%;0ÝzÏïO /½wà«Î„[\ Žø#oÁEàµZ'žÕØ‚^ š€ÃCþQµ_V>NǘµîÕ:Ìý¹(|9ˆz¥¥Ó]ïã2­.5Ð/D {O¤×Ž» ·ç®ÂŠ‚Äû¿;!|¤]Ž|çÅGŽí‹Ê/Ÿí g ½™_ï^ý=f„}öÆt?øÞßâ:ðã3¿ƒôç{ã{Ï6‡¼>KÉ”ÿ>r'ÇÑñì5‰øø³¢“W±Ksÿ£‰Šªæ¿Ú%’SŠê$Y‚ÖãŸâHÁlHP}Œ 9ØÁèa0„ª! U¦–žp…�(��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó •Ë ôŠÍjÔ³[³nÇä²ìmV…æ¶ûýD§×l¸ýŽBÔiyþXsÁ§R¨P'¨¸•Há‡p ÉhyYæh¨I)†ù ŠÔ¹ù@Úyªº’zàjèàÉJ[ÁiÀ†»‘Ziû ühª±‹|¼:ZœË‹ül§+¼³ mí&´[}²}í}ç\ÒMù].¨=Î<nÞ^›î/Ÿ!íQ?ÏÚÍþ ŸÿÃ_«I� b[GÍ BüreÓ–£á‰¨†Åÿ#”@äðÑBHŽ$VáöðÃÅ’,Ãàò8feË’³IœFh¦N‘¾¾¼ùJ%ÁD×ÕQ¦ÎË-Go}ŠáTÍ9äÉÄ5«4\ =drò§ŠWé©ÃQöZf@£MôÕ•X¥Ój Ö5L¤žL ª7£š}×Våwo_DIe5¶ºxÐa§U×J]ªXÓÊbýÞz¶¯Ô¼?Û#«­Ñ»wåd‹Œê§ìÀ `N[8´çb— .3 ÙóãX†-of¼çå XÀõ ¿=¶2ÛÍÏý‚q ·ŸHb~SMnwrǾ9§† Ø»té™b^²ü÷ðÌî¡Ó-.ú¸äÄ´µ‡ÿÅj_|F^TÄàDUt[mÃÎ>ûQ¶`&ÈSEhéçÓ~A¨v^ss\Öà|È¥gn÷aÖ™ƒÌÅW"qõÉ Cèu£Œíõg_¬í(Š2p XÛ`( d®‡QŠ'Žw‘‡8]‹¾(åv1*å¨až=ò&j´éhaƒâw]}ˆé¤dêÙFàQQ¦IךCE)æ›]VIÝ™ R˜0f×]_†‰(=†þáuºé¢&K&9$’(º™–G7ÖŠWj‡B·õ ›fU zªRd&gf©jz§‰È Zi›bª¥ŒPþ§*­Lî™'‹¹è«sÅ>¹!H7ÿõf @…Cg„ÎxRTv§ †ŠV"¤Nª£ˆœ·‰kˆ”ʪ.}AšK•­«%J/h{Á{ïªãŽsc¨g*7Þ¬™:ºž¶6ÚTðœøîúç$ýúÉžÁ–ŠŠ&©Ú°1ÉÞ»i‘­ [ï?? ©\qáœÀ:·)ÆgJâËÁQ[1yrŠÉØÃ®¾ü\“¯ö¶0Æ'Ïle¸!gå#ÑI9#ɵצ«ó3:ƒŒ ¡k´» Õj ü4Swi°N64/ÕhÙùÎfÕh‡ÙÄk>A;2Ö¿½ã†šõ"®Öé€7>W‹Ø=u"8kqo‚ÔØv'y¶9>Þà‘¯Ce²¼-×ëå$5dy…žïä6 ¡Ž¹¨¿M 8§¯.rçÃN»€�â\{í`Ãózîñ4®¬ï¾÷^´ðZŽ{GÆ£¾ûòÎßþ|ôˆKtó³ÏK½NÈS«(ñÙ3¿¢~´‘¦JþLüp’«é ™™{ÿ>^1—ýõ Î7ûáퟸÑè €­á ûHÀæO ÜÈØÀzIìzô+¹/0ƒd@��!ù ���,����ya��ÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡Ä¢ ȰՌ̦ó9\.~�ôŠÍjYK¤âgÝŠÇä§÷{8#¨å¶ûýV†Ñj¸ýŽÍ“õ´4(è³·6ˆ˜ˆW8ÃøÕWŦ8Iä9 vYéù×Ö)jzúA:ש±Ù…  â¥ZR*‹››Y•vÂjð§;Œ ¼ö`L¬¼ì@›•Ì=¶ MRÝ+ 8ŠŒQÍ{­-®>n~®émÎÞî]îÏ /:Á‹ÏEýb¯ŸÀôô¥¨70!Ápûvù"Ø, Â‰¢º] 'ÑÅÿ” ˈi]0Ž$Õ]jØ ä”c%[6vlH•h\ÚÄäq%F0+ ¼ ÔÚZ=²4j‚fЄgÔ öÔg—ZÅ¹ËØ(IN6³ÃŠØ‘ËÆöBiêU$©OsŠâíÕqN›®zøuƒÜ”n#�1k–V¶p±Y¬Õ'°_²cÁùýçèÖáˆkk~c¼Ö±à¬ýªüö‘¥sÍ":X߬C’ý˜óYžª?³Ôú:]âÜ¡ü[vU_(‹Þm8¯oà R~ݳ®ç“ÂHC]-ø¯lÉŸ'1Š;ùñÂZs.çŽ×ûʘá“_Œ­q)äÂ×wçݹøTÚõÙÿV×µ ÷˜¨ŸEä5ƒz>•#Ivy¶ß,Æe÷Ù^Ú'Ûd½½‡•{牶^{”ÉÅ\H(¦É]†DUZBTžjÁ¶gåq|"ZV`@ŠVq*~˜¢­ð¶R™-9^sõhc–qv…д¸]sô¥“d‡Êiž€«É'fpdJ9›“!šébkÌ5õ]he‚y&NJa©e üù wçÝ#†MÖ‰f¶ç„eöö‰?ú¶¥óÉ8iž´Yé©“3±h(f’©(‘Œ†˜æ£àM‰(”ºUJåŠtz¨$¬‰Êªªµj"/MõßEQØCj¬zÿZòä²Ä¶à…Wª *{ÊÒa^ùÍɤT<fÛ,„¼B%f£„\ + H Ê.1*«îc_Îæ©@Fy[º2zÜE­²io§÷þ¶i¹Aòù¸ŽŒ§³î’ \]ÿ°®°í–t7 Ëk –ýašªoæ{羦~jd½¶Aª`‰ ›)ˆ�¼2º1!©XQÅßÅ7\Y°Þn9n€<¼\ÒÊdŒ¨fà ì†ÒÄ”\í';j/W㻫ÏWIQê¶n}z¢‚àzÍŽZ¨eÒÓEç‰v–B;¨ÑVI*wi‡�[›yÿÍmËöq xá:íºcÕÐAd8P,ã…ì¹c|6@“žST¹ ™_O¡IqÃ¹Ü &zéƒ"h:ç7ëSêZò<­ëªËNûéC׎û3]çÞÒeIñ÷æÀÛT±ÈËÎxÙ‚¯7€2ÿ3ÝDû =ñ¨Ã­øtÂWŸËO¤¯ËG¼Ü»ã4µÝˆ?~ÚÊKûúé“zìmÿ~Úl#\?òõµOþ踢5ÿ€î UdbÀÂ0¥“CÿÁ��;�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.7-src/Help/layer.html�����������������������������������������������������������������������0000644�0001750�0001750�00000014176�12536111364�013123� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html> <title>Golly Help: Layer Menu

Golly supports up to ten layers. Each layer is a separate universe (unless cloned; see the Clone Layer item below) with its own algorithm, rule, viewport, cursor mode, selection, step size, origin offset, color scheme and name. The current layer's name is displayed in the main window's title bar. Most edit/control/view operations only apply to the current layer.

Note that most of Golly's options apply globally to all layers. This is true for all of the options set in the Preferences dialog. It's also true for many of the options set via menu items, like Save Extended RLE, Paste Mode, Paste Location, Show Grid Lines, etc., but not for any of the Control menu options (Auto Fit, Hyperspeed, and Show Hash Info).

The items at the bottom of the Layer menu show the current names of all the existing layers. The names of cloned layers are prefixed by one or more "=" signs; all layers with the same number of "=" signs share the same universe. The current layer is indicated by a tick. To switch to another layer just select the corresponding item. If a script is running then you can only switch to another layer if the script has called golly.setoption("switchlayers",True).

A layer containing a modified pattern is indicated by a "*" at the start of the layer's name. To avoid losing your changes, a "save changes" dialog will appear before creating a new pattern, opening a pattern file, deleting the layer, or quitting Golly. If you'd rather not see this dialog then untick the appropriate check boxes in Preferences > Layer.

Common layer functions are also available via buttons in the layer bar located underneath the status bar. Use the Show Layer Bar item in the View menu to show/hide the layer bar, or just hit the "\" key.

Add Layer

Adds a new layer (with an empty universe) immediately after the current layer. The new layer becomes the current layer and inherits the preceding layer's algorithm, rule, scale, location, and cursor mode. The step size is set to 1, there is no selection, no origin offset, and the layer's initial name is "untitled". The new layer starts off using the default color scheme for the current algorithm and rule.

Clone Layer

Adds a new layer that shares the same universe, undo/redo history, and color scheme as the current layer. All of the current layer's settings are duplicated and most will be kept synchronized so that a change to one clone automatically changes all the others. Each cloned layer does however have a separate viewport, so the same pattern can be viewed at different scales and locations (at the same time if layers are tiled). Cloned layers can also have different names, cursor modes, or control options (Auto Fit, Hyperspeed, and Show Hash Info).

Duplicate Layer

Adds a new layer with a copy of the current layer's pattern. Also duplicates all the current settings but, unlike a cloned layer, the settings are not kept synchronized. A duplicated layer starts with the same undo/redo history as the original layer but their histories will diverge if changes are made to either layer.

Delete Layer

Deletes the current layer. The current layer changes to the preceding layer (unless the first layer was deleted).

Delete Other Layers

Deletes all layers except the current layer.

Move Layer...

Opens a dialog that lets you move the current layer to a new position in the layer sequence, where 0 is the position of the first layer.

Name Layer...

Opens a dialog that lets you change the name of the current layer. Note that loading a pattern file also changes the layer's name. Creating a new pattern resets the name to "untitled".

Set Layer Colors...

Opens a dialog that lets you change any of the cell colors used by the current layer and its clones (if any). Note that any changes you make here are temporary. If you open a pattern file or create a new pattern, or if you change the current algorithm or rule, then the colors will be reset to their default values as specified in Preferences > Color. If the new rule has a corresponding .colors file then those colors will also be loaded. The format of a .colors file is described in Help > File Formats.

Synchronize Views

If ticked, then when you switch to another layer Golly will automatically switch to the same scale and location as the old layer. Most of the time you'll probably prefer to keep this option turned off so that each layer has a different scale and location.

Synchronize Cursors

If ticked, then when you switch to another layer Golly will automatically switch to the same cursor mode as the old layer. You'll probably find it less confusing if this option is kept turned on, but it can be useful in some situations for different layers to use different cursors. For example, you might want to make selections in one layer but draw cells in another layer.

Stack Layers

If ticked then all layers are displayed on top of one another, temporarily using the same scale and location as the current layer. The pattern in layer 0 is drawn first (100% opaque), then the patterns in other layers are drawn on top as translucent overlays. The opacity percentage of the pattern overlays can be set in Preferences > Layer. For an example of how stacked layers can be useful, load in a pattern and run the envelope.py script.

Tile Layers

If ticked then the viewport window is tiled into sub-windows and each layer is displayed in a separate tile. Clicking in the window of a non-current layer will change the current layer. Tiling is very handy with cloned layers as it allows you to view the same pattern at different scales and/or locations. golly-2.7-src/Help/tips.html0000644000175000017500000000741412536111364012763 00000000000000 Golly Help: Hints and Tips

Some useful hints and tips

  • To view a pattern file just drop it onto the Golly app or onto the Golly window if the app is already running.
  • When Golly starts up it looks for scripts called golly-start.pl or golly-start.py in the same directory as the Golly application and then in a user-specific data directory (see the Preferences item for the likely path on your system). If either script is found then it is automatically executed.
  • Displaying the population count can cause a significant slow-down when generating large patterns, especially when using HashLife. If you want to generate at maximum speed then just hit ";" to hide the status bar. You can toggle the status bar at any time, even in full screen mode.
  • Editing operations are fastest in QuickLife.
  • Pasting large, sparse patterns is much faster if using Or mode, or if the current pattern is empty, or if the paste rectangle is completely outside the current pattern edges.
  • The hand cursor can be used to scroll the view by clicking and dragging. If you drag the cursor outside any view edge then scrolling will occur continuously; ie. you don't have to move the cursor. If the cursor is outside any corner (ie. outside two edges) then the scrolling direction will be diagonal.
  • Actually, continuous scrolling also occurs if the hand cursor is dragged onto any view edge or corner. This allows such scrolling to occur in full screen mode.
  • While dragging the mouse to make (or modify) a selection, the escape key can be used to cancel the operation and restore the original selection.
  • Avoid the temptation to put your own patterns, scripts or rules inside Golly's supplied folders — it will make it difficult to upgrade to a future version. A much better idea is to create separate folders for your own files and put those folders alongside the supplied folders, so your Golly folder looks something like this:

    Golly
        Golly.exe (Golly.app on Mac, golly on Linux)
        Help
        Patterns
        Rules
        Scripts
        My-downloads (contains all your downloaded files; select in Preferences > File)
        My-patterns (contains all your pattern files)
        My-rules (contains all your .rule files; select in Preferences > Control)
        My-scripts (contains all your .pl/.py files)

    Use File > Set Patterns Folder and select the Golly folder. Now all your folders (and the supplied folders) are visible in the patterns panel, so with just a few clicks you can load any pattern, run any script, or switch to any .rule file. Or you can right-click (or control-click) on any of those files to open them in your preferred text editor. When upgrading to a new version of Golly, simply drag all the distributed files and folders into your Golly folder and replace the old versions.

golly-2.7-src/Help/perl.html0000644000175000017500000014722212536111364012750 00000000000000 Golly Help: Perl Scripting

Installing Perl
Incompatibility with Perl 5.14
Example scripts
Golly's scripting commands
Cell arrays
Rectangle arrays
Potential problems
Perl copyright notice

 
Installing Perl

Before you can run a .pl script, Perl needs to be installed on your system. Mac OS X users don't need to do anything because Perl is already installed. Windows and Linux users need to have Perl 5.10 or 5.12 (note that 5.14 or later won't work — see below). If you're using Linux then you might already have Perl 5.10 installed; if not, visit www.perl.org and download a suitable installer. Windows users are advised to download a Perl 5.12 installer from Strawberry Perl. Note that a 32-bit version of Golly requires a 32-bit version of Perl, and a 64-bit Golly requires a 64-bit Perl.

On Windows and Linux, the Perl library is loaded at runtime (the first time you try to run a .pl script). Golly initially attempts to load a particular version of the Perl library: perl510.dll on Windows or libperl.so.5.10 on Linux. The numbers correspond to Perl version 5.10.x. If that library can't be found then you'll be prompted to enter a different library name matching the version of Perl installed on your system. A successfully loaded library is remembered (in your GollyPrefs file) so you won't get the prompt again unless you remove Perl or install a new version. If Perl isn't installed then you'll have to hit Cancel and you won't be able to run any .pl scripts.

 
Incompatibility with Perl 5.14

The Linux and Windows versions of Golly are built with the Perl 5.10 headers. Unfortunately, Perl 5.14 and later is not compatible with these headers and you'll get an error message if you try to use a Perl 5.14 library with Golly. If your Linux system doesn't have Perl 5.10 (or 5.12) then you can build and install a local version for Golly using these commands:

sudo apt-get install perlbrew
perlbrew init
perlbrew install -Duseshrplib -Dusethreads perl-5.10.1

This creates perl5/perlbrew/build/perl-5.10.1/libperl.so in your home directory. Quit Golly, edit GollyPrefs (in ~/.golly/), find the line that sets perl_lib and change it to use the appropriate path:

perl_lib=/home/username/perl5/perlbrew/build/perl-5.10.1/libperl.so

Restart Golly and now all the Perl scripts should run okay.

 
Example scripts

The Scripts folder supplied with Golly contains a number of example Perl scripts:

density.pl — calculates the density of the current pattern
envelope.pl — uses multiple layers to remember a pattern's live cells
giffer.pl — creates an animated GIF using the current selection
goto.pl — goes to a given generation
invert.pl — inverts all cell states in the current selection
make-torus.pl — makes a toroidal universe from the current selection
oscar.pl — detects oscillating patterns, including spaceships
pop-plot.pl — displays a plot of population versus time
shift.pl — shifts the current selection by given x y amounts
tile.pl — tiles the current selection with the pattern inside it
tile-with-clip.pl — tiles the current selection with the clipboard pattern

To run one of these scripts, tick the Show Scripts item in the File menu and then simply click on the script's name. You can also select one of the Run items in the File menu. For a frequently used script you might like to assign a keyboard shortcut to run it (see Preferences > Keyboard).

When Golly starts up it looks for a script called golly-start.pl in the same directory as the Golly application and then in a user-specific data directory (see the g_getdir command for the likely path on your system). If the script is found then it is automatically executed.

There are a number of ways to abort a running script. Hit the escape key, or click on the stop button in the tool bar, or select the Stop item in the Control menu.

 
Golly's scripting commands

This section describes all the Golly-specific scripting commands that can be used in a Perl script. Commands are grouped by function (filing, editing, control, viewing, layers and miscellaneous) or you can search for individual commands alphabetically:

g_addlayer
g_advance
g_autoupdate
g_check
g_clear
g_clone
g_copy
g_cut
g_dellayer
g_doevent
g_duplicate
g_empty
g_error
g_evolve
g_exit
g_fit
g_fitsel
g_flip
g_getalgo
g_getbase
g_getcell
g_getcells
g_getclip
g_getclipstr
g_getcolor
g_getcolors
g_getcursor
g_getdir
g_getevent
g_getgen
g_getheight
g_getlayer
g_getmag
g_getname
g_getoption
g_getpop
g_getpos
g_getrect
g_getrule
g_getselrect
g_getstep
g_getstring
g_getwidth
g_getxy
g_hash
g_help
g_join
g_load
g_maxlayers
g_movelayer
g_new
g_note
g_numalgos
g_numlayers
g_numstates
g_open
g_opendialog
g_parse
g_paste
g_putcells
g_randfill
g_reset
g_rotate
g_run
g_save
g_savedialog
g_select
g_setalgo
g_setbase
g_setcell
g_setclipstr
g_setcolor
g_setcolors
g_setcursor
g_setdir
g_setgen
g_setlayer
g_setmag
g_setname
g_setoption
g_setpos
g_setrule
g_setstep
g_show
g_shrink
g_step
g_store
g_transform
g_update
g_visrect
g_warn

 
FILING COMMANDS

g_open($filename, $remember=0)
Open the given file and process it according to its type:

  • A HTML file (.htm or .html extension) is displayed in the help window.
  • A text file (.txt or .doc extension, or a name containing "readme") is opened in your text editor.
  • A script file (.pl or .py extension) is executed.
  • A zip file (.zip extension) is processed as described here.
  • Any other type of file is assumed to be a pattern file and is loaded into the current layer.

A non-absolute path is relative to the location of the script. The 2nd parameter is optional (default = 0) and specifies if the given pattern or zip file should be remembered in the Open Recent submenu, or in the Run Recent submenu if the file is a script.
Example: g_open("my-patterns/foo.rle");

g_save($filename, $format, $remember=0)
Save the current pattern in a given file using the specified format:

"rle" run length encoded (RLE)
"rle.gz" compressed RLE
"mc" macrocell
"mc.gz" compressed macrocell

A non-absolute path is relative to the location of the script. The 3rd parameter is optional (default = 0) and specifies if the file should be remembered in the Open Recent submenu. If the savexrle option is 1 then extended RLE format is used (see the Save Extended RLE item for details).
Example: g_save("foo.rle", "rle", 1);

g_opendialog($title, $filetypes, $initialdir, $initialfname, $mustexist=1)
Present a standard Open dialog to the user and return the chosen path in a string. All parameters are optional; the default is an Open dialog showing the current directory, with a title of "Choose a file" and a file type of "All files (*)|*". If the 5th parameter (default = 1) is set to 0, the user can specify a new filename instead of choosing an existing file. If the given file type is "dir" then the dialog lets the user choose a directory rather than a file. If the user cancels the dialog, the return value will be an empty string.
Example: my $fname = g_opendialog('Open MCell File', 'MCell files (*.mcl)|*.mcl', 'C:\\Temp', 'sample.mcl');
Example: my $dirname = g_opendialog('Choose a folder', 'dir');

g_savedialog($title, $filetypes, $initialdir, $initialfname, $suppressprompt=0)
Present a standard Save dialog to the user and return the chosen path in a string. All parameters are optional; the default is a Save dialog showing the current directory, with a title of "Choose a save location and filename" and a file type of "All files (*)|*". If a file already exists at the chosen location, an Overwrite? query will be displayed unless the 5th parameter (default = 0) is set to 1. If the user cancels the dialog, the return value will be an empty string.
Example: my $fname = g_savedialog('Save text file', 'Text files (*.txt;*.csv)|*.txt;*.csv', 'C:\\Temp', 'Params.txt', 1);

g_load($filename)
Read the given pattern file and return a cell array reference.
Example: $blinker = g_load("blinker.rle");

g_store($cellarray, $filename)
Write the pattern in the given cell array reference to the specified file in RLE format. If the savexrle option is 1 then extended RLE format is used (see the Save Extended RLE item for details).
Example: g_store($cellarray, "foo.rle");

g_getdir(dirname)
Return the path of the specified directory:

"app" — the directory containing the Golly application.

"data" — the user-specific data directory:
On Linux: ~/.golly/
On Mac OS X: ~/Library/Application Support/Golly/
On Windows: C:\Documents and Settings\username\Application Data\Golly\

"temp" — the directory Golly uses to store various temporary files. All these files are deleted when Golly quits.

"rules" — the user-specific rules directory set in Preferences > Control.

"patterns" — the directory displayed by File > Show Patterns.

"scripts" — the directory displayed by File > Show Scripts.

"download" — the directory Golly uses to store downloaded files.

In each case a full path is returned, terminated by the appropriate path separator for the current platform.
Example: g_open(g_getdir("app")."Patterns/Life/Breeders/breeder.lif");

g_setdir(dirname, dirpath)
Set the specified directory to the given path (which must be a full path to an existing directory). All the directory names listed above are allowed, except for "app", "data" and "temp".
Example: g_setdir("patterns", "/path/to/my-patterns/");

 
EDITING COMMANDS

g_new($title)
Create a new, empty universe and set the window title. If the given title is empty then the current title won't change.
Example: g_new("test-pattern");

g_cut()
Cut the current selection to the clipboard.

g_copy()
Copy the current selection to the clipboard.

g_clear($where)
Clear inside (where = 0) or outside (where = 1) the current selection.
Example: g_clear(1);

g_paste($x, $y, $mode)
Paste the clipboard pattern at x,y using the given mode ("and", "copy", "or", "xor").
Example: g_paste(0, 0, "or");

g_shrink()
Shrink the current selection to the smallest rectangle enclosing all of the selection's live cells.

g_randfill($percentage)
Randomly fill the current selection to a density specified by the given percentage (1 to 100).
Example: g_randfill(50);

g_flip($direction)
Flip the current selection left-right (direction = 0) or top-bottom (direction = 1).

g_rotate($direction)
Rotate the current selection 90 degrees clockwise (direction = 0) or anticlockwise (direction = 1).

g_evolve($cellarray, $numgens)
Advance the pattern in the given cell array reference by the specified number of generations and return a reference to the new cell array.
Example: $newpatt = g_evolve($currpatt, 100);

g_join($cellarray1, $cellarray2)
Join the given cell arrays and return a reference to the resulting cell array. If the given arrays are both one-state then the result is one-state. If at least one of the given arrays is multi-state then the result is multi-state, but with one exception: if both arrays have no cells then the result is an empty one-state array. See below for a description of one-state and multi-state cell arrays.
Example: $result = g_join($part1, $part2);

g_transform($cellarray, $x0, $y0, $axx=1, $axy=0, $ayx=0, $ayy=1)
Apply an affine transformation to the pattern in the given cell array reference and return a reference to the new cell array. For each x,y cell in the input array the corresponding xn,yn cell in the output array is calculated as xn = x0 + x*axx + y*axy, yn = y0 + x*ayx + y*ayy.
Example: $rot_blinker = g_transform($blinker, 0, 0, 0, -1, 1, 0);

g_parse($string, $x0=0, $y0=0, $axx=1, $axy=0, $ayx=0, $ayy=1)
Parse an RLE or Life 1.05 string and return a reference to an optionally transformed cell array.
Example: $blinker = g_parse("3o!");

g_putcells($cellarray, $x0=0, $y0=0, $axx=1, $axy=0, $ayx=0, $ayy=1, $mode="or")
Paste the pattern in the given cell array reference into the current universe using an optional affine transformation and optional mode ("and", "copy", "not", "or", "xor").
Example: g_putcells($cells, 6, -40, 1, 0, 0, 1, "xor");

g_getcells(@rectarray)
Return any live cells in the specified rectangle as a cell array reference. The given rectangle array can be empty (in which case the cell array is empty) or it must represent a valid rectangle of the form (x,y,width,height).
Example: $cells = g_getcells( g_getrect() );

g_getclip()
Parse the pattern data in the clipboard and return a cell array reference, but where the first two numbers are the pattern's width and height (not necessarily the minimal bounding box because the pattern might have empty borders, or it might even be empty). If the clipboard data is multi-state but all cell states happen to be zero then the returned cell array is (wd,ht) rather than (wd,ht,0).
Example: $cells = g_getclip();

g_hash(@rectarray)
Return an integer hash value for the pattern in the given rectangle. Two identical patterns will have the same hash value, regardless of their location in the universe. This command provides a fast way to detect pattern equality, but there is a tiny probability that two different patterns will have the same hash value, so you might need to use additional (slower) tests to check for true pattern equality.
Example: $h = g_hash( g_getrect() );

g_select(@rectarray)
Create a selection if the given array represents a valid rectangle of the form (x,y,width,height) or remove the current selection if the given array is empty.
Example: g_select(-10,-10,20,20);

g_getrect()
Return the current pattern's bounding box as an array. If there is no pattern then the array is empty, otherwise the array is of the form (x,y,width,height).
Example: @pattrect = g_getrect();

g_getselrect()
Return the current selection rectangle as an array. If there is no selection then the array is empty, otherwise the array is of the form (x,y,width,height).
Example: @selrect = g_getselrect();

g_setcell($x, $y, $state)
Set the given cell to the specified state (0 for a dead cell, 1 for a live cell).

g_getcell($x, $y)
Return the state of the given cell. The following example inverts the state of the cell at 0,0.
Example: g_setcell(0, 0, 1 - g_getcell(0, 0));

g_setcursor($string)
Set the current cursor according to the given string and return the old cursor string. The given string must match one of the names in the Cursor Mode menu.
Example: $oldcurs = g_setcursor("Draw");

g_getcursor()
Return the current cursor as a string (ie. the ticked name in the Cursor Mode menu).

 
CONTROL COMMANDS

g_run($numgens)
Run the current pattern for the specified number of generations. Intermediate generations are never displayed, and the final generation is only displayed if the current g_autoupdate setting is 1.
Example: g_run(100);

g_step()
Run the current pattern for the current step. Intermediate generations are never displayed, and the final generation is only displayed if the current g_autoupdate setting is 1.

g_setstep($exp)
Temporarily set the current step exponent to the given integer. A negative exponent sets the step size to 1 and also sets a delay between each step, but that delay is ignored by the g_run and g_step commands. Golly will reset the step exponent to 0 upon creating a new pattern, loading a pattern file, or switching to a different algorithm.
Example: g_setstep(0);

g_getstep()
Return the current step exponent.
Example: g_setstep( g_getstep() + 1 );

g_setbase($base)
Temporarily set the current base step to an integer from 2 to 10000. Golly will restore the default base step (set in Preferences > Control) upon creating a new pattern, loading a pattern file, or switching to a different algorithm.
Example: g_setbase(2);

g_getbase()
Return the current base step.

g_advance($where, $numgens)
Advance inside (where = 0) or outside (where = 1) the current selection by the specified number of generations. The generation count does not change.
Example: g_advance(0, 3);

g_reset()
Restore the starting pattern and generation count. Also reset the algorithm, rule, scale, location and step exponent to the values they had at the starting generation. The starting generation is usually zero, but it can be larger after loading an RLE/macrocell file that stores a non-zero generation count.

g_setgen($gen)
Set the generation count using the given string. Commas and other punctuation marks can be used to make a large number more readable. Include a leading +/- sign to specify a number relative to the current generation count.
Example: g_setgen("-1,000");

g_getgen($sepchar="")
Return the current generation count as a string. The optional parameter (default = "") specifies a separator character that can be used to make the resulting string more readable. For example, g_getgen(",") would return a string like "1,234,567" but g_getgen() would return "1234567". Use the latter call if you want to do arithmetic on the generation count.
Example: $gen = g_getgen();

g_getpop($sepchar="")
Return the current population as a string. The optional parameter (default = "") specifies a separator character that can be used to make the resulting string more readable. For example, g_getpop(",") would return a string like "1,234,567" but g_getpop() would return "1234567". Use the latter call if you want to do arithmetic on the population count.
Example: $pop = g_getpop();

g_empty()
Return 1 if the universe is empty or 0 if there is at least one live cell. This is much more efficient than testing getpop() == 0.
Example: g_exit("All cells are dead.") if g_empty();

g_numstates()
Return the number of cell states in the current universe. This will be a number from 2 to 256, depending on the current algorithm and rule.
Example: $maxstate = g_numstates() - 1;

g_numalgos()
Return the number of algorithms (ie. the number of items in the Set Algorithm menu).
Example: $maxalgo = g_numalgos() - 1;

g_setalgo($string)
Set the current algorithm according to the given string which must match one of the names in the Set Algorithm menu.
Example: g_setalgo("HashLife");

g_getalgo($index=current)
Return the algorithm name at the given index in the Set Algorithm menu, or the current algorithm's name if no index is supplied.
Example: $lastalgo = g_getalgo( g_numalgos() - 1 );

g_setrule($string)
Set the current rule according to the given string. If the current algorithm doesn't support the specified rule then Golly will automatically switch to the first algorithm that does support the rule. If no such algorithm can be found then you'll get an error message and the script will be aborted.
Example: g_setrule("b3/s23");

g_getrule()
Return the current rule as a string in canonical format.
Example: $oldrule = g_getrule();

g_getwidth()
Return the width of the current universe (0 if unbounded).
Example: $wd = g_getwidth();

g_getheight()
Return the height of the current universe (0 if unbounded).
Example: $ht = g_getheight();

 
VIEWING COMMANDS

g_setpos($x, $y)
Change the position of the viewport so the given cell is in the middle. The x,y coordinates are given as strings so the viewport can be moved to any location in the unbounded universe. Commas and other punctuation marks can be used to make large numbers more readable. Apart from a leading minus sign, most non-digits are simply ignored; only alphabetic characters will cause an error message. Note that positive y values increase downwards in Golly's coordinate system.
Example: g_setpos("1,000,000,000,000", "-123456");

g_getpos($sepchar="")
Return the x,y position of the viewport's middle cell in the form of a Perl array containing two strings. The optional parameter (default = "") specifies a separator character that can be used to make the resulting strings more readable. For example, g_getpos(",") might return two strings like "1,234" and "-5,678" but g_getpos() would return "1234" and "-5678". Use the latter call if you want to do arithmetic on the x,y values.
Example: my ($x, $y) = g_getpos();

g_setmag($mag)
Set the magnification, where 0 corresponds to the scale 1:1, 1 = 1:2, -1 = 2:1, etc. The maximum allowed magnification is 5 (= 1:32).
Example: g_setmag(0);

g_getmag()
Return the current magnification.
Example: g_setmag( g_getmag() - 1 );

g_fit()
Fit the entire pattern in the viewport.

g_fitsel()
Fit the current selection in the viewport. The script aborts with an error message if there is no selection.

g_visrect(@rectarray)
Return 1 if the given rectangle is completely visible in the viewport. The rectangle must be an array of the form (x,y,width,height).
Example: g_fitsel() if !g_visrect(@selrect);

g_autoupdate($bool)
When Golly runs a script this setting is initially 0. If the given parameter is 1 then Golly will automatically update the viewport and the status bar after each command that changes the universe or viewport in some way. Useful for debugging Perl scripts.
Example: g_autoupdate(1);

g_update()
Immediately update the viewport and the status bar, regardless of the current g_autoupdate setting. Note that Golly always does an update when a script finishes.

 
LAYER COMMANDS

g_addlayer()
Add a new, empty layer immediately after the current layer and return the new layer's index, an integer from 0 to g_numlayers() - 1. The new layer becomes the current layer and inherits most of the previous layer's settings, including its algorithm, rule, scale, location, cursor mode, etc. The step exponent is set to 0, there is no selection, no origin offset, and the layer's initial name is "untitled".
Example: $newindex = g_addlayer();

g_clone()
Like g_addlayer (see above) but the new layer shares the same universe as the current layer. The current layer's settings are duplicated and most will be kept synchronized so that a change to one clone automatically changes all the others. Each cloned layer does however have a separate viewport, so the same pattern can be viewed at different scales and locations (at the same time if layers are tiled).
Example: $cloneindex = g_clone();

g_duplicate()
Like g_addlayer (see above) but the new layer has a copy of the current layer's pattern. Also duplicates all the current settings but, unlike a cloned layer, the settings are not kept synchronized.
Example: $dupeindex = g_duplicate();

g_dellayer()
Delete the current layer. The current layer changes to the previous layer (unless layer 0 was deleted).

g_movelayer($fromindex, $toindex)
Move a specified layer to a new position in the layer sequence. The chosen layer becomes the current layer.
Example: g_movelayer(1, 0);

g_setlayer($index)
Set the current layer to the layer with the given index, an integer from 0 to g_numlayers() - 1.
Example: g_setlayer(0);

g_getlayer()
Return the index of the current layer, an integer from 0 to g_numlayers() - 1.
Example: $currindex = g_getlayer();

g_numlayers()
Return the number of existing layers, an integer from 1 to g_maxlayers().
Example: g_setoption("tilelayers",1) if g_numlayers() > 1;

g_maxlayers()
Return the maximum number of layers (10 in this implementation).

g_setname($string, $index=current)
Set the name of the given layer, or the current layer's name if no index is supplied.
Example: g_setname("temporary");

g_getname($index=current)
Return the given layer's name, or the current layer's name if no index is supplied.
Example: g_dellayer() if g_getname() eq "temporary";

g_setcolors($colorarray)
Set the color(s) of one or more states in the current layer and its clones (if any). If the given array contains a multiple of 4 integers then they are interpreted as state, red, green, blue values. A state value of -1 can be used to set all live states to the same color (state 0 is not changed). If the given array contains exactly 6 integers then they are interpreted as a color gradient from r1, g1, b1 to r2, g2, b2 for all the live states (state 0 is not changed). If the given array is empty then all states (including state 0) are reset to their default colors, depending on the current algorithm and rule. Note that the color changes made by this command are only temporary. Golly will restore the default colors if a new pattern is opened or created, or if the algorithm or rule changes, or if Preferences > Color is used to change any of the default colors for the current layer's algorithm.
Example: g_setcolors([1,0,0,0, 2,0,0,0]); # set states 1 and 2 to black
Example: g_setcolors([-1,0,255,0]); # set all live states to green
Example: g_setcolors([255,0,0, 0,0,255]); # live states vary from red to blue
Example: g_setcolors([]); # restore default colors

g_getcolors(state=-1)
Return the color of a given state in the current layer as a reference to an array of the form

( state, red, green, blue )

or if the given state is -1 (or not supplied) then return all colors as

( 0, r0, g0, b0, . . . N, rN, gN, bN )

where N equals g_numstates() - 1. Note that the array reference returned by g_getcolors can be passed into g_setcolors; this makes it easy to save and restore colors.
Example: $allcolors = g_getcolors();
Example: $deadcolor = g_getcolors(0);

 
MISCELLANEOUS COMMANDS

g_setoption($name, $value)
Set the given option to the given value. The old value is returned to make it easy to restore a setting. Here are all the valid option names and their possible values:

"autofit" 1 or 0
"boldspacing" 2 to 1000 (cells)
"drawingstate" 0 to g_numstates()-1
"fullscreen" 1 or 0
"hyperspeed" 1 or 0
"maxdelay" 0 to 5000 (millisecs)
"mindelay" 0 to 5000 (millisecs)
"opacity" 1 to 100 (percent)
"restoreview" 1 or 0
"savexrle" 1 or 0
"showallstates" 1 or 0
"showboldlines" 1 or 0
"showeditbar" 1 or 0
"showexact" 1 or 0
"showgrid" 1 or 0
"showhashinfo" 1 or 0
"showicons" 1 or 0
"showlayerbar" 1 or 0
"showpatterns" 1 or 0
"showscripts" 1 or 0
"showstatusbar" 1 or 0
"showtoolbar" 1 or 0
"stacklayers" 1 or 0
"swapcolors" 1 or 0
"switchlayers" 1 or 0
"synccursors" 1 or 0
"syncviews" 1 or 0
"tilelayers" 1 or 0

Example: $oldgrid = g_setoption("showgrid", 1);

g_getoption($name)
Return the current value of the given option. See above for a list of all the valid option names.
Example: g_fit() if g_getoption("autofit");

g_setcolor($name, $r, $g, $b)
Set the given color to the given RGB values (integers from 0 to 255). The old RGB values are returned as an array of 3 integers to make it easy to restore the color. Here is a list of all the valid color names and how they are used:

"border" color for border around bounded grid
"paste" color for pasting patterns
"select" color for selections (will be 50% transparent)
algoname status bar background for given algorithm

Example: @oldrgb = g_setcolor("HashLife", 255, 255, 255);

g_getcolor($name)
Return the current RGB values for the given color as an array of 3 integers. See above for a list of all the valid color names.
Example: my ($r, $g, $b) = g_getcolor("select");

g_getclipstr()
Return the current contents of the clipboard as an unmodified string.
Example: $illegalRLE = g_getclipstr();

g_setclipstr($string)
Copy an arbitrary string (not necessarily a cell pattern) directly to the clipboard.
Example: g_setclipstr($correctedRLE);

g_getstring($prompt, $initial="", $title="")
Display a dialog box and get a string from the user. If the initial string is supplied it will be shown and selected. If the title string is supplied it will be used in the dialog's title bar. The script will be aborted if the user hits the dialog's Cancel button.
Example: $i = g_getstring("Enter a number:", "100");

g_getevent($get=1)
When Golly runs a script it initially handles all keyboard and mouse events, but if the script calls g_getevent() then future events are put into a queue for retrieval via later calls. These events are returned in the form of strings (see below for the syntax). If there are no events in the queue then the returned string is empty. Note that the very first g_getevent() call will always return an empty string, but this isn't likely to be a problem because it normally occurs very soon after the script starts running. A script can call g_getevent(0) if it wants Golly to resume handling any further events.

Keyboard events are strings of the form "key charname modifiers" where charname can be any displayable ASCII character from '!' to '~' or one of the following names: space, home, end, pageup, pagedown, help, insert, delete, tab, enter, return, left, right, up, down, or f1 to f24. If no modifier key was pressed then modifiers is none, otherwise it is some combination of alt, cmd, ctrl, meta, shift. Note that cmd corresponds to the command key on a Mac and the control key on Windows/Linux (this lets you write portable scripts that work on any platform). The alt modifier corresponds to the option key on a Mac.

Mouse events are strings of the form "click x y button modifiers" where x and y are integers giving the cell position of the click, button is one of left, middle or right, and modifiers is the same as above. The following examples show the strings returned after various user events:

"key m none" user pressed M key
"key space shift" user pressed space bar and shift key
"key , altctrlshift" user pressed comma and 3 modifier keys
"click 100 20 left none" user clicked cell at 100,20 with left button
"click -10 9 middle alt" user clicked cell with middle button and pressed alt key
"click 0 1 right altshift" user clicked cell with right button and pressed 2 modifiers

Example: $evt = g_getevent();

g_doevent($string)
Pass the given event to Golly to handle in the usual manner (but events that can change the current pattern will be ignored). The given event must be a string with the exact same format as returned by the g_getevent command (see above). If the string is empty then Golly does nothing.
Example: g_doevent("key q cmd"); # quit Golly

g_getxy()
Return the mouse's current grid position as a string. The string is empty if the mouse is outside the viewport or outside a bounded grid or over the translucent buttons, otherwise the string contains x and y cell coordinates separated by a space; eg. "-999 12345".
Example: $mousepos = g_getxy();

g_show($message)
Show the given string in the bottom line of the status bar. The status bar is automatically shown if necessary.
Example: g_show("Hit any key to continue...");

g_error($message)
Beep and show the given string in the bottom line of the status bar. The status bar is automatically shown if necessary.
Example: g_error("The pattern is empty.");

g_warn($message)
Beep and show the given string in a modal warning dialog. Useful for debugging Perl scripts or displaying error messages.
Example: g_warn("xxx = $xxx");

g_note($message)
Show the given string in a modal information dialog. Useful for displaying multi-line results.
Example: g_note("Line 1\nLine 2\nLine 3");

g_help($htmlfile)
Open the given HTML file in the help window. A non-absolute path is relative to the location of the script.
Example: g_help("results.html");

g_check($bool)
When Golly runs a script this setting is initially 1, which means that event checking is enabled. If the given parameter is 0 then event checking is disabled. Typically used to prevent mouse clicks being seen at the wrong time. This should only be done for short durations because the script cannot be aborted while the setting is 0.
Example: g_check(0);

g_exit($message="")
Exit the script with an optional error message. If a non-empty string is supplied then it will be displayed in the status bar along with a beep, just like the g_error command. If no message is supplied, or if the string is empty, then there is no beep and the current status bar message will not be changed.
Example: g_exit("There is no pattern.") if g_empty();

 
Cell arrays

Some scripting commands manipulate patterns in the form of cell arrays. Golly supports two types of cell arrays: one-state and multi-state. A one-state cell array contains an even number of integers specifying the x,y coordinates for a set of cells, all of which are assumed to be in state 1:

( x1, y1, . . . xN, yN )

A multi-state cell array contains an odd number of integers specifying the x,y,state values for a set of cells. If the number of cells is even then a padding integer (zero) is added at the end of the array to ensure the total number of integers is odd:

( x1, y1, state1, . . . xN, yN, stateN )      if N is odd
( x1, y1, state1, . . . xN, yN, stateN, 0 )  if N is even

All scripting commands that input cell arrays use the length of the array to determine its type. When writing a script to handle multi-state cell arrays you may need to allow for the padding integer, especially if accessing cells within the array. See tile.pl for example.

Note that all scripting commands return () if the resulting cell array has no cells. They never return (0), although this is a perfectly valid multi-state cell array and all commands can input such an array. For example, $newarray = g_join($array1,[0]) can be used to convert a non-empty one-state array to multi-state.

One-state cell arrays are normally used in a two-state universe, but they can also be used in a universe with more than two states. A multi-state cell array can be used in a two-state universe, but only if the array's cell states are 0 or 1.

The ordering of cells within either type of array doesn't matter. Also note that positive y values increase downwards in Golly's coordinate system.

Cell arrays can contain millions of integers, so all commands that accept or return cell arrays actually use references to those arrays.

 
Rectangle arrays

Some commands manipulate rectangles in the form of arrays. An empty rectangle is indicated by an array with no items; ie. (). A non-empty rectangle is indicated by an array containing four integers:

( left, top, width, height )

The first two items specify the cell at the top left corner of the rectangle. The last two items specify the rectangle's size (in cells). The width and height must be greater than zero.

Unlike cell arrays, rectangle arrays only contain a few items (0 or 4), so all commands that accept or return rectangle arrays don't bother using array references.

 
Potential problems

1. Mac users need to ensure their Perl scripts use Unix line endings (LF). If a script uses Mac line endings (CR) and the first line is a comment then the Perl interpreter will treat the entire file as one long comment and nothing will happen when the script is executed.

2. The escape key check to abort a running script is not done by Perl but by each Golly scripting command. This means that very long Perl computations should call an occasional "no-op" command like g_doevent("") to allow the script to be aborted in a timely manner.

3. When writing a script that creates a pattern, make sure the script starts with a g_new command (or, less useful, a g_open command) otherwise the script might create lots of temporary files or use lots of memory. From the undo history's point of view there are two types of scripts:

  • A script that calls g_new or g_open is assumed to be creating some sort of pattern, so when Golly sees these commands it clears any undo history and sets an internal flag that says "don't mark this layer as dirty and don't bother recording any further changes".
  • A script that doesn't call g_new or g_open is assumed to modify the current pattern. Golly must record all the script's changes so that when it finishes you can select "Undo Script Changes" from the Edit menu. Generating changes (due to g_run calls) are stored in temporary files, while other changes are stored in memory.

 
Perl copyright notice

Golly uses an embedded Perl interpreter to execute scripts. Perl is Copyright (C) 1993-2007, by Larry Wall and others. It is free software; you can redistribute it and/or modify it under the terms of either: a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License". golly-2.7-src/Help/python.html0000644000175000017500000015754412536111364013337 00000000000000 Golly Help: Python Scripting

Installing Python
Example scripts
Golly's scripting commands
Cell lists
Rectangle lists
Using the glife package
Potential problems
Python on Mac OS X
Python copyright notice

 
Installing Python

Before you can run a .py script, Python needs to be installed on your system. Mac OS X users don't need to do anything because Python is already installed (but see below for how to force Golly to use a newer version of Python). Windows and Linux users can download a Python installer from www.python.org/download. Note that a 32-bit version of Golly requires a 32-bit version of Python, and a 64-bit Golly requires a 64-bit Python.

On Windows and Linux, the Python library is loaded at runtime (the first time you try to run a script). Golly initially attempts to load a particular version of the Python library: python27.dll on Windows or libpython2.7.so on Linux. The numbers correspond to Python version 2.7. If that library can't be found then you'll be prompted to enter a different library name matching the version of Python installed on your system. A successfully loaded library is remembered (in your GollyPrefs file) so you won't get the prompt again unless you remove Python or install a new version. If Python isn't installed then you'll have to hit Cancel and you won't be able to run any .py scripts.

 
Example scripts

The Scripts folder supplied with Golly contains a number of example Python scripts:

density.py — calculates the density of the current pattern
draw-lines.py — lets you draw one or more straight lines
envelope.py — uses multiple layers to remember a pattern's live cells
flood-fill.py — fills a clicked region with the current drawing state
goto.py — goes to a given generation
gun-demo.py — constructs a few spaceship guns
heisenburp.py — illustrates the use of cloned layers
invert.py — inverts all cell states in the current selection
make-torus.py — makes a toroidal universe from the current selection
metafier.py — converts the current selection into a meta pattern
move-object.py — lets you move a connected group of live cells
move-selection.py — lets you move the current selection
oscar.py — detects oscillating patterns, including spaceships
pd-glider.py — creates a set of pentadecathlon+glider collisions
pop-plot.py — displays a plot of population versus time
shift.py — shifts the current selection by given x y amounts
slide-show.py — displays all patterns in the Patterns folder
tile.py — tiles the current selection with the pattern inside it
tile-with-clip.py — tiles the current selection with the clipboard pattern

To run one of these scripts, tick the Show Scripts item in the File menu and then simply click on the script's name. You can also select one of the Run items in the File menu. For a frequently used script you might like to assign a keyboard shortcut to run it (see Preferences > Keyboard).

When Golly starts up it looks for a script called golly-start.py in the same directory as the Golly application and then in a user-specific data directory (see the getdir command for the likely path on your system). If the script is found then it is automatically executed.

There are a number of ways to abort a running script. Hit the escape key, or click on the stop button in the tool bar, or select the Stop item in the Control menu.

 
Golly's scripting commands

This section describes all the commands that can be used in a script after importing the golly module. Commands are grouped by function (filing, editing, control, viewing, layers and miscellaneous) or you can search for individual commands alphabetically:

addlayer
advance
autoupdate
check
clear
clone
copy
cut
dellayer
doevent
duplicate
empty
error
evolve
exit
fit
fitsel
flip
getalgo
getbase
getcell
getcells
getclip
getclipstr
getcolor
getcolors
getcursor
getdir
getevent
getgen
getheight
getlayer
getmag
getname
getoption
getpop
getpos
getrect
getrule
getselrect
getstep
getstring
getwidth
getxy
hash
help
join
load
maxlayers
movelayer
new
note
numalgos
numlayers
numstates
open
opendialog
parse
paste
putcells
randfill
reset
rotate
run
save
savedialog
select
setalgo
setbase
setcell
setclipstr
setcolor
setcolors
setcursor
setdir
setgen
setlayer
setmag
setname
setoption
setpos
setrule
setstep
show
shrink
step
store
transform
update
visrect
warn

 
FILING COMMANDS

open(filename, remember=False)
Open the given file and process it according to its type:

  • A HTML file (.htm or .html extension) is displayed in the help window.
  • A text file (.txt or .doc extension, or a name containing "readme") is opened in your text editor.
  • A script file (.pl or .py extension) is executed.
  • A zip file (.zip extension) is processed as described here.
  • Any other type of file is assumed to be a pattern file and is loaded into the current layer.

A non-absolute path is relative to the location of the script. The 2nd parameter is optional (default = False) and specifies if the given pattern or zip file should be remembered in the Open Recent submenu, or in the Run Recent submenu if the file is a script.
Example: golly.open("my-patterns/foo.rle")

save(filename, format, remember=False)
Save the current pattern in a given file using the specified format:

"rle" run length encoded (RLE)
"rle.gz" compressed RLE
"mc" macrocell
"mc.gz" compressed macrocell

A non-absolute path is relative to the location of the script. The 3rd parameter is optional (default = False) and specifies if the file should be remembered in the Open Recent submenu. If the savexrle option is True then extended RLE format is used (see the Save Extended RLE item for details).
Example: golly.save("foo.rle", "rle", True)

opendialog(title, filetypes, initialdir, initialfname, mustexist=True)
Present a standard Open dialog to the user and return the chosen path in a string. All parameters are optional; the default is an Open dialog showing the current directory, with a title of "Choose a file" and a file type of "All files (*)|*". If the 5th parameter (default = True) is set to False, the user can specify a new filename instead of choosing an existing file. If the given file type is "dir" then the dialog lets the user choose a directory rather than a file. If the user cancels the dialog, the return value will be an empty string.
Example: fname = golly.opendialog("Open MCell File", "MCell files (*.mcl)|*.mcl", "C:\\Temp", "sample.mcl")
Example: dirname = golly.opendialog("Choose a folder", "dir");

savedialog(title, filetypes, initialdir, initialfname, suppressprompt=False)
Present a standard Save dialog to the user and return the chosen path in a string. All parameters are optional; the default is a Save dialog showing the current directory, with a title of "Choose a save location and filename" and a file type of "All files (*)|*". If a file already exists at the chosen location, an Overwrite? query will be displayed unless the 5th parameter (default = False) is set to True. If the user cancels the dialog, the return value will be an empty string.
Example: fname = golly.savedialog("Save text file", "Text files (*.txt;*.csv)|*.txt;*.csv", "C:\\Temp", "Params.txt", 1)

load(filename)
Read the given pattern file and return a cell list.
Example: blinker = golly.load("blinker.rle")

store(cell_list, filename)
Write the given cell list to the specified file in RLE format. If the savexrle option is True then extended RLE format is used (see the Save Extended RLE item for details).
Example: golly.store(clist, "foo.rle")

getdir(dirname)
Return the path of the specified directory:

"app" — the directory containing the Golly application.

"data" — the user-specific data directory:
On Linux: ~/.golly/
On Mac OS X: ~/Library/Application Support/Golly/
On Windows: C:\Documents and Settings\username\Application Data\Golly\

"temp" — the directory Golly uses to store various temporary files. All these files are deleted when Golly quits.

"rules" — the user-specific rules directory set in Preferences > Control.

"patterns" — the directory displayed by File > Show Patterns.

"scripts" — the directory displayed by File > Show Scripts.

"download" — the directory Golly uses to store downloaded files.

In each case a full path is returned, terminated by the appropriate path separator for the current platform.
Example: golly.open(golly.getdir("app") + "Patterns/Life/Breeders/breeder.lif")

setdir(dirname, dirpath)
Set the specified directory to the given path (which must be a full path to an existing directory). All the directory names listed above are allowed, except for "app", "data" and "temp".
Example: golly.setdir("patterns", "/path/to/my-patterns/")

 
EDITING COMMANDS

new(title)
Create a new, empty universe and set the window title. If the given title is empty then the current title won't change.
Example: golly.new("test-pattern")

cut()
Cut the current selection to the clipboard.

copy()
Copy the current selection to the clipboard.

clear(where)
Clear inside (where = 0) or outside (where = 1) the current selection.
Example: golly.clear(1)

paste(x, y, mode)
Paste the clipboard pattern at x,y using the given mode ("and", "copy", "or", "xor").
Example: golly.paste(0, 0, "or")

shrink()
Shrink the current selection to the smallest rectangle enclosing all of the selection's live cells.

randfill(percentage)
Randomly fill the current selection to a density specified by the given percentage (1 to 100).
Example: golly.randfill(50)

flip(direction)
Flip the current selection left-right (direction = 0) or top-bottom (direction = 1).

rotate(direction)
Rotate the current selection 90 degrees clockwise (direction = 0) or anticlockwise (direction = 1).

evolve(cell_list, numgens)
Advance the pattern in the given cell list by the specified number of generations and return the resulting cell list.
Example: newpatt = golly.evolve(currpatt, 100)

join(cell_list1, cell_list2)
Join the given cell lists and return the resulting cell list. If the given lists are both one-state then the result is one-state. If at least one of the given lists is multi-state then the result is multi-state, but with one exception: if both lists have no cells then the result is [] (an empty one-state list) rather than [0]. See below for a description of one-state and multi-state cell lists.
Example: result = golly.join(part1, part2)

transform(cell_list, x0, y0, axx=1, axy=0, ayx=0, ayy=1)
Apply an affine transformation to the given cell list and return the resulting cell list. For each x,y cell in the input list the corresponding xn,yn cell in the output list is calculated as xn = x0 + x*axx + y*axy, yn = y0 + x*ayx + y*ayy.
Example: rot_blinker = golly.transform(blinker, 0, 0, 0, -1, 1, 0)

parse(string, x0=0, y0=0, axx=1, axy=0, ayx=0, ayy=1)
Parse an RLE or Life 1.05 string and return an optionally transformed cell list.
Example: blinker = golly.parse("3o!")

putcells(cell_list, x0=0, y0=0, axx=1, axy=0, ayx=0, ayy=1, mode="or")
Paste the given cell list into the current universe using an optional affine transformation and optional mode ("and", "copy", "not", "or", "xor").
Example: golly.putcells(currpatt, 6, -40, 1, 0, 0, 1, "xor")

getcells(rect_list)
Return any live cells in the specified rectangle as a cell list. The given list can be empty (in which case the cell list is empty) or it must represent a valid rectangle of the form [x,y,width,height].
Example: clist = golly.getcells( golly.getrect() )

getclip()
Parse the pattern data in the clipboard and return a cell list, but where the first two numbers are the pattern's width and height (not necessarily the minimal bounding box because the pattern might have empty borders, or it might even be empty). If the clipboard data is multi-state but all cell states happen to be zero then the returned cell list is [wd,ht] rather than [wd,ht,0].
Example: clist = golly.getclip()

hash(rect_list)
Return an integer hash value for the pattern in the given rectangle. Two identical patterns will have the same hash value, regardless of their location in the universe. This command provides a fast way to detect pattern equality, but there is a tiny probability that two different patterns will have the same hash value, so you might need to use additional (slower) tests to check for true pattern equality.
Example: h = golly.hash( golly.getrect() )

select(rect_list)
Create a selection if the given list represents a valid rectangle of the form [x,y,width,height] or remove the current selection if the given list is [].
Example: golly.select( [-10,-10,20,20] )

getrect()
Return the current pattern's bounding box as a list. If there is no pattern then the list is empty ([]), otherwise the list is of the form [x,y,width,height].
Example: if len(golly.getrect()) == 0: golly.show("No pattern.")

getselrect()
Return the current selection rectangle as a list. If there is no selection then the list is empty ([]), otherwise the list is of the form [x,y,width,height].
Example: if len(golly.getselrect()) == 0: golly.show("No selection.")

setcell(x, y, state)
Set the given cell to the specified state (0 for a dead cell, 1 for a live cell).

getcell(x, y)
Return the state of the given cell. The following example inverts the state of the cell at 0,0.
Example: golly.setcell(0, 0, 1 - golly.getcell(0, 0))

setcursor(string)
Set the current cursor according to the given string and return the old cursor string. The given string must match one of the names in the Cursor Mode menu.
Example: oldcurs = golly.setcursor("Draw")

getcursor()
Return the current cursor as a string (ie. the ticked name in the Cursor Mode menu).

 
CONTROL COMMANDS

run(numgens)
Run the current pattern for the specified number of generations. Intermediate generations are never displayed, and the final generation is only displayed if the current autoupdate setting is True.
Example: golly.run(100)

step()
Run the current pattern for the current step. Intermediate generations are never displayed, and the final generation is only displayed if the current autoupdate setting is True.

setstep(exp)
Temporarily set the current step exponent to the given integer. A negative exponent sets the step size to 1 and also sets a delay between each step, but that delay is ignored by the run and step commands. Golly will reset the step exponent to 0 upon creating a new pattern, loading a pattern file, or switching to a different algorithm.
Example: golly.setstep(0)

getstep()
Return the current step exponent.
Example: golly.setstep( golly.getstep() + 1 )

setbase(base)
Temporarily set the current base step to an integer from 2 to 10000. Golly will restore the default base step (set in Preferences > Control) upon creating a new pattern, loading a pattern file, or switching to a different algorithm.
Example: golly.setbase(2)

getbase()
Return the current base step.

advance(where, numgens)
Advance inside (where = 0) or outside (where = 1) the current selection by the specified number of generations. The generation count does not change.
Example: golly.advance(0, 3)

reset()
Restore the starting pattern and generation count. Also reset the algorithm, rule, scale, location and step exponent to the values they had at the starting generation. The starting generation is usually zero, but it can be larger after loading an RLE/macrocell file that stores a non-zero generation count.

setgen(gen)
Set the generation count using the given string. Commas and other punctuation marks can be used to make a large number more readable. Include a leading +/- sign to specify a number relative to the current generation count.
Example: golly.setgen("-1,000")

getgen(sepchar='\0')
Return the current generation count as a string. The optional parameter (default = '\0') specifies a separator character that can be used to make the resulting string more readable. For example, golly.getgen(',') would return a string like "1,234,567" but golly.getgen() would return "1234567". Use the latter call if you want to do arithmetic on the generation count because then it's easy to use int to convert the string to an integer. Note that Python supports arbitrarily large integers.
Example: gen = int( golly.getgen() )

getpop(sepchar='\0')
Return the current population as a string. The optional parameter (default = '\0') specifies a separator character that can be used to make the resulting string more readable. For example, golly.getpop(',') would return a string like "1,234,567" but golly.getpop() would return "1234567". Use the latter call if you want to do arithmetic on the population count. The following example converts the population to a floating point number.
Example: pop = float( golly.getpop() )

empty()
Return True if the universe is empty or False if there is at least one live cell. This is much more efficient than testing getpop() == "0".
Example: if golly.empty(): golly.show("All cells are dead.")

numstates()
Return the number of cell states in the current universe. This will be a number from 2 to 256, depending on the current algorithm and rule.
Example: maxstate = golly.numstates() - 1

numalgos()
Return the number of algorithms (ie. the number of items in the Set Algorithm menu).
Example: maxalgo = golly.numalgos() - 1

setalgo(string)
Set the current algorithm according to the given string which must match one of the names in the Set Algorithm menu.
Example: golly.setalgo("HashLife")

getalgo(index=current)
Return the algorithm name at the given index in the Set Algorithm menu, or the current algorithm's name if no index is supplied.
Example: lastalgo = golly.getalgo( golly.numalgos() - 1 )

setrule(string)
Set the current rule according to the given string. If the current algorithm doesn't support the specified rule then Golly will automatically switch to the first algorithm that does support the rule. If no such algorithm can be found then you'll get an error message and the script will be aborted.
Example: golly.setrule("b3/s23")

getrule()
Return the current rule as a string in canonical format.
Example: oldrule = golly.getrule()

getwidth()
Return the width of the current universe (0 if unbounded).
Example: wd = golly.getwidth()

getheight()
Return the height of the current universe (0 if unbounded).
Example: ht = golly.getheight()

 
VIEWING COMMANDS

setpos(x, y)
Change the position of the viewport so the given cell is in the middle. The x,y coordinates are given as strings so the viewport can be moved to any location in the unbounded universe. Commas and other punctuation marks can be used to make large numbers more readable. Apart from a leading minus sign, most non-digits are simply ignored; only alphabetic characters will cause an error message. Note that positive y values increase downwards in Golly's coordinate system.
Example: golly.setpos("1,000,000,000,000", "-123456")

getpos(sepchar='\0')
Return the x,y position of the viewport's middle cell in the form of a Python tuple containing two strings. The optional parameter (default = '\0') specifies a separator character that can be used to make the resulting strings more readable. For example, golly.getpos(',') might return two strings like "1,234" and "-5,678" but golly.getpos() would return "1234" and "-5678". Use the latter call if you want to do arithmetic on the x,y values, or just use the getposint() function defined in the glife package.
Example: x, y = golly.getpos()

setmag(mag)
Set the magnification, where 0 corresponds to the scale 1:1, 1 = 1:2, -1 = 2:1, etc. The maximum allowed magnification is 5 (= 1:32).
Example: golly.setmag(0)

getmag()
Return the current magnification.
Example: golly.setmag( golly.getmag() - 1 )

fit()
Fit the entire pattern in the viewport.

fitsel()
Fit the current selection in the viewport. The script aborts with an error message if there is no selection.

visrect(rect_list)
Return True if the given rectangle is completely visible in the viewport. The rectangle must be a list of the form [x,y,width,height].
Example: if golly.visrect( [0,0,44,55] ): . . .

autoupdate(bool)
When Golly runs a script this setting is initially False. If the given parameter is True then Golly will automatically update the viewport and the status bar after each command that changes the universe or viewport in some way. Useful for debugging Python scripts.
Example: golly.autoupdate(True)

update()
Immediately update the viewport and the status bar, regardless of the current autoupdate setting. Note that Golly always does an update when a script finishes.

 
LAYER COMMANDS

addlayer()
Add a new, empty layer immediately after the current layer and return the new layer's index, an integer from 0 to numlayers() - 1. The new layer becomes the current layer and inherits most of the previous layer's settings, including its algorithm, rule, scale, location, cursor mode, etc. The step exponent is set to 0, there is no selection, no origin offset, and the layer's initial name is "untitled".
Example: newindex = golly.addlayer()

clone()
Like addlayer (see above) but the new layer shares the same universe as the current layer. The current layer's settings are duplicated and most will be kept synchronized so that a change to one clone automatically changes all the others. Each cloned layer does however have a separate viewport, so the same pattern can be viewed at different scales and locations (at the same time if layers are tiled).
Example: cloneindex = golly.clone()

duplicate()
Like addlayer (see above) but the new layer has a copy of the current layer's pattern. Also duplicates all the current settings but, unlike a cloned layer, the settings are not kept synchronized.
Example: dupeindex = golly.duplicate()

dellayer()
Delete the current layer. The current layer changes to the previous layer (unless layer 0 was deleted).

movelayer(fromindex, toindex)
Move a specified layer to a new position in the layer sequence. The chosen layer becomes the current layer.
Example: golly.movelayer(1, 0)

setlayer(index)
Set the current layer to the layer with the given index, an integer from 0 to numlayers() - 1.
Example: golly.setlayer(0)

getlayer()
Return the index of the current layer, an integer from 0 to numlayers() - 1.
Example: currindex = golly.getlayer()

numlayers()
Return the number of existing layers, an integer from 1 to maxlayers().
Example: if golly.numlayers() > 1: golly.setoption("tilelayers",1)

maxlayers()
Return the maximum number of layers (10 in this implementation).

setname(string, index=current)
Set the name of the given layer, or the current layer's name if no index is supplied.
Example: golly.setname("temporary")

getname(index=current)
Return the given layer's name, or the current layer's name if no index is supplied.
Example: if golly.getname() == "temporary": golly.dellayer()

setcolors(color_list)
Set the color(s) of one or more states in the current layer and its clones (if any). If the given list contains a multiple of 4 integers then they are interpreted as state, red, green, blue values. A state value of -1 can be used to set all live states to the same color (state 0 is not changed). If the given list contains exactly 6 integers then they are interpreted as a color gradient from r1, g1, b1 to r2, g2, b2 for all the live states (state 0 is not changed). If the given list is empty then all states (including state 0) are reset to their default colors, depending on the current algorithm and rule. Note that the color changes made by this command are only temporary. Golly will restore the default colors if a new pattern is opened or created, or if the algorithm or rule changes, or if Preferences > Color is used to change any of the default colors for the current layer's algorithm.
Example: golly.setcolors([1,0,0,0, 2,0,0,0]) # set states 1 and 2 to black
Example: golly.setcolors([-1,0,255,0]) # set all live states to green
Example: golly.setcolors([255,0,0, 0,0,255]) # live states vary from red to blue
Example: golly.setcolors([]) # restore default colors

getcolors(state=-1)
Return the color of a given state in the current layer as a list of the form

[ state, red, green, blue ]

or if the given state is -1 (or not supplied) then return all colors as

[ 0, r0, g0, b0, . . . N, rN, gN, bN ]

where N equals numstates() - 1. Note that the list returned by getcolors can be passed into setcolors; this makes it easy to save and restore colors.
Example: allcolors = golly.getcolors()
Example: deadcolor = golly.getcolors(0)

 
MISCELLANEOUS COMMANDS

setoption(name, value)
Set the given option to the given value. The old value is returned to make it easy to restore a setting. Here are all the valid option names and their possible values:

"autofit" 1 or 0 (True or False)
"boldspacing" 2 to 1000 (cells)
"drawingstate" 0 to numstates()-1
"fullscreen" 1 or 0 (True or False)
"hyperspeed" 1 or 0 (True or False)
"maxdelay" 0 to 5000 (millisecs)
"mindelay" 0 to 5000 (millisecs)
"opacity" 1 to 100 (percent)
"restoreview" 1 or 0 (True or False)
"savexrle" 1 or 0 (True or False)
"showallstates" 1 or 0 (True or False)
"showboldlines" 1 or 0 (True or False)
"showeditbar" 1 or 0 (True or False)
"showexact" 1 or 0 (True or False)
"showgrid" 1 or 0 (True or False)
"showhashinfo" 1 or 0 (True or False)
"showicons" 1 or 0 (True or False)
"showlayerbar" 1 or 0 (True or False)
"showpatterns" 1 or 0 (True or False)
"showscripts" 1 or 0 (True or False)
"showstatusbar" 1 or 0 (True or False)
"showtoolbar" 1 or 0 (True or False)
"stacklayers" 1 or 0 (True or False)
"swapcolors" 1 or 0 (True or False)
"switchlayers" 1 or 0 (True or False)
"synccursors" 1 or 0 (True or False)
"syncviews" 1 or 0 (True or False)
"tilelayers" 1 or 0 (True or False)

Example: oldgrid = golly.setoption("showgrid", True)

getoption(name)
Return the current value of the given option. See above for a list of all the valid option names.
Example: if golly.getoption("autofit"): golly.fit()

setcolor(name, r, g, b)
Set the given color to the given RGB values (integers from 0 to 255). The old RGB values are returned as a 3-tuple to make it easy to restore the color. Here is a list of all the valid color names and how they are used:

"border" color for border around bounded grid
"paste" color for pasting patterns
"select" color for selections (will be 50% transparent)
algoname status bar background for given algorithm

Example: oldrgb = golly.setcolor("HashLife", 255, 255, 255)

getcolor(name)
Return the current RGB values for the given color as a 3-tuple. See above for a list of all the valid color names.
Example: selr, selg, selb = golly.getcolor("select")

getclipstr()
Return the current contents of the clipboard as an unmodified string.
Example: illegalRLE = golly.getclipstr()

setclipstr(string)
Copy an arbitrary string (not necessarily a cell pattern) directly to the clipboard.
Example: golly.setclipstr(correctedRLE)

getstring(prompt, initial="", title="")
Display a dialog box and get a string from the user. If the initial string is supplied it will be shown and selected. If the title string is supplied it will be used in the dialog's title bar. The script will be aborted if the user hits the dialog's Cancel button.
Example: i = int( golly.getstring("Enter a number:", "100") )

getevent(get=True)
When Golly runs a script it initially handles all keyboard and mouse events, but if the script calls getevent() then future events are put into a queue for retrieval via later calls. These events are returned in the form of strings (see below for the syntax). If there are no events in the queue then the returned string is empty. Note that the very first getevent() call will always return an empty string, but this isn't likely to be a problem because it normally occurs very soon after the script starts running. A script can call getevent(False) if it wants Golly to resume handling any further events. See flood-fill.py for a good example.

Keyboard events are strings of the form "key charname modifiers" where charname can be any displayable ASCII character from '!' to '~' or one of the following names: space, home, end, pageup, pagedown, help, insert, delete, tab, enter, return, left, right, up, down, or f1 to f24. If no modifier key was pressed then modifiers is none, otherwise it is some combination of alt, cmd, ctrl, meta, shift. Note that cmd corresponds to the command key on a Mac and the control key on Windows/Linux (this lets you write portable scripts that work on any platform). The alt modifier corresponds to the option key on a Mac.

Mouse events are strings of the form "click x y button modifiers" where x and y are integers giving the cell position of the click, button is one of left, middle or right, and modifiers is the same as above. The following examples show the strings returned after various user events:

"key m none" user pressed M key
"key space shift" user pressed space bar and shift key
"key , altctrlshift" user pressed comma and 3 modifier keys
"click 100 20 left none" user clicked cell at 100,20 with left button
"click -10 9 middle alt" user clicked cell with middle button and pressed alt key
"click 0 1 right altshift" user clicked cell with right button and pressed 2 modifiers

Example: evt = golly.getevent()

doevent(event)
Pass the given event to Golly to handle in the usual manner (but events that can change the current pattern will be ignored). The given event must be a string with the exact same format as returned by the getevent command (see above). If the string is empty then Golly does nothing.
Example: golly.doevent("key q cmd") # quit Golly

getxy()
Return the mouse's current grid position as a string. The string is empty if the mouse is outside the viewport or outside a bounded grid or over the translucent buttons, otherwise the string contains x and y cell coordinates separated by a space; eg. "-999 12345". See draw-lines.py for a good example of how to use this command.
Example: mousepos = golly.getxy()

show(message)
Show the given string in the bottom line of the status bar. The status bar is automatically shown if necessary.
Example: golly.show("Hit any key to continue...")

error(message)
Beep and show the given string in the bottom line of the status bar. The status bar is automatically shown if necessary.
Example: golly.error("The pattern is empty.")

warn(message)
Beep and show the given string in a modal warning dialog. Useful for debugging Python scripts or displaying error messages.
Example: golly.warn("xxx = " + str(xxx))

note(message)
Show the given string in a modal information dialog. Useful for displaying multi-line results.
Example: golly.note("Line 1\nLine 2\nLine 3")

help(htmlfile)
Display the given HTML file in the help window. A non-absolute path is relative to the location of the script.
Example: golly.help("results.html")

check(bool)
When Golly runs a script this setting is initially True, which means that event checking is enabled. If the given parameter is False then event checking is disabled. Typically used to prevent mouse clicks being seen at the wrong time. This should only be done for short durations because the script cannot be aborted while the setting is False.
Example: golly.check(False)

exit(message="")
Exit the script with an optional error message. If a non-empty string is supplied then it will be displayed in the status bar along with a beep, just like the error command. If no message is supplied, or if the string is empty, then there is no beep and the current status bar message will not be changed.
Example: if golly.empty(): golly.exit("There is no pattern.")

 
Cell lists

Some scripting commands manipulate patterns in the form of cell lists. Golly supports two types of cell lists: one-state and multi-state. A one-state cell list contains an even number of integers specifying the x,y coordinates for a set of cells, all of which are assumed to be in state 1:

[ x1, y1, . . . xN, yN ]

A multi-state cell list contains an odd number of integers specifying the x,y,state values for a set of cells. If the number of cells is even then a padding integer (zero) is added at the end of the list to ensure the total number of integers is odd:

[ x1, y1, state1, . . . xN, yN, stateN ]      if N is odd
[ x1, y1, state1, . . . xN, yN, stateN, 0 ]  if N is even

All scripting commands that input cell lists use the length of the list to determine its type. When writing a script to handle multi-state cell lists you may need to allow for the padding integer, especially if accessing cells within the list. See tile.py for example.

Note that all scripting commands return [] if the resulting cell list has no cells. They never return [0], although this is a perfectly valid multi-state cell list and all commands can input such a list. For example, newlist = golly.join(list1,[0]) can be used to convert a non-empty one-state list to multi-state.

One-state cell lists are normally used in a two-state universe, but they can also be used in a universe with more than two states. A multi-state cell list can be used in a two-state universe, but only if the list's cell states are 0 or 1.

The ordering of cells within either type of list doesn't matter. Also note that positive y values increase downwards in Golly's coordinate system.

 
Rectangle lists

Some commands manipulate rectangles in the form of lists. An empty rectangle is indicated by a list with no items; ie. []. A non-empty rectangle is indicated by a list containing four integers:

[ left, top, width, height ]

The first two items specify the cell at the top left corner of the rectangle. The last two items specify the rectangle's size (in cells). The width and height must be greater than zero.

 
Using the glife package

The glife folder included in the Scripts/Python folder is a Python package that provides a high-level interface to some of Golly's scripting commands (it's based on Eugene Langvagen's life package included in PLife). When a script imports glife or any of its submodules, Python automatically executes the __init__.py module. This module defines the pattern and rect classes as well as a number of useful synonyms and helper functions. For example, consider this script:

from glife import *
blinker = pattern("3o!")
blinker.put(1, 2)
blinker.put(6, 7, rcw)   # rcw means rotate clockwise

Here is the equivalent script without using glife:

import golly as g
blinker = g.parse("3o!", 0, 0, 1, 0, 0, 1)
g.putcells(blinker, 1, 2, 1, 0, 0, 1)
g.putcells(blinker, 6, 7, 0, -1, 1, 0)

Here are some helper functions defined in glife:

validint(s) — return True if given string is a valid integer
getposint() — return viewport position as a tuple with 2 integers
setposint(x,y) — use given integers to set viewport position
getminbox(patt) — return minimal bounding box of given pattern

Most of the examples in the Scripts folder import glife, but it isn't compulsory. You might prefer to create your own high-level interface for the scripts you write.

 
Potential problems

1. The Python interpreter's memory allocator never releases memory back to the operating system. If you run a complicated or buggy script that uses lots of (Python) memory then that memory is no longer available for use by Golly, so you might need to quit Golly and restart. Python 2.5 has a smarter memory allocator that does release memory in some stuations, but it's still far from ideal.

2. The first time you run a script that imports a particular module, the Python interpreter caches the results so it won't need to reload that module the next time it is imported. This is good for efficiency, but it's a problem if you've modified an imported module and you want to test your changes. One solution is to quit Golly and restart. Another solution is to force the module to be reloaded by inserting a line like

import mymodule ; reload(mymodule)

at the start of each script that imports the module. When the module is stable you can remove or comment out the reload command.

3. The escape key check to abort a running script is not done by Python but by each Golly scripting command. This means that very long Python computations should call an occasional "no-op" command like doevent("") to allow the script to be aborted in a timely manner.

4. When writing a script that creates a pattern, make sure the script starts with a new command (or, less useful, an open command) otherwise the script might create lots of temporary files or use lots of memory. From the undo history's point of view there are two types of scripts:

  • A script that calls new or open is assumed to be creating some sort of pattern, so when Golly sees these commands it clears any undo history and sets an internal flag that says "don't mark this layer as dirty and don't bother recording any further changes".
  • A script that doesn't call new or open is assumed to modify the current pattern. Golly must record all the script's changes so that when it finishes you can select "Undo Script Changes" from the Edit menu. Generating changes (due to run calls) are stored in temporary files, while other changes are stored in memory.

 
Python on Mac OS X

Even though Apple supply Python with OS X, it is usually not the latest version. Golly is linked against the Python 2.6 framework stored in /System/Library/Frameworks. If you have Python 2.7 installed in your system you can tell Golly to use it by quitting Golly, opening Terminal.app and entering this command (on one line):

install_name_tool -change \
/System/Library/Frameworks/Python.framework/Versions/2.6/Python \
/Library/Frameworks/Python.framework/Versions/2.7/Python \
/path/to/Golly/folder/Golly.app/Contents/MacOS/Golly

If you ever need to switch back to the older Python then just run the command again with the framework paths swapped. To verify which version of Python Golly is using, copy the following code, start up Golly and select Run Clipboard from the File menu:

import golly, sys
golly.note(sys.version)

 
Python copyright notice

Golly uses an embedded Python interpreter to execute scripts. The Python license agreement is included in Golly's LICENSE file. Here is the official Python copyright notice:

Copyright (c) 2001-2007 Python Software Foundation.
All Rights Reserved.

Copyright (c) 2000 BeOpen.com.
All Rights Reserved.

Copyright (c) 1995-2001 Corporation for National Research Initiatives.
All Rights Reserved.

Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
All Rights Reserved.

golly-2.7-src/Help/view.html0000644000175000017500000001337412536111364012760 00000000000000 Golly Help: View Menu

Full Screen

Switches to full screen mode, automatically hiding the menu bar, the status bar, the tool bar, the layer bar, the edit bar, the pattern/script folder and the scroll bars. To exit from this mode just hit the menu item's keyboard shortcut or any unassigned key.

Fit Pattern

Changes the scale and location so the entire pattern fits within the current view.

Fit Selection

Changes the scale and location so the entire selection fits within the current view.

Middle

Moves the origin cell (0,0) to the middle of the view.

Restore Origin

Restores the true origin. The origin cell can be changed by hitting "0" while the cursor is over the view — the cell under the cursor will become the new origin and its location will be displayed as 0,0. This can be handy for measuring distances or for saving a location and returning to it quickly by hitting "m".

Zoom In

Zooms in by doubling the current scale. If the scale is 1:32 then you can't zoom in any further.

Zoom Out

Zooms out by halving the current scale. You can zoom out as far as you like.

Set Scale

This submenu lets you set the scale from 1:1 to 1:32. (A quicker is to use keyboard shortcuts. The initial shortcuts are: "1" for 1:1, "2" for 1:2, "4" for 1:4, "8" for 1:8, "6" for 1:16 and "3" for 1:32.)

Show Tool Bar

Shows or hides the tool bar at the left edge of the main window.

Show Layer Bar

Shows or hides the layer bar above the viewport window (and above the edit bar if it's visible).

Show Edit Bar

Shows or hides the edit bar above the viewport window. The edit bar contains buttons for undo and redo, buttons for changing the cursor mode, a button for showing/hiding all states (see below), boxes showing the current drawing state's color and icon, and a scroll bar for changing the drawing state.

Show All States

If ticked then the edit bar is made larger and the colors and icons for all cell states in the current universe are displayed. A box is drawn around the current drawing state; to change it just click on a different state.

Show Status Bar

Shows or hides the status bar at the top of the main window.

Show Exact Numbers

If ticked then the status bar is made larger and exact numbers are displayed instead of using scientific notation.

Show Grid Lines

Shows or hides the grid lines. Use Preferences > View to turn off the bold grid lines or change their spacing. You can also set the minimum scale at which grid lines should be displayed (1:4, 1:8, 1:16 or 1:32).

Show Cell Icons

If ticked then icons will be displayed at scales 1:8, 1:16 or 1:32. Icons are small bitmaps that can have any shape but their color is automatically synchronized with the cell's state color. Each algorithm can have a different set of icons. You can change these icons by loading suitably formatted files via the "Load Icons" button in Preferences > Color.

It's also possible to have rule-specific icons. Whenever Golly switches to a new rule it looks inside the Rules folder for a matching rule.icons file and, if it exists, loads the bitmaps stored in the file. The format of a .icons file is identical to that used above. See Help > File Formats for a description of the format.

Invert Colors

If ticked then the colors of all cell states in all layers are inverted; i.e., each RGB value is changed to 255-R, 255-G, 255-B.

Buffered

If ticked then window buffering is used to avoid flicker, but it does slow down pattern rendering a bit so you might prefer to live with the flicker. Note that buffering is always used if grid lines are displayed or if a selection is visible.

This option is disabled on Mac OS X and Linux/GTK because windows are automatically buffered on those systems.

Show Timeline

Shows or hides the timeline bar below the viewport window. If the current algorithm supports timelines (only QuickLife doesn't) then the timeline bar has a button to start/stop recording a timeline. This button is equivalent to the Control menu's Start/Stop Recording item.

When recording stops, or after a timeline is loaded from a .mc file, you'll see a scroll bar that lets you view any frame within the timeline. There are also buttons to automatically play the timeline forwards or backwards, a slider to adjust the speed of auto-play, and a button at the right edge to delete the timeline. Note that if the Control menu's Auto Fit option is ticked then Golly will force each timeline pattern to fit the viewport.

A number of keyboard shortcuts can be used while a timeline exists. Hit the escape key to stop recording or to stop auto-play. Hit your preferred keys for Faster/Slower to change the speed of auto-play. Hit your preferred key for Start Generating to play the timeline forwards and, if you wish, use Preferences > Keyboard to assign a keyboard shortcut for Play Timeline Backwards.

Pattern Info

Displays any comments in the current pattern file. golly-2.7-src/Help/Algorithms/0000755000175000017500000000000012536111545013302 500000000000000golly-2.7-src/Help/Algorithms/HashLife.html0000644000175000017500000000120512536111364015570 00000000000000 Golly Help: HashLife

HashLife uses Bill Gosper's hashlife algorithm to achieve remarkable speeds when generating patterns that have a lot of regularity in time and/or space.

HashLife supports the same set of rules as QuickLife, but with one exception: if a rule contains B0 it must also contain S8 (or S6 if the rule ends with H, or S4 if it ends with V).

Note that HashLife performs very poorly on highly chaotic patterns, so in those cases you are better off switching to QuickLife. golly-2.7-src/Help/Algorithms/Generations.html0000644000175000017500000000637212536111364016375 00000000000000 Golly Help: Generations

The Generations algorithm supports rules similar to Life but with an extra history component that allows cells to have up to 256 states. The rule notation is "0..8/1..8/n" where the 1st set of digits specify the live neighbor counts necessary for a cell to survive to the next generation. The 2nd set of digits specify the live neighbor counts necessary for a cell to be born in the next generation. The final number n specifies the maximum number of cell states (from 2 to 256).

Here are some example rules:

2367/3457/5 [Banners] - an exploding rule by Mirek Wojtowicz.
234/34678/24 [Bloomerang] - an expanding rule by John Elliott.
/2/3 [Brian's Brain] - a chaotic rule by Brian Silverman.
124567/378/4 [Caterpillars] - a chaotic rule by Mirek Wojtowicz.
23/2/8 [Cooties] - an exploding rule by Rudy Rucker.
2/13/21 [Fireworks] - an exploding rule by John Elliott.
12/34/3 [Frogs] - a chaotic rule by Scott Robert Ladd.
12345/45678/8 [Lava] - an expanding rule by Mirek Wojtowicz.
012345/458/3 [Lines] - a stable rule by Anders Starmark.
345/2/4 [Star Wars] - an exploding rule by Mirek Wojtowicz.
3456/2/6 [Sticks] - an exploding rule by Rudy Rucker.
345/26/5 [Transers] - an exploding rule by John Elliott.
1456/2356/16 [Xtasy] - an exploding rule by John Elliott.

Other rules in this family, along with more detailed descriptions, can be found at Mirek Wojtowicz's MCell website. See also the Patterns/Generations folder which contains a number of interesting patterns extracted from the MCell pattern collection. golly-2.7-src/Help/Algorithms/RuleLoader.html0000644000175000017500000003206312536111364016151 00000000000000 Golly Help: RuleLoader

The RuleLoader algorithm allows rules to be specified in external files. Given the rule string "Foo", RuleLoader will search for a file called Foo.rule. It looks for the file in your rules folder first, then in the supplied Rules folder. The format of a .rule file is described here. A number of examples can be found in the Rules folder:

B3/S23 or Life
Conway's Life. This is the default rule for the RuleLoader algorithm and is built in (there is no corresponding .rule file).

Banks-I, Banks-II, Banks-III, Banks-IV
In 1971, Edwin Roger Banks (a student of Ed Fredkin) made simpler versions of Codd's 1968 CA, using only two states in some cases. These four rules are found in his PhD thesis. To see the rules in action, open Banks-I-demo.rle and the other examples in Patterns/Banks/.

BBM-Margolus-emulated
Ed Fredkin's Billiard Ball Model, using the Margolus neighborhood to implement a simple reversible physics of bouncing balls. In this implementation we are emulating the system using a Moore-neighborhood CA with extra states. Open BBM.rle to see the rule in action.

BriansBrain
An alternative implementation of the Generations rule /2/3.

Byl-Loop
A six state 5-neighborhood CA that supports small self-replicating loops. To see the rule in action, open Byl-Loop.rle.

Caterpillars
An alternative implementation of the Generations rule 124567/378/4.

Chou-Reggia-1 and Chou-Reggia-2
Two 5-neighborhood CA that supports tiny self-replicating loops. To see the rules in action, open Chou-Reggia-Loop-1.rle and Chou-Reggia-Loop-2.rle.

Codd
In 1968, Edgar F. Codd (who would later invent the relational database) made a simpler version of von Neumann's 29-state CA, using just 8 states. To see the rule in action, open repeater-emitter-demo.rle and the other examples in Patterns/Codd/.

Codd2
A very minor extension of Codd's transition table, to allow for some sheathing cases that were found with large patterns. See sheathing-problems.rle for a demonstration of the problem cases.

CrittersMargolus_emulated
The Critters rule is reversible and has Life-like gliders. See CrittersCircle.rle.

Devore
In 1973, John Devore altered Codd's transition table to allow for simple diodes and triodes, enabling him to make a much smaller replicator than Codd's. See Devore-rep.rle and the other examples in Patterns/Devore/.

DLA-Margolus-emulated
Diffusion-limited aggregation (DLA) is where moving particles can become stuck, forming a distinctive fractal pattern seen in several different natural physical systems. See DLA.rle.

Ed-rep
A version of Fredkin's parity rule, for 7 states. See Ed-rep.rle for an image of Ed Fredkin that photocopies itself.

Evoloop and Evoloop-finite
An extension of the SDSR Loop, designed to allow evolution through collisions. To see the rule in action, open Evoloop-finite.rle.

HPP
The HPP lattice gas. A simple model of gas particles moving at right angles at a fixed speed turns out to give an accurate model of fluid dynamics on a larger scale. Though the later FHP gas improved on the HPP gas by using a hexagonal lattice for more realistic results, the HPP gas is where things began. Open HPP-demo.rle.

Langtons-Ant
Chris Langton's other famous CA. An ant walks around on a binary landscape, collecting and depositing pheremones. See Langtons-Ant.rle.

Langtons-Loops
The original loop. Chris Langton adapted Codd's 1968 CA to support a simple form of self-replication based on a circulating loop of instructions. To see the rule in action, open Langtons-Loops.rle.

LifeHistory
A 7-state extension of the HistoricalLife rule from MCell, allowing for on and off marked cells (states 3 and 4) as well as the history envelope (state 2). State 3 is useful for labels and other identifying marks, since an active pattern can touch or even cross it without being affected. State 5 is an alternate marked ON state most often used to mark a 'starting' location; once a cell changes to state 2, it can not return to this start state. State 6 cells kill any adjacent live cells; they are intended to be used as boundaries between subpatterns, e.g. in an active stamp collection where flying debris from one subpattern might adversely affect another subpattern. See Herschel-conduit-stamp-collection.rle for an example using all of LifeHistory's extra states.

LifeOnTheEdge
A CA proposed by Franklin T. Adams-Watters in which all the action occurs on the edges of a square grid. Each edge can be on or off and has six neighbors, three at each end. An edge is on in the next generation iff exactly two of the edges in its seven edge neighborhood (including the edge itself) are on. This implementation has 3 live states with suitable icons that allow any pattern of edges to be created. Open life-on-the-edge.rle.

LifeOnTheSlope
The same behavior as LifeOnTheEdge but patterns are rotated by 45 degrees. This implementation has only 2 live states (with icons \ and /), so it's a lot easier to enter patterns and they run faster. Open life-on-the-slope.rle.

Perrier
Perrier extended Langton's Loops to allow for universal computation. See Perrier-Loop.rle.

Sand-Margolus-emulated
MCell's Sand rule is a simple simulation of falling sand particles. See Sand.rle.

SDSR-Loop
An extension of Langton's Loops, designed to cause dead loops to disappear, allowing other loops to replicate further. To see the rule in action, open SDSR-Loop.rle.

StarWars
An alternative implementation of the Generations rule 345/2/4.

Tempesti
A programmable loop that can construct shapes inside itself after replication. To see the rule in action, open Tempesti-Loop.rle. This loop prints the letters 'LSL' inside each copy — the initials of Tempesti's university group.

TMGasMargolus_emulated
A different version of the HPP gas, implemented in the Margolus neighborhood, see TMGas.rle.

TripATronMargolus_emulated
The Trip-A-Tron rule in the Margolus neighborhood. See TripATron.rle.

WireWorld
A 4-state CA created by Brian Silverman. WireWorld models the flow of currents in wires and makes it relatively easy to build logic gates and other digital circuits. Open primes.mc and the other examples in Patterns/WireWorld/.

Worm-1040512, Worm-1042015, Worm-1042020, Worm-1252121, Worm-1525115
Examples of Paterson's Worms, a simulation created by Mike Paterson in which a worm travels around a triangular grid according to certain rules. There's also a rule called Worm-complement which can be used to show the uneaten edges within a solid region. Open worm-1040512.rle and the other examples in Patterns/Patersons-Worms/.

References:

Banks-I, Banks-II, Banks-III, Banks-IV (1971)
E. R. Banks. "Information Processing and Transmission in Cellular Automata" PhD Thesis, MIT, 1971.

Byl-Loop (1989)
J. Byl. "Self-Reproduction in small cellular automata." Physica D, Vol. 34, pages 295-299, 1989.

Chou-Reggia-1 and Chou-Reggia-2 (1993)
J. A. Reggia, S. L. Armentrout, H.-H. Chou, and Y. Peng. "Simple systems that exhibit self-directed replication." Science, Vol. 259, pages 1282-1287, February 1993.

Codd (1968)
E. F. Codd, "Cellular Automata" Academic Press, New York, 1968.

Devore (1973)
Devore, J. and Hightower, R. (1992) "The Devore variation of the Codd self-replicating computer" Third Workshop on Artificial Life, Santa Fe, New Mexico, Original work carried out in the 1970s though apparently never published. Reported by John R. Koza, "Artificial life: spontaneous emergence of self-replicating and evolutionary self-improving computer programs," in Christopher G. Langton, Artificial Life III, Proc. Volume XVII Santa Fe Institute Studies in the Sciences of Complexity, Addison-Wesley Publishing Company, New York, 1994, p. 260.

Evoloop (1999)
Hiroki Sayama "Toward the Realization of an Evolving Ecosystem on Cellular Automata", Proceedings of the Fourth International Symposium on Artificial Life and Robotics (AROB 4th '99), M. Sugisaka and H. Tanaka, eds., pp.254-257, Beppu, Oita, Japan, 1999.

HPP (1973)
J. Hardy, O. de Pazzis, and Y. Pomeau. J. Math. Phys. 14, 470, 1973.

Langtons-Ant (1986)
C. G. Langton. "Studying artificial life with cellular automata" Physica D 2(1-3):120-149, 1986.

Langtons-Loops (1984)
C. G. Langton. "Self-reproduction in cellular automata." Physica D, Vol. 10, pages 135-144, 1984.

Paterson's Worms (1973)
See these sites for a good description and the latest results:
http://www.maa.org/editorial/mathgames/mathgames_10_24_03.html
http://wso.williams.edu/~Ebchaffin/patersons_worms/
http://tomas.rokicki.com/worms.html

Perrier (1996)
J.-Y. Perrier, M. Sipper, and J. Zahnd. "Toward a viable, self-reproducing universal computer" Physica D 97: 335-352. 1996

SDSR-Loop (1998)
Hiroki Sayama. "Introduction of Structural Dissolution into Langton's Self-Reproducing Loop." Artificial Life VI: Proceedings of the Sixth International Conference on Artificial Life, C. Adami, R. K. Belew, H. Kitano, and C. E. Taylor, eds., pp.114-122, Los Angeles, California, 1998, MIT Press.

Tempesti (1995)
G. Tempesti. "A New Self-Reproducing Cellular Automaton Capable of Construction and Computation". Advances in Artificial Life, Proc. 3rd European Conference on Artificial Life, Granada, Spain, June 4-6, 1995, Lecture Notes in Artificial Intelligence, 929, Springer Verlag, Berlin, 1995, pp. 555-563.

WireWorld (1987)
A. K. Dewdney, Computer Recreations. Scientific American 282:136-139, 1990. golly-2.7-src/Help/Algorithms/JvN.html0000644000175000017500000000473612536111364014616 00000000000000 Golly Help: JvN

John von Neumann created the very first cellular automata in the 1940's, together with fellow mathematician Stanislaw Ulam.

The JvN algorithm supports 3 rules:

JvN29
The original 29-state CA as created by von Neumann. To see how his rules work, load the simpler examples first: counter-demo.rle and cell-coders-demo.rle and read their pattern info (hit the 'i' button). For a more complex example, see read-arm-demo.rle which shows one component of von Neumann's original design, the tape reader. For a complete self-replicating machine within von Neumann's CA, open sphinx.mc.gz.

Nobili32
An extension of JvN29 created by Renato Nobili in 1994. This rule adds three new states to allow signal crossing, allowing self-replicating machines to be greatly reduced in size. The example pattern construction-arm-demo.rle shows some of the crossing cells in action under this rule. The pattern NP-replicator.rle.gz shows the 1994 design that was the first implementation of von Neumann's vision of a self-reproducing universal constructor in a CA.

Hutton32
Created by Tim Hutton in 2008, this rule uses the same states as Nobili32 but has a slightly modified rule table. Examples golly-constructor.rle and Hutton-replicator.rle show what it can do.

References:

http://en.wikipedia.org/wiki/Von_Neumann_universal_constructor
http://en.wikipedia.org/wiki/Von_Neumann_cellular_automata
http://www.pd.infn.it/~rnobili/wjvn/index.htm
http://www.pd.infn.it/~rnobili/au_cell/
http://www.sq3.org.uk/Evolution/JvN/

golly-2.7-src/Help/Algorithms/QuickLife.html0000644000175000017500000001256512536111364015774 00000000000000 Golly Help: QuickLife

QuickLife is a fast, conventional (non-hashing) algorithm for exploring Life and other 2D outer-totalistic rules. Such rules are defined using "B0...8/S0...8" notation, where the digits after B specify the counts of live neighbors necessary for a cell to be born in the next generation, and the digits after S specify the counts of live neighbors necessary for a cell to survive to the next generation. Here are some example rules:

B3/S23 [Life]
John Conway's rule is by far the best known and most explored CA.

B36/S23 [HighLife]
Very similar to Conway's Life but with an interesting replicator.

B3678/S34678 [Day & Night]
Dead cells in a sea of live cells behave the same as live cells in a sea of dead cells.

B35678/S5678 [Diamoeba]
Creates diamond-shaped blobs with unpredictable behavior.

B2 [Seeds]
Every living cell dies every generation, but most patterns still explode.

B234 [Serviettes or Persian Rug]
A single 2x2 block turns into a set of Persian rugs.

B345/S5 [LongLife]
Oscillators with extremely long periods can occur quite naturally.

 
Emulating B0 rules

Rules containing B0 are tricky to handle in an unbounded universe because every dead cell becomes alive in the next generation. If the rule doesn't contain S8 then the "background" cells alternate from all-alive to all-dead, creating a nasty strobing effect. To avoid these problems, Golly emulates rules with B0 in the following way:

A rule containing B0 and S8 is converted into an equivalent rule (without B0) by inverting the neighbor counts, then using S(8-x) for the B counts and B(8-x) for the S counts. For example, B0123478/S01234678 (AntiLife) is changed to B3/S23 (Life) via these steps: B0123478/S01234678 -> B56/S5 -> B3/S23.

A rule containing B0 but not S8 is converted into a pair of rules (both without B0): one is used for the even generations and the other for the odd generations. The rule for even generations uses inverted neighbor counts. The rule for odd generations uses S(8-x) for the B counts and B(8-x) for the S counts. For example, B03/S23 becomes B1245678/S0145678 (even) and B56/S58 (odd).

In both cases, the replacement rule(s) generate patterns that are equivalent to the requested rule. However, you need to be careful when editing an emulated pattern in a rule that contains B0 but not S8. If you do a cut or copy then you should only paste into a generation with the same parity.

 
Von Neumann neighborhood

The above rules use the Moore neighborhood, where each cell has 8 neighbors. In the von Neumann neighborhood each cell has only the 4 orthogonal neighbors. To specify this neighborhood just append "V" to the usual "B.../S..." notation and use neighbor counts ranging from 0 to 4 (counts above 4 are silently ignored). For example, try B13/S012V or B2/S013V.

Note that when viewing patterns at scales 1:8 or 1:16 or 1:32, Golly displays diamond-shaped icons for rules using the von Neumann neighborhood and circular dots for rules using the Moore neighborhood.

 
Hexagonal neighborhood

QuickLife can emulate a hexagonal neighborhood on a square grid by ignoring the NE and SW corners of the Moore neighborhood so that every cell has 6 neighbors:

   NW N NE         NW  N
   W  C  E   ->   W  C  E
   SW S SE         S  SE
To specify a hexagonal neighborhood just append "H" to the usual "B.../S..." notation and use neighbor counts ranging from 0 to 6 (counts above 6 are silently ignored). Here's an example:
x = 7, y = 6, rule = B245/S3H
obo$4bo$2bo$bo2bobo$3bo$5bo!
Editing hexagonal patterns in a square grid can be somewhat confusing, so to help make things a bit easier Golly displays slanted hexagons (in icon mode) at scales 1:8 or 1:16 or 1:32.

 
Wolfram's elementary rules

QuickLife supports Stephen Wolfram's elementary 1D rules. These rules are specified as "Wn" where n is an even number from 0 to 254. For example:

W22
A single live cell creates a beautiful fractal pattern.

W30
Highly chaotic and an excellent random number generator.

W110
Matthew Cook proved that this rule is capable of universal computation.

The binary representation of a particular number specifies the cell states resulting from each of the 8 possible combinations of a cell and its left and right neighbors, where 1 is a live cell and 0 is a dead cell. Here are the state transitions for W30:

   111  110  101  100  011  010  001  000
    |    |    |    |    |    |    |    | 
    0    0    0    1    1    1    1    0  = 30 (2^4 + 2^3 + 2^2 + 2^1)
Note that odd-numbered rules have the same problem as B0 rules, but Golly currently makes no attempt to emulate such rules. golly-2.7-src/Help/about.html0000644000175000017500000000116112536111364013107 00000000000000


This is Golly version 2.7

© 2015 The Golly Gang:
Tom Rokicki, Andrew Trevorrow, Tim Hutton,
Dave Greene, Jason Summers, Maks Verver, Robert Munafo.



Golly is an open source, cross-platform application for
exploring the Game of Life and other cellular automata.

http://golly.sourceforge.net/
golly-2.7-src/Help/formats.html0000644000175000017500000011735612536111364013466 00000000000000 Golly Help: File Formats

Here are the important file formats used by Golly:

Extended RLE format (.rle)
Macrocell format (.mc)
Rule format (.rule)
     @RULE
     @TABLE
     @TREE
     @COLORS
     @ICONS
          Specifying icons using XPM
          Grayscale icons or multi-color icons
          Requesting built-in icons
          Tools for creating icons
     How Golly finds .rule files
     Related rules can share colors and/or icons
     How to override a supplied or built-in rule
     The easy way to install a new .rule file
     Deprecated files (.table, .tree, .colors, .icons)
Zip files (.zip)

 
Extended RLE format

Golly prefers to store patterns and pattern fragments in a simple concise textual format we call "Extended RLE" (it's a modified version of the RLE format created by Dave Buckingham). The data is run-length encoded which works well for sparse patterns while still being easy to interpret (either by a machine or by a person). The format permits retention of the most critical data:

  • The cell configuration; ie. which cells have what values.
  • The transition rule to be applied.
  • Any comments or description.
  • The generation count.
  • The absolute position on the screen.

Golly uses this format for internal cuts and pastes, which makes it very convenient to move cell configurations to and from text files. For instance, the r-pentomino is represented as

x = 3, y = 3, rule = B3/S23
b2o$2o$bo!

I just drew this pattern in Golly, selected the whole thing, copied it to the clipboard, and then in my editor I did a paste to get the textual version. Similarly, data in this format can be cut from a browser or email window and pasted directly into Golly.

RLE data is indicated by a file whose first non-comment line starts with "x". A comment line is either a blank line or a line beginning with "#". The line starting with "x" gives the dimensions of the pattern and usually the rule, and has the following format:

x = width, y = height, rule = rule

where width and height are the dimensions of the pattern and rule is the rule to be applied. Whitespace can be inserted at any point in this line except at the beginning or where it would split a token. The dimension data is ignored when Golly loads a pattern, so it need not be accurate, but it is not ignored when Golly pastes a pattern; it is used as the boundary of what to paste, so it may be larger or smaller than the smallest rectangle enclosing all live cells.

Any line that is not blank, or does not start with a "#" or "x " or "x=" is treated as run-length encoded pattern data. The data is ordered a row at a time from top to bottom, and each row is ordered left to right. A "$" represents the end of each row and an optional "!" represents the end of the pattern.

For two-state rules, a "b" represents an off cell, and a "o" represents an on cell. For rules with more than two states, a "." represents a zero state; states 1..24 are represented by "A".."X", states 25..48 by "pA".."pX", states 49..72 by "qA".."qZ", and on up to states 241..255 represented by "yA".."yO". The pattern reader is flexible and will permit "b" and "." interchangeably and "o" and "A" interchangeably.

Any data value or row terminator can be immediately preceded with an integer indicating a repetition count. Thus, "3o" and "ooo" both represent a sequence of three on cells, and "5$" means finish the current row and insert four blank rows, and start at the left side of the row after that.

The pattern writer attempts to keep lines about 70 characters long for convenience when sharing patterns or storing them in text files, but the reader will accept much longer lines.

If the File menu's "Save Extended RLE" option is ticked then comment lines with a specific format will be added at the start of the file to convey extra information. These comment lines start with "#CXRLE" and contain keyword/value pairs. The keywords currently supported are "Pos", which denotes the absolute position of the upper left cell (which may be on or off), and "Gen", which denotes the generation count. For instance,

#CXRLE Pos=0,-1377 Gen=3480106827776

indicates that the upper left corner of the enclosing rectange is at an X coordinate of 0 and a Y coordinate of -1377, and that the pattern stored is at generation 3,480,106,827,776.

All comment lines that are not CXRLE lines, and occur at the top or bottom of the file, are treated as information lines and are displayed when the user clicks the "information" button in Golly's tool bar. Any comment lines interspersed with the pattern data will not be displayed.

 
Macrocell format

The size of an Extended RLE file is frequently proportional to the number of cells it contains, yet Golly supports universes that can contain trillions of cells or more, using hashlife-based algorithms. The storage of these huge universes, for which Extended RLE is not feasible, is done by essentially dumping the in-memory compressed representation of the universe in "Macrocell format". Since little translation need be done between external and internal representation, this format is also used to store backups of universes at certain points in Golly's operation when using one of the hashlife-based algorithms.

The macrocell format has two parts: the header, and the tree. The first portion of the file is the header; this contains the format identifier, the rule, the generation count (if non-zero), and any comments associated with this file. The format identifier is a line that starts with "[M2]" and contains the name and version of the program used to write it:

[M2] (golly 2.0)

Following this is any comment lines, which are lines that begin with '#'. If the first two characters of a line are '#R', then the remainder of the line (after intervening whitespace) is the rule for the pattern. If the first two characters are '#G', then the remainder of the line is the current generation count. Any other line starting with a '#' is treated as an ordinary comment line.

Following the header is is a child-first textual representation of a canonicalized quadtree. Each line is either a leaf node, or a non-leaf node. For two-state algorithms, the leaf nodes contain an 8x8 pixel array in a simplified raster format, left-to-right, then top-down, with "." representing an empty cell, "*" representing a live cell, and "$" representing the end of line; empty cells at the end of each row are suppressed. No whitespace is permitted; lines representing leaf nodes for two-state algorithms are recognized because they start with ".", "*", or "$". A sample leaf node containing a glider is:

$$..*$...*$.***$$$$

For algorithms with more than two states, leaf nodes represent a two-by-two square of the universe. They contain five integers separated by single spaces; the first integer is 1, and the next four are the state values for the northwest, northeast, southwest, and southeast values of the square.

Nodes with children are represented by lines with five integers. The first integer is the logarithm base 2 of the size of the square this node representes; for two-state patterns, this must be 4 or larger; for multi-state patterns, this must be 2 or larger. The next four values are the node numbers of the northwest, northeast, southwest, and southeast child nodes. Each of these child nodes must be the appropriate size; that is, a square one fourth the area of the current node.

All nodes, both leaf and non-leaf, are numbered in the order they occur in the file, starting with 1. No node number can point to a node that has yet been defined. The special node number "0" is used to represent all squares that have no live cells.

The total universe represented by a macrocell file is that of the last node in the file (the root node), which also must be the single node with the largest size. By convention, the upper left cell of the southeast child of the root node is at coordinate position (x=0,y=1).

Macrocell files saved from two-state algorithms and from multi-state algorithms are not compatible.

 
Rule format

A .rule file contains all the information about a rule: its name, documentation, table/tree data (used by the RuleLoader algorithm), and any color/icon information. The .rule format is textual and consists of one or more sections. Each section starts with a line of the form @XXX... where X is an uppercase letter. If there is more than one section with the same name then only the first one is used. Any unrecognized sections are silently ignored (this will allow us to add new sections in the future without breaking old versions of Golly).

The currently recognized sections are described below. You might like to refer to WireWorld.rule while reading about each section.

 
@RULE

This is the only mandatory section. The first line of a .rule file must start with @RULE followed by a space and then the rule name. For example:

@RULE WireWorld

The supplied rule name must match exactly the name of the .rule file. This helps Golly to avoid problems that can occur on case-sensitive file systems. When naming a new rule it's best to stick to the following conventions, especially if you'd like to share the .rule file with other Golly users:

  • Please capitalize all rule names and create files like Foo.rule rather than foo.rule. This helps to emphasize that rule names are important, especially on case-sensitive file systems. If the rule "foo" is specified inside a .rle or .mc file then Golly won't be able to find Foo.rule on a case-sensitive system like Linux.
  • To allow for possible future extensions in the way Golly handles rule names, it's best to use only letters and digits. Hyphens and underscores are also okay if you need some sort of separator. Hyphens can allow a set of related rules to share colors and/or icons (see below). Note in particular that spaces and colons must not be used.

After the @RULE line and before the next section (or end of file) you can include any amount of arbitrary text, so this is the place to include a description of the rule or any other documentation. If the .rule file has a @TREE section then this is a good place to put the Python transition function that was used to create the tree data.

 
@TABLE

This section is optional. If present, it contains a transition table that can be loaded by the RuleLoader algorithm. The contents of this section is identical to the contents of a .table file. A detailed specification of the .table format is available here. This is a simple example:

# Signals (2/3) pass alongside a wire (1):
n_states:4
neighborhood:vonNeumann
symmetries:rotate4
var a={2,3}
var b={2,3}
var c={2,3}
a,0,b,1,c,b

Empty lines and anything following the hash symbol "#" are ignored. The following descriptors must appear before other content:

  • n_states: specifies the number of states in the CA (from 0 to n_states-1 inclusive).
  • neighborhood: specifies the cell neighborhood for the CA update step. Must be one of: vonNeumann, Moore, hexagonal, oneDimensional.
  • Other neighborhoods are supported through emulation, using RuleTableToTree.py, see the RoadMap for a full list.
  • symmetries: can be none, permute or one of the symmetries supported for the neighborhood you have chosen. For a full list, see the RoadMap.

After the descriptors comes the variables and transitions. Each variable line should follow the form given in the above example to list the states. Variables should appear before the first transition that uses them. Variables can be used inside later variables.

Transition lines should have states or variables separated by commas. If there are no variables and n_states is less than 11 then the commas can be omitted. Only one transition (or variable) should appear on each line. Inputs are listed in the order C,N,E,S,W,C' for the von Neumann neighborhood, C,N,NE,E,SE,S,SW,W,NW,C' for the Moore neighborhood, C,N,E,SE,S,W,NW,C' for the hexagonal neighborhood, and C,W,E,C' for the oneDimensional neighborhood.

Where the same variable appears more than once in a transition, it stands for the same state each time. For example, the transition in the example above expands to the following: 20212->2, 20213->2, 20312->3, 20313->3, 30212->2, 30213->2, 30312->3, 30313->3, and all 90-degree rotations of those (because of the rotate4 symmetry).

A transition can have a variable as its output (C') if that variable appears more than once in the transition (as in the example above), so that it has a definite value.

Rule tables usually don't specify every possible set of inputs. For those not listed, the central cell remains unchanged.

Transition rules are checked in the order given — the first rule that matches is applied. If you want, you can write rules in the form of general cases and exceptions, as long as the exceptions appear first.

(This form of CA rule table representation was inspired by that in Gianluca Tempesti's PhD thesis: http://lslwww.epfl.ch/pages/embryonics/thesis/AppendixA.html.)

If you have a C/C++ implementation of a transition function, there is a way to automatically produce a rule table. See Rules/TableGenerators/make-ruletable.cpp for instructions.

To share your rule tables with others, you can archive them at the public Rule Table Repository.

 
@TREE

This section is optional. If present, it contains a rule tree that can be loaded by the RuleLoader algorithm. (If the .rule file also contains a @TABLE section, RuleLoader will use the first one it finds.) The contents of this section is identical to the contents of a .tree file.

A detailed description of a rule tree is provided below, but most people don't need to know these details because Golly provides a number of tools for creating rule trees. The make-ruletree.py script in Scripts/Python/Rule-Generators can convert a Python transition function (passed via the clipboard) into a rule tree. The script will either create a new .rule file or update the @TREE section in an existing .rule file. Another script, RuleTableToTree.py, does much the same job using a requested .table file as input.

Golly also includes programs that permit you to transform a given transition function in C++, Perl, or Java into a .tree file (see Rules/TreeGenerators) if the number of states is sufficiently small (approximately 10 states for eight-neighbor rules, and 32 states for four-neighbor rules). The contents of the .tree file can then be copied into the @TREE section of your .rule file.

Essentially, the tree format allows you to add your own rules to Golly without needing to know how to recompile Golly and without dealing with the intricacies of external libraries; it generates relatively compact files, and the data structure is designed for very fast execution.

A rule tree is nothing more than a complete transition table for a rule, expressed in a compressed, canonicalized tree format. For an n state rule, each tree node has n children; each child is either another tree node or a next state value. To look up a function of m variables, each of which is a state value, you start at the root node and select the child node corresponding to the value of the first variable. From that node, you select the child node corresponding to the value of the second variable, and so on. When you finally look up the value of the final variable in the last node, the result value is the actual next state value, rather than another node.

The tree format has fixed the order of variables used for these lookups. For a four-neighbor rule, the order is always north, west, east, south, center; for an eight-neighbor rule, the order is always northwest, northeast, southwest, southeast, north, west, east, south, center.

Without compression, for an n-state rule, there would be a total of 1+n+n^2+n^3+n^4 nodes for a four-neighbor rule, and 1+n+...+n^8 for an eight-neighbor rule; this could quickly get unmanageable. Almost all rules show significant redundancy, with identical rows in the transition table, and identical nodes in the rule tree. To compress this tree, all we do is merge identical nodes, from the bottom up. This can be done explicitly as we construct the tree from a transition function (see Rules/TreeGenerators/RuleTreeGen.java) or symbolically as we evaluate a more expressive format.

The tree format itself is simple, and has similarities to the macrocell format. It is not intended for human authorship or consumption. The tree format has two parts: a header, and the rule tree itself. The header consists of comments (lines starting with a "#") that are ignored, and three required parameter values that must be defined before the first tree node. These values are defined, one per line, starting with the parameter name, then an equals sign, and finally an integer value. The three parameters are num_states, which must be in the range 2..256 inclusive, num_neighbors, which must be 4 or 8, and num_nodes, which must match the number of node lines.

The tree is represented by a sequence of node lines. Each node line consists of exactly num_states integers separated by single spaces. The first integer of each node line is the depth of that node, which must range from 1..num_neighbors+1. The remaining integers for nodes of depth one are state values. The remaining integers for nodes of depth greater than one are node numbers. Nodes are numbered in the order they appear in the file, starting with zero; each node must be defined before its node number is used. The root node, which must be the single node at depth num_neighbors+1, must be the last node defined in the file.

 
@COLORS

This section is optional and can be used to specify the RGB colors for one or more states using lines with 4 numbers, like these:

0  48  48  48   dark gray
1   0 128 255   light blue
2 255 255 255   white
3 255 128   0   orange

Golly silently ignores any states that are invalid for the rule. To specify a color gradient for all live states (all states except 0) you can use a line with 6 numbers, like this:

0 0 255  255 0 0   blue to red

In both cases, any text after the final number on each line is ignored. Blank lines or lines starting with "#" are also ignored.

Note that a .rule file is loaded after switching to the current algorithm's default color scheme, so you have the choice of completely changing all the default colors, or only changing some of them. Use Preferences > Color to change the default colors for each algorithm.

 
@ICONS

This section is optional and can be used to override the default icons displayed for this rule (when Golly is in icon mode).

 
Specifying icons using XPM

Icon bitmaps can be specified using a simple subset of the XPM format. Here's a small example that describes two 7x7 icons suitable for a 3-state rule (icons are never used for state 0):

XPM
/* width height num_colors chars_per_pixel */
"7 14 2 1"
/* colors */
". c #000000"
"A c #FFFFFF"
/* icon for state 1 */
"A......"
".A....."
"..A...."
"...A..."
"....A.."
".....A."
"......A"
/* icon for state 2 */
"......A"
".....A."
"....A.."
"...A..."
"..A...."
".A....."
"A......"

Any blank lines or lines starting with "#" or "/" are ignored. A line with XPM by itself indicates the start of a set of icon bitmaps at a particular size. The @ICONS section can contain any number of XPM subsections, and their order is not important. Three different icon sizes are currently supported: 7x7, 15x15 and 31x31 (for displaying at scales 1:8, 1:16 and 1:32 respectively). Any missing icon sizes will be created automatically by scaling a supplied size. Scaled icons can look rather ugly, so if you want good looking icons it's best to supply all three sizes.

After seeing an XPM line, Golly then looks for lines containing strings delimited by double quotes. The first double quote must be at the start of the line (any text after the second double quote is ignored). The first string contains crucial header information in the form of 4 positive integers:

  • The 1st number is the bitmap's width which also defines the icon size. If it is not 7, 15 or 31 then Golly simply ignores the rest of the XPM data. (This provides upward compatibility if we ever decide to support more sizes.)
  • The 2nd number is the bitmap's height. This must be an integer multiple of the width — the number of icons is the height divided by the width.
  • The 3rd number is the total number of different colors used in the bitmap. After the first string comes the strings that specify each color.
  • The 4th number is the number of characters used to specify each pixel and must be 1 or 2. After the color strings comes the strings with the pixel data for each row of the bitmap. Each such string should contain width × chars_per_pixel characters.

The total number of strings after the XPM line should be 1 + num_colors + height. You'll get an error message if there aren't enough strings. Any extra strings are ignored.

The 1st icon specified is for state 1, the 2nd is for state 2, etc. If the number of icons supplied is fewer than the number of live states then the last icon is automatically duplicated. If there are more icons than required then the extra icons are simply ignored.

 
Grayscale icons or multi-color icons

Golly recognizes two types of icons: grayscale or multi-color. Grayscale icons only use shades of gray (including black and white), as in the above example. Any black areas will be transparent; ie. those pixels will be replaced by the color for state 0. White pixels will be replaced by the color for the cell's current state. Gray pixels are used to do anti-aliasing; ie. the darker the gray the greater the transparency. Using grayscale icons minimizes the amount of XPM data needed to describe a set of icons, especially if the icons use the same shape for each state (as in WireWorld.rule).

If a set of icons contains at least one color that isn't a shade of gray (including black or white) then the icons are said to be multi-colored. Any black pixels are still converted to the state 0 color, but non-black pixels are displayed without doing any substitutions.

If you want to use multi-colored icons then you'll probably want a @COLORS section as well so that the non-icon colors match the icon colors as closely as possible. For example, if the icon for state 1 consists of red and blue triangles then it would be best to set the color of state 1 to purple in the @COLORS section. This minimizes "color shock" when switching between icon and non-icon display mode.

 
Requesting built-in icons

Instead of specifying icon bitmaps using XPM data, you might prefer to use Golly's built-in grayscale icons by supplying one of the following words on a line by itself:

  • circles — circular icons (normally used for Moore neighborhood rules).
  • diamonds — diamond-shaped icons (normally used for von Neumann neighborhood rules).
  • hexagons — hexagonal icons (normally used for hexagonal neighborhood rules).
  • triangles — triangular icons (only suitable for a 4-state rule that is emulating a triangular neighborhood).

 
Tools for creating icons

One way to create XPM icons is to use a painting application that can write .xpm files. Their contents can then be pasted into a .rule file with a small amount of editing.

Another way is to use two Python scripts called icon-importer.py and icon-exporter.py (both can be found in Scripts/Python/Rule-Generators). These scripts allow Golly to be used as an icon editor. Here's how:

Step 1: Switch to the rule whose icons you wish to change or create and then run icon-importer.py. This will create a new layer called "imported icons for rulename" (the name will be used by icon-exporter.py, so don't change it). The script searches for rulename.rule in your rules folder, then in the supplied Rules folder. If found, it extracts any @ICONS data and displays the icon bitmaps in gray boxes. The location of these boxes will be used by icon-exporter.py, so don't move them.

If the @ICONS data is missing icons at a particular size then the script creates them by scaling up or down an existing set of icons. For example, missing 31x31 icons will be created by scaling up the 15x15 icons.

The new layer uses a Generations rule with the maximum number of states (//256) so we can have lots of colors. The initial palette contains a grayscale gradient from white to black, followed by the colors used in the imported icons (if any), followed by three rainbow gradients (bright, pale, dark). You can change these colors by using Layer > Set Layer Colors.

Step 2: Edit the icon bitmaps using Golly's editing capabilities. Golly isn't as powerful as a full-blown painting app, but hopefully it's sufficient for such small images.

Step 3: When you've finshed editing, run icon-exporter.py. This script will extract the icon data and create a suitable @ICONS section in rulename.rule in your rules folder (the script will never create or modify a .rule file in the supplied Rules folder). If rulename.rule already exists in your rules folder then the script replaces any existing @ICONS section (and any @COLORS section if the icons are multi-color) so it won't clobber any other info in the file.

If rulename.rule doesn't exist in your rules folder then it will be created. This file won't have any @TABLE or @TREE section, but that's perfectly valid. It means either the rule is built-in (ie. recognized by a non-RuleLoader algorithm), or else rulename.rule also exists in the supplied Rules folder and so the RuleLoader algorithm will use that file when it can't find any @TABLE or @TREE section in the .rule file in your rules folder.

Finally, icon-exporter.py creates a new layer called "icon test" which uses the original rule and displays a simple pattern containing all live states so you can check what the new icons look like.

 
How Golly finds .rule files

There are two situations where Golly needs to look for a .rule file:

1. If the RuleLoader algorithm is asked to switch to a rule called "Foo" then it first looks for Foo.rule in your rules folder. If not found, or if Foo.rule has no @TABLE or @TREE section, it will then look for Foo.rule in the supplied Rules folder. If Foo.rule doesn't exist then it will use the same search procedure to look for Foo.table, then Foo.tree.

2. After switching to a new rule (not necessarily using RuleLoader), Golly needs to look for color and/or icon information specific to that rule. A similar search procedure to the one above is used again, where this time Golly looks for any @COLORS and/or @ICONS sections in Foo.rule. (Unlike the above search, if Foo.rule is found in your rules folder but doesn't have any color/icon info then Golly will not look for Foo.rule in the Rules folder.)

Note that the 2nd search always occurs after clicking OK in the Control menu's Set Rule dialog, even if the current rule wasn't changed. This is a quick way to test changes to a .rule file.

 
Related rules can share colors and/or icons

If rulename.rule is missing either the @COLORS or @ICONS section, Golly checks to see if rulename contains a hyphen. If it does then it looks for the missing color/icon data in another .rule file called prefix-shared.rule where prefix consists of all the characters before the final hyphen. (As in the above searches, it looks in your rules folder first, then in the supplied Rules folder.) This allows related rules to share a single source of colors and/or icons.

For example, suppose you have a set of related rules in files called Foo-1.rule, Foo-2.rule, etc. If you want all these rules to use the same colors then create a file called Foo-shared.rule:

@RULE Foo-shared
This file contains the colors shared by Foo-* rules.

@TABLE
n_states:3
neighborhood:Moore
symmetries:none
# do nothing

@COLORS
0 0 0 0     black
1 255 0 0   red
2 0 0 255   blue

Note that a shared .rule file should contain a valid @TABLE section with an appropriate value for n_states (the neighborhood setting doesn't really matter, as long as it's legal). This allows the RuleLoader algorithm to load it, which means you can switch to the Foo-shared rule in case you want to add/edit icons using icon-importer.py.

For another good example, see Worm-shared.rule in Golly's Rules folder. It contains the icons shared by all the other Worm-* rules.

 
How to override a supplied or built-in rule

The search procedure described above makes it easy to override a supplied .rule file, either completely or partially. Note that there is never any need to add or modify files in the supplied Rules folder. For example, if you want to override the colors and icons used in the supplied WireWorld.rule then you can create a file with the same name in your rules folder. Its contents might look like this:

@RULE WireWorld

@COLORS
0 0 0 0               black background
0 255 0   255 255 0   live states fade from green to yellow

@ICONS
diamonds

It's also possible to override a built-in rule (ie. a rule recognized by an algorithm other than RuleLoader). A built-in rule name can contain characters not allowed in file names ("/" and "\"), so Golly will substitute those characters with underscores when looking for the corresponding .rule file. For example, if you want to change the colors and/or icons for Life (B3/S23) then you'll need to create a file called B3_S23.rule. This example uses a multi-colored icon to show a blue sphere on a white background:

@RULE B3_S23

Override the default colors and icons for Life (B3/S23).

@COLORS

0 255 255 255   white (matches icon background below)
1 54 54 194     dark blue (average color of icon below)

@ICONS

# 7x7 and 15x15 icons will be created by scaling down this 31x31 icon:

XPM
/* width height num_colors chars_per_pixel */
"31 31 78 2"
/* colors */
".. c #FFFFFF"   white background
"BA c #CECEDE"
"CA c #7B7BAD"
"DA c #4A4A84"
"EA c #18187B"
"FA c #08006B"
"GA c #18186B"
"HA c #29297B"
"IA c #6B6BAD"
"JA c #ADADDE"
"KA c #EFF7FF"
"LA c #ADADC6"
"MA c #39398C"
"NA c #3939BD"
"OA c #7B7BCE"
"PA c #ADB5DE"
"AB c #8C8CD6"
"BB c #4A4A9C"
"CB c #18188C"
"DB c #EFEFEF"
"EB c #EFEFFF"
"FB c #525A9C"
"GB c #08088C"
"HB c #ADADE7"
"IB c #DEDEEF"
"JB c #D6D6F7"
"KB c #DEE7F7"
"LB c #BDBDEF"
"MB c #525ABD"
"NB c #21219C"
"OB c #292984"
"PB c #CECEE7"
"AC c #ADB5CE"
"BC c #2929BD"
"CC c #7B7BDE"
"DC c #BDC6E7"
"EC c #CECEF7"
"FC c #8C8CE7"
"GC c #4242C6"
"HC c #A5A5BD"
"IC c #08087B"
"JC c #3939CE"
"KC c #5A5AC6"
"LC c #BDBDF7"
"MC c #BDBDDE"
"NC c #6B6BD6"
"OC c #9494DE"
"PC c #3931DE"
"AD c #1818AD"
"BD c #2929CE"
"CD c #9C9CC6"
"DD c #10087B"
"ED c #9C9CBD"
"FD c #1818B5"
"GD c #1818C6"
"HD c #847BCE"
"ID c #181094"
"JD c #6B6BCE"
"KD c #7B7BB5"
"LD c #2121AD"
"MD c #BDC6D6"
"ND c #0808AD"
"OD c #4A42B5"
"PD c #00009C"
"AE c #3942BD"
"BE c #3129B5"
"CE c #B5B5CE"
"DE c #0000BD"
"EE c #0000CE"
"FE c #0000DE"
"GE c #42427B"
"HE c #C6CECE"
"IE c #0000EF"
"JE c #9494AD"
"KE c #F7FFEF"
"LE c #10086B"
"ME c #7B849C"
"NE c #0000F7"
/* icon for state 1 */
".............................................................."
".............................................................."
"......................BACADAEAFAGAHAIAJA......................"
"................KALAMAFANAOAJAPAJAABBBCBEAIADB................"
"..............EBFBGBNAHBIBDBJBKAKBEBJBLBMBNBOBPB.............."
"............ACHABCCCDCECIBPBJBPBIBPBJBIBECFCGCCBCAKA.........."
"..........HCICJCKCLBLCLBMCLBLBLBLBMCLBLBMCLCNCJCCBCAKA........"
"........DBOBBCJCCCJAJAJAJAJAJAJAJAJAJAJAJAJAOCJCPCICAC........"
"......KADAADBDBCABABOCABOCOCOCOCABOCABOCABCDFCJCBDBCDDBA......"
"......EDGBFDGDADCCABOAOAOAOAOAOAOAOAHDOAHDCCCCNAADGDIDMA......"
"....KAHAADFDFDADJDMBOAJDJDJDJDJDKDJDJDJDJDJDJDLDFDFDFDICBA...."
"....MDFANDNDNDADODMBMBMBMBMBMBMBKCKCMBMBMBMBODADNDNDNDGBIA...."
"....CAGBNDPDNDPDADGCODODODODODODNAODODGCODAEBCPDNDPDNDPDGA...."
"....OBPDPDNDPDNDNDADBCBEBCBEBCBCBEBCBCBCNAADPDNDNDPDPDNDICPB.."
"....ICNDNDPDNDNDNDPDNDADADADADADADADADADNDNDNDNDNDNDNDPDGBCE.."
"....FANDNDDENDNDNDDENDDENDNDNDNDNDNDNDNDNDNDNDNDNDNDNDNDGBLA.."
"....FANDDENDDEDENDDEDENDDENDDEDEDEDEDEDEDEDEDEDEDENDDEDEGBED.."
"....GANDEEDEDEDEDEDEDEDEDEDEDEDENDDENDDEDEDEDEDEDEDEDEDEGBLA.."
"....BBPDEEDEEEDEEEDEEEDEEEDEDEDEEEDEEEDEDEDEDEDEEEDEEEDEFABA.."
"....EDGBDEEEDEEEEEEEDEEEDEEEEEEEEEEEEEEEEEEEEEEEEEDEEENDGADB.."
"....KBICDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEGBDA...."
"......FBNDFEFEEEEEEEEEFEEEEEFEEEEEEEEEEEEEEEEEEEEEFEDEICHC...."
"......IBEADEFEFEEEFEFEFEFEFEEEFEFEFEFEFEFEFEFEFEFEDEGBGEDB...."
"........LAGBFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFENDGAHE......"
"..........FBNDFEFEIEFEFEIEIEIEFEIEFEFEIEFEFEFEFEEEDDJEKE......"
"..........EBFBIDEEIEIEIEFEFEFEIEFEIEIEIEIEIEIENDLEMEKE........"
"..............CDGBDEIEIENENEIEIEIEIEIEIEIEGDPDGAJEKE.........."
"................BAOBGBADFEIENEIENEIEIEEENDFAGECEKE............"
"....................CDBBDDPDIDNDADPDICEAGEJEDB................"
"........................EBBALAEDEDHCMCDBKE...................."
".............................................................."

 
The easy way to install a new .rule file

Golly provides a quick and easy way to create a new .rule file in the right place. Simply copy the rule contents to the clipboard, then select the Open Clipboard command (in the File menu) or the Paste command (in the Edit menu). If the first line of the clipboard starts with "@RULE rulename" then Golly will save the text as rulename.rule in your rules folder and switch to that rule.

 
Deprecated files (.table, .tree, .colors, .icons)

Golly still supports the old rule-related files with extensions of .table, .tree, .colors and .icons, but their use is discouraged. To help speed up the transition to .rule files, Golly has a couple of handy features:

1. At the bottom of the Control menu is a new command called Convert Old Rules. This will convert all .table/tree/colors/icons files into corresponding .rule files (but existing .rule files will not be changed). The results are displayed in the help window. If the conversion succeeds you'll be asked if you want to delete the .table/tree/colors/icons files.

2. When Golly opens a .zip file containing .table/tree/colors/icons files it will automatically convert them into .rule files, but only if the zip file has no .rule files. Unlike the Convert Old Rules command, this conversion will overwrite existing .rule files (in case the zip file contents have changed).

 
Zip files

Golly can open a standard zip file and process its contents in the following way:

If the zip file is "complex" then Golly builds a temporary HTML file with special unzip links to each included file and shows the result in the help window. A complex zip file is one that contains:

  • Any folders.
  • Any rule files (.rule extension). Such files are automatically extracted and installed into your rules folder. Note that files with a .colors or .icons or .table or .tree extension are automatically converted into corresponding .rule files, but only if those .rule files aren't present in the zip file.
  • Any HTML files (.htm or .html extension).
  • Any text files (.txt or .doc extension, or a name containing "readme").
  • Multiple scripts (.pl or .py extension).
  • Multiple patterns (no extension, or one that doesn't match any of the above).

A "simple" zip file contains at most one pattern and at most one script. In this case Golly will load the pattern (if present) and then run the script (if present). For security reasons, if the zip file was downloaded via a get link then Golly will ask if you really want to run the included script. Both the pattern and the script must be at the root level of the zip file; ie. not inside a folder. For an example of such a zip file, open Langtons-ant.zip from the Patterns/WireWorld/ folder. This zip file contains a pattern file and a simple Python script that sets up a nicer initial view and step size.

A number of pattern collections in the form of zip files can be downloaded from the online archives. golly-2.7-src/Help/help.html0000644000175000017500000000633612536111364012736 00000000000000 Golly Help: Help Menu

The Help menu items can be used to display information on a variety of topics. Each item corresponds to a HTML file in the Help folder. The information is displayed in a separate help window which behaves like a simplified browser. The size and location of this window is remembered when it closes.

Keyboard shortcuts

Various keyboard shortcuts can be used when the help window is in front:

  • Hit "+" and "-" to change the font size.
  • Hit the left arrow or "[" to go back.
  • Hit the right arrow or "]" to go forwards.
  • Hit the home key to go to the Contents page.
  • Hit the up/down arrow keys or page up/down keys if a scroll bar appears.
  • Hit Ctrl-A on Windows/Linux or Cmd-A on Mac to select all text.
  • Hit Ctrl-C on Windows/Linux or Cmd-C on Mac to copy selected text to the clipboard.
  • Hit escape or return to close the help window.

Special links

The help window supports a number of Golly-specific links:

  • edit:file
    Open the given file in your preferred text editor. A non-absolute path is relative to the location of the Golly application.
  • get:url
    Download the specified file and process it according to its type:
    • A HTML file (.htm or .html) is displayed in the help window. Note that this HTML file can contain get links with partial URLs. For a good example of their use, see the LifeWiki Pattern Archive.
    • A text file (.txt or .doc or a name containing "readme") is opened in your text editor.
    • A zip file is opened and processed as described in the File Formats help.
    • A rule file (.rule) is installed into your rules folder and Golly then switches to the corresponding rule.
    • A script file (.pl or .py) is run, but only if you answer "Yes" to the query dialog that appears.
    • A pattern file is loaded into the current layer.
  • lexpatt:pattern
    Load the given Life Lexicon pattern into a "lexicon" layer which is automatically created if it doesn't already exist.
  • open:file
    Load the given pattern or run the given script or switch to the given rule. A non-absolute path is relative to the location of the Golly application.
  • prefs:pane
    Open the Preferences dialog at the given pane. The pane string must be lowercase and must match a known pane: file, edit, control, etc.
  • rule:rulename
    Switch to the given rule.
  • unzip:zip:file
    Extract a file from the given zip file and process it in the same manner as a get link (see above). Golly creates unzip links when it opens a zip file, so you probably won't ever need to use such links in your own HTML files.

Note that for some links (get, open, unzip) you can tell Golly to open the specified file in your text editor by control-clicking or right-clicking on the link. golly-2.7-src/Help/control.html0000644000175000017500000002317512536111364013466 00000000000000 Golly Help: Control Menu

Start/Stop Generating

Starts or stops generating the current pattern. This item can also be used to stop a running script, but it's much easier to hit escape or click the tool bar's stop button.

Next Generation

Advances the pattern to the next generation. Note that you can hit control-space to advance only the current selection, or shift-space to advance everything outside the selection (in both cases the generation count will not change).

Next Step

Advances the pattern to the next step. The current step size is displayed in the status bar as a number of the form "b^e" where b is the base step and e is the exponent. The base step can be changed by the Set Base Step dialog (see below), and the exponent can be changed by the Faster/Slower items (see below).

Reset

Restores the starting pattern and generation count. It also resets the algorithm, rule, scale, location, step size, selection and layer name to the values they had at the starting generation. The starting generation is typically zero, but it can be larger after loading an RLE/macrocell file that stores a non-zero generation count.

Set Generation...

Opens a dialog to change the generation count. You can enter readable numbers like "1,234,567", or include a leading +/- sign to specify a number relative to the current generation count.

Faster

Increases the step exponent in the status bar by 1. This increases the speed by displaying fewer generations. The step exponent is reset to 0 when you create a new pattern, load a pattern file, or switch to a different algorithm.

Slower

Decreases the step exponent in the status bar by 1. This decreases the speed by displaying more generations. The step exponent is reset to 0 when you create a new pattern, load a pattern file, or switch to a different algorithm. If the exponent is 0 when you select this item then a small delay will occur between each generation. Further slowing will double the delay until a maximum value is reached. Use Preferences > Control to set the minimum and maximum delay times.

Set Base Step...

Opens a dialog to change the current base step, but only temporarily. Golly will restore the default base step (set in Preferences > Control) when you create a new pattern, load a pattern file, or switch to a different algorithm. The base step can be any number from 2 to 10,000 (but be aware that Golly's hashing algorithms are most efficient when the base step is a power of 2).

Auto Fit

If ticked then Golly will automatically fit a generating pattern inside the view if any part of the pattern moves out of view. This option is only used when doing many generations via Start or Next Step (that's why it's in the Control menu rather than the View menu), or when displaying patterns in a timeline (see Show Timeline).

Note that if you are generating a pattern and decide to change scale or do any sort of scrolling then the Auto Fit option is automatically turned off (the assumption being that you now want manual control over the scale and/or location).

TIP: If you find the Auto Fit option too confusing then leave it off and hit "f" to manually fit the pattern inside the view whenever you like.

Hyperspeed

If ticked, and the current algorithm uses hashing, then Golly will automatically increase the step exponent at regular intervals (every 64 steps). Hyperspeed mode is a convenient way to run a complex pattern as far as possible. (For very chaotic patterns, using QuickLife may actually run it further.) For highly regular patterns, hyperspeed mode quickly "runs away", generating exponentially fast.

Show Hash Info

Tick this option to turn on status messages that inform you when a hashing algorithm is doing garbage collection, resizing its internal hash table, or changing the step size (which can involve walking the entire hash). The garbage collection messages say which garbage collection it is overall, and if it is a subsequent garbage collection for the same step (the count will be in parentheses), and the percentage of memory reclaimed.

Interpreting these numbers is more an art than a science because some patterns exhibit odd behavior, but in general, if a garbage collection is reclaiming less than 70% of the total memory, or more than ten garbage collections occur for a single step, you can be fairly certain that the algorithm is effectively stalled and further progress will be extremely slow. Reducing the step size may help, but it may need to be reduced substantially in order to have an impact. Increasing the maximum memory that the algorithm can use may also help.

Start/Stop Recording

This item lets you start recording a new timeline (if none exists), or extend an existing timeline (always from its final frame). Golly will proceed to generate and save (in memory) a sequence of patterns separated by the current step size.

If a timeline is being recorded then this item will stop the recording. Note that it's probably easier to click on the start/stop button in the timeline bar (use Show Timeline in the View menu to show/hide this bar). Recording will also stop if you hit the escape key, or if the maximum number of frames is reached (32,000).

A lot of Golly's functionality is disabled while a timeline exists (which includes when it's being recorded). For example, you can't do any editing or generating, nor can you change the current algorithm, rule or step size. You can however do the usual zooming and panning, and you can add/delete/switch layers (each non-cloned layer has its own separate timeline). You can also make selections, but only the last selection is remembered when the timeline is deleted.

Delete Timeline

Deletes the existing timeline. The currently displayed frame becomes the current generation (any later frames are lost), but Golly saves the first frame of the timeline so you can Reset/Undo back to that generation.

Set Algorithm

This submenu lets you switch algorithms. Note that changing the current algorithm can change the current rule. If the new algorithm doesn't support the current rule then Golly will switch to the new algorithm's default rule. If a pattern exists then some cell states might have to be modified if the new universe has fewer states than the old universe.

Golly assigns a different status bar color to each algorithm to give you some feedback about which algorithm is currently in use. You can use Preferences > Color to change these colors.

Most of Golly's algorithms (all except QuickLife) use a hashing technique to generate patterns. This method performs brilliantly on patterns that have a lot of regularity in time or space. Conversely, it can perform very poorly on chaotic patterns. A hashing algorithm may initially appear to be slow, but as the hash table fills up with knowledge about the pattern, it will run faster and faster, so be patient.

Use Preferences > Control to set the maximum amount of hash memory for each algorithm. The initial setting is 500MB. The higher you set the memory limit, the larger patterns you can run and the farther and faster you can run them. However, setting this limit high also increases the amount of time required to change the step size (both manually and in hyperspeed mode) and increases the length of the garbage collection pauses. Nonetheless, it is generally best to set this quite high — typically 80% of the amount of physical memory in your computer. Setting this number high enough often makes more than a difference of 1000 in performance. How high is high enough depends greatly on the pattern and the step size, however, in unpredictable ways.

Set Rule...

Opens a dialog to change the current rule (which is displayed inside square brackets in the main window's title bar). The dialog also allows you to change the current algorithm — if the current rule is not valid in the new algorithm then the algorithm's default rule will be used.

A help button can be used to expand the dialog and display information about the current algorithm along with examples of the rules it supports. If you click on one of the special rule links then the rule string is automatically pasted into the new rule box. Another way to enter a new rule is to choose one from the list of named rules. You can add your own names to this list.

By default, all algorithms create an unbounded universe, but it's also possible to create a bounded universe by adding a special suffix to the usual rule. See here for details.

Convert Old Rules

Converts any .table/tree/colors/icons files into corresponding .rule files (but existing .rule files will not be changed). Golly looks in the supplied Rules folder first, then in your rules folder. The results are displayed in the help window. If the conversion succeeds you'll be asked if you want to delete the .table/tree/colors/icons files. golly-2.7-src/Help/index.html0000644000175000017500000000263512536111364013113 00000000000000 Golly Help: Contents

 

Table of Contents

Introduction
Hints and Tips
Algorithms
Life Lexicon
Online Archives

Perl Scripting
Python Scripting

Keyboard Shortcuts
Mouse Shortcuts
File Menu
Edit Menu
Control Menu
View Menu
Layer Menu
Help Menu
References
File Formats
Bounded Grids
Known Problems
Changes
Credits

golly-2.7-src/Help/mouse.html0000644000175000017500000000212612536111364013127 00000000000000 Golly Help: Mouse Shortcuts

Mouse shortcuts

  • Click in the status bar's "Generation=..." text to change the generation count.
  • Click in the "Scale=..." text to reset the scale to 1:1.
  • Click in the "Step/Delay=..." text to reset the base step to its default value (specified in Preferences > Control) and the step exponent to 0.
  • Double-click in the edit bar's color/icon boxes to open the Set Layer Colors dialog.
  • Shift-click with the cross cursor to expand or shrink an existing selection. Hit the escape key to cancel the operation and restore the original selection.
  • In zoom in/out mode, use right-click or control-click to zoom in the opposite direction.
  • The mouse wheel can be used for zooming, regardless of cursor mode.
  • Right-click or control-click on a pattern/script file to open the file in a text editor. Use Preferences > File to select your preferred text editor.
golly-2.7-src/Help/Lexicon/0000755000175000017500000000000012536111546012573 500000000000000golly-2.7-src/Help/Lexicon/lex_m.htm0000644000175000017500000004720012536111364014332 00000000000000 Life Lexicon (M)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:mango (p1)


.OO..
O..O.
.O..O
..OO.

:mathematician (p5) Found by Dave Buckingham, 1972.


....O....
...O.O...
...O.O...
..OO.OO..
O.......O
OOO...OOO
.........
OOOOOOOOO
O.......O
...OOOO..
...O..OO.

:Max A name for the smallest known spacefiller. The name represents the fact that the growth rate is the fastest possible. (This has not quite been proved, however. There remains the possibility, albeit not very likely, that a periodic agar could have an average density greater than 1/2, and a spacefiller stretching such an agar at the same speed as the known spacefillers would have a faster average growth rate.)

:mazing (p4) In terms of its minimum population of 12 this ties with mold as the smallest p4 oscillator. Found by Dave Buckingham in December 1973. For some constructions using mazings, see popover and sixty-nine.


...OO..
.O.O...
O.....O
.O...OO
.......
...O.O.
....O..

:medium fish = MWSS

:metacatacryst A 52-cell pattern exhibiting quadratic growth. Found by Nick Gotts, December 2000. This is currently the smallest known pattern (in terms of initial population) with superlinear growth. See also catacryst.

:metamorphosis An oscillator built by Robert Wainwright that uses the following reaction (found by Bill Gosper) to turn gliders into LWSS, and converts these LWSS back into gliders by colliding them head on. (There are in fact two ways to do the following reaction, because the spark of the twin bees shuttle is symmetric.)


...................O.........
....................O........
..................OOO........
.............................
.............................
.............................
.............................
.............................
............O...O.....O.OO...
OO.........O.....O....O.O.O..
OO.........O.........O....O..
...........OO...O.....O.O.O..
.............OOO......O.OO...
.............................
.............OOO.............
...........OO...O............
OO.........O...............OO
OO.........O.....O.........OO
............O...O............

:metamorphosis II An oscillator built by Robert Wainwright in December 1994 based on the following p30 glider-to-LWSS converter. This converter was first found by Paul Rendell, January 1986 or earlier, but wasn't widely known about until Paul Callahan rediscovered it in December 1994.


......................O.
.....................O..
.....................OOO
........................
........................
.........O.O............
.........O..O...........
OO..........OO..........
OO........O...OO........
.....OO.....OO..........
....O....O..O...........
.........O.O............
........................
........................
........................
........................
................O.......
...............OOO......
..............OOOOO.....
.............O.O.O.O....
.............OO...OO....
........................
........................
................O.......
...............O.O......
...............O.O......
................O.......
...............OO.......
...............OO.......
...............OO.......

:methuselah Any small pattern that stabilizes only after a long time. Term coined by Conway. Examples include rabbits, acorn, the R-pentomino, blom, Iwona, Justyna and Lidka. See also ark.

:Mickey Mouse (p1) A name proposed by Mark Niemiec for the following still life:


.OO....OO.
O..O..O..O
O..OOOO..O
.OO....OO.
...OOOO...
...O..O...
....OO....

:middleweight emulator = MW emulator

:middleweight spaceship = MWSS

:middleweight volcano = MW volcano

:mini pressure cooker (p3) Found by Robert Wainwright before June 1972. Compare pressure cooker.


.....O.....
....O.O....
....O.O....
...OO.OO...
O.O.....O.O
OO.O.O.O.OO
...O...O...
...O.O.O...
....O.O....
.....O.....

:M.I.P. value The maximum population divided by the initial population for an unstable pattern. For example, the R-pentomino has an M.I.P. value of 63.8, since its maximum population is 319. The term is no longer in use.

:MIT oscillator = cuphook

:MMM breeder See breeder.

:MMS breeder See breeder.

:mod The smallest number of generations it takes for an oscillator or spaceship to reappear in its original form, possibly subject to some rotation or reflection. The mod may be equal to the period, but it may also be a quarter of the period (for oscillators that rotate 90 degrees every quarter period) or half the period (for other oscillators which rotate 180 degrees every half period, and also for flippers).

:mold (p4) Found by Achim Flammenkamp in 1988, but not widely known until Dean Hickerson rediscovered it (and named it) in August 1989. Compare with jam. In terms of its minimum population of 12 it ties with mazing as the smallest p4 oscillator. But in terms of its 6x6 bounding box it wins outright. In fact, of all oscillators that fit in a 6x7 box it is the only one with period greater than 2.


...OO.
..O..O
O..O.O
....O.
O.OO..
.O....

:monogram (p4) Found by Dean Hickerson, August 1989.


OO...OO
.O.O.O.
.OO.OO.
.O.O.O.
OO...OO

:moose antlers (p1)


OO.....OO
O.......O
.OOO.OOO.
...O.O...
....O....

:mosquito See mosquito1, mosquito2. mosquito3, mosquito4 and mosquito5.

:mosquito1 A breeder constructed by Nick Gotts in September 1998. The original version had an initial population of 103, which was then the smallest for any known pattern with superlinear growth (beating the record previously held by Jaws). This was reduced to 97 by Stephen Silver the following month, but was then almost immediately superseded by mosquito2.

Mosquito1 consists of the classic puffer train plus four LWSS and four MWSS (mostly in predecessor form, to keep the population down). Once it gets going it produces a new block-laying switch engine (plus a lot of junk) every 280 generations. It is therefore an MMS breeder, albeit a messy one.

:mosquito2 A breeder constructed by Nick Gotts in October 1998. Its initial population of 85 was for a couple of hours the smallest for any known pattern with superlinear growth, but was then beaten by mosquito3.

Mosquito2 is very like mosquito1, but uses two fewer MWSS and one more LWSS.

:mosquito3 A breeder constructed by Nick Gotts in October 1998. Its initial population of 75 was at the time the smallest for any known pattern with superlinear growth, but was beaten a few days later by mosquito4.

Mosquito3 has one less LWSS than mosquito2. It is somewhat different from the earlier mosquitoes in that the switch engines it makes are glider-producing rather than block-laying.

:mosquito4 A slightly improved version of mosquito3 which Stephen Silver produced in October 1998 making use of another discovery of Nick Gotts (September 1997): an 8-cell pattern that evolves into a LWSS plus some junk. Mosquito4 is a breeder with an initial population of 73, at the time the smallest for any known pattern with superlinear growth, but superseded a few days later by mosquito5.

:mosquito5 A slightly improved version of mosquito4 which Nick Gotts produced in October 1998. The improvement is of a similar nature to the improvement of mosquito4 over mosquito3. Mosquito5 is a breeder with an initial population of 71. At the time, this was the smallest population for any known pattern with superlinear growth, but it has since been superseded by teeth, catacryst and metacatacryst.

:mould = mold

:moving sawtooth A sawtooth such that no cell is ON for more than a finite number generations. David Bell has constructed patterns of this type, with a c/2 front end and a c/3 back end.

:MSM breeder See breeder.

:multi-state Life = colorized Life

:multum in parvo (stabilizes at time 3933) A methuselah found by Charles Corderman, but not as long-lasting as his acorn.


...OOO
..O..O
.O....
O.....

:muttering moat Any oscillator whose rotor consists of a closed chain of cells each of which is adjacent to exactly two other rotor cells. Compare babbling brook. Examples include the bipole, the blinker, the clock, the cuphook, the Gray counter, the quad, the scrubber, the skewed quad and the p2 snake pit. The following diagram shows a p2 example (by Dean Hickerson, May 1993) with a larger rotor. See ring of fire for a very large one.


OO.....
O.O.OO.
.....O.
.O..O..
..O....
..O.O.O
.....OO

:MW emulator (p4) Found by Robert Wainwright in June 1980. See also emulator and filter.


.......O.......
..OO.O...O.OO..
..O.........O..
...OO.....OO...
OOO..OOOOO..OOO
O..O.......O..O
.OO.........OO.

:MWSS (c/2 orthogonally, p4) A middleweight spaceship, the third most common spaceship. Found by Conway in 1970. See also LWSS and HWSS.


...O..
.O...O
O.....
O....O
OOOOO.

:MWSS emulator = MW emulator

:MWSS out of the blue The following reaction, found by Peter Rott in November 1997, in which a LWSS passing by a p46 oscillator creates a MWSS travelling in the opposite direction. Together with some reactions found by Dieter Leithner, and a LWSS-turning reaction which Rott had found in November 1993 (but which was not widely known until Paul Callahan rediscovered it in June 1994) this can be used to prove that there exist gliderless guns for LWSS, MWSS and HWSS for every period that is a multiple of 46.


O..O.................................
....O................................
O...O................................
.OOOO................................
.....................................
.....................................
.....................................
.....................................
.....................................
...................OO..............OO
..................OO...............OO
...................OOOOO.............
..OO................OOOO.............
..OO.....O...........................
........OOO.........OOOO.............
.......O.O.O.......OOOOO.............
........O..O......OO...............OO
........OOO........OO..............OO
.........O...........................
.....................................
.....................................
.....................................
.....................................
..O.......O..........................
.....................................
OOO.......OOO........................
.OO.OO.OO.OO.........................
..OOO...OOO..........................
...O.....O...........................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
..OO.....OO..........................
..OO.....OO..........................

:MW volcano (p5) Found by Dean Hickerson in April 1992.


......O......
....O...O....
.............
...O.....O...
.OOO.OOO.OOO.
O...OO.OO...O
O.OOO.O.OOOO.
.O...........
...O.O.O.OO.O
..OO.OOO.O.OO
...O.O..O....
...O..OO.....
..OO.........

:My Experience with B-heptominos in Oscillators An article by Dave Buckingham (October 1996) that describes his discovery of Herschel conduits, including sufficient (indeed ample) stable conduits to enable, for the first time, the construction of period n oscillators - and true period n guns - for every sufficiently large integer n. (See Herschel loop and emu.)


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_w.htm0000644000175000017500000002603412536111364014346 00000000000000 Life Lexicon (W)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:washerwoman (2c/3 p18 fuse) A fuse by Earl Abbe.


O.......................................................
OO....O.....O.....O.....O.....O.....O.....O.....O.....O.
OOO..O.O...O.O...O.O...O.O...O.O...O.O...O.O...O.O...O.O
OO....O.....O.....O.....O.....O.....O.....O.....O.....O.
O.......................................................

:washing machine (p2) Found by Robert Wainwright before June 1972.


.OO.OO.
O.OO..O
OO....O
.O...O.
O....OO
O..OO.O
.OO.OO.

:wasp (c/3 orthogonally, p3) The following spaceship which produces a domino spark at the back. It is useful for perturbing other objects. Found by David Bell, March 1998.


..........OO.OO.......
........OO.O.OO.OO....
.....OOO.O..OOO..OOOO.
.OOO....OOO.....O....O
O.O.O.OOO.O........OO.
O.O.O.OOOO............
.O.O....O..O..........
..........O...........
..O...................
..O...................

:wavefront (p4) Found by Dave Buckingham, 1976 or earlier.


........OO...
........O....
.........O...
........OO...
.....OO...OO.
....O..OOO..O
....O.....OO.
.....O...O...
OO.O.O...O...
O.OO.O.OO....
....O.O......
....O.O......
.....O.......

:waveguide See superstring.

:weekender (2c/7 orthogonally, p7) Found by David Eppstein in January 2000. In April 2000 Stephen Silver found a tagalong for a pair of weekenders. At present, n weekenders pulling n-1 tagalongs constitute the only known spaceships of this speed or period.


.O............O.
.O............O.
O.O..........O.O
.O............O.
.O............O.
..O...OOOO...O..
......OOOO......
..OOOO....OOOO..
................
....O......O....
.....OO..OO.....

:weld To join two or more still lifes or oscillators together. This is often done in order to fit the objects into a smaller space than would otherwise be possible. The simplest useful example is probably the integral sign, which can be considered as a pair of welded eater1s.

:Wheels, Life, and other Mathematical Amusements One of Martin Gardner's books (1983) that collects together material from his column in Scientific American. The last three chapters of this book contain all the Life stuff.

:why not (p2) Found by Dave Buckingham, July 1977.


...O...
...O.O.
.O.....
O.OOOOO
.O.....
...O.O.
...O...

:wick A stable or oscillating linearly repeating pattern that can be made to burn at one end. See fuse.

:wickstretcher A spaceship-like object which stretches a wick that is fixed at the other end. The wick here is assumed to be in some sense connected, otherwise most puffers would qualify as wickstretchers. The first example of a wickstretcher was found in October 1992 (front end by Hartmut Holzwart and back end by Dean Hickerson) and stretches ants at a speed of c/4. This is shown below with an improved back end found by Hickerson the following month.


.................OO..............................
.............OO....O.............................
............OOO.O................................
O.OO..OO...O...OOOO.O.O....OO.......OO...........
O....OO..O........O.OOO....O....OO.O..O.OO.O.....
O.OO....OO.OO....O...........O...O.O.OO.O.OO.....
......O.......O.............OO.....O..O.O...OO...
.....O.........O.O....OOO...O....O..O.O.OOO...O..
.....O.........O.O....OOO.OO.O..OO.O.O...O..OO.O.
......O.......O.............OO.O...OO....OO....O.
O.OO....OO.OO....O..........O........OO.O.O.OO.OO
O....OO..O........O.OOO........O...O...OO.O..O.O.
O.OO..OO...O...OOOO.O.O.......O.O...OO....O..O.O.
............OOO.O..............O.....O.OOO....O..
.............OO....O.................O.O.........
.................OO...................O..........
Diagonally moving c/4 and c/12 wickstretchers have also been built: see tubstretcher and linestretcher. In July 2000 Jason Summers constructed a c/2 wickstretcher, stretching a p50 traffic jam wick, based on an earlier (October 1994) pattern by Hickerson.

:wicktrailer Any extensible tagalong, that is, one which can be attached to the back of itself, as well as to the back of a spaceship. The number of generations which it takes for the tagalong to occur again in the same place is often called the period of the wicktrailer - this has little relation to the period of the tagalong units themselves.

:windmill (p4) Found by Dean Hickerson, November 1989.


...........O......
.........OO.O.....
.......OO.........
..........OO......
.......OOO........
..................
OOO...............
...OO..OOO.OO.....
..........OOOOOOO.
.OOOOOOO..........
.....OO.OOO..OO...
...............OOO
..................
........OOO.......
......OO..........
.........OO.......
.....O.OO.........
......O...........

:wing The following induction coil. This is generation 2 of block and glider.


.OO.
O..O
.O.O
..OO

:WinLifeSearch Jason Summers' GUI version of lifesrc for MS Windows. It is available from http://entropymine.com/jason/life/software/.

:Winning Ways A two-volume book (1982) by Elwyn Berlekamp, John Conway and Richard Guy on mathematical games. The last chapter of the second volume concerns Life, and outlines a proof of the existence of a universal constructor.

:with-the-grain grey ship A grey ship in which the region of density 1/2 consists of lines of ON cells lying parallel to the direction in which the spaceship moves. See also against-the-grain grey ship.

:WLS = WinLifeSearch

:worker bee (p9) Found by Dave Buckingham in 1972. Unlike the similar snacker this produces no sparks, and so is not very important. Like the snacker, the worker bee is extensible - it is, in fact, a finite version of the infinite oscillator which consists of six ON cells and two OFF cells alternating along a line. Note that Dean Hickerson's new snacker ends also work here.


OO............OO
.O............O.
.O.O........O.O.
..OO........OO..
................
.....OOOOOO.....
................
..OO........OO..
.O.O........O.O.
.O............O.
OO............OO

:W-pentomino Conway's name for the following pentomino, a common loaf predecessor.


O..
OO.
.OO

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_a.htm0000644000175000017500000003122512536111364014316 00000000000000 Life Lexicon (A)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Achim's p144 (p144) This was found (minus the blocks shown below) on a cylinder of width 22 by Achim Flammenkamp in July 1994. Dean Hickerson reduced it to a finite form using figure-8s the same day. The neater finite form shown here - replacing the figure-8s with blocks - was found by David Bell in August 1994. See factory for a use of this oscillator.


OO........................OO
OO........................OO
..................OO........
.................O..O.......
..................OO........
..............O.............
.............O.O............
............O...O...........
............O..O............
............................
............O..O............
...........O...O............
............O.O.............
.............O..............
........OO..................
.......O..O.................
........OO..................
OO........................OO
OO........................OO

:Achim's p16 (p16) Found by Achim Flammenkamp, July 1994.


.......OO....
.......O.O...
..O....O.OO..
.OO.....O....
O..O.........
OOO..........
.............
..........OOO
.........O..O
....O.....OO.
..OO.O....O..
...O.O.......
....OO.......

:Achim's p4 (p4) Dave Buckingham found this in a less compact form (using two halves of sombreros) in 1976. The form shown here was found by Achim Flammenkamp in 1988. The rotor is two copies of the rotor of 1-2-3-4, so the oscillator is sometimes called the "dual 1-2-3-4".


..OO...OO..
.O..O.O..O.
.O.OO.OO.O.
OO.......OO
..O.O.O.O..
OO.......OO
.O.OO.OO.O.
.O..O.O..O.
..OO...OO..

:Achim's p5 = pseudo-barberpole

:Achim's p8 (p8) Found by Achim Flammenkamp, July 1994.


.OO......
O........
.O...O...
.O...OO..
...O.O...
..OO...O.
...O...O.
........O
......OO.

:acorn (stabilizes at time 5206) A methuselah found by Charles Corderman.


.O.....
...O...
OO..OOO

:A for all (p6) Found by Dean Hickerson in March 1993.


....OO....
...O..O...
...OOOO...
.O.O..O.O.
O........O
O........O
.O.O..O.O.
...OOOO...
...O..O...
....OO....

:against-the-grain grey ship A grey ship in which the region of density 1/2 consists of lines of ON cells lying perpendicular to the direction in which the spaceship moves. See also with-the-grain grey ship.

:agar Any pattern covering the whole plane that is periodic in both space and time. The simplest (nonempty) agar is the stable one extended by the known spacefillers. For some more examples see chicken wire, houndstooth agar, onion rings, squaredance and Venetian blinds. Tiling the plane with the pattern O......O produces another interesting example: a p6 agar which has a phase of density 3/4, which is the highest yet obtained for any phase of an oscillating pattern.

:aircraft carrier (p1) This is the smallest still life that has more than one island.


OO..
O..O
..OO

:airforce (p7) Found by Dave Buckingham in 1972. The rotor consists of two copies of that used in the burloaferimeter.


.......O......
......O.O.....
.......O......
..............
.....OOOOO....
....O.....O.OO
...O.OO...O.OO
...O.O..O.O...
OO.O...OO.O...
OO.O.....O....
....OOOOO.....
..............
......O.......
.....O.O......
......O.......

:AK47 reaction The following reaction (found by Rich Schroeppel and Dave Buckingham) in which a honey farm predecessor, catalysed by an eater and a block, reappears at another location 47 generations later, having produced a glider and a traffic light. This is the basis of a very small (but pseudo) p94 glider gun found by Paul Callahan in July 1994, and was in 1990 the basis for the Dean Hickerson's construction of the first true p94 gun. (This latter gun was enormous, and has now been superseded by comparatively small Herschel loop guns.)


.....O....
....O.O...
...O...O..
...O...O..
...O...O..
....O.O...
.....O....
..........
..OO......
...O......
OOO.....OO
O.......OO

:Al Jolson = Jolson

:almosymmetric (p2) Found in 1971.


....O....
OO..O.O..
O.O......
.......OO
.O.......
O......O.
OO.O.O...
.....O...

:anteater A pattern that consumes ants.

:antlers = moose antlers

:ants (p5 wick) The standard form is shown below. It is also possible for any ant to be displaced by one or two cells relative to either or both of its neighbouring ants. Dean Hickerson found fenceposts for both ends of this wick in October 1992 and February 1993. See electric fence, and also wickstretcher.


OO...OO...OO...OO...OO...OO...OO...OO...OO..
..OO...OO...OO...OO...OO...OO...OO...OO...OO
..OO...OO...OO...OO...OO...OO...OO...OO...OO
OO...OO...OO...OO...OO...OO...OO...OO...OO..

:antstretcher Any wickstretcher that stretches ants.

:anvil The following induction coil.


.OOOO.
O....O
.OOO.O
...O.OO

:APPS (c/5 orthogonally, p30) An asymmetric PPS. The same as the SPPS, but with the two halves 15 generations out of phase with one another. Found by Alan Hensel in May 1998.

:ark A pair of mutually stabilizing switch engines. The archetype is Noah's ark. The diagram below shows an ark found by Nick Gotts that takes until generation 736692 to stabilize, and can therefore be considered as a methuselah.


...........................O....
............................O...
.............................O..
............................O...
...........................O....
.............................OOO
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
OO..............................
..O.............................
..O.............................
...OOOO.........................

:arm A long extension hanging off from the main body of a spaceship or puffer perpendicular to the direction of travel.

A lot of known spaceships have multiple arms. This is an artefact of the search methods used to find such spaceships, rather than an indication of what a "typical" spaceship might look like.

:ash The (stable or oscillating) debris left by a random reaction. Experiments show that for random soups with moderate initial densities (say 0.25 to 0.5) the resulting ash has a density of about 0.0287. (This is, of course, based on what happens in finite fields. In infinite fields the situation may conceivably be different in the long run because of the effect of certain initially very rare objects such as replicators.)

:aVerage (p5) Found by Dave Buckingham, 1973. The average number of live rotor cells is five (V), which is also the period.


...OO........
....OOO......
..O....O.....
.O.OOOO.O....
.O.O....O..O.
OO.OOO..O.O.O
.O.O....O..O.
.O.OOOO.O....
..O....O.....
....OOO......
...OO........

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_u.htm0000644000175000017500000002322712536111364014345 00000000000000 Life Lexicon (U)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:underpopulation Death of a cell caused by it having fewer than two neighbours. See also overpopulation.

:unit Life cell A rectangular pattern, of size greater than 1x1, that can simulate Life in the following sense. The pattern by itself represents a dead Life cell, and some other pattern represents a live Life cell. When the plane is tiled by these two patterns (which then represent the state of a whole Life universe) they evolve, after a fixed amount of time, into another tiling of the plane by the same two patterns which correctly represents the Life generation following the one they initially represented. It is usual to use capital letters for the simulated things, so, for example, for the first known unit Life cell (constructed by David Bell in January 1996), one Generation is 5760 generations, and one Cell is 500x500 cells.

In December 2005, Jason Summers constructed an analogous unit cell for Wolfram's Rule 100, a one-dimensional cellular automaton that is know be universal.

:universal computer A computer that can compute anything that is computable. (The concept of computability can be defined in terms of Turing machines, or by Church's lambda calculus, or by a number of other methods, all of which can be shown to lead to equivalent definitions.) The relevance of this to Life is that both Bill Gosper and John Conway proved early on that it is possible to construct a universal computer in the Life universe. (To prove the universality of a cellular automaton with simple rules was in fact Conway's aim in Life right from the start.) Conway's proof is outlined in Winning Ways, and also in The Recursive Universe.

Until recently, no universal Life computer had ever been built in practice, because it would be enormous, even with the improvements that have been devised since those early proofs. In April 2000, Paul Rendell completed a Turing machine construction (described in http://www.cs.ualberta.ca/~bulitko/F02/papers/tm_words.pdf). This, however, has a finite tape, as opposed to the infinite tape of a true Turing machine, and is therefore not a universal computer. But in November 2002, Paul Chapman announced the construction of a universal computer, details of which can be found at http://www.igblan.free-online.co.uk/igblan/ca/. This is a universal register machine based around Dean Hickerson's sliding block memory.

See also universal constructor.

:universal constructor A pattern that is capable of constructing almost any pattern that has a glider synthesis. This definition is a bit vague. A precise definition seems impossible because it has not been proved that all possible glider fleets are constructible. In any case, a universal constructor ought to be able to construct itself in order to qualify as such. An outline of Conway's proof that such a pattern exists can be found in Winning Ways, and also in The Recursive Universe. The key mechanism for the production of gliders with any given path and timing is known as side-tracking, and is based on the kickback reaction. A universal constructor designed in this way can also function as a universal destructor - it can delete almost any pattern that can be deleted by gliders.

In May 2004, Paul Chapman and Dave Greene produced a prototype programmable universal constructor. This is able to construct objects by means of slow glider constructions. It likely that it could be programmed to be construct itself, but the necessary program would be very large; moreover an additional mechanism would be needed in order to copy the program.

A universal constructor is most useful when attached to a universal computer, which can be programmed to control the constructor to produce the desired pattern of gliders. In what follows I will assume that a universal constructor always includes this computer.

The existence of a universal constructor/destructor has a number of theoretical consequences.

For example, the constructor could be programmed to make copies of itself. This is a replicator.

The constructor could even be programmed to make just one copy of itself translated by a certain amount and then delete itself. This would be a (very large, very high period) spaceship. Any translation is possible (except that it must not be too small), so that the spaceship could travel in any direction. It could also travel slower than any given speed, since we could program it to perform some time-wasting task (such as repeatedly constructing and deleting a block) before copying itself. Of course, we could also choose for it to leave some debris behind, thus making a puffer.

It is also possible to show that the existence of a universal constructor implies the existence of a stable reflector. This proof is not so easy, however, and is no longer of much significance now that explicit examples of such reflectors are known.

:universal destructor See universal constructor.

:universal register machine = URM

:universal regulator A regulator in which the incoming gliders are aligned to period 1, that is, they have arbitrary timing (subject to some minimum time required for the regulator to recover from the previous glider).

Paul Chapman constructed the first universal regulator in March 2003. It is adjustable, so that the output can be aligned to any desired period.

:unix (p6) Two blocks eating a long barge. This is a useful sparker, found by Dave Buckingham in February 1976. The name derives from the fact that it was for some time the mascot of the Unix lab of the mathematics faculty at the University of Waterloo.


.OO.....
.OO.....
........
.O......
O.O.....
O..O..OO
....O.OO
..OO....

:up boat with tail = trans-boat with tail

:U-pentomino Conway's name for the following pentomino, which rapidly dies.


O.O
OOO

:URM A universal register machine, particularly Paul Chapman's Life implementation of such a machine. See universal computer for more information.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_f.htm0000644000175000017500000004356012536111364014330 00000000000000 Life Lexicon (F)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:factory Another word for gun, but not used in the case of glider guns. The term is also used for a pattern that repeatedly manufactures objects other than spaceships or rakes. In this case the new objects do not move out of the way, and therefore must be used up in some way before the next one is made. The following shows an example of a p144 gun which consists of a p144 block factory whose output is converted into gliders by a p72 oscillator. (This gun is David Bell's improvement of the one Bill Gosper found in July 1994. The p72 oscillator is by Robert Wainwright, 1990, and the block factory is Achim's p144 minus one of its stabilizing blocks.)


.......................OO........................OO
.......................OO........................OO
.........................................OO........
........................................O..O.......
.........................................OO........
...................................................
....................................OOO............
....................................O.O............
.........OO.........................OOO............
.........OO.........................OO.............
........O..O.......................OOO.............
........O..O.OO....................O.O.............
........O....OO....................OOO.............
..........OO.OO....................................
...............................OO..................
.....................OO.......O..O.................
.....................OO........OO..................
.................................................OO
.................................................OO
...................................................
....OO..................O..........................
OO....OOOO..........OO..OO.OOO.....................
OO..OO.OOO..........OO....OOOO.....................
....O...................OO.........................

:familiar fours Common patterns of four identical objects. The five commonest are traffic light (4 blinkers), honey farm (4 beehives), blockade (4 blocks), fleet (4 ships, although really 2 ship-ties) and bakery (4 loaves, although really 2 bi-loaves).

:fanout A mechanism that emits two or more objects of some type for each one that it receives. Typically the objects are gliders or Herschels; glider duplicators are a special case.

:Fast Forward Force Field The following reaction found by Dieter Leithner in May 1994. In the absence of the incoming LWSS the gliders would simply annihilate one another, but as shown they allow the LWSS to advance 11 spaces in the course of the next 6 generations. A neat illusion. See also star gate. (Leithner named the Fast Forward Force Field in honour of his favourite science fiction writer, the physicist Robert L. Forward.)


.......O......O..
........O......OO
..OO..OOO.....OO.
OO.OO............
OOOO.........O...
.OO.........OO...
............O.O..

:father = parent

:featherweight spaceship = glider

:fencepost Any pattern that stabilizes one end of a wick.

:Fermat prime calculator A pattern constructed by Jason Summers in January 2000 that exhibits infinite growth if and only if there are no Fermat primes greater than 65537. The question of whether or not it really does exhibit infinite growth is therefore equivalent to a well-known and long-standing unsolved mathematical problem. It will, however, still be growing at generation 102585827975. The pattern is based on Dean Hickerson's primer and caber tosser patterns and a p8 beehive puffer by Hartmut Holzwart.

:F-heptomino Name given by Conway to the following heptomino.


OO..
.O..
.O..
.OOO

:figure-8 (p8) Found by Simon Norton in 1970.


OOO...
OOO...
OOO...
...OOO
...OOO
...OOO

:filter Any oscillator used to delete some but not all of the spaceships in a stream. An example is the blocker, which can be positioned so as to delete every other glider in a stream of period 8n+4, and can also do the same for LWSS streams. Other examples are the MW emulator and T-nosed p4 (either of which can be used to delete every other LWSS in a stream of period 4n+2), the fountain (which does the same for MWSS streams) and a number of others, such as the p6 pipsquirter, the pentadecathlon and the p72 oscillator shown under factory. Another example, a p4 oscillator deleting every other HWSS in a stream of period 4n+2, is shown below. (The p4 oscillator here was found, with a slightly larger stator, by Dean Hickerson in November 1994.)


..........OOOO............
....OO...OOOOOO...........
OOOO.OO..OOOO.OO..........
OOOOOO.......OO...........
.OOOO.....................
..........................
................OO........
..............O....O......
..........................
.............O.O..O.O.....
...........OOOO.OO.OOOO...
........O.O....O..O....O.O
........OO.OO.O....O.OO.OO
...........O.O......O.O...
........OO.O.O......O.O.OO
........OO.O..........O.OO
...........O.O.OOOO.O.O...
...........O.O......O.O...
..........OO.O.OOOO.O.OO..
..........O..OOO..OOO..O..
............O..OOOO..O....
...........OO.O....O.OO...
...........O..O....O..O...
............O..O..O..O....
.............OO....OO.....

:fire-spitting (p3) Found by Nicolay Beluchenko, September 2003.


...O......
.OOO......
O.........
.O.OOO....
.O.....O..
..O..O....
..O.O..O.O
........OO

:fish A generic term for LWSS, MWSS and HWSS, or, more generally, for any spaceship.

:fishhook = eater1

:fleet (p1) A common formation of two ship-ties.


....OO....
....O.O...
.....OO...
.......OO.
OO.....O.O
O.O.....OO
.OO.......
...OO.....
...O.O....
....OO....

:flip-flop Any p2 oscillator. However, the term is also used in two more specific (and non-equivalent) senses: (a) any p2 oscillator whose two phases are mirror images of one another, and (b) any p2 oscillator in which all rotor cells die from underpopulation. In the latter sense it contrasts with on-off. The term has also been used even more specifically for the 12-cell flip-flop shown under phoenix.

:flip-flops Another name for the flip-flop shown under phoenix.

:flipper Any oscillator or spaceship that forms its mirror image halfway through its period.

:flotilla A spaceship composed of a number of smaller interacting spaceships. Often one or more of these is not a true spaceship and could not survive without the support of the others. The following example shows an OWSS escorted by two HWSS.


....OOOO.......
...OOOOOO......
..OO.OOOO......
...OO..........
...............
...........OO..
.O............O
O..............
O.............O
OOOOOOOOOOOOOO.
...............
...............
....OOOO.......
...OOOOOO......
..OO.OOOO......
...OO..........

:fly A certain c/3 tagalong found by David Bell, April 1992. Shown here attached to the back of a small spaceship (also by Bell).


..O...............................
.O.O..............................
.O.O......................O.O...O.
.O.......................OO.O.O..O
...........OOO........O.........O.
OO.........OO..O.OO...O..OOOO.....
.O.O.........OOOO..O.O..OO....OO..
.OO........O..O...OOO.....OOO.....
..O.......O....O..OO..OO..O..O....
...O..O...O....O..OOO.O.O....OO...
.......O.OO....O..OOOO.....O......
....OO...OO....O..OOOO.....O......
....O.O...O....O..OOO.O.O....OO...
...OO.....O....O..OO..OO..O..O....
....O.O....O..O...OOO.....OOO.....
.....O.......OOOO..O.O..OO....OO..
...........OO..O.OO...O..OOOO.....
...........OOO........O.........O.
.........................OO.O.O..O
..........................O.O...O.

:flying machine = Schick engine

:fore and back (p2) Compare snake pit. Found by Achim Flammenkamp, July 1994.


OO.OO..
OO.O.O.
......O
OOO.OOO
O......
.O.O.OO
..OO.OO

:forward glider A glider which moves at least partly in the same direction as the puffer(s) or spaceship(s) under consideration.

:fountain (p4) Found by Dean Hickerson in November 1994, and named by Bill Gosper. See also filter and superfountain.


.........O.........
...................
...OO.O.....O.OO...
...O.....O.....O...
....OO.OO.OO.OO....
...................
......OO...OO......
OO...............OO
O..O...O.O.O...O..O
.OOO.OOOOOOOOO.OOO.
....O....O....O....
...OO.........OO...
...O...........O...
.....O.......O.....
....OO.......OO....

:fourteener (p1)


....OO.
OO..O.O
O.....O
.OOOOO.
...O...

:fox (p2) This is the smallest asymmetric p2 oscillator. Found by Dave Buckingham, July 1977.


....O..
....O..
..O..O.
OO.....
....O.O
..O.O.O
......O

:French kiss (p3) Found by Robert Wainwright, July 1971.


O.........
OOO.......
...O......
..O..OO...
..O....O..
...OO..O..
......O...
.......OOO
.........O

:frog II (p3) Found by Dave Buckingham, October 1972.


..OO...OO..
..O.O.O.O..
....O.O....
...O.O.O...
...OO.OO...
.OO.....OO.
O..O.O.O..O
.O.O...O.O.
OO.O...O.OO
....OOO....
...........
...O.OO....
...OO.O....

:frothing puffer A frothing puffer (or a frothing spaceship) is a puffer (or spaceship) whose back end appears to be unstable and breaking apart, but which nonetheless survives. The exhaust festers and clings to the back of the puffer/spaceship before breaking off. The first known frothing puffers were c/2, and most were found by slightly modifying the back ends of p2 spaceships. A number of these have periods which are not a multiple of 4 (as with some line puffers). Paul Tooke has also found c/3 frothing puffers.

The following p78 c/2 frothing puffer was found by Paul Tooke in April 2001.


.......O.................O.......
......OOO...............OOO......
.....OO....OOO.....OOO....OO.....
...OO.O..OOO..O...O..OOO..O.OO...
....O.O..O.O...O.O...O.O..O.O....
.OO.O.O.O.O....O.O....O.O.O.O.OO.
.OO...O.O....O.....O....O.O...OO.
.OOO.O...O....O.O.O....O...O.OOO.
OO.........OO.O.O.O.OO.........OO
............O.......O............
.........OO.O.......O.OO.........
..........O...........O..........
.......OO.O...........O.OO.......
.......OO...............OO.......
.......O.O.O.OOO.OOO.O.O.O.......
......OO...O...O.O...O...OO......
......O..O...O.O.O.O...O..O......
.........OO....O.O....OO.........
.....OO....O...O.O...O....OO.....
.........O.OO.O...O.OO.O.........
..........O.O.O.O.O.O.O..........
............O..O.O..O............
...........O.O.....O.O...........

:frothing spaceship See frothing puffer.

:fumarole (p5) Found by Dean Hickerson in September 1989. In terms of its 7x8 bounding box this is the smallest p5 oscillator.


...OO...
.O....O.
.O....O.
.O....O.
..O..O..
O.O..O.O
OO....OO

:fuse A wick burning at one end. For examples, see baker, beacon maker, blinker ship, boat maker, cow, harvester, lightspeed wire, pi ship, reverse fuse, superstring and washerwoman. Useful fuses are usually clean.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_c.htm0000644000175000017500000011225212536111364014320 00000000000000 Life Lexicon (C)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:c = speed of light

:CA = cellular automaton

:caber tosser Any pattern whose population is asymptotic to c.log(t) for some constant c, and which contains a glider (or other spaceship) bouncing between a slower receding spaceship and a fixed reflector which emits a spaceship (in addition to the reflected one) whenever the bouncing spaceship hits it.

As the receding spaceship gets further away the bouncing spaceship takes longer to complete each cycle, and so the extra spaceships emitted by the reflector are produced at increasingly large intervals. More precisely, if v is the speed of the bouncing spaceship and u the speed of the receding spaceship, then each interval is (v+u)/(v-u) times as long as the previous one. The population at time t is therefore n.log(t)/log((v+u)/(v-u)) + O(1), where n is the population of one of the extra spaceships (assumed constant).

The first caber tosser was built by Dean Hickerson in May 1991.

:Cambridge pulsar CP 48-56-72 = pulsar (The numbers refer to the populations of the three phases. The Life pulsar was indeed discovered at Cambridge, like the first real pulsar a few years earlier.)

:Canada goose (c/4 diagonally, p4) Found by Jason Summers, January 1999. It consists of a glider plus a tagalong.


OOO..........
O.........OO.
.O......OOO.O
...OO..OO....
....O........
........O....
....OO...O...
...O.O.OO....
...O.O..O.OO.
..O....OO....
..OO.........
..OO.........
At the time of its discovery the Canada goose was the smallest known diagonal spaceship other than the glider, but this record has since been beaten, first by the second spaceship shown under Orion, and more recently by quarter.

:candelabra (p3) By Charles Trawick. See also the note under cap.


....OO....OO....
.O..O......O..O.
O.O.O......O.O.O
.O..O.OOOO.O..O.
....O.O..O.O....
.....O....O.....

:candlefrobra (p3) Found by Robert Wainwright in November 1984.


.....O....
.O.OO.O.OO
O.O...O.OO
.O....O...
.....OO...
The following diagram shows that a pair of these can act in some ways like killer toads. See also snacker.

....O...........O....
OO.O.OO.O...O.OO.O.OO
OO.O...O.O.O.O...O.OO
...O....O...O....O...
...OO...........OO...
.....................
.....................
.........OOO.........
.........O..O........
.........O...........
.........O...O.......
.........O...O.......
.........O...........
..........O.O........

:canoe (p1)


...OO
....O
...O.
O.O..
OO...

:cap The following induction coil. It can also be easily be stabilized to form a p3 oscillator - see candelabra for a slight variation on this.


.OO.
O..O
OOOO

:carnival shuttle (p12) Found by Robert Wainwright in September 1984 (using MW emulators at the end, instead of the monograms shown here).


.................................O...O
OO...OO..........................OOOOO
.O.O.O...O..O......OO...O..O.......O..
.OO.OO..OO...OO....OO..OO...OO....O.O.
.O.O.O...O..O......OO...O..O.......O..
OO...OO..........................OOOOO
.................................O...O

:carrier = aircraft carrier

:casing That part of the stator of an oscillator which is not adjacent to the rotor. Compare bushing.

:catacryst A 58-cell quadratic growth pattern found by Nick Gotts in April 2000. This was formerly the smallest known pattern with superlinear growth, but has since been superseded by the related metacatacryst. The catacryst consists of three arks plus a glider-producing switch engine. It produces a block-laying switch engine every 47616 generations. Each block-laying switch engine has only a finite life, but the length of this life increases linearly with each new switch engine, so that the pattern overall grows quadratically, as an unusual type of MMS breeder.

:catalyst An object that participates in a reaction but emerges from it unharmed. The term is mostly applied to still lifes, but can also be used of oscillators, spaceships, etc. The still lifes and oscillators which form a conduit are examples of catalysts.

:caterer (p3) Found by Dean Hickerson, August 1989. Compare with jam. In terms of its minimum population of 12 this is the smallest p3 oscillator. See also double caterer and triple caterer.


..O.....
O...OOOO
O...O...
O.......
...O....
.OO.....
More generally, any oscillator which serves up a bit in the same manner may be referred to as a caterer.

:Caterpillar A spaceship that works by laying tracks at its front end. The only example constructed to date is a p270 17c/45 spaceship built by Gabriel Nivasch in December 2004, based on work by himself, Jason Summers and David Bell. This Caterpillar has a population of about 12 million in each generation and was put together by a computer program that Nivasch wrote. It is by far the largest and most complex Life object ever constructed.

The 17c/45 Caterpillar is based on the following reaction between a pi-heptomino and a blinker:


...............O
O.............OO
O............OO.
O.............OO
...............O
In this reaction, the pi moves forward 17 cells in the course of 45 generations, while the blinker moves back 6 cells and is rephased. This reaction has been known for many years, but it was only in September 2002 that David Bell suggested that it could be used to build a 17c/45 spaceship, based on a reaction he had found in which pis crawling along two rows of blinkers interact to emit a glider every 45 generations. Similar glider-emitting interactions were later found by Gabriel Nivasch and Jason Summers. The basic idea of the spaceship design is that streams of gliders created in this way can be used to construct fleets of standard spaceships which convey gliders to the front of the blinker tracks, where they can be used to build more blinkers.

A different Caterpillar may be possible based on the following reaction, in which the pattern at top left reappears after 31 generations displaced by (13,1), having produced a new NW-travelling glider. In this case the tracks would be waves of backward-moving gliders.


.OO.....................
...O....................
...O.OO.................
OOO....O................
.......O................
.....OOO................
........................
........................
........................
........................
........................
........................
.....................OOO
.....................O..
......................O.

:Catherine wheel = pinwheel

:cauldron (p8) Found in 1971 independently by Don Woods and Robert Wainwright. Compare with Hertz oscillator.


.....O.....
....O.O....
.....O.....
...........
...OOOOO...
O.O.....O.O
OO.O...O.OO
...O...O...
...O...O...
....OOO....
...........
....OO.O...
....O.OO...

:cavity = eater plug

:cell The fundamental unit of space in the Life universe. The term is often used to mean a live cell - the sense is usually clear from the context.

:cellular automaton A certain class of mathematical objects of which Life is an example. A cellular automaton consists of a number of things. First there is a positive integer n which is the dimension of the cellular automaton. Then there is a finite set of states S, with at least two members. A state for the whole cellular automaton is obtained by assigning an element of S to each point of the n-dimensional lattice Zn (where Z is the set of all integers). The points of Zn are usually called cells. The cellular automaton also has the concept of a neighbourhood. The neighbourhood N of the origin is some finite (nonempty) subset of Zn. The neighbourhood of any other cell is obtained in the obvious way by translating that of the origin. Finally there is a transition rule, which is a function from SN to S (that is to say, for each possible state of the neighbourhood the transition rule specifies some cell state). The state of the cellular automaton evolves in discrete time, with the state of each cell at time t+1 being determined by the state of its neighbourhood at time t, in accordance with the transition rule.

There are some variations on the above definition. It is common to require that there be a quiescent state, that is, a state such that if the whole universe is in that state at generation 0 then it will remain so in generation 1. (In Life the OFF state is quiescent, but the ON state is not.) Other variations allow spaces other than Zn, neighbourhoods that vary over space and/or time, probabilistic or other non-deterministic transition rules, etc.

It is common for the neighbourhood of a cell to be the 3x...x3 (hyper)cube centred on that cell. (This includes those cases where the neighbourhood might more naturally be thought of as a proper subset of this cube.) This is known as the Moore neighbourhood.

:centinal (p100) Found by Bill Gosper. This combines the mechanisms of the p46 and p54 shuttles (see twin bees shuttle and p54 shuttle).


OO................................................OO
.O................................................O.
.O.O.....................OO.....................O.O.
..OO........O............OO............OO.......OO..
...........OO..........................O.O..........
..........OO.............................O..........
...........OO..OO......................OOO..........
....................................................
....................................................
....................................................
...........OO..OO......................OOO..........
..........OO.............................O..........
...........OO..........................O.O..........
..OO........O............OO............OO.......OO..
.O.O.....................OO.....................O.O.
.O................................................O.
OO................................................OO

:century (stabilizes at time 103) This is a common pattern which evolves into three blocks and a blinker. In June 1996 Dave Buckingham built a neat p246 glider gun using a century as the engine. See also bookend and diuresis.


..OO
OOO.
.O..

:chemist (p5)


.......O.......
.......OOO.....
..........O....
.....OOO..O..OO
....O.O.O.O.O.O
....O...O.O.O..
.OO.O.....O.OO.
..O.O.O...O....
O.O.O.O.O.O....
OO..O..OOO.....
....O..........
.....OOO.......
.......O.......

:C-heptomino Name given by Conway to the following heptomino, a less common variant of the B-heptomino.


.OOO
OOO.
.O..

:Cheshire cat A block predecessor by C. R. Tompkins that unaccountably appeared both in Scientific American and in Winning Ways. See also grin.


.O..O.
.OOOO.
O....O
O.OO.O
O....O
.OOOO.

:chicken wire A type of stable agar of density 1/2. The simplest version is formed from the tile:


OO..
..OO
But the "wires" can have length greater than two and need not all be the same. For example:

OO...OOOO.....
..OOO....OOOOO

:cigar = mango

:cis-beacon on anvil (p2)


...OO.
....O.
.O....
.OO...
......
.OOOO.
O....O
.OOO.O
...O.OO

:cis-beacon on table (p2)


..OO
...O
O...
OO..
....
OOOO
O..O

:cis-boat with tail (p1)


.O...
O.O..
OO.O.
...O.
...OO

:cis fuse with two tails (p1) See also pulsar quadrant.


...O..
.OOO..
O...OO
.O..O.
..O.O.
...O..

:cis-mirrored R-bee (p1)


.OO.OO.
O.O.O.O
O.O.O.O
.O...O.

:cis snake = canoe

:clean Opposite of dirty. A reaction which produces a small number of different products which are desired or which are easily deleted is said to be clean. For example, a puffer which produces just one object per period is clean. Clean reactions are useful because they can be used as building blocks in larger constructions.

When a fuse is said to be clean, or to burn cleanly, this usually means that no debris at all is left behind.

:clock (p2) Found by Simon Norton, May 1970. This is the fifth or sixth most common oscillator, being about as frequent as the pentadecathlon, but much less frequent than the blinker, toad, beacon or pulsar. But it's surprisingly rare considering its small size.


..O.
O.O.
.O.O
.O..

:clock II (p4) Compare with pinwheel.


......OO....
......OO....
............
....OOOO....
OO.O....O...
OO.O..O.O...
...O..O.O.OO
...O.O..O.OO
....OOOO....
............
....OO......
....OO......

:cloud of smoke = smoke

:cloverleaf This name was given by Robert Wainwright to his p2 oscillator washing machine. But Achim Flammenkamp also gave this name to Achim's p4.

:cluster Any pattern in which each live cell is connected to every other live cell by a path that does not pass through two consecutive dead cells. This sense is due to Nick Gotts, but the term has also been used in other senses, often imprecise.

:CNWH Conweh, creator of the Life universe.

:Coe ship (c/2 orthogonally, p16) A puffer engine discovered by Tim Coe in October 1995.


....OOOOOO
..OO.....O
OO.O.....O
....O...O.
......O...
......OO..
.....OOOO.
.....OO.OO
.......OO.

:Coe's p8 (p8) Found by Tim Coe in August 1997.


OO..........
OO..OO......
.....OO.....
....O..O....
.......O..OO
.....O.O..OO

:colorized Life A cellular automaton which is the same as Life except for the use of a number of different ON states ("colours"). All ON states behave the same for the purpose of applying the Life rule, but additional rules are used to specify the colour of the resulting ON cells. Examples are Immigration and QuadLife.

:colour of a glider The colour of a glider is a property of the glider which remains constant while the glider is moving along a straight path, but which can be changed when the glider bounces off a reflector. It is an important consideration when building something using reflectors.

The colour of a glider can be defined as follows. First choose some cell to be the origin. This cell is then considered to be white, and all other cells to be black or white in a checkerboard pattern. (So the cell with coordinates (m,n) is white if m+n is even, and black otherwise.) Then the colour of a glider is the colour of its leading cell when it is in a phase which can be rotated to look like this:


OOO
..O
.O.

A reflector which does not change the colour of gliders obviously cannot be used to move a glider onto a path of different colour than it started on. But a 90-degree reflector which does change the colour of gliders is similarly limited, as the colour of the resulting glider will depend only on the direction of the glider, no matter how many reflectors are used. For maximum flexibility, therefore, both types of reflector are required.

:complementary blinker = fore and back

:compression = repeat time

:conduit Any arrangement of still lifes and/or oscillators which move an active object to another location, perhaps also transforming it into a different active object at the same time, but without leaving any permanent debris (except perhaps gliders, or other spaceships) and without any of the still lifes or oscillators being permanently damaged. Probably the most important conduit is the following remarkable one (Dave Buckingham, July 1996) in which a B-heptomino is transformed into a Herschel in 59 generations.


.........OO.O
O.OO......OOO
OO.O.......O.
.............
.........OO..
.........OO..

:confused eaters (p4) Found by Dave Buckingham before 1973.


O..........
OOO........
...O.......
..O........
..O..O.....
.....O.....
...O.O.....
...OO..OO..
.......O.O.
.........O.
.........OO

:converter A conduit in which the input object is not of the same type as the output object. This term tends to be preferred when either the input object or the output object is a spaceship.

The following diagram shows a p8 pi-heptomino-to-HWSS converter. This was originally found by Dave Buckingham in a larger form (using a figure-8 instead of the boat). The improvement shown here is by Bill Gosper (August 1996). Dieter Leithner has since found (much larger) oscillators of periods 44, 46 and 60 to replace the Kok's galaxy.


.O.O..O........
.OOO.O.OO......
O......O.....O.
.O.....OO...O.O
.............OO
OO.....O.......
.O......O......
OO.O.OOO.......
..O..O.O.......
............OOO
............O.O
............O.O

:convoy A collection of spaceships all moving in the same direction at the same speed.

:Corder- Prefix used for things involving switch engines, after Charles Corderman.

:Corder engine = switch engine

:Cordergun A gun firing Corderships. The first was built by Jason Summers in July 1999, using a glider synthesis by Stephen Silver.

:Cordership Any spaceship based on switch engines. These necessarily move at a speed of c/12 diagonally with a period of 96 (or a multiple thereof). The first was found by Dean Hickerson in April 1991. Corderships are the slowest spaceships so far constructed, although arbitrarily slow spaceships are known to exist (see universal constructor). Hickerson's original Cordership used 13 switch engines. He soon reduced this to 10, and in August 1993 to 7. In July 1998 he reduced it to 6. In January 2004, Paul Tooke found the 3-engine Cordership shown below.


................................OO.O...........................
...............................OOO.O......O.O..................
..............................O....O.O....O....................
...............................OO......O.O...O.................
................................O...O..O..OO...................
...................................O.OO...O....................
..................................O.O................OO........
..................................O.O................OO........
...............................................................
...............................................................
...............................................................
...............................................................
...............................................................
...............................................................
.............................................................OO
....................................................OO.......OO
.......................................O.........O.OOOO........
..................................O...OOOOO.....OO.O...OO......
.................................O.O.......OO....O..OO.OO......
.................................O.......O.OO.....OOOOOO.......
..................................O........OO......O...........
...................................O...OOOO....................
........................................OOO....................
........................O.O.........OO.........................
........................O.O.O......O.O.........................
.......................O..OO.O....OO...........................
........................OO...O.O.OO.O..........................
........................OO...OO.OOOOO..........................
............................O.OO...OO..........................
...........................O.O.................................
..OO.O.........................................................
.OOO.O......O.O................................................
O....O.O....O..................................................
.OO......O.O...O...............................................
..O...O..O..OO...........O.....................................
.....O.OO...O...........OOO....................................
....O.O.................O..O...................................
....O.O................O....O..................................
........................O......................................
...............................................................
........................O..O...................................
.........................O.O...................................
...............................................................
.....................O.........................................
....................OOO........................................
...................OO.OO.......................................
.........O........OO.O.....O...................................
....O...OOOOO....OO......OO....................................
...O.O.......OO..OO.......OO...................................
...O.......O.OO................................................
....O........OO................................................
.....O...OOOO..................................................
..........OOO..................................................
...............................................................
...............................................................
...............................................................
...........OO..................................................
...........OO..................................................

:cousins (p3) This contains two copies of the stillater rotor.


.....O.OO....
...OOO.O.O...
O.O......O...
OO.OO.OO.O.OO
...O.O....O.O
...O.O.OOO...
....OO.O.....

:cover The following induction coil. See scrubber for an example of its use.


....O
..OOO
.O...
.O...
OO...

:covered table = cap

:cow (c p8 fuse)


OO.......OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO.....
OO....O.OOO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO...OO
....OO.O.................................................O.O
....OO...OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO..
....OO.O..................................................O.
OO....O.OOO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO.
OO.......OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO.....

:CP pulsar = pulsar

:crane (c/4 diagonally, p4) The following spaceship found by Nicolay Beluchenko in September 2005, a minor modification of a tubeater found earlier by Hartmut Holzwart. The wing is of the same form as in the swan and Canada goose.


.OO.................
OO..................
..O.................
....OO...O..........
....OO..O.O.........
.......OO.O.........
.......OO...........
.......OO...........
.................OO.
.........O....OO.O..
.........OOO..OO....
.........OOO..OO....
..........OO........
....................
............O.......
...........OO.......
...........O........
............O.......
....................
.............OO.....
..............O.OO..
..................O.
...............OO...
...............OO...
.................O..
..................OO

:cross (p3) Found by Robert Wainwright in October 1989.


..OOOO..
..O..O..
OOO..OOO
O......O
O......O
OOO..OOO
..O..O..
..OOOO..
In February 1993, Hartmut Holzwart noticed that this is merely the smallest of an infinite family of p3 oscillators. The next smallest member is shown below.

..OOOO.OOOO..
..O..O.O..O..
OOO..OOO..OOO
O...........O
O...........O
OOO.......OOO
..O.......O..
OOO.......OOO
O...........O
O...........O
OOO..OOO..OOO
..O..O.O..O..
..OOOO.OOOO..

:crowd (p3) Found by Dave Buckingham in January 1973.


...........O..
.........OOO..
.....OO.O.....
.....O...O....
.......OO.O...
...OOOO...O...
O.O.....O.O.OO
OO.O.O.....O.O
...O...OOOO...
...O.OO.......
....O...O.....
.....O.OO.....
..OOO.........
..O...........

:crown The p12 part of the following p12 oscillator, where it is hassled by caterer, a jam and a HW emulator. This oscillator was found by Noam Elkies in January 1995.


..........O...........
..........O......O....
...O....O...O...OO....
...OO....OOO..........
.........OOO..OOO..O.O
.O..OOO.........O.OOOO
O.O.O...............OO
O..O..................
.OO........OO.........
......OO.O....O.OO....
......O..........O....
.......OO......OO.....
....OOO..OOOOOO..OOO..
....O..O........O..O..
.....OO..........OO...

:crucible = cauldron

:crystal A regular growth that is sometimes formed when a stream of gliders, or other spaceships, is fired into some junk.

The most common example is initiated by the following collision of a glider with a block. With a glider stream of even period at least 82, this gives a crystal which forms a pair beehives for every 11 gliders which hit it.


.O......
..O...OO
OOO...OO

:cuphook (p3) Found by Rich Schroeppel, October 1970. This is one of only three essentially different p3 oscillators with only three cells in the rotor. The others are 1-2-3 and stillater.


....OO...
OO.O.O...
OO.O.....
...O.....
...O..O..
....OO.O.
.......O.
.......OO
The above is the original form, but it can be made more compact:

....OO.
...O.O.
...O...
OO.O...
OO.O..O
...O.OO
...O...
..OO...

:curl = loop


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_r.htm0000644000175000017500000004216012536111364014337 00000000000000 Life Lexicon (R)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:R = R-pentomino

:R2D2 (p8) This was found, in the form shown below, by Peter Raynham in the early 1970s. The name derives from a form with a larger and less symmetric stator discovered by Noam Elkies in August 1994. Compare with Gray counter.


.....O.....
....O.O....
...O.O.O...
...O.O.O...
OO.O...O.OO
OO.O...O.OO
...O...O...
...O.O.O...
....O.O....
.....O.....

:r5 = R-pentomino

:rabbits (stabilizes at time 17331) A 9-cell methuselah found by Andrew Trevorrow in 1986.


O...OOO
OOO..O.
.O.....
The following predecessor, found by Trevorrow in October 1995, has the same number of cells and lasts two generations longer.

..O....O
OO......
.OO.OOO.

:rake Any puffer whose debris consists of spaceships. A rake is said to be forwards, backwards or sideways according to the direction of the spaceships relative to the direction of the rake. Originally the term "rake" was applied only to forwards c/2 glider puffers (see space rake). Many people prefer not to use the term in the case where the puffed spaceships travel parallel or anti-parallel to the puffer, as in this case they do not rake out any significant region of the Life plane (and, in contrast to true rakes, these puffers cannot travel in a stream, and so could never be produced by a gun).

Although the first rakes (circa 1971) were c/2, rakes of other velocities have since been built. Dean Hickerson's construction of Corderships in 1991 made it easy for c/12 diagonal rakes to be built, although no one actually did this until 1998, by which time David Bell had constructed c/3 and c/5 rakes (May 1996 and September 1997, respectively). Jason Summers constructed a 2c/5 rake in June 2000 (building on work by Paul Tooke and David Bell) and a c/4 orthogonal rake in October 2000 (based largely on reactions found by David Bell).

The smallest possible period for a rake is probably 7, as this could be achieved by a 3c/7 orthogonal backwards glider puffer. The smallest period attained to date is 8 (Jason Summers, March 2001) - see backrake.

:$rats (p6) Found by Dave Buckingham, 1972.


.....OO.....
......O.....
....O.......
OO.O.OOOO...
OO.O.....O.O
...O..OOO.OO
...O....O...
....OOO.O...
.......O....
......O.....
......OO....

:R-bee = bun

:receiver See Herschel receiver.

:reflector Any stable or oscillating pattern that can reflect some type of spaceship (usually a glider) without suffering permanent damage. The first known reflector was the pentadecathlon, which functions as a 180-degree glider reflector (see relay). Other examples include the buckaroo, the twin bees shuttle and some oscillators based on the traffic jam reaction. Glider guns can also be made into reflectors, although these are mostly rather large.

In September 1998 Noam Elkies found some fast small-period glider reflectors. The p8 version is shown below. Replacing the figure-8 by the p6 pipsquirter gives a p6 version. A more complicated construction allows a p5 version (which, as had been anticipated, soon led to a true p55 gun - see Quetzal). And in August 1999 Elkies found a suitable p7 sparker, allowing the first p49 oscillator to be constructed.


......OO.....OO..
O.O...OO.....O...
.OO........O.O...
.O.........OO....
.......OO........
.......O.O.......
........O........
.................
...........OOO...
...........OOO...
...........OOO...
..............OOO
..............OOO
..............OOO

Stable reflectors are special in that if they satisfy certain conditions they can be used to construct oscillators of all sufficiently large periods. It was known for some time that stable reflectors were possible (see universal constructor), but no one was able to construct an explicit example until Paul Callahan did so in October 1996.

All known stable reflectors are very slow. Callahan's original reflector has a repeat time of 4840, soon improved to 1686 and then 894 and then 850. In November 1996 Dean Hickerson found a variant in which this is reduced to 747. Dave Buckingham reduced it to 672 in May 1997 using a somewhat different method, and in October 1997 Stephen Silver reduced it to 623 by a method closer to the original. In November 1998 Callahan reduced this to 575 with a new initial reaction. A small modification by Silver a few days later brought this down to 497.

But in April 2001 Dave Greene found a 180-degree stable reflector with a repeat time of only 202 (see boojum reflector). This reflector also won the $100 prize that Dieter Leithner had offered in April 1997 for the first stable reflector to fit in a 50x50 box, and the additional $100 that Alan Hensel had offered in January 1999 for the same feat. Dave Greene has subsequently offered $50 for the first 90-degree stable glider reflector that fits in a 50x50 box, and a further $50 for the first in a 35x35 box.

See also glider turner.

:regulator An object which converts input gliders aligned to some period to output gliders aligned to a different period. The most interesting case is a universal regulator.

:relay Any oscillator in which spaceships (typically gliders) travel in a loop. The simplest example is the p60 one shown below using two pentadecathlons. Pulling the pentadecathlons further apart allows any period of the form 60+120n to be achieved - this is the simplest proof of the existence of oscillators of arbitrarily large period.


...........................O....O..
................OO.......OO.OOOO.OO
.................OO........O....O..
................O..................
..O....O...........................
OO.OOOO.OO.........................
..O....O...........................

:repeater Any oscillator or spaceship.

:repeat time The minimum number of generations that is possible between the arrival of one object and the arrival of the next. This term is used for things such as reflectors or conduits and the objects (gliders or Herschels, for example) will interact fatally with each other (or one will interact fatally with a disturbance caused by the other) if they are too close together. For example, the repeat time of Dave Buckingham's 59-step B-heptomino to Herschel conduit (shown under conduit) is 58.

:rephaser The following reaction that shifts the phase and path of a pair of gliders. There is another form of this reaction that reflects the gliders 180 degrees - see glider-block cycle.


..O..O..
O.O..O.O
.OO..OO.
........
........
...OO...
...OO...

:replicator A finite pattern which repeatedly creates copies of itself. Such objects are known to exist (see universal constructor), but no concrete example is known.

:reverse fuse A fuse that produces some initial debris, but then burns cleanly. The following is a simple example.


.............OO
............O.O
...........O...
..........O....
.........O.....
........O......
.......O.......
......O........
.....O.........
....O..........
...O...........
..O............
OO.............

:revolver (p2)


O............O
OOO....O...OOO
...O.O.O..O...
..O......O.O..
..O.O......O..
...O..O.O.O...
OOO...O....OOO
O............O

:ring of fire (p2) The following muttering moat found by Dean Hickerson in September 1992.


................O.................
..............O.O.O...............
............O.O.O.O.O.............
..........O.O.O.O.O.O.O...........
........O.O.O..OO.O.O.O.O.........
......O.O.O.O......O..O.O.O.......
....O.O.O..O..........O.O.O.O.....
.....OO.O..............O..O.O.O...
...O...O..................O.OO....
....OOO....................O...O..
..O.........................OOO...
...OO...........................O.
.O...O........................OO..
..OOOO.......................O...O
O.............................OOO.
.OOO.............................O
O...O.......................OOOO..
..OO........................O...O.
.O...........................OO...
...OOO.........................O..
..O...O....................OOO....
....OO.O..................O...O...
...O.O.O..O..............O.OO.....
.....O.O.O.O..........O..O.O.O....
.......O.O.O..O......O.O.O.O......
.........O.O.O.O.OO..O.O.O........
...........O.O.O.O.O.O.O..........
.............O.O.O.O.O............
...............O.O.O..............
.................O................

:rle Run-length encoded. Run-length encoding is a simple (but not very efficient) method of file compression. In Life the term refers to a specific ASCII encoding used for Life patterns (and patterns for other similar cellular automata). This encoding was introduced by Dave Buckingham and is now the usual means of exchanging Life patterns (especially large ones) by e-mail.

:rock Dean Hickerson's term for an eater which remains intact throughout the eating process. The snake in Dave Buckingham's 59-step B-to-Herschel conduit (shown under conduit) is an example. Other still lifes that sometimes act as rocks include the tub, the hook with tail, the eater1 (eating with its tail) and the hat (in Heinrich Koenig's stabilization of the twin bees shuttle).

:roteightor (p8) Found by Robert Wainwright in 1972.


.O............
.OOO........OO
....O.......O.
...OO.....O.O.
..........OO..
..............
.....OOO......
.....O..O.....
.....O........
..OO..O...O...
.O.O......O...
.O.......O....
OO........OOO.
............O.

:rotor The cells of an oscillator that change state. Compare stator. It is easy to see that any rotor cell must be adjacent to another rotor cell.

:R-pentomino This is by far the most active polyomino with less than six cells: all the others stabilize in at most 10 generations, but the R-pentomino does not do so until generation 1103, by which time it has a population of 116.


.OO
OO.
.O.

:rule 22 Wolfram's rule 22 is the 2-state 1-D cellular automaton in which a cell is ON in the next generation if and only if exactly one of its three neighbours is ON in the current generation (a cell being counted as a neighbour of itself). This is the behaviour of Life on a cylinder of width 1.

:ruler A pattern constructed by Dean Hickerson in May 2005 that produces a stream of LWSS with gaps in it, such that the number of LWSS between successive gaps follows the "ruler function" (sequence A001511 in The On-Line Encyclopedia of Integer Sequences).

:rumbling river Any oscillator in which the rotor is connected and contained in a strip of width 2. The following p3 example is by Dean Hickerson, November 1994.


..............OO......OO......OO...O.OO..........
....O........O..O....O..O....O..O..OO.O..........
O..O.O....O...OO..O...OO..O...O.O.....O.OO.......
OOOO.O..OOOOOO..OOOOOO..OOOOOO..OOOOOO.O.O.......
.....O.O.....O.O.....O.O.....O.O.....O.O......OO.
..OO.O.O.O.O...O.O.O...O.O.O...O.O.O...O.O.....O.
.O.....O.O...O.O.O...O.O.O...O.O.O...O.O.O.O.OO..
.OO......O.O.....O.O.....O.O.....O.O.....O.O.....
.......O.O.OOOOOO..OOOOOO..OOOOOO..OOOOOO..O.OOOO
.......OO.O.....O.O...O..OO...O..OO...O....O.O..O
..........O.OO..O..O....O..O....O..O........O....
..........OO.O...OO......OO......OO..............

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_l.htm0000644000175000017500000004524012536111364014333 00000000000000 Life Lexicon (L)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:lake Any still life consisting of a simple closed curve made from diagonally connected dominoes. The smallest example is the pond, and the next smallest is this (to which the term is sometimes restricted):


....OO....
...O..O...
...O..O...
.OO....OO.
O........O
O........O
.OO....OO.
...O..O...
...O..O...
....OO....

:Laputa (p2) Found by Rich Schroeppel, September 1992.


...OO.OO....
...OO.O...OO
........O..O
.OOOOOO.OOO.
O..O.O......
OO...O.OO...
....OO.OO...

:large S = big S

:Lidka (stabilizes at time 29053) A methuselah found by Andrzej Okrasinski in July 2005.


..........OOO..
..........O....
..........O...O
...........O..O
............OOO
...............
.O.............
O.O............
.O.............
The following variant, pointed out by David Bell, has two fewer cells and lasts two generations longer.

..........OOO..
...............
...........OO.O
............O.O
..............O
...............
.O.............
O.O............
.O.............

:Life A 2-dimensional 2-state cellular automaton discovered by John Conway in 1970. The states are referred to as ON and OFF (or live and dead). The transition rule is as follows: a cell that is ON will remain ON in the next generation if and only if exactly 2 or 3 of the 8 adjacent cells are also ON, and a cell that is OFF will turn ON if and only if exactly 3 of the 8 adjacent cells are ON. (This is more succinctly stated as: "If 2 of your 8 nearest neighbours are ON, don't change. If 3 are ON, turn ON. Otherwise, turn OFF.")

:Life32 A freeware Life program by Johan Bontes for Microsoft Windows 95/98/ME/NT/2000/XP: http://www.xs4all.nl/~jbontes/.

:LifeLab A shareware Life program by Andrew Trevorrow for the Macintosh (MacOS 8.6 or later): http://www.trevorrow.com/lifelab/.

:LifeLine A newsletter edited by Robert Wainwright from 1971 to 1973. During this period it was the main forum for discussions about Life. The newsletter was nominally quarterly, but the actual dates of its eleven issues were as follows:


Mar, Jun, Sep, Dec 1971
Sep, Oct, Nov, Dec 1972
Mar, Jun, Sep 1973

:Lifenthusiast A Life enthusiast. Term coined by Robert Wainwright.

:lifesrc David Bell's Life search program, for finding new spaceships and oscillators. This is a C implementation of an algorithm developed by Dean Hickerson in 6502 assembler. Most of the spaceships and many of the oscillators shown in this lexicon were found with lifesrc or by Hickerson's original program.

Although lifesrc itself is a command-line program, Jason Summers has made a GUI version called WinLifeSearch for Microsoft Windows.

The lifesrc algorithm is only useful for very small periods, as the amount of computing power required rises rapidly with increasing period. For most purposes, period 7 is the practical limit with current hardware.

Lifesrc is available from http://www.canb.auug.org.au/~dbell/ (source code only).

Compare gfind.

:light bulb (p2) Found in 1971.


.OO.O..
.O.OO..
.......
..OOO..
.O...O.
.O...O.
..O.O..
O.O.O.O
OO...OO
The same rotor can be embedded in a slightly smaller stator like this:

...O.....
.OOO.....
O........
OOOOOO...
......O..
..O...O..
..OO.O...
......OOO
........O

:lightspeed ribbon = superstring

:lightspeed wire Any wick that can burn non-destructively at the speed of light. These are potentially useful for various things, but so far no one has found the necessary mechanisms. The following diagram shows an example of a lightspeed wire, with a small defect that travels along it at the speed of light.


....OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO....
....OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO....
..........................................................
..OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO..
.O......O...............................................O.
O.OOOOO....OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.O
.O.....O................................................O.
..OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO..
..........................................................
....OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO....
....OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO....

:lightweight emulator = LW emulator

:lightweight spaceship = LWSS

:lightweight volcano = toaster

:line puffer A puffer which produces its output by means of an orthogonal line of cells at right angles to the direction of travel. The archetypal line puffer was found by Alan Hensel in March 1994, based on a spaceship found earlier that month by Hartmut Holzwart. The following month Holzwart found a way to make extensible c/2 line puffers, and Hensel found a much smaller stabilization the following day. But in October 1995 Tim Coe discovered that for large widths these were often unstable, although typically lasting millions of generations. In May 1996, however, Coe found a way to fix the instability. The resulting puffers appear to be completely stable and to exhibit an exponential increase in period as a function of width, although neither of these things has been proved.

Line puffers have enabled the construction of various difficult periods for c/2 spaceships and puffers, including occasionally periods which are not multiples of 4 and which would therefore be impossible to attain with the usual type of construction based on standard spaceships. (See frothing puffer for another method of constructing such periods.) In particular, the first c/2 rake with period not divisible by 4 was achieved in January 2000 when David Bell constructed a p42 backrake by means of line puffers.

See also hivenudger and puff suppressor.

:line ship A spaceship in which the front end is a linestretcher, the line being eaten by the back end.

:linestretcher A wickstretcher that stretches a single diagonal line of cells. The first example was constructed by Jason Summers in March 1999; this was c/12 and used switch engine based puffers found earlier by Dean Hickerson. The first c/4 example was found by Hartmut Holzwart in November 2004.

:loading dock (p3) Found by Dave Buckingham, September 1972.


....O....
..OOO....
.O...OO..
O.OO...O.
.O...OO.O
..OO...O.
....OOO..
....O....

:loaf (p1)


.OO.
O..O
.O.O
..O.

:loaflipflop (p15) Here four pentadecathlons hassle a loaf. Found by Robert Wainwright in 1990.


................O.................
...............OOO................
..................................
..................................
...............OOO................
..................................
...............O.O................
...............O.O................
..................................
...............OOO................
..................................
..................................
...............OOO................
................O.................
..................................
.O..O.OO.O..O...............OO....
OO..O....O..OO...OO.......O....O..
.O..O.OO.O..O...O..O.....O......O.
................O.O.....O........O
.................O......O........O
........................O........O
.........................O......O.
..........................O....O..
............................OO....
..................OOO.............
.................O...O............
................O.....O...........
..................................
...............O.......O..........
...............O.......O..........
..................................
................O.....O...........
.................O...O............
..................OOO.............

:loaf on loaf = bi-loaf

:loaf siamese barge (p1)


..OO.
.O..O
O.O.O
.O.O.
..O..

:LoM = lumps of muck

:lone dot agar An agar in which every live cell is isolated in every generation.

:lonely bee = worker bee

:long A term applied to an object that is of the same basic form as some standard object, but longer. For examples see long barge, long boat, long bookend, long canoe, long shillelagh, long ship and long snake.

:long^3 The next degree of longness after long long. Some people prefer "extra long".

:long^4 The next degree of longness after long^3. Some people prefer "extra extra long".

:long barge (p1)


.O...
O.O..
.O.O.
..O.O
...O.

:long boat (p1)


.O..
O.O.
.O.O
..OO

:long bookend The following induction coil, longer than a bookend.


...OO
O...O
OOOO.

:long canoe (p1)


....OO
.....O
....O.
...O..
O.O...
OO....

:long hat = loop

:long hook = long bookend

:long house = dock

:long integral (p1)


..OO
.O.O
.O..
..O.
O.O.
OO..

:long long The next degree of longness after long. Some people prefer "very long".

:long long barge (p1)


.O....
O.O...
.O.O..
..O.O.
...O.O
....O.

:long long boat (p1)


.O...
O.O..
.O.O.
..O.O
...OO

:long long canoe (p1)


.....OO
......O
.....O.
....O..
...O...
O.O....
OO.....

:long long ship (p1)


OO...
O.O..
.O.O.
..O.O
...OO

:long long snake (p1)


OO....
O.O...
...O.O
....OO

:long shillelagh (p1)


OO..OO
O..O.O
.OO...

:long ship (p1)


OO..
O.O.
.O.O
..OO

:long sinking ship = long canoe

:long snake (p1)


OO...
O.O.O
...OO

:loop (p1)


.OO..
O..O.
.O.O.
OO.OO

:low-density Life = sparse Life

:lumps of muck The common evolutionary sequence that ends in the blockade. The name is sometimes used of the blockade itself, and can in general be used of any stage of the evolution of the stairstep hexomino.

:LW emulator (p4) The smallest (and least useful) emulator, found by Robert Wainwright in June 1980.


..OO.O..O.OO..
..O........O..
...OO....OO...
OOO..OOOO..OOO
O..O......O..O
.OO........OO.

:LWSS (c/2 orthogonally, p4) A lightweight spaceship, the smallest known orthogonally moving spaceship, and the second most common (after the glider). Found by Conway in 1970. See also MWSS and HWSS.


.O..O
O....
O...O
OOOO

:LWSS emulator = LW emulator

:LWTDS Life Worker Time Deficiency Syndrome. Term coined by Dieter Leithner to describe the problem of having to divide scarce time between Life and real life.

:LW volcano = toaster


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex.htm0000644000175000017500000001726512536111364014026 00000000000000 Life Lexicon (Introduction)
Life Lexicon

Release 25, 2006 February 28
Multipage HTML version


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

INTRODUCTION
This is a lexicon of terms relating to John Horton Conway's Game of Life. It is also available in a single-page HTML version and an ASCII version.

This lexicon was compiled by Stephen A. Silver - see below for additional credits. See my web-site for contact information.

The latest versions of this lexicon (both HTML and ASCII) should be available from the Life Lexicon Home Page.

CREDITS
The largest single source for the early versions of this lexicon was a glossary compiled by Alan Hensel "with indispensable help from John Conway, Dean Hickerson, David Bell, Bill Gosper, Bob Wainwright, Noam Elkies, Nathan Thompson, Harold McIntosh, and Dan Hoey".

Other sources include the works listed in the bibliography at the end of this lexicon, as well as pattern collections by Alan Hensel and David Bell (and especially Dean Hickerson's file stamp.l in the latter collection), and the web sites of Mark Niemiec, Paul Callahan, Achim Flammenkamp, Robert Wainwright and Heinrich Koenig. Recent releases also use a lot of information from Dean Hickerson's header to his 1995 stamp file.

Most of the information on recent results is from the discoverers themselves.

The following people all provided useful comments on earlier releases of this lexicon: David Bell, Nicolay Beluchenko, Johan Bontes, Scot Ellison, Nick Gotts, Dave Greene, Alan Hensel, Dean Hickerson, Dieter Leithner, Mark Niemiec, Gabriel Nivasch, Andrew Okrasinski, Peter Rott, Ken Takusagawa, Andrew Trevorrow and Malcolm Tyrrell.

The format, errors, use of British English and anything else you might want to complain about are by Stephen Silver.

COPYING
This lexicon is copyright © Stephen Silver, 1997-2005. It may be freely copied and/or modified as long as due credit is given. This includes not just credit to those who have contributed in some way to the present version (see above), but also credit to those who have made any modifications.
LEXICOGRAPHIC ORDER
I have adopted the following convention: all characters (including spaces) other than letters and digits are ignored for the purposes of ordering the entries in this lexicon. (Many terms are used by some people as a single word, with or without a hyphen, and by others as two words. My convention means that I do not have to list these in two separate places. Indeed, I list them only once, choosing whichever form seems most common or sensible.) Digits lexicographically precede letters.
FORMAT
The diagrams in this lexicon are in a very standard format. You should be able to simply copy a pattern, paste it into a new file and run it in your favourite Life program. If you use Johan Bontes' Life32, Mirek Wojtowicz' MCell or Andrew Trevorrow and Tomas Rokicki's Golly then you can just paste the pattern directly into the Life program. I have restricted myself to diagrams of size 64x64 or less.

Most definitions that have a diagram have also some data in brackets after the keyword. Oscillators are maked as pn (where n is a positive integer), meaning that the period is n (p1 indicates a still life). Wicks are marked in the same way but with the word "wick" added. For spaceships the speed (as a fraction of c, the speed of light), the direction and the period are given. Fuses are marked with speed and period and have the word "fuse" added. Wicks and fuses are infinite in extent and so have necessarily been truncated, with the ends stabilized wherever practical.

SCOPE
This lexicon covers only Conway's Life, and provides no information about other cellular automata. David Bell has written articles on two other interesting cellular automata: HighLife (which is similar to Life, but has a tiny replicator) and Day & Night (which is very different, but exhibits many of the same phenomena). These articles can be found on his web-site.
ERRORS AND OMISSIONS
If you find any errors (including typos) or serious omissions, then please let me know.
NAMES
When deciding whether to use full or abbreviated forms of forenames I have tried, wherever possible, to follow the usage of the person concerned.
QUOTE
Every other author may aspire to praise; the lexicographer can only hope to escape reproach.    Samuel Johnson, 1775
DEDICATION
This lexicon is dedicated to the memory of Dieter Leithner, who died on 26 February 1999.
1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_n.htm0000644000175000017500000001671712536111364014344 00000000000000 Life Lexicon (N)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:natural Occurring often in random patterns. There is no precise measure of naturalness, since the most useful definition of "random" in this context is open to debate. Nonetheless, it is clear that objects such as blocks, blinkers, beehives and gliders are very natural, while eater2s, darts, guns, etc., are not.

:negentropy (p2) Compare Hertz oscillator.


...OO.O....
...O.OO....
...........
....OOO....
...O.O.O.OO
...OO..O.OO
OO.O...O...
OO.O...O...
....OOO....
...........
....OO.O...
....O.OO...

:neighbour Any of the eight cells adjacent to a given cell. A cell is therefore not considered to be a neighbour of itself, although the neighbourhood used in Life does in fact include this cell (see cellular automaton).

:new five (p3) Found by Dean Hickerson, January 1990.


..OO.....
.O..O....
.O.O..O..
OO.O.OO..
O........
.OOO.OOOO
.....O..O
O.OO.....
OO.OO....

:new gun An old name for the second known basic gun (found, like the first, by Bill Gosper), shown below. A number of other ways of constructing a gun from two twin bees shuttles have since been found - see edge shooter for one of these.


.........................OO.....OO
.........................OO.....OO
..................................
..................................
..................................
..................................
..................................
..................................
..................................
..................................
..................................
..................................
..................................
...........................OO.OO..
..........................O.....O.
..................................
.........................O.......O
.........................O..O.O..O
.........................OOO...OOO
..................................
..................................
..................................
..................................
.................O................
OO...............OO...............
OO................OO..............
.............OO..OO...............
..................................
..................................
..................................
.............OO..OO...............
OO................OO.......OO.....
OO...............OO........OO.....
.................O................

:Noah's ark The following diagonal puffer consisting of two switch engines. This was found by Charles Corderman in 1971. The name comes from the variety of objects it leaves behind: blocks, blinkers, beehives, loaves, gliders, ships, boats, long boats, beacons and block on tables.


..........O.O..
.........O.....
..........O..O.
............OOO
...............
...............
...............
...............
...............
.O.............
O.O............
...............
O..O...........
..OO...........
...O...........

See also ark.

:n-omino Any polyomino with exactly n cells.

:non-monotonic A spaceship is said to be non-monotonic if its leading edge falls back in some generations. The first example (shown below) was found by Hartmut Holzwart in August 1992. This is p4 and travels at c/4. In April 1994, Holzwart found examples of p3 spaceships with this property, and this is clearly the smallest possible period. Another non-monotonic spaceship is the weekender.


..........OO.O.......
......OOO.O.OOO......
..O.O..........O...OO
OO....OO.....O...OOOO
..O.OO..O....OOO.O...
........O....O.......
..O.OO..O....OOO.O...
OO....OO.....O...OOOO
..O.O..........O...OO
......OOO.O.OOO......
..........OO.O.......

:non-spark Something that looks like a spark, but isn't. An OWSS produces one of these instead of a belly spark, and is destroyed by it.

:non-standard spaceship Any spaceship other than a glider, LWSS, MWSS or HWSS.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_x.htm0000644000175000017500000000652712536111364014354 00000000000000 Life Lexicon (X)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:x66 (c/2 orthogonally, p4) Found by Hartmut Holzwart, July 1992. Half of this can be escorted by a HWSS. The name refers to the fact that every cell (live or dead) has at most 6 live neighbours (in contrast to spaceships based on LWSS, MWSS or HWSS). In fact this spaceship was found by a search with this restriction.


..O......
OO.......
O..OOO..O
O....OOO.
.OOO..OO.
.........
.OOO..OO.
O....OOO.
O..OOO..O
OO.......
..O......

:Xlife A popular freeware Life program that runs under the X Window System. The main Life code was written by Jon Bennett, and the X code by Chuck Silvers.

:X-pentomino Conway's name for the following pentomino, a traffic light predecessor.


.O.
OOO
.O.

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_t.htm0000644000175000017500000011322612536111364014343 00000000000000 Life Lexicon (T)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:T = T-tetromino

:table The following induction coil.


OOOO
O..O

:table on table (p1)


O..O
OOOO
....
OOOO
O..O

:tag = tagalong

:tagalong An object which is not a spaceship in its own right, but which can be attached to one or more spaceships to form a larger spaceship. For examples see Canada goose, fly, pushalong, sidecar and sparky. See also Schick engine, which consists of a tagalong attached to two LWSS (or similar).

:tail spark A spark at the back of a spaceship. For example, the 1-bit spark at the back of a LWSS, MWSS or HWSS in their less dense phases.

:tame To perturb a dirty reaction using other patterns so as to make it clean and hopefully useful. Or to make a reaction work which would otherwise fail due to unwanted products which interfere with the reaction.

:taming See tame.

:teardrop The following induction coil, or the formation of two beehives that it evolves into after 20 generations. (Compare butterfly, where the beehives are five cells further apart.)


OOO.
O..O
O..O
.OO.

:technician (p5) Found by Dave Buckingham, January 1973.


.....O.....
....O.O....
....OO.....
..OO.......
.O...OOO...
O..OO...O.O
.OO....O.OO
...O.O.O...
...O...O...
....OOO....
......O.O..
.......OO..

:technician finished product = technician

:teeth A 65-cell quadratic growth pattern found by Nick Gotts in March 2000. This (and a related 65-cell pattern which Gotts found at about the same time) beat the record previously held by mosquito5 for smallest population known to have superlinear growth. Now superseded by catacryst and metacatacryst.

:ternary reaction Any reaction between three objects. In particular, a reaction in which two gliders from one stream and one glider from a crossing stream of the same period annihilate each other. This can be used to combine two glider guns of the same period to produce a new glider gun with double the period.

:test tube baby (p2)


OO....OO
O.O..O.O
..O..O..
..O..O..
...OO...

:tetraplet Any 4-cell polyplet.

:tetromino Any 4-cell polyomino. There are five such objects, shown below. The first is the block, the second is the T-tetromino and the remaining three rapidly evolve into beehives.


OO......OOO......OOOO......OOO......OO.
OO.......O...................O.......OO

:The Recursive Universe A popular science book by William Poundstone (1985) dealing with the nature of the universe, illuminated by parallels with the game of Life. This book brought to a wider audience many of the results that first appeared in LifeLine. It also outlines the proof of the existence of a universal constructor in Life first given in Winning Ways.

:thumb A spark-like protrusion which flicks out in a manner resembling a thumb being flicked.

Here are two examples. On the left is a p9 thumb sparker found by Dean Hickerson in October 1998. On the right is a p4 one found by David Eppstein in June 2000.


.......O..............O.....
...OO...O.........OO...O....
...O.....O.OO.....O.....O...
OO.O.O......O......OOO.O.OO.
OO.O.OO.OOOO............OO.O
...O.O...........OOOOOO....O
...O.O.OOO.......O....OOOOO.
....O.O...O.........O.......
......O..OO........O.OOOO...
......OO...........O.O..O...
....................O.......

:thunderbird (stabilizes at time 243)


OOO
...
.O.
.O.
.O.

:tick = generation

:tie A term used in naming certain still lifes (and the stator part of certain oscillators). It indicates that the object consists of two smaller objects joined point to point, as in ship tie boat.

:time bomb The following pattern by Doug Petrie, which is really just a glider-producing switch engine in disguise. See infinite growth for some better examples of a similar nature.


.O...........OO
O.O....O......O
.......O....O..
..O..O...O..O..
..OO......O....
...O...........

:titanic toroidal traveler The superstring with the following repeating segment. The front part becomes p16, but the eventual fate of the detached back part is unknown.


OOOOOO
OOO...

:TL = traffic light

:T-nosed p4 (p4) Found by Robert Wainwright in October 1989. See also filter.


.....O.....
.....O.....
....OOO....
...........
...........
...........
...OOOOO...
..O.OOO.O..
..O.O.O.O..
.OO.O.O.OO.
O..OO.OO..O
OO.......OO

:T-nosed p6 (p6) Found by Achim Flammenkamp in September 1994. There is also a much larger and fully symmetric version found by Flammenkamp in August 1994.


......OO...OO......
......O.O.O.O......
.......O...O.......
...................
..O.O.O.....O.O.O..
OOO.O.OO...OO.O.OOO
..O.O.O.....O.O.O..
...................
.......O...O.......
......O.O.O.O......
......OO...OO......

:toad (p2) Found by Simon Norton, May 1970. This is the second most common oscillator, although blinkers are more than a hundred times as frequent. See also killer toads.


.OOO
OOO.

:toad-flipper A toad hassler that works in the manner of the following example. Two domino sparkers, here pentadecathlons, apply their sparks to the toad in order to flip it over. When the sparks are applied again it is flipped back. Either or both domino sparkers can be moved down two spaces from the position shown and the toad-flipper will still work, but because of symmetry there are really only two different types. Compare toad-sucker.


.O..............O.
.O..............O.
O.O............O.O
.O..............O.
.O......O.......O.
.O......OO......O.
.O......OO......O.
O.O......O.....O.O
.O..............O.
.O..............O.

:toad-sucker A toad hassler that works in the manner of the following example. Two domino sparkers, here pentadecathlons, apply their sparks to the toad in order to shift it. When the sparks are applied again it is shifted back. Either or both domino sparkers can be moved down two spaces from the position shown and the toad-sucker will still work, but because of symmetry there are really only three different types. Compare toad-flipper.


.O................
.O..............O.
O.O.............O.
.O.............O.O
.O......O.......O.
.O......OO......O.
.O......OO......O.
O.O......O......O.
.O.............O.O
.O..............O.
................O.

:toaster (p5) Found by Dean Hickerson, April 1992.


....O......OO..
...O.O.OO..O...
...O.O.O.O.O...
..OO.O...O.OO..
O...OO.O.OO...O
...O.......O...
...O.......O...
O...OO.O.OO...O
..OO.O...O.OO..
...O.O.O.O.O...
...O.O.OO..O...
....O......OO..

:torus As applies to Life, usually means a finite Life universe which takes the form of an m x n rectangle with the bottom edge considered to be joined to the top edge and the left edge joined to the right edge, so that the universe is topologically a torus. There are also other less obvious ways of obtaining an toroidal universe.

See also Klein bottle.

:total aperiodic Any finite pattern which evolves in such a way that no cell in the Life plane is eventually periodic. The first example was found by Bill Gosper in November 1997. A few days later he found the following much smaller example consisting of three copies of a p12 backrake by Dave Buckingham.


.........................................O.................
........................................OOO................
.......................................OO.O.....O..........
.......................................OOO.....OOO.........
........................................OO....O..OO...OOO..
..............................................OOO....O..O..
........................................................O..
........................................................O..
........................................................O..
........................................OOO............O...
........................................O..O...............
........................................O..................
........................................O..................
.........................................O.................
...........................................................
...........................................................
...........................................................
...........................................................
...........................................................
...........................................................
......................................OOO..................
......................................O..O...........O.....
......................................O.............OOO....
......................................O............OO.O....
......................................O............OOO.....
.......................................O............OO.....
...........................................................
...........................................................
...................................OOO.....................
..................................OOOOO....................
..................................OOO.OO.......OO........O.
.....................................OO.......OOOO........O
..............................................OO.OO...O...O
................................................OO.....OOOO
...........................................................
...........................................................
....................O......................................
.....................O.....................................
.OO.............O....O................................OOO..
OOOO.............OOOOO..................................O..
OO.OO...................................................O..
..OO...................................................O...
....................................O......................
.....................................O.....................
.....................OO..........O...O.....................
......................OO..........OOOO...............OO....
.....................OO...........................OOO.OO...
.....................O............................OOOOO....
...................................................OOO.....
...........................................................
......................OO...................................
.............OOOO....OOOO..................................
............O...O....OO.OO.................................
.OOOOO..........O......OO..................................
O....O.........O...........................................
.....O.....................................................
....O......................................................

:T-pentomino Conway's name for the following pentomino, which is a common parent of the T-tetromino.


OOO
.O.
.O.

:track A path made out of conduits, often ending where it begins so that the active object is cycled forever, forming an oscillator or a gun.

:tractor beam A stream of spaceships that can draw an object towards the source of the stream. The example below shows a tractor beam pulling a loaf; this was used by Dean Hickerson to construct a sawtooth.


.....................O..O......................
.....OOOO...........O..............OOOO........
.....O...O..........O...O..........O...O.......
.....O........OO....OOOO...........O........OO.
.OO...O..O...OOOO...........OO......O..O...OOOO
O..O........OO.OO..........OO.OO..........OO.OO
O.O..........OO.............OOOO...........OO..
.O...........................OO................

:traffic circle (p100)


.....................OO....OO...................
.....................O.O..O.O...................
.......................O..O.....................
......................OO..OO....................
.....................OOO..OOO...................
.......................O..O.....................
...............................O................
..............................O.OO..............
..................................O.............
..........................O...O..O.O............
..........................O.....O..O............
..........................O......OO.............
.........OO.....................................
........O..O..........OOO...OOO.................
.......O.O.O....................................
......OOO.O...............O.....................
......OOO.................O.....................
..........................O.....................
............OOO.................................
OO..O................OOO........................
O..OO.....O.....O...............................
.OOOOO....O.....O..O.....O.................O..OO
..........O.....O..O.....O.................OO..O
...................O.....O.......OOO......OOOOO.
.OOOOO......OOO.................................
O..OO................OOO.......O.....O..........
OO..O..........................O.....O....OOOOO.
...............................O.....O.....OO..O
...........................................O..OO
.................................OOO............
.......................................OO.......
......................................OOO.......
.....................................O.OO.......
....................................O.O.........
....................OOO.............O..O........
.....................................OO.........
.............OO....O..O.........................
............O..O................................
............O.O.O...............................
.............O..O...............................
.................O..............................
..............O.O...............................
.....................O..O.......................
...................OOO..OOO.....................
....................OO..OO......................
.....................O..O.......................
...................O.O..O.O.....................
...................OO....OO.....................

:traffic jam Any traffic light hassler, such as traffic circle. The term is also applied to the following reaction, used in most traffic light hasslers, in which two traffic lights interact in such a way as to reappear after 25 generations with an extra 6 spaces between them.


..OOO...........
...........OOO..
O.....O.........
O.....O..O.....O
O.....O..O.....O
.........O.....O
..OOO...........
...........OOO..

:traffic light (p2) A common formation of four blinkers.


..OOO..
.......
O.....O
O.....O
O.....O
.......
..OOO..

:trans-beacon on table (p2)


....OO
.....O
..O...
..OO..
......
OOOO..
O..O..

:trans-boat with tail (p1)


OO...
O.O..
.O.O.
...O.
...OO

:transceiver See Herschel transceiver.

:trans-loaf with tail (p1)


.O....
O.O...
O..O..
.OO.O.
....O.
....OO

:transmitter See Herschel transmitter.

:transparent block reaction A certain reaction between a block and a Herschel predecessor in which the block reappears in its original place some time later, the reaction having effectively passed through it. This reaction was found by Dave Buckingham in 1988. It has been used in some Herschel conduits, and in the gunstars. Because the reaction involves a Herschel predecessor rather than an actual Herschel, the following diagram shows instead a B-heptomino (which by itself would evolve into a block and a Herschel).


O.............
OO..........OO
.OO.........OO
OO............

:transparent debris effect A reaction in which a Herschel or other active region destroys a still life, then later, having passed through the place where the still life was, recreates the still life in its original position. For an example, see transparent block reaction.

:trice tongs (p3) Found by Robert Wainwright, February 1982. In terms of its 7x7 bounding box this ties with jam as the smallest p3 oscillator.


..O....
..OOO..
OO...O.
.O.O.O.
.O.....
..OO..O
.....OO

:triomino Either of the two 3-cell polyominoes. The term is rarely used in Life, since the two objects in question are simply the blinker and the pre-block.

:triple caterer (p3) Found by Dean Hickerson, October 1989. Compare caterer and double caterer.


.....OO.........
....O..O..OO....
....OO.O...O....
......O.OOO....O
..OOO.O.O....OOO
.O..O..O....O...
O.O..O...O..OO..
.O..............
..OO.OO.OO.OO...
...O...O...O....
...O...O...O....

:triplet Any 3-cell polyplet. There are 5 such objects, shown below. The first two are the two triominoes, and the other three vanish in two generations.


O..................O.......O.......O..
OO......OOO......OO.......O.O.......O.
.....................................O

:tripole (p2) The barberpole of length 3.


OO....
O.O...
......
..O.O.
.....O
....OO

:tritoad (p3) Found by Dave Buckingham, October 1977.


.........OO.......
.........O........
..........O..OO...
.......OOO.O..O...
......O....OO.O.OO
......O.OO..O.O.OO
...OO.O...OO..O...
...O..OO...O.OO...
OO.O.O..OO.O......
OO.O.OO....O......
...O..O.OOO.......
...OO..O..........
........O.........
.......OO.........

:true Opposite of pseudo. A gun emitting a period n stream of spaceships (or rakes) is said to be a true period n gun if its mechanism oscillates with period n. (The same distinction between true and pseudo also exists for puffers.) True period n guns are known to exist for all periods greater than 61 (see My Experience with B-heptominos in Oscillators), but only a few smaller periods have been achieved, namely 22, 24, 30, 36, 44, 46, 48, 50, 54, 55, 56 and 60. (Credits for these small period guns are: p30, p46 and p60 by Bill Gosper in 1970-1971, p44 by Dave Buckingham in 1992, p50 by Dean Hickerson in 1996, p24 and p48 by Noam Elkies in 1997, p54 and p56 by Dieter Leithner in early 1998, p55 by Stephen Silver in late 1998, p22 by David Eppstein in 2000 and p36 by Jason Summers in 2004.)

The following diagram shows the p22 gun (David Eppstein, August 2000, using two copies of a p22 oscillator found earlier the same day by Jason Summers).


..................OO.........................
...................O.......O.................
...................O.O..............OO.......
....................OO............OO..O......
........................OOO.......OO.OO......
........................OO.OO.......OOO......
........................O..OO............OO..
.........................OO..............O.O.
...................................O.......O.
...........................................OO
.............................................
OO.......................O...................
.O.....................O.O...................
.O.O.............OOO....OO...................
..OO...O........O...O........................
......O.OO......O....O.......................
.....O....O......OO.O.........O..............
......O...O........O...OO......O.............
.......OOO.............O.O...OOO.............
.........................O...................
.........................OO..................

:T-tetromino The following common predecessor of a traffic light.


OOO
.O.

:tub (p1)


.O.
O.O
.O.

:tubber (p3) Found by Robert Wainwright before June 1972.


....O.O......
....OO.O.....
.......OOO...
....OO....O..
OO.O..OO..O..
.O.O....O.OO.
O...O...O...O
.OO.O....O.O.
..O..OO..O.OO
..O....OO....
...OOO.......
.....O.OO....
......O.O....

:tubeater A pattern that consumes the output of a tubstretcher. The smallest known tubeater was found by Hartmut Holzwart, and is shown below in conjunction with the smallest known tubstretcher.


.......OO.........................
.......O.O........................
.......O..........................
..........O.......................
..........OO......................
..........OO......................
.........OO.......................
OO......OO...O....................
O.O...OO..O.O.O...................
O.....OOO....O.O..................
...O..........O.O.................
...OO..........O.O................
................O.O...............
.................O.O...O..........
..................OO..O.O.........
.....................OO.O.........
.....................OO...........
.....................OO...........
...............................OO.
.......................O....OO.O..
.......................OOO..OO....
.......................OOO..OO....
........................OO........
..................................
..........................O.......
.........................OO.......
.........................O........
..........................O.......
..................................
...........................OO.....
............................O.OO..
................................O.
.............................OO...
.............................OO...
...............................O..
................................OO

:tubstretcher Any wickstretcher in which the wick is two diagonal lines of cells forming, successively, a tub, a barge, a long barge, etc. The first one was found by Hartmut Holzwart in June 1993, although at the time this was considered to be a boatstretcher (as it was shown with an extra cell, making the tub into a boat). The following small example is by Nicolay Beluchenko (August 2005), using a quarter.


.......OOO.....
.......O.......
........O......
..........OO...
...........O...
...............
........OO...O.
OOO.....OO..O.O
O......O.O...O.
.O....OO.......
...OOOO.O......
....OO.........

:tub with tail (p1)


.O...
O.O..
.O.O.
...O.
...OO

:tugalong = tagalong

:tumbler (p14) The smallest known p14 oscillator. Found by George Collins in 1970.


.O.....O.
O.O...O.O
O..O.O..O
..O...O..
..OO.OO..

:tumbling T-tetson (p8) A T-tetromino hassled by two figure-8s. Found by Robert Wainwright.


.OOO.................
O..................OO
O...O............O.OO
O..O.O..........O....
..O.O..O...........O.
...O...O.......OO.O..
.......O.......OO....
....OOO....O.........
.........OO..........
...........O.........

:Turing machine See universal computer.

:turning toads (p4 wick) Found by Dean Hickerson, October 1989.


..............OO.....OO.....OO.....OO.....OO..............
.......O.....O......O......O......O......O................
......OO...O....O.O....O.O....O.O....O.O....O.O.O.OO......
..OO.O.OOO.O..OO..O..OO..O..OO..O..OO..O..OO..O..O..O.OO..
O..O.OO.........................................OOOOO.O..O
OO.O..............................................OO..O.OO
...O..................................................O...
...OO................................................OO...

:turtle (c/3 orthogonally, p3) Found by Dean Hickerson.


.OOO.......O
.OO..O.OO.OO
...OOO....O.
.O..O.O...O.
O....O....O.
O....O....O.
.O..O.O...O.
...OOO....O.
.OO..O.OO.OO
.OOO.......O

:twin bees shuttle (p46) Found by Bill Gosper in 1971, this is the basis of all known p46 oscillators, and so of all known true p46 guns (see new gun for an example). There are numerous ways to stabilize the ends, two of which are shown in the diagram. On the left is David Bell's double block reaction (which results in a shorter, but wider, shuttle than usual), and on the right is the stabilization by a single block. This latter method produces a very large spark which is useful in a number of ways (see, for example, metamorphosis). Adding a symmetrically placed block below this one suppresses the spark. See also p54 shuttle.


.OO........................
.OO........................
...........................
...............O...........
OO.............OO........OO
OO..............OO.......OO
...........OO..OO..........
...........................
...........................
...........................
...........OO..OO..........
OO..............OO.........
OO.............OO..........
...............O...........
...........................
.OO........................
.OO........................

:twinhat (p1) See also hat and sesquihat.


..O...O..
.O.O.O.O.
.O.O.O.O.
OO.O.O.OO
....O....

:twin peaks = twinhat

:twirling T-tetsons II (p60) Found by Robert Wainwright. This is a pre-pulsar hassled by killer toads.


.......OO...OO..........
......O.......O.........
.........O.O............
.......OO...OO..........
........................
........................
........................
.....................OOO
....................OOO.
.............O..........
OOO.........OOO.........
.OOO....................
....................OOO.
.....................OOO
........................
.OOO....................
OOO.........OOO.........
.............O..........
........................
........................
..........OO...OO.......
............O.O.........
.........O.......O......
..........OO...OO.......

:TWIT = tub with tail

:two eaters (p3) Found by Bill Gosper, September 1971.


OO.......
.O.......
.O.O.....
..OO.....
.....OO..
.....O.O.
.......O.
.......OO

:two pulsar quadrants (p3) Found by Dave Buckingham, July 1973. Compare pulsar quadrant.


....O....
....O....
...OO....
..O......
O..O..OOO
O...O.O..
O....O...
.........
..OOO....

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_q.htm0000644000175000017500000001716012536111364014340 00000000000000 Life Lexicon (Q)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Q = Quetzal

:Q-pentomino Conway's name for the following pentomino, a traffic light predecessor.


OOOO
...O

:quad (p2) Found by Robert Kraus, April 1971. Of all oscillators that fit in a 6x6 box this is the only flipper.


OO..OO
O..O.O
.O....
....O.
O.O..O
OO..OO

:QuadLife A form of colorized Life in which there are four types of ON cell. A newly-born cell takes the type of the majority of its three parent cells, or the remaining type if its parent cells are all of different types. In areas where there are only two types of ON cell QuadLife reduces to Immigration.

:quadpole (p2) The barberpole of length 4.


OO.....
O.O....
.......
..O.O..
.......
....O.O
.....OO

:quapole = quadpole

:quarter (c/4 diagonally, p4) The following 25-cell spaceship, found by Jason Summers in September 2000. See also tubstretcher.


........OO...
.......OO....
.........O...
...........OO
..........O..
.............
.........O..O
.OO.....OO...
OO.....O.....
..O....O.O...
....OO..O....
....OO.......

:quasar (p3) Found by Robert Wainwright, August 1971. See pulsar.


..........OOO...OOO..........
.............................
........O....O.O....O........
........O....O.O....O........
........O....O.O....O........
..........OOO...OOO..........
.............................
........OOO.......OOO........
..OOO..O....O...O....O..OOO..
.......O....O...O....O.......
O....O.O....O...O....O.O....O
O....O.................O....O
O....O..OOO.......OOO..O....O
..OOO...................OOO..
.............................
..OOO...................OOO..
O....O..OOO.......OOO..O....O
O....O.................O....O
O....O.O....O...O....O.O....O
.......O....O...O....O.......
..OOO..O....O...O....O..OOO..
........OOO.......OOO........
.............................
..........OOO...OOO..........
........O....O.O....O........
........O....O.O....O........
........O....O.O....O........
.............................
..........OOO...OOO..........

:queen bee See queen bee shuttle.

:queen bee shuttle (p30) Found by Bill Gosper in 1970. There are a number of ways to stabilize the ends. Gosper originally stabilized shuttles against one another in a square of eight shuttles. Two simpler methods are shown here; for a third see buckaroo. The queen bee shuttle is the basis of all known true p30 guns (see Gosper glider gun).


.........O............
.......O.O............
......O.O.............
OO...O..O.............
OO....O.O.............
.......O.O........OO..
.........O........O.O.
....................O.
....................OO

:Quetzal Dieter Leithner's name for the true p54 glider gun he built in January 1998. (This is short for Quetzalcoatlus and expresses the fact that the gun was a very large Herschel loop that was not an emu.) Shortly afterwards Leithner also built a p56 Quetzal using a mechanism found by Noam Elkies for this purpose. In October 1998 Stephen Silver constructed a p55 Quetzal using Elkies' p5 reflector of the previous month.

Some of the more recent Quetzals are not Herschel loops, but are instead short Herschel tracks firing several glider streams all but one of which is reflected back to the beginning of the track to create a new Herschel. Noam Elkies first had the idea of doing this for the p55 case, and Stephen Silver constructed the resulting gun shortly after building the original (much larger) p55 Quetzal. Jason Summers later built a p54 version, which is more complicated because the evenness of the period makes the timing problems considerably more difficult.

:Quetzalcoatlus A giant flying dinosaur after which Dieter Leithner named his p54 gun. Usually abbreviated to Quetzal, or simply Q (as in Q54, Q55, Q56, Q-gun, etc.).

:quilt = squaredance


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_1.htm0000644000175000017500000001063412536111364014237 00000000000000 Life Lexicon (1)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:101 (p5) Found by Achim Flammenkamp in August 1994. The name was suggested by Bill Gosper, noting that the phase shown below displays the period in binary.


....OO......OO....
...O.O......O.O...
...O..........O...
OO.O..........O.OO
OO.O.O..OO..O.O.OO
...O.O.O..O.O.O...
...O.O.O..O.O.O...
OO.O.O..OO..O.O.OO
OO.O..........O.OO
...O..........O...
...O.O......O.O...
....OO......OO....

:1-2-3 (p3) Found by Dave Buckingham, August 1972. This is one of only three essentially different p3 oscillators with only three cells in the rotor. The others are stillater and cuphook.


..OO......
O..O......
OO.O.OO...
.O.O..O...
.O....O.OO
..OOO.O.OO
.....O....
....O.....
....OO....

:1-2-3-4 (p4) See also Achim's p4.


.....O.....
....O.O....
...O.O.O...
...O...O...
OO.O.O.O.OO
O.O.....O.O
...OOOOO...
...........
.....O.....
....O.O....
.....O.....

:14-ner = fourteener

:2 eaters = two eaters

:4-8-12 diamond The following pure glider generator.


....OOOO....
............
..OOOOOOOO..
............
OOOOOOOOOOOO
............
..OOOOOOOO..
............
....OOOO....

:4 boats (p2)


...O....
..O.O...
.O.OO...
O.O..OO.
.OO..O.O
...OO.O.
...O.O..
....O...

:4F = Fast Forward Force Field


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_y.htm0000644000175000017500000000462112536111364014346 00000000000000 Life Lexicon (Y)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Y-pentomino Conway's name for the following pentomino, which rapidly dies.


..O.
OOOO

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_b.htm0000644000175000017500000010634712536111364014327 00000000000000 Life Lexicon (B)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:B = B-heptomino

:B29 (c/4 diagonally, p4) The following spaceship, found by Hartmut Holzwart in September 2004.


.......OOO.......
.......O.........
OOO......O.......
O......O.O.......
.O....OO.OOOO....
...OOOO.OOOOO.OO.
....OO.......OO.O

:B-52 bomber The following p104 double-barrelled glider gun. It uses a B-heptomino and emits one glider every 52 generations. It was found by Noam Elkies in March 1996, except that Elkies used blockers instead of molds, the improvement being found by David Bell later the same month.


.OO....................................
.OO.................O..................
...................O.O............O.O..
....................O............O.....
OO.......OO.......................O..O.
OO.O.....OO.......................O.O.O
...O.......................O.......O..O
...O.......................OO.......OO.
O..O.................OO.....O..........
.OO..................O.................
.....................OOO...............
....................................OO.
....................................OO.
.OO....................................
O..O...................................
O.O.O................O.O....OO.....OO..
.O..O.................OO....OO.....OO.O
.....O............O...O...............O
..O.O............O.O..................O
..................O................O..O
....................................OO.

:babbling brook Any oscillator whose rotor consists of a string of cells each of which is adjacent to exactly two other rotor cells, except for the endpoints which are adjacent to only one other rotor cell. Compare muttering moat. Examples include the beacon, the great on-off, the light bulb and the spark coil. The following less trivial example (by Dean Hickerson, August 1997) is the only one known with more than four cells in its rotor. It is p4 and has a 6-cell rotor.


.......O........
.....OOO....OO..
....O...OO..O...
.O..O.OO..O.O...
O.O.O....OO..OO.
.OO..OO....O.O.O
...O.O..OO.O..O.
...O..OO...O....
..OO....OOO.....
........O.......

:backrake Another term for a backwards rake. A p8 example by Jason Summers is shown below. See total aperiodic for a p12 example.


.....OOO...........OOO.....
....O...O.........O...O....
...OO....O.......O....OO...
..O.O.OO.OO.....OO.OO.O.O..
.OO.O....O.OO.OO.O....O.OO.
O....O...O..O.O..O...O....O
............O.O............
OO.......OO.O.O.OO.......OO
............O.O............
......OOO.........OOO......
......O...O.........O......
......O.O....OOO...........
............O..O....OO.....
...............O...........
...........O...O...........
...........O...O...........
...............O...........
............O.O............

:backward glider A glider which moves at least partly in the opposite direction to the puffer(s) or spaceship(s) under consideration.

:baker (c p4 fuse) A fuse by Keith McClelland.


..............OO
.............O.O
............O...
...........O....
..........O.....
.........O......
........O.......
.......O........
......O.........
.....O..........
....O...........
...O............
OOO.............
.O..............

:baker's dozen (p12) A loaf hassled by two blocks and two caterers. The original form (using p4 and p6 oscillators to do the hassling) was found by Robert Wainwright in August 1989.


OO.........OO..........
OOOO.O.....OO..........
O.O..OOO...............
...........O...........
....OO....O.O..........
....O.....O..O....O....
...........OO....OO....
.......................
...............OOO..O.O
..........OO.....O.OOOO
..........OO.........OO

:bakery (p1) A common formation of two bi-loaves.


....OO....
...O..O...
...O.O....
.OO.O...O.
O..O...O.O
O.O...O..O
.O...O.OO.
....O.O...
...O..O...
....OO....

:barberpole Any p2 oscillator in the infinite sequence bipole, tripole, quadpole, pentapole, hexapole, heptapole ... (It wasn't my idea to suddenly change from Latin to Greek.) This sequence of oscillators was found by the MIT group in 1970. The term is also used (usually in the form "barber pole") to describe other extensible sections of oscillators or spaceships, especially those (usually of period 2) in which all generations look alike except for a translation and/or rotation/reflection.

:barberpole intersection = quad

:barber's pole = barberpole

:barge (p1)


.O..
O.O.
.O.O
..O.

:basic shuttle = queen bee shuttle

:beacon (p2) The third most common oscillator. Found by Conway, March 1970.


OO..
O...
...O
..OO

:beacon maker (c p8 fuse)


..............OO
.............O.O
............O...
...........O....
..........O.....
.........O......
........O.......
.......O........
......O.........
.....O..........
....O...........
...O............
OOO.............
..O.............
..O.............

:beehive (p1) The second most common still life.


.OO.
O..O
.OO.

:beehive and dock (p1)


...OO.
..O..O
...OO.
......
.OOOO.
O....O
OO..OO

:beehive on big table = beehive and dock

:beehive pusher = hivenudger

:beehive with tail (p1)


.OO...
O..O..
.OO.O.
....O.
....OO

:belly spark The spark of a MWSS or HWSS other than the tail spark.

:bent keys (p3) Found by Dean Hickerson, August 1989. See also odd keys and short keys.


.O........O.
O.O......O.O
.O.OO..OO.O.
....O..O....
....O..O....

:B-heptomino (stabilizes at time 148) This is a very common pattern. It often arises with the cell at top left shifted one space to the left, which does not affect the subsequent evolution. B-heptominoes acquired particular importance in 1996 due to Dave Buckingham's work on B tracks - see in particular My Experience with B-heptominos in Oscillators.


O.OO
OOO.
.O..

:B-heptomino shuttle = twin bees shuttle

:bi-block (p1) The smallest pseudo still life.


OO.OO
OO.OO

:bi-boat = boat-tie

:biclock The following pure glider generator consisting of two clocks.


..O....
OO.....
..OO...
.O...O.
...OO..
.....OO
....O..

:big beacon = figure-8

:big fish = HWSS

:big glider (c/4 diagonally, p4) This was found by Dean Hickerson in December 1989 and was the first known diagonal spaceship other than the glider.


...OOO............
...O..OOO.........
....O.O...........
OO.......O........
O.O....O..O.......
O........OO.......
.OO...............
.O..O.....O.OO....
.O.........OO.O...
...O.O......OO..O.
....OO.O....OO...O
........O.......O.
.......OOOO...O.O.
.......O.OO...OOOO
........O...OO.O..
.............OO...
.........O.OOO....
..........O..O....

:big S (p1)


....OO.
...O..O
...O.OO
OO.O...
O..O...
.OO....

:big table = dock

:billiard table configuration Any oscillator in which the rotor is enclosed within the stator. Examples include airforce, cauldron, clock II, Hertz oscillator, negentropy, pinwheel, pressure cooker and scrubber.

:bi-loaf This term has been used in at least three different senses. A bi-loaf can be half a bakery:


.O.....
O.O....
O..O...
.OO.O..
...O.O.
...O..O
....OO.
or it can be the following much less common still life:

..O....
.O.O...
O..O...
.OO.OO.
...O..O
...O.O.
....O..
or the following pure glider generator:

..O.
.O.O
O..O
.OO.
O..O
O.O.
.O..

:bipole (p2) The barberpole of length 2.


OO...
O.O..
.....
..O.O
...OO

:bi-pond (p1)


.OO....
O..O...
O..O...
.OO.OO.
...O..O
...O..O
....OO.

:bi-ship = ship-tie

:bit A live cell.

:biting off more than they can chew (p3) Found by Peter Raynham, July 1972.


O...........
OOO.........
...O........
..OO........
...OO.......
....OO......
...O..O.....
...O..OO....
....OO.OOO..
........O.O.
..........O.
..........OO

:Black&White = Immigration

:blasting cap The pi-heptomino (after the shape at generation 1). A term used at MIT and still occasionally encountered.

:blinker (p2) The smallest and most common oscillator. Found by Conway, March 1970.


OOO

:blinker puffer Any puffer whose output is blinkers. However, the term is particularly used for p8 c/2 puffers. The first such blinker puffer was found by Robert Wainwright in 1984, and was unexpectedly simple:


...O.....
.O...O...
O........
O....O...
OOOOO....
.........
.........
.........
.OO......
OO.OOO...
.OOOO....
..OO.....
.........
.....OO..
...O....O
..O......
..O.....O
..OOOOOO.
Since then many more blinker puffers have been found. The following one was found by David Bell in 1992 when he was trying to extend an x66:

.............OOO.
............OOOOO
...........OO.OOO
............OO...
.................
.................
.........O.O.....
..O.....O..O.....
.OOOOO...O.O.....
OO...OO.OO.......
.O.......O.......
..OO..O..O.......
..........O......
..OO..O..O.......
.O.......O.......
OO...OO.OO.......
.OOOOO...O.O.....
..O.....O..O.....
.........O.O.....
.................
.................
............OO...
...........OO.OOO
............OOOOO
.............OOO.
The importance of this larger blinker puffer (and others like it), is that the engine which produces the blinker output is only p4. The blinker row produced by the puffer can easily be ignited, and burns cleanly with a speed of 2c/3. When the burning catches up to the engine, it causes a phase change in the puffer. This fact allows p8 blinker puffers to be used to construct rakes of all periods which are large multiples of four.

:blinkers bit pole (p2) Found by Robert Wainwright, June 1977.


.....OO
OOO.O.O
.......
.O.O..O
O....O.
OO...O.

:blinker ship A growing spaceship in which the wick consists of a line of blinkers. An example by Paul Schick based on his Schick engine is shown below. Here the front part is p12 and moves at c/2, while the back part is p26 and moves at 6c/13. Every 156 generations 13 blinkers are created and 12 are destroyed, so the wick becomes one blinker longer.


..........OOOO.............
..........O...O............
..........O................
.OO........O..O............
OO.OO......................
.OOOO...O..................
..OO...O.OO........O....OOO
......O...O........O....O.O
..OO...O.OO........O....OOO
.OOOO...O..................
OO.OO......................
.OO........O..O............
..........O................
..........O...O............
..........OOOO.............

:block (p1) The most common still life.


OO
OO

:blockade (p1) A common formation of four blocks. The final form of lumps of muck.


OO.....................
OO.....................
.......................
.......................
.OO.................OO.
.OO.................OO.
.......................
.......................
.....................OO
.....................OO

:block and dock (p1)


...OO.
...OO.
......
.OOOO.
O....O
OO..OO

:block and glider (stabilizes at time 106)


OO..
O.O.
..OO

:blocker (p8) Found by Robert Wainwright. See also filter.


......O.O.
.....O....
OO..O....O
OO.O..O.OO
....OO....

:block on big table = block and dock

:block on table (p1)


..OO
..OO
....
OOOO
O..O

:block pusher A pattern emitting streams of gliders which can repeatedly push a block further away. This can be used as part of a sliding block memory.

The following pattern, in which three gliders push a block one cell diagonally, is an example of how a block pusher works.


...................O.O
...................OO.
....................O.
......................
......................
......................
...O..................
..O...................
..OOO.................
......................
......................
......................
......................
OO...O................
OO...O.O..............
.....OO...............

:blom (stabilizes at time 23314) The following methuselah, found by Dean Hickerson in July 2002.


O..........O
.OOOO......O
..OO.......O
..........O.
........O.O.

:blonk A block or a blinker. This term is mainly used in the context of sparse Life and was coined by Rich Schroeppel in September 1992.

:blonker (p6) The following oscillator, found by Nicolay Beluchenko in April 2004.


O..OO....O..
OO..O.OO.O..
....O.O.....
.....OO.....
.......O....
.......O...O
.........O.O
..........O.

:boat (p1) The only 5-cell still life.


OO.
O.O
.O.

:boat-bit A binary digit represented by the presence of a boat next to a snake (or other suitable object, such as an aircraft carrier). The bit can be toggled by a glider travelling along a certain path. A correctly timed glider on a crossing path can detect whether the transition was from 1 to 0 (in which case the crossing glider is deleted) or from 0 to 1 (in which case it passes unharmed). Three gliders therefore suffice for a non-destructive read. The mechanisms involved are shown in the diagram below. Here the bit is shown in state 0. It is about to be set to 1 and then switched back to 0 again. The first crossing glider will survive, but the second will be destroyed. (In January 1997 David Bell found a method of reading the bit while setting it to 0. A MWSS is fired at the boat-bit. If it is already 0 then the MWSS passes unharmed, but if it is 1 then the boat and the MWSS are destroyed and, with the help of an eater1, converted into a glider which travels back along exactly the same path that is used by the gliders that toggle the boat-bit.)


......O..................
.......O.................
.....OOO.................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
................O........
..............O.O........
..........OO...OO........
...........OO............
..........O..........O.OO
.....................OO.O
.........................
.........................
.........................
.........................
.........................
.O.......................
.OO......................
O.O......................

:boat maker (c p4 fuse)


................OO
...............O.O
..............O...
.............O....
............O.....
...........O......
..........O.......
.........O........
........O.........
.......O..........
......O...........
.....O............
OOOOO.............
....O.............
....O.............
....O.............
....O.............

:boat on boat = boat-tie

:boat-ship-tie = ship tie boat

:boatstretcher See tubstretcher.

:boat-tie (p1) A 10-cell still life consisting of two boats placed tip-to-tip. The name is a pun on "bow tie".


.O....
O.O...
.OO...
...OO.
...O.O
....O.

:boojum reflector (p1) Dave Greene's name for the following reflector which he found in April 2001, and which is currently the smallest known stable reflector.


....O.O......OO.............................
.....OO......OO.............................
.....O......................................
............................................
............................................
............................................
............................................
............................................
............................................
........................................O...
.......................................O.O..
.......................................O.O..
....................OO................OO.OO.
....................OO......................
......................................OO.OO.
..OO..................................OO.O..
.O.O.......................................O
.O........................................OO
OO..........................................
............................................
..................................OO........
..................................OO....OO..
...........OO...........................O.O.
..........O.O.............................O.
..........O...............................OO
.........OO.......................OO........
..................................OO........
............................................
............................................
.............................O..............
............................O.O.............
.............................O..............

:bookend The following induction coil. It is generation 1 of century.


..OO
O..O
OOO.

:bookends (p1)


OO...OO
O.O.O.O
..O.O..
.OO.OO.

:boss (p4) Found by Dave Buckingham, 1972.


.....O.....
....O.O....
....O.O....
...OO.OO...
..O.....O..
.O.O.O.O.O.
.O.O...O.O.
OO.O...O.OO
O..O.O.O..O
..O.....O..
...OO.OO...
....O.O....
....O.O....
.....O.....

:bottle (p8) Found by Achim Flammenkamp in August 1994. The name is a back-formation from ship in a bottle.


....OO......OO....
...O..O....O..O...
...O.O......O.O...
.OO..OOO..OOO..OO.
O......O..O......O
O.OO..........OO.O
.O.O..........O.O.
...OO........OO...
..................
..................
...OO........OO...
.O.O..........O.O.
O.OO..........OO.O
O......O..O......O
.OO..OOO..OOO..OO.
...O.O......O.O...
...O..O....O..O...
....OO......OO....

:bounding box The smallest rectangular array of cells that contains the whole of a given pattern. For oscillators and guns this usually is meant to include all phases of the pattern, but excludes, in the case of guns, the outgoing stream(s).

:bow tie = boat-tie

:brain (c/3 orthogonally, p3) Found by David Bell, May 1992.


.OOO.........OOO.
O.O.OO.....OO.O.O
O.O.O.......O.O.O
.O.OO.OO.OO.OO.O.
.....O.O.O.O.....
...O.O.O.O.O.O...
..OO.O.O.O.O.OO..
..OOO..O.O..OOO..
..OO..O...O..OO..
.O....OO.OO....O.
.O.............O.

:breeder Any pattern whose population grows at a quadratic rate, although it is usual to exclude spacefillers. It is easy to see that this is the fastest possible growth rate.

The term is also sometimes used to mean specifically the breeder created by Bill Gosper's group at MIT, which was the first known pattern exhibiting superlinear growth.

There are four basic types of breeder, known as MMM, MMS, MSM and SMM (where M=moving and S=stationary). Typically an MMM breeder is a rake puffer, an MMS breeder is a puffer producing puffers which produce stationary objects (still lifes and/or oscillators), an MSM breeder is a gun puffer and an SMM breeder is a rake gun. There are, however, less obvious variants of these types. The original breeder was of type MSM (a p64 puffer puffing p30 glider guns).

The known breeder with the smallest initial population is the metacatacryst.

:bridge A term used in naming certain still lifes (and the stator part of certain oscillators). It indicates that the object consists of two smaller objects joined edge to edge, as in snake bridge snake.

:broken lines A pattern constructed by Dean Hickerson in May 2005 which produces complex broken lines of gliders and blocks.

:broth = soup

:BTC = billiard table configuration

:B track A track for B-heptominoes. The term is more-or-less synonymous with Herschel track, since a B-heptomino becomes a Herschel plus a block in twenty generations.

:buckaroo A queen bee shuttle stabilized at one end by an eater in such a way that it can turn a glider, as shown below. This was found by Dave Buckingham in the 1970s. The name is due to Bill Gosper.


..O.....................
O.O.....................
.OO.....................
...........O............
.........O.O............
........O.O.............
.......O..O...........OO
........O.O...........OO
...OO....O.O............
..O.O......O............
..O.....................
.OO.....................

:bullet heptomino Generation 1 of the T-tetromino.


.O.
OOO
OOO

:bun The following induction coil. By itself this is a common predecessor of the honey farm. See also cis-mirrored R-bee.


.OO.
O..O
.OOO

:bunnies (stabilizes at time 17332) This is a parent of rabbits and was found independently by Robert Wainwright and Andrew Trevorrow.


O.....O.
..O...O.
..O..O.O
.O.O....

:burloaf = loaf

:burloaferimeter (p7) Found by Dave Buckingham in 1972. See also airforce.


....OO....
.....O....
....O.....
...O.OOO..
...O.O..O.
OO.O...O.O
OO.O....O.
....OOOO..
..........
....OO....
....OO....

:bushing That part of the stator of an oscillator which is adjacent to the rotor. Compare casing.

:butterfly The following pattern, or the formation of two beehives that it evolves into after 33 generations. (Compare teardrop, where the beehives are five cells closer together.)


O...
OO..
O.O.
.OOO

:by flops (p2) Found by Robert Wainwright.


...O..
.O.O..
.....O
OOOOO.
.....O
.O.O..
...O..

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_o.htm0000644000175000017500000002324112536111364014333 00000000000000 Life Lexicon (O)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:obo spark A spark of the form O.O (so called after its rle encoding).

:octagon II (p5) The first known p5 oscillator, discovered in 1971 independently by Sol Goodman and Arthur Taber. The name is due to the latter.


...OO...
..O..O..
.O....O.
O......O
O......O
.O....O.
..O..O..
...OO...

:octagon IV (p4) Found by Robert Wainwright, January 1979.


.......OO.......
.......OO.......
................
......OOOO......
.....O....O.....
....O......O....
...O........O...
OO.O........O.OO
OO.O........O.OO
...O........O...
....O......O....
.....O....O.....
......OOOO......
................
.......OO.......
.......OO.......

:octomino Any 8-cell polyomino. There are 369 such objects. The word is particularly applied to the following octomino (or its two-generation successor), which is fairly common but lacks a proper name:


..OO
..OO
OOO.
.O..

:odd keys (p3) Found by Dean Hickerson, August 1989. See also short keys and bent keys.


..........O.
.O.......O.O
O.OOO..OO.O.
.O..O..O....
....O..O....

:omino = polyomino

:omniperiodic A cellular automaton is said to be omniperiodic if it has oscillators of all periods. It is not known if Life is omniperiodic, although this seems likely. Dave Buckingham's work on Herschel conduits in 1996 (see My Experience with B-heptominos in Oscillators) reduced the number of unresolved cases to a finite number. At the time of writing the only periods for which no oscillator is known are 19, 23, 31, 37, 38, 41, 43 and 53. If we insist that the oscillator must contain a cell oscillating at the full period, then 34 and 51 should be added to this list. The most recently achieved periods were all found by Noam Elkies: p49 in August 1999 (a glider loop using p7 reflectors built from his new p7 pipsquirter), p39 (previously only possible without a p39 cell) in July 2000, and p27 in November 2002.

Note that if we were to allow infinite oscillators, then all periods are certainly possible, as any period of 14 or more can be obtained using a glider (or LWSS) stream.

:one-sided spaceship synthesis A glider synthesis of a spaceship in which all gliders come from the same side of the spaceship's path. Such syntheses are used extensively in the 17c/45 Caterpillar.

:onion rings For each integer n>1 onion rings of order n is a stable agar of density 1/2 obtained by tiling the plane with a certain 4n x 4n pattern. The tile for order 3 onion rings is shown below - the reader should then be able to deduce the form of tiles of other orders.


......OOOOOO
.OOOO.O....O
.O..O.O.OO.O
.O..O.O.OO.O
.OOOO.O....O
......OOOOOO
OOOOOO......
O....O.OOOO.
O.OO.O.O..O.
O.OO.O.O..O.
O....O.OOOO.
OOOOOO......

:on-off Any p2 oscillator in which all rotor cells die from overpopulation. The simplest example is a beacon. Compare flip-flop.

:O-pentomino Conway's name for the following pentomino, a traffic light predecessor, although not one of the more common ones.


OOOOO

:orbit A term proposed by Jason Summers to refer to a natural stabilization of a puffer. For example, the switch engine has two (known) orbits, the block-laying one and the glider-producing one.

:Orion (c/4 diagonally, p4) Found by Hartmut Holzwart, April 1993.


...OO.........
...O.O........
...O..........
OO.O..........
O....O........
O.OO......OOO.
.....OOO....OO
......OOO.O.O.
.............O
......O.O.....
.....OO.O.....
......O.......
....OO.O......
.......O......
.....OO.......
In May 1999, Jason Summers found the following smaller variant:

.OO..........
OO...........
..O..........
....O....OOO.
....OOO....OO
.....OOO.O.O.
............O
.....O.O.....
....OO.O.....
.....O.......
...OO.O......
......O......
....OO.......

:orphan Conway's preferred term for a Garden of Eden.

:oscillator Any pattern that is a predecessor of itself. The term is usually restricted to non-stable finite patterns. An oscillator is divided into a rotor and a stator. See also omniperiodic.

In general cellular automaton theory the term "oscillator" usually covers spaceships as well, but this usage is not normal in Life.

:overcrowding = overpopulation

:over-exposure = underpopulation

:overpopulation Death of a cell caused by it having more than three neighbours. See also underpopulation.

:overweight spaceship = OWSS

:OWSS A would-be spaceship similar to LWSS, MWSS and HWSS but longer. On its own an OWSS is unstable, but it can be escorted by true spaceships to form a flotilla.

:Ox A 1976 novel by Piers Anthony which involves Life.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_s.htm0000644000175000017500000015226512536111364014350 00000000000000 Life Lexicon (S)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:S Usually means big S, but may sometimes mean paperclip.

:sailboat (p16) A boat hassled by a Kok's galaxy, a figure-8 and two eater3s. Found by Robert Wainwright in June 1984.


........O...........O........
.......O.O.........O.O.......
........O...........O........
.............................
......OOOOO.......OOOOO......
.....O....O.......O....O.....
....O..O.............O..O....
.O..O.OO.............OO.O..O.
O.O.O.....O.......O.....O.O.O
.O..O....O.O.....O.O....O..O.
....OO..O..O.....O..O..OO....
.........OO.......OO.........
.............OO..............
.............O.O.............
........O..O..O..............
.......O.....................
.....OO..........OOO.........
..O......OO.O....OOO.........
.....O...O..O....OOO.........
.....OOO.O...O......OOO......
..O...........O.....OOO......
...O...O.OOO........OOO......
....O..O...O.................
....O.OO......O..............
..........OO.................
.........O...................
.....O..O....................

:sawtooth Any finite pattern whose population grows without bound but does not tend to infinity. (In other words, the population reaches new heights infinitely often, but also infinitely often returns to some fixed value.) Conway's preferred plural is "sawteeth".

The first sawtooth was constructed by Dean Hickerson in April 1991. The least infinitely repeating population of any known sawtooth is 262 (David Bell, July 2005).

See also tractor beam.

:SBM = sliding block memory

:Schick engine (c/2 orthogonally, p12) This spaceship, found by Paul Schick in 1972, produces a large spark (the 15 live cells at the rear in the phase shown below) which can be perturbed by other c/2 spaceships to form a variety of puffers. The diagram below shows the smallest form of the Schick engine, using two LWSS. It is also possible to use two MWSS or two HWSS, or even a LWSS and a HWSS.


OOOO..............
O...O.........O...
O...........OO....
.O..O..OO.....OOO.
......OOO......OOO
.O..O..OO.....OOO.
O...........OO....
O...O.........O...
OOOO..............

:Schick ship = Schick engine

:scorpion (p1)


...O...
.OOO...
O...OO.
O.O.O.O
.OO.O.O
.....O.

:scrubber (p2) Found in 1971.


....O......
..OOO......
.O.........
.O..OOO....
OO.O...O...
...O...O...
...O...O.OO
....OOO..O.
.........O.
......OOO..
......O....

:SE = switch engine

:seal (c/6 diagonally, p6) The first c/6 diagonal spaceship, found by Nicolay Beluchenko in September 2005.


...O..OO..........................
.OOO.O.O.O........................
.O..OOO..OO.......................
O..OOOOOO.O.OOO...................
.O..OOO.O.OOOOO...................
......O.O.O.O.....................
O.O...O.O.OOOOO...................
O..O.O..O.OO...O..................
...O..OO.......OOO................
.O...OOOOO.OOO..OO................
....O.........O...................
..O.O.........O...................
....OO.OOOOO...O..................
......O.OOO..O.....OO.............
......O..O...O.OOO.OO.............
........OO...OOO.O..O...O.........
........OO....OO.OOOO...OOO.......
...................O.O..O.........
.............O.O.....OO..OO.......
.............O..O.....O.OOO.....O.
.............O...O....OO..O...O..O
...............OOO.....OO........O
...............O.O..O..O.....OO..O
.................O..OO.OO.O..O....
................O.......O.O.......
.................O...OOOO.........
..................O...O...........
..................................
.......................O..........
......................O.O.........
.....................OO...........
.....................O.O..........
.....................OO...........
.......................O..........
......................O...........

:second glider domain The second glider domain of an edge shooter is the set of displacements (in space and time, relative to the glider stream emitted by the edge shooter) that a glider stream may have without interfering with the edge shooter. This is useful to know, because edge shooters are often used to generate glider streams very close to other glider streams.

:sesquihat (p1) Halfway between a hat and a twinhat.


....O
OO.O.O.
.O.O.O.
.O.O.OO
..O...

:SGR Abbreviation for stable glider reflector.

:shillelagh (p1)


OO...
O..OO
.OO.O

:ship (p1) The term is also used as a synonym of spaceship.


OO.
O.O
.OO

:ship in a bottle (p16) Found by Bill Gosper in August 1994. See also bottle.


....OO......OO....
...O..O....O..O...
...O.O......O.O...
.OO..OOO..OOO..OO.
O......O..O......O
O.OO..........OO.O
.O.O..........O.O.
...OO...OO...OO...
.......O.O........
.......OO.........
...OO........OO...
.O.O..........O.O.
O.OO..........OO.O
O......O..O......O
.OO..OOO..OOO..OO.
...O.O......O.O...
...O..O....O..O...
....OO......OO....

:ship on boat = ship tie boat

:ship on ship = ship-tie

:ship-tie (p1) The name is by analogy with boat-tie.


OO....
O.O...
.OO...
...OO.
...O.O
....OO

:ship tie boat (p1)


OO....
O.O...
.OO...
...OO.
...O.O
....O.

:short keys (p3) Found by Dean Hickerson, August 1989. See also bent keys and odd keys.


.O........O.
O.OOO..OOO.O
.O..O..O..O.
....O..O....

:shuttle Any oscillator which consists of an active region moving back and forth between stabilizing objects. The most well-known examples are the queen bee shuttle (which has often been called simply "the shuttle") and the twin bees shuttle. See also p54 shuttle and Eureka. Another example is the p72 R-pentomino shuttle that forms part of the pattern given under factory.

:siamese A term used in naming certain still lifes (and the stator part of certain oscillators). It indicates that the object consists of two smaller objects sharing two or more cells. See snake siamese snake and loaf siamese barge for examples.

:side Half a sidewalk. In itself this is unstable and requires an induction coil.


OO...
O.OOO
....O

:sidecar A small tagalong for a HWSS that was found by Hartmut Holzwart in 1992. The resulting spaceship (shown below) has a phase with only 24 cells, making it in this respect the smallest known spaceship other than the standard spaceships and some trivial two-spaceship flotillas derived from them. Note also that a HWSS can support two sidecars at once.


.O......
O.....O.
O.....O.
OOOOO.O.
........
....OO..
..O....O
.O......
.O.....O
.OOOOOO.

:side-shooting gun = slide gun

:side-tracking See universal constructor.

:sidewalk (p1)


.OO.OO
..O.O.
.O..O.
.O.O..
OO.OO.

:siesta (p5) Found by Dave Buckingham in 1973. Compare sombreros.


...........OO...
...OO.....O.O...
...O.O....O.....
.....O...OO.O...
...O.OO.....OOO.
.OOO.....O.O...O
O...O.O.....OOO.
.OOO.....OO.O...
...O.OO...O.....
.....O....O.O...
...O.O.....OO...
...OO...........

:signal Movement of information through the Life universe. Signals can be carried by spaceships, fuses, drifters, or conduits. Spaceships can only transfer a signal at the speed of the spaceship, while fuses can transfer a signal at speeds up to the speed of light.

In practice, many signals are encoded as the presence or absence of a glider (or other spaceship) at a particular point at a particular time. Such signals can be combined by the collision of gliders to form logic operations such as AND, OR, and NOT gates. Signals can be duplicated using glider duplicators or other fanout devices, and can be used up by causing perturbations on other parts of the Life object.

Signals are used in pseudo-random glider generators, the unit Life cell and the Fermat prime calculator, among others.

:Silver's p5 (p5) The following oscillator found by Stephen Silver in February 2000:


OO.........
O..........
.O..O......
...OO......
...O...O.OO
..O....OO.O
..OO.......

As this has no spark, it appears useless. Nonetheless, in March 2000, David Eppstein found a way to use it to reduce the size of Noam Elkies' p5 reflector.

:singular flip flop (p2) Found by Robert Wainwright, July 1972.


..O...
..O.O.
O....O
OOOOOO
......
..OO..
..OO..

:sinking ship = canoe

:six Ls (p3) This is a compact form of loading dock.


...O...
.OOO..O
O...OOO
OOO....
....OOO
OOO...O
O..OOO.
...O...

:sixty-nine (p4) Found by Robert Wainwright, October 1978.


.........O...........
........O.O..........
.....................
......O...OO.........
.....O.....O.........
......O.O............
........OO......O....
................O....
..O.....OO....OOO....
..O...........OO.....
OOO.......OO..OO..OOO
OO......O.OO....OOO..
OO..OOO.O.O.....OOO..
..OOO................
..OOO......O.........
..........O.O........
.....................
........O...OO.......
.......O.....O.......
........O.O..........
..........OO.........

:skewed quad (p2)


.OO....
.O...OO
..O.O.O
.......
O.O.O..
OO...O.
....OO.

:skewed traffic light (p3) Found by Robert Wainwright, August 1989.


.............OO.........
............O..O........
.............O.O........
.........OO...O.........
..........O.OO..........
............O...........
............O...........
........................
OO........OOO......O....
OOOO.O........O...OO....
O.O..OOO.O....O.........
.........O....O.OOO..O.O
....OO...O........O.OOOO
....O......OOO........OO
........................
...........O............
...........O............
..........OO.O..........
.........O...OO.........
........O.O.............
........O..O............
.........OO.............

:slide gun A gun which fires sideways from an extending arm. The arm consists of streams of spaceships which are pushing a pattern away from the body of the gun and releasing an output spaceship every time they do so. Each output spaceship therefore travels along a different path.

Dieter Leithner constructed the first slide gun in July 1994 (although he used the term "side shooting gun"). The following pattern shows the key reaction of this slide gun. The three gliders shown will push the block one cell diagonally, thereby extending the length of the arm by one cell, and at the same time they release an output glider sideways. (In 1999, Jason Summers constructed slide guns using other reactions.)


..............OO.
..............OO.
........OOO......
..........O......
.........O.....OO
..............O.O
................O
.................
.................
.................
.................
.................
.................
.................
.................
.................
.................
.O...............
.OO..............
O.O..............

:sliding block memory A memory register whose value is stored as the position of a block. The block can be moved by means of glider collisions - see block pusher for an example.

In Conway's original formulation (as part of his proof of the existence of a universal computer in Life) 2 gliders were used to pull the block inwards by three diagonal spaces, and 30 gliders were used to push it out by the same amount. Dean Hickerson later greatly improved on this, finding a way to pull a block inwards by one diagonal space using 2 gliders, and push it out using 3 gliders. In order for the memory to be of any use there also has to be a way to read the value held. It suffices to be able to check whether the value is zero (as Conway did), or to be able to detect the transition from one to zero (as Hickerson did).

Dean Hickerson's sliding block memory is used in Paul Chapman's URM.

:slow glider construction Construction an object by a "slow salvo" of gliders all coming from the same direction, in such a way that timing of the gliders does not matter as long as they are not too close behind one another. This type of construction requires an initial seed object, such as a block, which is modified by each glider in turn until the desired object is produced.

In May 1997, Nick Gotts produced a slow glider construction of a block-laying switch engine from a block, using a slow salvo of 53 gliders. Constructions like this are important in the study of sparse Life, as they will occur naturally as gliders created in the first few generations collide with blonks and other debris.

Slow glider constructions are also useful in some designs for universal constructors. However, in this case the above definition is usually too restrictive, and it is desirable to allow constructions in which some gliders in the salvo are required to have a particular timing modulo 2 (a "p2 slow salvo"). This gives much greater flexibility, as blinkers can now be freely used in the intermediate construction steps.

:slow salvo See slow glider construction.

:small fish = LWSS

:small lake (p1) See also lake.


....O....
...O.O...
...O.O...
.OO...OO.
O.......O
.OO...OO.
...O.O...
...O.O...
....O....

:smiley (p8) Found by Achim Flammenkamp in July 1994 and named by Alan Hensel.


OO.O.OO
...O...
O.....O
.OOOOO.
.......
.......
OOO.OOO

:SMM breeder See breeder.

:smoke Debris which is fairly long-lived but eventually dies completely. Basically, a large spark. This term is used especially when talking about the output from a spaceship - see smoking ship.

:smoking ship A spaceship which produces smoke. If the smoke extends past the edge of the rest of the spaceship, then it can be used to perturb other objects as the spaceship passes by. Running gliders into the smoke is often a good way to turn or duplicate the them, or convert them into other objects. Sometimes the smoke from a smoking ship may itself be perturbed by accompanying spaceships in order to form a puffer. A simple example of a smoking ship is the Schick engine.

:snacker (p9) Found by Mark Niemiec in 1972. This is a pentadecathlon with stabilizers which force it into a lower period.


OO................OO
.O................O.
.O.O............O.O.
..OO............OO..
.......O....O.......
.....OO.OOOO.OO.....
.......O....O.......
..OO............OO..
.O.O............O.O.
.O................O.
OO................OO
The stabilizers make the domino spark largely inaccessible, but the snacker is extensible, as shown in the next diagram, and so a more accessible p9 domino spark can be obtained. In April 1998 Dean Hickerson found an alternative stabilizer that is less obtrusive than the original one, and this is also shown in this diagram.

OO................................
.O................................
.O.O.........................OO...
..OO.......................O..O...
.......O....O..............OOO....
.....OO.OOOO.OO...O....O......OOO.
.......O....O...OO.OOOO.OO...O...O
..OO..............O....O......OOO.
.O.O.......................OOO....
.O.........................O..O...
OO...........................OO...
An end can also be stabilized by killer candlefrobras, although this isn't efficient.

:snail (c/5 orthogonally, p5) The first known c/5 spaceship, discovered by Tim Coe in January 1996. For some time it was the slowest known orthogonal spaceship.


.O....................................
.O....................................
O.....................................
.OOO.................OOO...OOO........
.OO.O.........O...O.O......OOO........
..O...........OO.O.......O....OOOO....
......O......O...O.O...OO.O.....OO....
...O..O.OOO...OO.........O........OO.O
...OO.O.....O.....O.................O.
.........O.OOOOOOO....................
......................................
.........O.OOOOOOO....................
...OO.O.....O.....O.................O.
...O..O.OOO...OO.........O........OO.O
......O......O...O.O...OO.O.....OO....
..O...........OO.O.......O....OOOO....
.OO.O.........O...O.O......OOO........
.OOO.................OOO...OOO........
O.....................................
.O....................................
.O....................................

:snake (p1)


OO.O
O.OO

:snake bit An alternative name for a boat-bit. Not a very sensible name, because various other things can be used instead of a snake.

:snake bridge snake (p1)


....OO
....O.
.....O
....OO
OO.O..
O.OO..

:snake dance (p3) Found by Robert Wainwright, May 1972.


...OO.O..
...O.OO..
OO.O.....
.O..O.OOO
O..O.O..O
OOO.O..O.
.....O.OO
..OO.O...
..O.OO...

:snake pit This term has been used for two different oscillators: the p2 snake pit (essentially the same as fore and back)


O.OO.OO
OO.O.O.
......O
OOO.OOO
O......
.O.O.OO
OO.OO.O
and the p3 snake pit.

.....OO....
....O..O...
....O.OO...
.OO.O......
O.O.O.OOOO.
O.........O
.OOOO.O.O.O
......O.OO.
...OO.O....
...O..O....
....OO.....

:snake siamese snake (p1)


OO.OO.O
O.OO.OO

:sombrero One half of sombreros or siesta.

:sombreros (p6) Found by Dave Buckingham in 1972. If the two halves are moved three spaces closer to one another then the period drops to 4, and the result is just a less compact form of Achim's p4. Compare also siesta.


...OO........OO...
...O.O......O.O...
.....O......O.....
...O.OO....OO.O...
.OOO..........OOO.
O...O.O....O.O...O
.OOO..........OOO.
...O.OO....OO.O...
.....O......O.....
...O.O......O.O...
...OO........OO...

:soup A random initial pattern, often assumed to cover the whole Life universe.

:space dust A part of a spaceship or oscillator which looks like a random mix of ON and OFF cells. It is usually very difficult to find a glider synthesis for an object that consists wholly or partly of space dust.

:spacefiller Any pattern that grows at a quadratic rate by filling space with an agar. The first example was found in September 1993 by Hartmut Holzwart, following a suggestion by Alan Hensel. The diagram below shows a smaller spacefiller found by Tim Coe. See also Max. Spacefillers can be considered as breeders (more precisely, MMS breeders), but they are very different from ordinary breeders. The word "spacefiller" was suggested by Harold McIntosh and soon became the accepted term.


..................O........
.................OOO.......
............OOO....OO......
...........O..OOO..O.OO....
..........O...O.O..O.O.....
..........O....O.O.O.O.OO..
............O....O.O...OO..
OOOO.....O.O....O...O.OOO..
O...OO.O.OOO.OO.........OO.
O.....OO.....O.............
.O..OO.O..O..O.OO..........
.......O.O.O.O.O.O.....OOOO
.O..OO.O..O..O..OO.O.OO...O
O.....OO...O.O.O...OO.....O
O...OO.O.OO..O..O..O.OO..O.
OOOO.....O.O.O.O.O.O.......
..........OO.O..O..O.OO..O.
.............O.....OO.....O
.OO.........OO.OOO.O.OO...O
..OOO.O...O....O.O.....OOOO
..OO...O.O....O............
..OO.O.O.O.O....O..........
.....O.O..O.O...O..........
....OO.O..OOO..O...........
......OO....OOO............
.......OOO.................
........O..................

:space rake The following p20 forwards glider rake, which was the first known rake. It consists of an ecologist with a LWSS added to turn the dying debris into gliders.


...........OO.....OOOO
.........OO.OO...O...O
.........OOOO........O
..........OO.....O..O.
......................
........O.............
.......OO........OO...
......O.........O..O..
.......OOOOO....O..O..
........OOOO...OO.OO..
...........O....OO....
......................
......................
......................
..................OOOO
O..O.............O...O
....O................O
O...O............O..O.
.OOOO.................

:spaceship Any finite pattern that reappears (without additions or losses) after a number of generations and displaced by a non-zero amount. By far the most natural spaceships are the glider, LWSS, MWSS and HWSS. For further examples see B29, big glider, brain, Canada goose, Coe ship, Cordership, crane, dart, dragon, ecologist, edge-repair spaceship, Enterprise, flotilla, fly, hammerhead, hivenudger, non-monotonic, Orion, puff suppressor, pushalong, quarter, Schick engine, seal, sidecar, snail, still life tagalong, sparky, swan, turtle, wasp, weekender and x66. See also Caterpillar.

It is known that there exist spaceships travelling in all rational directions and at arbitrarily slow speeds (see universal constructor). Before 1989, however, the only known examples travelled at c/4 diagonally (gliders) or c/2 orthogonally (everything else). In 1989 Dean Hickerson started to use automated searches to look for new spaceships, and had considerable success. Other people have continued these searches using tools such as lifesrc and gfind, and as a result we now have a great variety of spaceships travelling at twelve different velocities. The following table details the discovery of spaceships with new velocities.


-----------------------------------------------------
Speed   Direction    Discoverer                Date
-----------------------------------------------------
c/4     diagonal     Richard Guy                 1970
c/2     orthogonal   John Conway                 1970
c/3     orthogonal   Dean Hickerson          Aug 1989
c/4     orthogonal   Dean Hickerson          Dec 1989
c/12    diagonal     Dean Hickerson          Apr 1991
2c/5    orthogonal   Dean Hickerson          Jul 1991
c/5     orthogonal   Tim Coe                 Jan 1996
2c/7    orthogonal   David Eppstein          Jan 2000
c/6     orthogonal   Paul Tooke              Apr 2000
c/5     diagonal     Jason Summers           Nov 2000
17c/45  orthogonal   Gabriel Nivasch et al.  Dec 2004
c/6     diagonal     Nicolay Beluchenko      Sep 2005
-----------------------------------------------------

A period p spaceship that displaces itself (m,n) during its period, where m>=n, is said to be of type (m,n)/p. It was proved by Conway in 1970 that p>=2m+2n. (This follows immediately from the easily-proved fact that a pattern cannot advance diagonally at a rate greater than one half diagonal step every other generation.)

The following diagram shows one of only two known c/5 diagonal spaceships. It was found by Jason Summers in January 2005.


..........OO..........
.........O..O.........
........OO............
.........O.OO.........
..........O.OOO.......
..........OO.OOO......
............O....OO...
............OOO....OO.
..O.........O.O.......
.OOO........O..O......
O...OO................
O..O.O.......OO.O..O..
.O.OO.OOOO...O...OOOO.
....OO.O...OO.......O.
....OO.OO..O.........O
.....O...O........O.OO
...........O.......O..
......O.....O......O..
......O.....O..O......
.......O...OO...OO....
.......O....OO.O......
..............OO......

:Spaceships in Conway's Life A series of articles posted by David Bell to the newsgroup comp.theory.cell-automata during the period August-October 1992 that described many of the new spaceships found by himself, Dean Hickerson and Hartmut Holzwart. Bell produced an addendum covering more recent developments in 1996.

:spark A pattern that dies. The term is typically used to describe a collection of cells periodically thrown off by an oscillator or spaceship, but other dying patterns, particularly those consisting or only one or two cells (such as produced by certain glider collisions, for example), are also described as sparks. For examples of small sparks see unix and HWSS. For an example of a much larger spark see Schick engine.

:spark coil (p2) Found in 1971.


OO....OO
O.O..O.O
..O..O..
O.O..O.O
OO....OO

:sparker An oscillator or spaceship that produces sparks. These can be used to perturb other patterns without being themselves affected.

:sparky A certain c/4 tagalong, shown here attached to the back of a spaceship.


..........O....................
..........O...............OO...
......OO.O.OOO..........OO...O.
O.OO.OO.OO..O.O...OO.OOOO......
O...OO..O.OO..OOO..O.OO..OO...O
O.OO....OOO.O.OOO......OO..O...
........OO.O...............O..O
O.OO....OOO.O.OOO......OO..O...
O...OO..O.OO..OOO..O.OO..OO...O
O.OO.OO.OO..O.O...OO.OOOO......
......OO.O.OOO..........OO...O.
..........O...............OO...
..........O....................

:sparse Life This refers to the study of the evolution of a Life universe which starts off as a random soup of extremely low density. Such a universe is dominated at an early stage by blocks and blinkers (often referred to collectively as blonks) in a ratio of about 2:1. Much later it will be dominated by simple infinite growth patterns (presumably mostly switch engines). The long-term fate of a sparse Life universe is less certain. It may possibly become dominated by self-reproducing patterns (see universal constructor), but it is not at all clear that there is any mechanism for these to deal with the all junk produced by switch engines.

:speed of light A speed of one cell per generation, the greatest speed at which any effect can propagate.

:S-pentomino Conway's name for the following pentomino, which rapidly dies.


..OO
OOO.

:spider (c/5 orthogonally, p5) This is the smallest known c/5 spaceship, and was found by David Bell in April 1997. Its side sparks have proved very useful in constructing c/5 puffers, including rakes. See also pre-pulsar.


......O...OOO.....OOO...O......
...OO.OOOOO.OO...OO.OOOOO.OO...
.O.OO.O.....O.O.O.O.....O.OO.O.
O...O.O...OOOOO.OOOOO...O.O...O
....OOO.....OO...OO.....OOO....
.O..O.OOO.............OOO.O..O.
...O.......................O...

:spiral (p1) Found by Robert Wainwright in 1971.


OO....O
.O..OOO
.O.O...
..O.O..
...O.O.
OOO..O.
O....OO

:SPPS (c/5 orthogonally, p30) The symmetric PPS. The original PPS found by David Bell in May 1998. Compare APPS.

:squaredance The p2 agar formed by tiling the plane with the following pattern. Found by Don Woods in 1971.


OO......
....OO..
..O....O
..O....O
....OO..
OO......
...O..O.
...O..O.

:squirter = pipsquirter

:S-spiral = big S

:stable A pattern is said to be stable if it is a parent of itself. See still life.

:stairstep hexomino (stabilizes at time 63) The following predecessor of the blockade.


..OO
.OO.
OO..

:stamp collection A collection of oscillators (or perhaps other Life objects) in a single diagram, displaying the exhibits much like stamps in a stamp album. The classic examples are by Dean Hickerson (see http://www.radicaleye.com/DRH/stamps.html).

:standard spaceship A glider, LWSS, MWSS or HWSS. These have all been known since 1970.

:star (p3) Found by Hartmut Holzwart, February 1993.


.....O.....
....OOO....
..OOO.OOO..
..O.....O..
.OO.....OO.
OO.......OO
.OO.....OO.
..O.....O..
..OOO.OOO..
....OOO....
.....O.....

:star gate A device by Dieter Leithner (October 1996) for transporting a LWSS faster than the speed of light. The key reaction is the Fast Forward Force Field.

:stator The cells of an oscillator that are always on. Compare rotor. (The stator is sometimes taken to include also some of those cells which are always off.) The stator is divided into the bushing and the casing.

By analogy, the cells of an eater that remain on even when the eater is eating are considered to constitute the stator of the eater. This is not necessarily well-defined, because the eater may have more than one eating action.

:step Another term for a generation. This term is particularly used in describing conduits. For example, a 64-step conduit is one through which the active object takes 64 generations to pass.

:stillater (p3) Found by Robert Wainwright, September 1985. This is one of only three essentially different p3 oscillators with only three cells in the rotor. The others are 1-2-3 and cuphook.


...O....
..O.O.OO
..O.OO.O
OO......
.O.O.OO.
.O.O..O.
..O..O..
...OO...

:still life Any stable pattern, usually assumed to be finite and nonempty. For the purposes of enumerating still lifes this definition is, however, unsatisfactory because, for example, any pair of blocks would count as a still life, and there would therefore be an infinite number of 8-bit still lifes. For this reason a stricter definition is often used, counting a stable pattern as a single still life only if its islands cannot be divided into two nonempty sets both of which are stable in their own right. Compare pseudo still life.

The requirement that a still life not be decomposable into two separate stable patterns may seem a bit arbitrary, as it does not rule out the possibility that it might be decomposable into more than two. This is shown by the patterns in the following diagram, both found by Gabriel Nivasch in July 2001. On the left is a 32-cell pattern that can be broken down into three stable pieces but not into two. On the right is a 34-cell pattern that can be broken down into four stable pieces but not into two or three. (Note that, as a consequence of the Four-Colour Theorem, four is as high as you need ever go.) It is arguable that patterns like these ought not to be considered as single still lifes.


......OO...........OO.
..O.O..O......OO.O..O.
.O.OO.O.......O.OO.O..
.O....OO...........OO.
OO.OO.........O.OO...O
...OO.OO....OOO.OO.OO.
OO....O....O.......O..
.O.OO.O.....OOO.OO.O..
O..O.O........O.O.O...
OO....................

Still lifes have been enumerated by Conway (4-7 bits), Robert Wainwright (8-10 bits), Dave Buckingham (11-13 bits), Peter Raynham (14 bits) and Mark Niemiec (15-24 bits). The resulting figures are shown below. (These figures shouldn't be affected by the above discussion of the strict definition of "still life", because it is unlikely that there are any doubtful cases with much less than 32 cells.)


-------------
Bits   Number
-------------
  4        2
  5        1
  6        5
  7        4
  8        9
  9       10
 10       25
 11       46
 12      121
 13      240
 14      619
 15     1353
 16     3286
 17     7773
 18    19044
 19    45759
 20   112243
 21   273188
 22   672172
 23  1646147
 24  4051711
-------------

:still life tagalong A tagalong which takes the form of a still life in at least one phase. An example is shown below.


..OO...............
.OO.OO.............
..OOOO.............
...OO..............
...................
...OOOOO...........
..OOOOOOO..........
.OO.OOOOO..........
..OO...............
...................
........O.O.....OO.
......O....O...O..O
......OO.....O.O..O
.O..O..OOOO.O...OO.
O.......OO.........
O...O..............
OOOO...............

:stretcher Any pattern that grows by stretching a wick or agar. See wickstretcher and spacefiller.

:strict volatility A term suggested by Noam Elkies in August 1998 for the proportion of cells involved in a period n oscillator which themselves oscillate with period n. For prime n this is the same as the ordinary volatility.

:super beehive = honeycomb

:superfountain (p4) A p4 sparker which produces a 1-cell spark that is separated from the rest of the oscillator by two clear rows of cells. The first superfountain was found by Noam Elkies in February 1998. In January 2006 Nicolay Beluchenko found the much smaller one shown below. See also fountain.


...........O...........
.......................
.......................
.....O..O.....O..O.....
...OO..O.OOOOO.O..OO...
.....O...........O.....
...O.OO.........OO.O...
.O.O...OOO...OOO...O.O.
OOO.O.............O.OOO
..........O.O..........
....OOO...O.O...OOO....
....O..O...O...O..O....
...OOOO..O.O.O..OOOO...
...OO..OOO.O.OOO..OO...
..O...O...O.O...O...O..
...O..O.O.O.O.O.O..O...
....O.O.OO...OO.O.O....
.....O...........O.....

:superstring An infinite orthogonal row of cells stabilized on one side so that it moves at the speed of light, often leaving debris behind. The first examples were found in 1971 by Edward Fitzgerald and Robert Wainwright. Superstrings were studied extensively by Peter Rott during 1992-1994, and he found examples with many different periods. (But no odd periods. In August 1998 Stephen Silver proved that odd-period superstrings are impossible.)

Sometimes a finite section of a superstring can be made to run between two tracks ("waveguides"). This gives a fuse which can be made as wide as desired. The first example was found by Tony Smithurst and uses tubs. (This is shown below. The superstring itself is p4 with a repeating section of width 9 producing one blinker per period and was one of those discovered in 1971. With the track in place, however, the period is 8. This track can also be used with a number of other superstrings.) Shortly after seeing this example, in March 1997 Peter Rott found another superstring track consisting of boats. At present these are the only two waveguides known. Both are destroyed by the superstring as it moves along - it would be interesting to find one that remains intact.

See titanic toroidal traveler for another example of a superstring.


.OO..........................................................
O..O...O...O...O...O...O...O...O...O...O...O...O...O...O...O.
....O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O
O..O...O...O...O...O...O...O...O...O...O...O...O...O...O...O.
.OOO.........................................................
..OO.........................................................
..OO.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
..OO.........................................................
..OO.........................................................
.OOO.........................................................
O..O...O...O...O...O...O...O...O...O...O...O...O...O...O...O.
....O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O
O..O...O...O...O...O...O...O...O...O...O...O...O...O...O...O.
.OO..........................................................

:support Those parts of an object which are only present in order to keep the rest of the object (such an engine or an edge spark) working correctly. These can be components of the object, or else accompanying objects used to perturb the object. In many cases there is a wide variation of support possible for an engine. The arms in many puffers are an example of support.

:surprise (p3) Found by Dave Buckingham, November 1972.


...O....OO
...OOO..O.
.OO...O.O.
O..OO.O.OO
.O......O.
OO.O.OO..O
.O.O...OO.
.O..OOO...
OO....O...

:swan (c/4 diagonally, p4) A diagonal spaceship producing some useful sparks. Found by Tim Coe in February 1996.


.O..........OO..........
OOOOO......OO...........
O..OO........O.......OO.
..OO.O.....OO......OOO.O
...........OO...O.OO....
.....O.O......OO........
..........OOO.O....O....
.......OOO...O....O.....
........O.......O.......
........O......O........
........................
...........O............

:switch engine The following pattern, which in itself is unstable, but which can be used to make c/12 diagonal puffers and spaceships.


.O.O..
O.....
.O..O.
...OOO

The switch engine was discovered by Charles Corderman in 1971. He also found the two basic types of stabilized switch engine: a p288 block-laying type (the more common of the two) and p384 glider-producing type. These two puffers are the most natural infinite growth patterns in Life, being the only ones ever seen to occur from random starting patterns.

Patterns giving rise to block-laying switch engines can be seen under infinite growth, and one giving rise to a glider-producing switch engine is shown under time bomb. See also Cordership and ark.

:synthesis = glider synthesis


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_h.htm0000644000175000017500000007505312536111364014334 00000000000000 Life Lexicon (H)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:half bakery See bi-loaf.

:half fleet = ship-tie

:hammer To hammer a LWSS, MWSS or HWSS is to smash things into the rear end of it in order to transform it into a different type of spaceship. A hammer is the object used to do the hammering. In the following example by Dieter Leithner a LWSS is hammered by two more LWSS to make it into a MWSS.


O..O................
....O...OO..........
O...O..OOO.....OOOO.
.OOOO..OO.O....O...O
........OOO....O....
.........O......O..O

:hammerhead A certain front end for c/2 spaceships. The central part of the hammerhead pattern is supported between two MWSS. The picture below shows a small example of a spaceship with a hammerhead front end (the front 9 columns).


................O..
.OO...........O...O
OO.OOO.......O.....
.OOOOO.......O....O
..OOOOO.....O.OOOO.
......OOO.O.OO.....
......OOO....O.....
......OOO.OOO......
..........OO.......
..........OO.......
......OOO.OOO......
......OOO....O.....
......OOO.O.OO.....
..OOOOO.....O.OOOO.
.OOOOO.......O....O
OO.OOO.......O.....
.OO...........O...O
................O..

:handshake An old MIT name for lumps of muck, from the following form (2 generations on from the stairstep hexomino):


..OO.
.O.OO
OO.O.
.OO..

:harbor (p5) Found by Dave Buckingham in September 1978. The name is by Dean Hickerson.


.....OO...OO.....
.....O.O.O.O.....
......O...O......
.................
.....OO...OO.....
OO..O.O...O.O..OO
O.O.OO.....OO.O.O
.O.............O.
.................
.O.............O.
O.O.OO.....OO.O.O
OO..O.O...O.O..OO
.....OO...OO.....
.................
......O...O......
.....O.O.O.O.....
.....OO...OO.....

:harvester (c p4 fuse) Found by David Poyner, this was the first published example of a fuse. The name refers to the fact the it produces debris in the form of blocks which contain the same number of cells as the fuse has burnt up.


................OO
...............O.O
..............O...
.............O....
............O.....
...........O......
..........O.......
.........O........
........O.........
.......O..........
......O...........
.....O............
OOOOO.............
OOOO..............
O.OO..............

:hashlife A Life algorithm by Bill Gosper that is designed to take advantage of the considerable amount of repetitive behaviour in many large patterns of interest. This algorithm is described by Gosper in his paper listed in the bibliography at the end of this lexicon. Roughly speaking, the idea is to store subpatterns in a hash table so that the results of their evolution do not need to be recomputed if they arise again at some other place or time in the evolution of the full pattern. This does, however, mean that complex patterns can require substantial amounts of memory.

Hashlife provides a means of evolving repetitive patterns millions (or even billions or trillions) of generations further than normal Life algorithms can manage in a reasonable amount of time. It is not, however, suitable for showing a continuous display of the evolution of a pattern, because it works asynchronously - at any given moment it will usually have evolved different parts of the pattern through different numbers of generations.

:hassle See hassler.

:hassler An oscillator that works by hassling (repeatedly moving or changing) some object. For some examples, see Jolson, baker's dozen, toad-flipper, toad-sucker and traffic circle.

:hat (p1) Found in 1971. See also twinhat and sesquihat.


..O..
.O.O.
.O.O.
OO.OO

:heat For an oscillator or spaceship, the average number of cells which change state in each generation. For example, the heat of a glider is 4, because 2 cells are born and 2 die every generation.

For a period n oscillator with an r-cell rotor the heat is at least 2r/n and no more than r(1-(n mod 2)/n). For n=2 and n=3 these bounds are equal.

:heavyweight emulator = HW emulator

:heavyweight spaceship = HWSS

:heavyweight volcano = HW volcano

:hebdarole (p7) Found by Noam Elkies, November 1997. Compare fumarole. The smaller version shown below was found soon after by Alan Hensel using a component found by Dave Buckingham in June 1977. The top tens rows can be stabilized by their mirror image (giving an inductor) and this was the original form found by Elkies.


...........OO...........
....OO...O....O...OO....
.O..O..O.O....O.O..O..O.
O.O.O.OO.O....O.OO.O.O.O
.O..O..O.O.OO.O.O..O..O.
....OO....O..O....OO....
...........OO...........
.......O..O..O..O.......
......O.OO....OO.O......
.......O........O.......
........................
...OO..............OO...
...O..OOOO....OOOO..O...
....O.O.O.O..O.O.O.O....
...OO.O...OOOO...O.OO...
.......OO......OO.......
.........OO..OO.........
.........O..O.O.........
..........OO............

:hectic (p30) Found by Robert Wainwright in September 1984.


......................OO...............
......................OO...............
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.........O..........OO...OO............
.......O.O............OOO..............
......O.O............O...O.............
OO...O..O.............O.O..............
OO....O.O..............O...............
.......O.O......O.O....................
.........O......OO.....................
.................O...O.................
.....................OO......O.........
....................O.O......O.O.......
...............O..............O.O....OO
..............O.O.............O..O...OO
.............O...O............O.O......
..............OOO............O.O.......
............OO...OO..........O.........
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
...............OO......................
...............OO......................

:Heisenburp device A pattern which can detect the passage of a glider without affecting the glider's path or timing. The first such device was constructed by David Bell in December 1992. The term is due to Bill Gosper.

The following is an example of the kind of reaction used at the heart of a Heisenburp device. The glider at bottom right alters the reaction of the other two gliders without itself being affected in any way.


O.....O....
.OO...O.O..
OO....OO...
...........
...........
...........
.........OO
........O.O
..........O

:helix A convoy of standard spaceships used in a Caterpillar to move some piece of debris at the speed of the Caterpillar. The following diagram illustrates the idea.


...............................O.............
.................O............OOO............
................OOO....OOO....O.OO...........
.........OOO....O.OO...O..O....OOO..OOO......
.........O..O....OOO...O.......OO...O........
.........O.......OO....O...O.........O.......
.........O...O.........O...O.................
OOO......O...O.........O.....................
O..O.....O..............O.O..................
O.........O.O................................
O............................................
.O.O.........................................
.............................................
.............................................
..........O..................................
.........OOO.................................
.........O.OO................................
..........OOO................................
..........OO.................................
.............................................
.............................................
...............OOO...........................
...............O..O....O.....OOO.............
...............O......OOO....O..O....O.......
...............O.....OO.O....O......OOO......
....OOO.........O.O..OOO.....O.....OO.O......
....O..O.............OOO......O.O..OOO.......
....O................OOO...........OOO.......
....O.................OO...........OOO.......
.....O.O............................OO.......
...........................................O.
..........................................OOO
.........................................OO.O
.........................................OOO.
..........................................OO.
.............................................
.............................................
.............................................
.............................................
.............................................
.............................................
.........................................O...
..............................OOO.......OOO..
................OOO.....O....O..O......OO.O..
..........O....O..O....OOO......O......OOO...
.........OOO......O....O.OO.....O......OOO...
.........O.OO.....O.....OOO..O.O........OO...
..........OOO..O.O......OOO..................
.O........OOO...........OOO..................
OOO.......OOO...........OO...................
O.OO......OO.................................
.OOO......................................O..
.OO......................................OOO.
........................................OO.O.
........................................OOO..
.........................................OO..
.........OOO.................................
........O..O.................................
...........O.................................
...........O.................................
........O.O..................................

:heptaplet Any 7-cell polyplet.

:heptapole (p2) The barberpole of length 7.


OO........
O.O.......
..........
..O.O.....
..........
....O.O...
..........
......O.O.
.........O
........OO

:heptomino Any 7-cell polyomino. There are 108 such objects. Those with names in common use are the B-heptomino, the Herschel and the pi-heptomino.

:Herschel (stabilizes at time 128) The following pattern which occurs at generation 20 of the B-heptomino.


O..
OOO
O.O
..O

:Herschel conduit A conduit that moves a Herschel from one place to another. See also Herschel loop.

Sixteen simple stable Herschel conduits are currently known, having been discovered from 1995 onwards by Dave Buckingham (DJB) and Paul Callahan (PBC). (Of course, the number depends on what is meant by "simple".) These are shown in the following table. In this table "steps" is the number of steps, "m" tells how the Herschel is moved (R = turned right, L = turned left, B = turned back, F = unturned, f = flipped), and "dx" and "dy" give the displacement of the centre cell of the Herschel (assumed to start in the orientation shown above).


------------------------------------
steps  m     dx   dy     discovery
------------------------------------
  64   R    -11    9   DJB, Sep 1995
  77   Ff   -25   -8   DJB, Aug 1996
 112   L    -12  -33   DJB, Jul 1996
 116   F    -32    1   PBC, Feb 1997
 117   F    -40   -6   DJB, Jul 1996
 119   Ff   -20   14   DJB, Sep 1996
 125   Bf     9  -17   PBC, Nov 1998
 153   Ff   -48   -4   PBC, Feb 1997
 156   L    -17  -41   DJB, Aug 1996
 158   Ff   -27   -5   DJB, Jul 1996
 166   F    -49    3   PBC, May 1997
 176   Ff   -45    0   PBC, Oct 1997
 190   R    -24   16   DJB, Jul 1996
 200   Lf   -17  -40   PBC, Jun 1997
 202   Rf    -7   32   DJB, May 1997
 222   Bf     6  -16   PBC, Oct 1998
------------------------------------

See also Herschel transceiver.

:Herschel loop A cyclic Herschel track. Although no loop of length less than 256 generations has been constructed it is possible to make oscillators of smaller periods by putting more than one Herschel in the track. In this way oscillators, and in most cases guns, of all periods from 54 onwards can now be constructed (although the p55 case is a bit strange, shooting itself with gliders in order to stabilize itself). See also emu and omniperiodic.

:Herschel receiver A pattern found by Paul Callahan in 1996, as part of the first stable glider reflector. Used as a receiver, it converts two parallel input gliders (with path separations of 2, 5, or 6) to an R-pentomino, which is then converted to a Herschel by one of two known mechanisms (the first of which was found by Dave Buckingham way back in 1972, and the second by Stephen Silver in October 1997). The version using Buckingham's R-to-Herschel converter is shown below.


...............................................O.O
......................................OO.......OO.
......................................OO........O.
...OO.............................................
...O..............................................
....O.............................................
...OO.............................................
............OO....................................
...........O.O....................................
............O..............................O......
......................................OO...O.O....
.....................................O..O..OO.....
OO....................................OO..........
OO.............................OO.................
...............................OO.................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
............................................OO....
............................................OO....
........................................OO........
........................................O.O.......
..........................................O.......
..........................................OO......
.............................OO...................
.............................OO...................
..................................................
..................................................
...........................OO.....................
...........................OO.....................

:Herschel track A track for Herschels. See also B track.

:Herschel transceiver An adjustable Herschel conduit made up of a Herschel transmitter and a Herschel receiver. The intermediate stage consists of two gliders on parallel tracks, so the transmitter and receiver can be separated by any required distance. The conduit may be stable, or may contain low-period oscillators.

:Herschel transmitter Any Herschel-to-glider converter that produces two gliders on parallel tracks which can be used as input to a Herschel receiver. If the gliders are far enough apart, a suitably oriented mirror image of the receiver will also work: the first glider triggers the receiver and the second glider deletes the extra beehive.

The following diagram shows a stable Herschel transmitter found by Paul Callahan in May 1997:


......OO...........
.....O.O...........
...OOO.............
..O...O......O.....
..OO.OO......OOO...
.............O.O...
...............O...
...................
...................
OO.O...............
O.OO...............
...................
...................
...................
...............OO..
...............O...
................OOO
..................O
Examples of small reversible p6 and p7 transmitters are also known.

:Hertz oscillator (p8) Compare negentropy, and also cauldron. Found by Conway's group in 1970.


...OO.O....
...O.OO....
...........
....OOO....
...O.O.O.OO
...O...O.OO
OO.O...O...
OO.O...O...
....OOO....
...........
....OO.O...
....O.OO...

:hexadecimal = beehive and dock

:hexaplet Any 6-cell polyplet.

:hexapole (p2) The barberpole of length 6.


OO.......
O.O......
.........
..O.O....
.........
....O.O..
.........
......O.O
.......OO

:hexomino Any 6-cell polyomino. There are 35 such objects. For some examples see century, stairstep hexomino, table, toad and Z-hexomino.

:H-heptomino Name given by Conway to the following heptomino. After one generation this is the same as the I-heptomino.


OO..
.O..
.OOO
..O.

:hive = beehive

:hivenudger (c/2 orthogonally, p4) A spaceship found by Hartmut Holzwart in July 1992. (The name is due to Bill Gosper.) It consists of a pre-beehive escorted by four LWSS. In fact any LWSS can be replaced by a MWSS or a HWSS, so that there are 45 different single-hive hivenudgers.


OOOO.....O..O
O...O...O....
O.......O...O
.O..O...OOOO.
.............
.....OO......
.....OO......
.....OO......
.............
.O..O...OOOO.
O.......O...O
O...O...O....
OOOO.....O..O
Wider versions can be made by stabilizing the front of the extended "pre-beehive", as in the line puffer shown below.

.........O.O..................
........O..O..................
.......OO.....................
......O...O...................
.....OOO.O....................
..OO..........................
.O...OOOOO.......OOOO.....O..O
O...O............O...O...O....
O.....OO.........O.......O...O
OOO...OOOO........O..O...OOOO.
.O.......O....................
.OO...................OO......
.O.O..................OO......
.OO..OO.O........O.O..OO......
..O.OOO.O...O.OOOO.O..OO......
.........OO.O.OO..O...OO...OOO
....OOOOOO.OO...OOOO..OO...OOO
.....O....OOO......O..OO...OOO
......OO.....OO..OO...OO......
.......O..O.....OOOO..OO......
........O.O.OO.....O..OO......
......................OO......
..............................
..................O..O...OOOO.
.................O.......O...O
.................O...O...O....
.................OOOO.....O..O

:honeycomb (p1)


..OO..
.O..O.
O.OO.O
.O..O.
..OO..

:honey farm (p1) A common formation of four beehives.


......O......
.....O.O.....
.....O.O.....
......O......
.............
.OO.......OO.
O..O.....O..O
.OO.......OO.
.............
......O......
.....O.O.....
.....O.O.....
......O......

:hook Another term for a bookend. It is also used for other hook-shaped things, such as occur in the eater1 and the hook with tail, for example.

:hook with tail (p1) For a long time this was the smallest still life without a well-established name. It is now a vital component of the smallest known HWSS gun, where it acts as a rock.


O.O..
OO.O.
...O.
...OO

:houndstooth agar The p2 agar that results from tiling the plane with the following pattern.


.OOO
.O..
..O.
OOO.

:house The following induction coil. It is generation 3 of the pi-heptomino. See spark coil and dead spark coil.


.OOO.
O...O
OO.OO

:hustler (p3) Found by Robert Wainwright, June 1971.


.....OO....
.....OO....
...........
...OOOO....
O.O....O...
OO.O...O...
...O...O.OO
...O....O.O
....OOOO...
...........
....OO.....
....OO.....

:hustler II (p4)


....O...........
....OOO.........
.......O........
......O..OO.....
O.OO.O.OO..O....
OO.O.O.....O....
.....O....O.....
....O.....O.O.OO
....O..OO.O.OO.O
.....OO..O......
........O.......
.........OOO....
...........O....

:HW emulator (p4) Found by Robert Wainwright in June 1980. See also emulator.


.......OO.......
..OO.O....O.OO..
..O..........O..
...OO......OO...
OOO..OOOOOO..OOO
O..O........O..O
.OO..........OO.

:HWSS (c/2 orthogonally, p4) A heavyweight spaceship, the fourth most common spaceship. Found by Conway in 1970. See also LWSS and MWSS.


...OO..
.O....O
O......
O.....O
OOOOOO.

:HWSS emulator = HW emulator

:HW volcano (p5) A p5 domino sparker, found by Dean Hickerson in February 1995. There are at least two known forms for this, one of which is shown below.


.........O..........................
........O.O.........................
......OOO.O.........................
.....O....OO.O......................
.....O.OO...OO......OO..............
....OO.O.OO.........O.O.............
.........O.OOOOO......O..O.OO.......
..O.OO.OO.O.....O....OO.O.OO.O......
.....OO.....OOOO........O....O......
O...O.O..O...O.O....OO.O.OOOO.OO....
O...O.O..OO.O.OO.OO....O.O....O.O...
.....OO...OOO.OO.O.OOO.O..OOO...O...
..O.OO.OO.OO.............O.O..O.O.OO
...........O......O.O.O.O..OO.O.O.O.
....OO.O.O.OO......OO.O.O.O...O.O.O.
.....O.OO.O..O.......O.OO..OOOO.OO..
.....O....O.O........O...OO.........
....OO....OO........OO...O..O.......
...........................OO.......

:hybrid grey ship A grey ship containing more than one type of region of density 1/2, usually a combination of a with-the-grain grey ship and an against-the-grain grey ship.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_v.htm0000644000175000017500000001135112536111364014341 00000000000000 Life Lexicon (V)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:vacuum Empty space. That is, space containing only dead cells.

:Venetian blinds The p2 agar obtained by using the pattern O..O to tile the plane.

:very long = long long

:very long house The following induction coil.


.OOOOO.
O..O..O
OO...OO

:volatility The volatility of an oscillator is the size (in cells) of its rotor divided by the sum of the sizes of its rotor and its stator. In other words, it is the proportion of cells involved in the oscillator which actually oscillate. For many periods there are known oscillators with volatility 1, see for example Achim's p16, figure-8, Kok's galaxy, mazing, pentadecathlon, phoenix, relay, smiley and tumbler. The smallest period for which the existence of such statorless oscillators is undecided is 3, although Dean Hickerson showed in 1994 that there are p3 oscillators with volatility arbitrarily close to 1 (as is the case for all but finitely many periods, because of the possibility of feeding the gliders from a true period n gun into an eater).

The term "volatility" is due to Robert Wainwright. See also strict volatility.

:volcano Any of a number of p5 oscillators which produce sparks. See lightweight volcano, middleweight volcano and heavyweight volcano.

:V-pentomino Conway's name for the following pentomino, a loaf predecessor.


O..
O..
OOO

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_k.htm0000644000175000017500000001237212536111364014332 00000000000000 Life Lexicon (K)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:keys See short keys, bent keys and odd keys.

:kickback reaction The following collision of two gliders whose product is a single glider travelling in the opposite direction to one of the original gliders. This is important in the proof of the existence of a universal constructor, and in Bill Gosper's total aperiodic, as well as a number of other constructions.


.....O..
......OO
.OO..OO.
O.O.....
..O.....

:kidney A Gosperism for century. See also diuresis.

:killer toads A pair of toads acting together so that they can eat things. Here, for example, are some killer toads eating a HWSS. Similarly they can eat a MWSS (but not a LWSS). For another example see twirling T-tetsons II. See also candlefrobra.


..OO.......OOO
O....O....OOO.
......O.......
O.....O.......
.OOOOOO.......
..........OOO.
...........OOO

:Klein bottle As an alternative to a torus, it's possible to make a finite Life universe in the form of a Klein bottle. The simplest way to do this is to use an m x n rectangle with the top edge joined to the bottom edge (as for a torus) and the left edge twisted and joined to the right.

:knightship Any spaceship of type (2m,m)/n. Such spaceships do exist (see universal constructor), but no concrete example is known. A knightship must be asymmetric and its period must be at least 6, which makes searching for them using programs like lifesrc very difficult.

By analogy with the corresponding fairy chess pieces, spaceships of types (3m,m)/n, (3m,2m)/n and (4m,m)/n would presumably be called camelships, zebraships and giraffeships, respectively. But no examples of these are known either, and they are even more difficult to search for.

:Kok's galaxy (p8) Found by Jan Kok in 1971. See converter for a use of this sparker.


OOOOOO.OO
OOOOOO.OO
.......OO
OO.....OO
OO.....OO
OO.....OO
OO.......
OO.OOOOOO
OO.OOOOOO

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_p.htm0000644000175000017500000012613412536111364014341 00000000000000 Life Lexicon (P)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:p = period

:p30 shuttle = queen bee shuttle

:p46 shuttle = twin bees shuttle

:p54 shuttle (p54) A surprising variant of the twin bees shuttle found by Dave Buckingham in 1973. See also centinal.


OO.........................OO
.O.........................O.
.O.O.......O.............O.O.
..OO.....O..O.....O......OO..
............O.....OO.........
........O..........OO........
........O...OO....OO.........
.........OOOOO...............
.............................
.........OOOOO...............
........O...OO....OO.........
........O..........OO........
............O.....OO.........
..OO.....O..O.....O......OO..
.O.O.......O.............O.O.
.O.........................O.
OO.........................OO

:p6 shuttle (p6) The following oscillator found by Nicolay Beluchenko in February 2004.


O.............
OOO...........
...O..........
..OO..........
..............
......O.......
.....OOOO.....
......O..O....
.......OOO....
..............
..........OO..
..........O...
...........OOO
.............O
This is extensible in more than one way:

O........................
OOO......................
...O.....................
..OO.....................
.........................
......O..................
.....OOOO................
......O..O...............
.......OOO...............
.........................
..........OOO............
..........O..O...........
...........OOOO..........
.............O...........
.........................
.................O.......
................OOO......
.................O.O.....
.................O.O.....
..................OO.....
.....................OO..
.....................O.O.
.......................O.
.......................OO

:pair of bookends = bookends

:pair of tables = table on table

:paperclip (p1)


..OO.
.O..O
.O.OO
OO.O.
O..O.
.OO..

:parallel grey ship = with-the-grain grey ship

:parent A pattern is said to be a parent of the pattern it gives rise to after one generation. Some patterns have infinitely many parents, but other have none at all (see Garden of Eden).

:parent cells The three cells that cause a new cell to be born.

:PD = pentadecathlon

:pedestle (p5)


.....O.....
....O.O....
.O..OO.....
.OOO.......
.....OOO...
...OO...O..
..O....O..O
.O.O.O.O.OO
.O.O...O.O.
OO.O.O.O.O.
O..O....O..
..O...OO...
...OOO.....
.......OOO.
.....OO..O.
....O.O....
.....O.....

:penny lane (p4) Found by Dave Buckingham, 1972.


...OO.....OO...
...O.......O...
OO.O.......O.OO
OO.O.OOOOO.O.OO
....O..O..O....
.....OOOOO.....
...............
.......O.......
......O.O......
.......O.......

:pentadecathlon (p15) Found in 1970 by Conway while tracking the history of short rows of cells, 10 cells giving this object, which is the most natural oscillator of period greater than 3. In fact it is the fifth or sixth most common oscillator overall, being about as frequent as the clock, but much less frequent than the blinker, toad, beacon or pulsar.


..O....O..
OO.OOOO.OO
..O....O..
The pentadecathlon is the only known oscillator which is a polyomino in more than one phase.

:pentant (p5) Found by Dave Buckingham, July 1976.


OO........
.O........
.O.O......
..OO....OO
.........O
.....OOOO.
.....O....
..O...OOO.
..OOOO..O.
.....O....
....O.....
....OO....

:pentaplet Any 5-cell polyplet.

:pentapole (p2) The barberpole of length 5.


OO......
O.O.....
........
..O.O...
........
....O.O.
.......O
......OO

:pentoad (p5) Found by Bill Gosper, June 1977. This is extensible: if an eater is moved back four spaces then another Z-hexomino can can be inserted. (This extensibility was discovered by Scott Kim.)


...........OO
...........O.
.........O.O.
.........OO..
.....OO......
......O......
......O......
......OO.....
..OO.........
.O.O.........
.O...........
OO...........

:pentomino Any 5-cell polyomino. There are 12 such patterns, and Conway assigned them all letters in the range O to Z, loosely based on their shapes. Only in the case of the R-pentomino has Conway's label remained in common use, but all of them can nonetheless be found in this lexicon.

:period The smallest number of generations it takes for an oscillator or spaceship to reappear in its original form. The term can also be used for a puffer, wick, fuse, superstring, stream of spaceships, factory or gun. In the last case there is a distinction between true period and pseudo period. There is also a somewhat different concept of period for wicktrailers.

:perpendicular grey ship = against-the-grain grey ship

:perturb To change the fate of an object by reacting it with other objects. Typically, the other objects are sparks from spaceships or oscillators, or are eaters or impacting spaceships. Perturbations are typically done to turn a dirty reaction into a clean one, or to change the products of a reaction. In many desirable cases the perturbing objects are not destroyed by the reaction, or else are easily replenished.

:perturbation See perturb.

:phase A representative generation of a periodic object such as an oscillator or spaceship. The number of phases is equal to the period of the object. The phases of an object usually repeat in the same cyclic sequence forever, although some perturbations can cause a phase change.

:phase change A perturbation of a periodic object which causes the object to skip ahead by one or more phases. If the perturbation is repeated indefinitely, this can effectively change the period of the object. An example of this, found by Dean Hickerson in November 1998, is shown below. In this example, the period of the oscillator would be 7 if the mold were removed, but the period is increased to 8 because of the repeated phase changes caused by the mold's spark.


..........O....
.........O.OO..
..OO.........O.
..O......O..O.O
.......O...O..O
OOOOOO.O....OO.
O..............
.OO.OO...OO....
..O.O....O.O...
..O.O......O...
...O.......OO..
The following pattern demonstrates a p4 c/2 spaceship found by Jason Summers, in which the phase is changed as it deletes a forward glider. This phase change allows the spaceship to be used to delete a glider wave produced by a rake whose period is 2 (mod 4).

........O...........................
.......OOO.OO.......................
......OO...O.OO.....................
.....OO..O.....O....................
......O.....O...O.OOO...............
.....OO.....O...O.O..O..............
...OO.O.OO....O.O.O...O.............
....O.O..OO...........O.............
.OO.O..O..O.........O...............
.OO.O.....OO.........O.OOO..........
.O.O.............OOO.O.O.OO.........
OO.OO...........OO.O..O.O.O.........
..............OO.O...OOO..OO.....OO.
.............O...O......O........O.O
............O.....O..OO.O.OO.....O..
...........O..O.O......O.O..........
...........O.....OO....OOO..........
.............O..........O...........
..........O.O...........O...........
.........OO.O.OOO...................
........O.O.O...O...................
.......OO.O.........................
......O...O.....OO..................
....................................
......OO.OO.........................

Phase changing reactions have enabled the construction of spaceships having periods that were otherwise unknown, and also allow the construction of period-doubling and period-tripling convoys to easily produce very high period rakes.

See also blinker puffer.

:phi The following common spark. The name comes from the shape in the generation after the one shown here.


.OOO.
O...O
O...O
.OOO.

:phoenix Any pattern all of whose cells die in every generation, but which never dies as a whole. A spaceship cannot be a phoenix, and in fact every finite phoenix eventually evolves into an oscillator. The following 12-cell oscillator (found by the MIT group in December 1971) is the smallest known phoenix, and is sometimes called simply "the phoenix".


....O...
..O.O...
......O.
OO......
......OO
.O......
...O.O..
...O....
Every known phoenix oscillator has period 2. In January 2000, Stephen Silver showed that a period 3 oscillator cannot be a phoenix. The situation for higher periods is unknown.

:pi = pi-heptomino

:pi-heptomino (stabilizes at time 173) A common pattern. The name is also applied to later generations of this object - in a pi ship, for example, the pi-heptomino itself never arises.


OOO
O.O
O.O

:pincers = great on-off

:pinwheel (p4) Found by Simon Norton, April 1970. Compare clock II.


......OO....
......OO....
............
....OOOO....
OO.O....O...
OO.O..O.O...
...O...OO.OO
...O.O..O.OO
....OOOO....
............
....OO......
....OO......

:pi orbital (p168) Found by Noam Elkies, August 1995. In this oscillator, a pi-heptomino is turned ninety degrees every 42 generations. A second pi can be inserted to reduce the period to 84.


..............OO....OO....OO...............................
.............O..O.O....O.O..O..............................
.............OOO..........OOO..............................
................OO......OO.................................
...............O..OOOOOO..O................................
...............OO........OO................................
...........................................................
........O.............................OO..........O........
.......O...OOO......O.........O.......OO.........O.O.......
........O.OOOOO..........OOO...O...........................
............O...O.....O.OOOOO.O..................O.........
............OO....OOO.....O......................OO........
............OO....OOO....OO...................OOOOO........
...................O.....OO...................OO.OO.....OO.
.................................................O......O.O
.....................................................OO.O.O
.....................................................O.O.O.
.......................................................O...
...................................OOO.........O.O...O..O..
.......OO..........................O..O........O..O.....O..
.......OO..............................O.......O.O..O...O..
...................................O..O.............O...O..
...................................OOO..................O..
.....................................................O..O..
................................................O......O...
.............................................OO.OO...O.O.O.
.............................................OOOOO...OO.O.O
.........O......................................OO......O.O
........O.O.....................................O.......OO.
...........................................................
.OO.......O.....................................O.O........
O.O......OO......................................O.........
O.O.OO...OOOOO.............................................
.O.O.O...OO.OO.............................................
...O......O................................................
..O..O.....................................................
..O........................................................
..O...O....................................................
..O...O..O.O......................................OO.......
..O.....O..O......................................OO.......
..O..O...O.O...............................................
...O.......................................................
.O.O.O.....................................................
O.O.OO.....................................................
O.O......O.................................................
.OO.....OO.OO...................OO.....O...................
........OOOOO...................OO....OOO....OO............
........OO......................O.....OOO....OO............
.........O..................O.OOOOO.O.....O...O............
...........................O...OOO..........OOOOO.O........
.......O.O.........OO.......O.........O......OOO...O.......
........O..........OO.............................O........
...........................................................
................................OO........OO...............
................................O..OOOOOO..O...............
.................................OO......OO................
..............................OOO..........OOO.............
..............................O..O.O....O.O..O.............
...............................OO....OO....OO..............

:pi portraitor (p32) Found by Robert Wainwright in 1984 or 1985. Compare with gourmet and popover.


...........OO...........
......OO.O....O.OO......
......O..........O......
.......OO......OO.......
....OOO..OOOOOO..OOO....
....O..O........O..O....
.OO.O.O..........O.O.OO.
.O.O.O............O.O.O.
...O................O...
.O..O..............O..O.
....O.......OOO....O....
O...O.......O.O....O...O
O...O.......O.O....O...O
....O..............O....
.O..O..............O..O.
...O................O...
.O.O.O............O.O.O.
.OO.O.O..........O.O.OO.
....O..O........O..O....
....OOO..OOOOOO..OOO....
.......OO......OO.......
......O..........O......
......OO.O....O.OO......
...........OO...........

:pipsquirt = pipsquirter

:pipsquirter An oscillator that produces a domino spark that is orientated parallel to the direction from which it is produced (in contrast to domino sparkers like the pentadecathlon and HWSS, which produce domino sparks perpendicular to the direction of production). The following is a small p6 example found by Noam Elkies in November 1997.


.....O.........
.....O.........
...............
...O...O.......
.OOO.O.OOO.....
O...OO....O....
O.OO..OO.O.O...
.O..OO..OO.O...
..OO..OO.O.O.OO
....O..O.O.O.OO
....OOOO.OO....
........O......
......O.O......
......OO.......

:pi ship A growing spaceship in which the back part consists of a pi-heptomino travelling at a speed of 3c/10. The first example was constructed by David Bell. All known pi ships are too large to show here, but the following diagram shows how the pi fuse works.


............O............
...........O.O...........
OO........OO.OO........OO
OO.....................OO

:piston (p2) Found in 1971.


OO.......OO
O.O..O..O.O
..OOOO..O..
O.O..O..O.O
OO.......OO

:pi wave A line of pi-heptominoes stabilizing one another. For example, an infinite line of pi-heptominoes arranged as shown below produces a pi wave that moves at a speed of 3c/10, and leaves no debris.


OOO...............OOO...............OOO...............OOO
O.O...............O.O...............O.O...............O.O
O.O...............O.O...............O.O...............O.O

:pixel = cell

:plet = polyplet

:polyomino A finite collection of orthogonally connected cells. The mathematical study of polyominoes was initiated by Solomon Golomb in 1953. Conway's early investigations of Life and other cellular automata involved tracking the histories of small polyominoes, this being a reasonable way to ascertain the typical behaviour of different cellular automata when the patterns had to be evolved by hand rather than by computer. Polyominoes have no special significance in Life, but their extensive study during the early years lead to a number of important discoveries and has influenced the terminology of Life. (Note on spelling: As with "dominoes" the plural may also be spelt without an e. In this lexicon I have followed Golomb in using the longer form.)

It is possible for a polyomino to be an oscillator. In fact there are infinitely many examples of such polyominoes, namely the cross and its larger analogues. The only other known examples are the block, the blinker, the toad, the star and (in two different phases) the pentadecathlon.

A polyomino can also be a spaceship, as the LWSS, MWSS and HWSS show.

:polyplet A finite collection of orthogonally or diagonally connected cells. This king-wise connectivity is a more natural concept in Life than the orthogonal connectivity of the polyomino.

:pond (p1)


.OO.
O..O
O..O
.OO.

:pond on pond (p1) This term is often used to mean bi-pond, but may also be used of the following pseudo still life.


.OO...OO.
O..O.O..O
O..O.O..O
.OO...OO.

:popover (p32) Found by Robert Wainwright in August 1984. Compare with gourmet and pi portraitor.


.....................O..........
.....................O..........
.....................OOO........
.............OO.......OO........
.............OO..OOO..OO........
...................OOO..........
...................OOO..........
..............OO................
..OOO........O..O...............
..OOO........O.O................
OOO..OO...O...O....OOO..........
.....OO...O.....................
....OOO...O.....................
....O.................OO...OO...
....O...........OOO..O..O..OO...
........O.......O.O...O.O.......
.......O.O......O.O....O........
...OO..O..O................O....
...OO...OO.................O....
.....................O...OOO....
.....................O...OO.....
..........OOO........O...OO..OOO
.................OO........OOO..
................O..O.......OOO..
................O.O.............
..........OOO....O..............
..........OOO...................
........OO..OOO..OO.............
........OO.......OO.............
........OOO.....................
..........O.....................
..........O.....................

:population The number of ON cells.

:P-pentomino Conway's name for the following pentomino, a common spark.


OO
OO
O.

:PPS (c/5 orthogonally, p30) A pre-pulsar spaceship. Any of three different p30 c/5 orthogonal spaceships in which a pre-pulsar is pushed by a pair of spiders. The back sparks of the spaceship can be used to perturb gliders in many different ways, allowing the easy construction of c/5 puffers. The first PPS was found by David Bell in May 1998 based on a p15 pre-pulsar spaceship found by Noam Elkies in December 1997. See also SPPS and APPS.

:pre-beehive The following common parent of the beehive.


OOO
OOO

:pre-block The following common parent of the block. Another such pattern is the grin.


O.
OO

:precursor = predecessor

:predecessor Any pattern that evolves into a given pattern after one or more generations.

:pre-pulsar A common predecessor of the pulsar, such as that shown below. This duplicates itself in 15 generations. (It fails, however, to be a true replicator because of the way the two copies then interact.)


OOO...OOO
O.O...O.O
OOO...OOO

A pair of tubs can be placed to eat half the pre-pulsar as it replicates; this gives the p30 oscillator Eureka where the pre-pulsar's replication becomes a movement back and forth. (See twirling T-tetsons II for a variation on this idea.) By other means the replication of the pre-pulsar can be made to occur in just 14 generations as half of it is eaten; this allows the construction of p28 and p29 oscillators, and is in fact the only known method for creating a p29 oscillator. The pre-pulsar is also a vital component of the only known p47 oscillator.

See also PPS.

:pre-pulsar spaceship See PPS.

:pressure cooker (p3) Found by the MIT group in September 1971. Compare mini pressure cooker.


.....O.....
....O.O....
....O.O....
...OO.OO...
O.O.....O.O
OO.O.O.O.OO
...O...O...
...O...O...
....OOO....
...........
...O.OO....
...OO.O....

:primer A pattern originally constructed by Dean Hickerson in November 1991 that emits a stream of LWSSs representing the prime numbers. Some improvements were found by Jason Summers in October 2005.

:protein (p3) Found by Dave Buckingham, November 1972.


....OO.......
....O........
......O......
..OOOO.O.OO..
.O.....O.O..O
.O..OO.O.O.OO
OO.O.....O...
...O..OO.O...
...O....O....
....OOOO.....
.............
....OO.......
....OO.......

:pseudo Opposite of true. A gun emitting a period n stream of spaceships (or rakes) is said to be a pseudo period n gun if its mechanism oscillates with a period different from n. This period will necessarily be a multiple of n. Pseudo period n glider guns are known to exist for all periods greater than or equal to 14, with smaller periods being impossible. The first pseudo p14 gun was built by Dieter Leithner in 1995.

The same distinction between true and pseudo also exists for puffers.

:pseudo-barberpole (p5) Found by Achim Flammenkamp in August 1994. In terms of its minimum population of 15 this is the smallest known p5 oscillator.


..........OO
...........O
.........O..
.......O.O..
............
.....O.O....
............
...O.O......
............
..OO........
O...........
OO..........

:pseudo-random glider generator An object which emits a random-looking stream of gliders, like the sequence of bits from a pseudo-random number generator. Pseudo-random glider generators contain gliders or other spaceships in a loop with a feedback mechanism which causes later spaceships to interfere with the generation of earlier spaceships. The period can be very high, since a loop of n spaceships has 2n possible states.

The first pseudo-random glider generator was built by Bill Gosper. David Bell built the first moving one in 1997, using c/3 rakes.

:pseudo still life The strict definition of still life rules out such stable patterns as the bi-block. In such patterns there are dead cells which have more than 3 neighbours in total, but fewer than 3 in any component still life. These patterns are called pseudo still lifes. Mark Niemiec has enumerated the pseudo still lifes up to 24 bits, and his figures are shown below.


-------------
Bits   Number
-------------
  8        1
  9        1
 10        7
 11       16
 12       55
 13      110
 14      279
 15      620
 16     1645
 17     4067
 18    10843
 19    27250
 20    70637
 21   179011
 22   462086
 23  1184882
 24  3068984
-------------

:puffer An object that moves like a spaceship, except that it leaves debris behind. The first known puffers were found by Bill Gosper and travelled at c/2 orthogonally (see diagram below for the very first one, found in 1971). Not long afterwards c/12 diagonal puffers were found (see switch engine). Discounting wickstretchers (which are not puffers in the conventional sense), no new velocity was obtained after this until David Bell found the first c/3 orthogonal puffer in April 1996. Since then c/5 orthogonal puffers have also been found, the first by Tim Coe in May 1997. Jason Summers built the first c/4 orthogonal puffer in January 1999, and the first 2c/5 orthogonal puffer in February 1999. Hartmut Holzwart built the first c/4 diagonal puffer (as opposed to a wickstretcher) in February 2004.


.OOO......O.....O......OOO.
O..O.....OOO...OOO.....O..O
...O....OO.O...O.OO....O...
...O...................O...
...O..O.............O..O...
...O..OO...........OO..O...
..O...OO...........OO...O..

:puffer engine A pattern which can be used as the main component of a puffer. The pattern may itself be a puffer (e.g. the classic puffer train), it may be a spaceship (e.g. the Schick engine), or it may even be unstable (e.g. the switch engine).

:puffer train The full name for a puffer, coined by Conway before any examples were known. The term was also applied specifically to the classic puffer train found by Bill Gosper and shown below. This is very dirty, and the tail does not stabilize until generation 5533. It consists of a B-heptomino (shown here one generation before the standard form) escorted by two LWSS. (This was the second known puffer. The first is shown under puffer.)


.OOO...........OOO
O..O..........O..O
...O....OOO......O
...O....O..O.....O
..O....O........O.

:puff suppressor An attachment at the back of a line puffer that suppresses all or some of its puffing action. The example below (by Hartmut Holzwart) has a 3-cell puff suppressor at the back which suppresses the entire puff, making a p2 spaceship. If you delete this puff suppressor then you get a p60 double beehive puffer. Puff suppressors were first recognised by Alan Hensel in April 1994.


............O....................
..........OO.O...................
..........OO...O.................
........O...OO.O.....O...........
........OOOO.OO...OOOO.......O.O.
......O......O....OOO.....O.O..O.
......OOOOOOO...O...O....O..O....
...O.O......OO..O...O.O.OO....O..
..OOOOOOOOO.....O..OO........O...
.OO..............O.OO.OOOO...O..O
OO....OO.O..........O...O..O.O...
.OO....O........OOO......O.O.O..O
.........O......OO......O....OO..
.OO....O........OOO......O.O.O..O
OO....OO.O..........O...O..O.O...
.OO..............O.OO.OOOO...O..O
..OOOOOOOOO.....O..OO........O...
...O.O......OO..O...O.O.OO....O..
......OOOOOOO...O...O....O..O....
......O......O....OOO.....O.O..O.
........OOOO.OO...OOOO.......O.O.
........O...OO.O.....O...........
..........OO...O.................
..........OO.O...................
............O....................

:pulsar (p3) Despite its size, this is the fourth most common oscillator (and by far the most common of period greater than 2) and was found very early on by Conway. See also pre-pulsar and pulsar quadrant.


..OOO...OOO..
.............
O....O.O....O
O....O.O....O
O....O.O....O
..OOO...OOO..
.............
..OOO...OOO..
O....O.O....O
O....O.O....O
O....O.O....O
.............
..OOO...OOO..

:pulsar 18-22-20 = two pulsar quadrants

:pulsar CP 48-56-72 = pulsar (The numbers refer to the populations of the three phases.)

:pulsar quadrant (p3) This consists of a quarter of the outer part of a pulsar stabilized by a cis fuse with two tails. This is reminiscent of mold and jam. Found by Dave Buckingham in July 1973. See also two pulsar quadrants.


.....O..
...OOO..
..O...OO
O..O..O.
O...O.O.
O....O..
........
..OOO...

:pulse A moving object, such as a spaceship or Herschel, which can be used to transmit information. See pulse divider.

Also another name for a pulsar quadrant.

:pulse divider A mechanism that lets every n-th object that reaches it pass through, and deletes all the rest, where n > 1 and the objects are typically spaceships or Herschels.

The following diagram shows a p5 glider pulse divider by Dieter Leithner (February 1998). The first glider moves the centre block and is reflected at 90 degrees. The next glider to come along will not be reflected, but will move the block back to its original position. The small size and low period of this example make it useful for constructing glider guns of certain periods. p7, p22, p36 and p46 versions of this pulse divider are also known.


.....OO...................
.....OO...................
..........................
..................OO......
.................O..O.....
.................O.O..O..O
O...............OO.O.OOOOO
.OO...........O...OO......
OO...............OO..OOO..
.............O...O.O..O.O.
........OO.......OO..OO.O.
........OO....O...OO...O..
................OO.O.OO...
.................O.O.O....
.................O.O..O...
..................O..OO...
..OO......................
...O......................
OOO.......................
O.........................
..........................
............OO............
............O.............
.............OOO..........
...............O..........

:pulshuttle V (p30) Found by Robert Wainwright, May 1985. Compare Eureka.


.............O..............O.............
............O.O.......O....O.O............
.............O......OO.OO...O.............
......................O...................
..OO......OO..................OO......OO..
O....O..O....O..............O....O..O....O
O....O..O....O..............O....O..O....O
O....O..O....O........O.....O....O..O....O
..OO......OO........OO.OO.....OO......OO..
......................O...................
..........................................
..........................................
..OO......OO..................OO......OO..
O....O..O....O........O.....O....O..O....O
O....O..O....O......OO.OO...O....O..O....O
O....O..O....O........O.....O....O..O....O
..OO......OO..................OO......OO..
..........................................
..........................................
......................O...................
..OO......OO........OO.OO.....OO......OO..
O....O..O....O........O.....O....O..O....O
O....O..O....O..............O....O..O....O
O....O..O....O..............O....O..O....O
..OO......OO..................OO......OO..
......................O...................
.............O......OO.OO...O.............
............O.O.......O....O.O............
.............O..............O.............

:pure glider generator A pattern that evolves into one or more gliders, and nothing else. There was some interest in these early on, but they are no longer considered important. Here's a neat example:


..O............
..O............
OOO............
...............
......OOO......
.......O.......
............OOO
............O..
............O..

:pushalong Any tagalong at the front of a spaceship. The following is an example (found by David Bell in 1992) attached to the front of a MWSS.


..OOO.O.....
.OOOO.O.....
OO..........
.O.O........
..OOOO.O....
...OOO......
............
............
......OOOOO.
......O....O
......O.....
.......O...O
.........O..

:pyrotechnecium (p8) Found by Dave Buckingham in 1972.


.......O........
.....OOOOO......
....O.....O.....
.O..O.O.OO.O....
O.O.O.O....O..O.
.O..O....O.O.O.O
....O.OO.O.O..O.
.....O.....O....
......OOOOO.....
........O.......

:pyrotechneczum A common mistaken spelling of pyrotechnecium, caused by a copying error in the early 1990s.

:python = long snake


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_bib.htm0000644000175000017500000001025012536111364014625 00000000000000 Life Lexicon (Bibliography)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

BIBLIOGRAPHY

David I. Bell, Spaceships in Conway's Life. Series of articles posted on comp.theory.cell-automata, Aug-Oct 1992. Now available from his web-site.

David I. Bell, Speed c/3 Technology in Conway's Life, 17 December 1999. Available from his web-site.

Elwyn R. Berlekamp, John H. Conway and Richard K. Guy, Winning Ways for your Mathematical Plays, II: Games in Particular. Academic Press, 1982.

David J Buckingham, Some Facts of Life. BYTE, December 1978.

Dave Buckingham, My Experience with B-heptominos in Oscillators. 12 October 1996. Available from Paul Callahan's web-site.

David J. Buckingham and Paul B. Callahan, Tight Bounds on Periodic Cell Configurations in Life. Experimental Mathematics 7:3 (1998) 221-241. Available at http://www.expmath.org/restricted/7/7.3/callahan.ps.

Noam D. Elkies, The still-Life density problem and its generalizations, pp228-253 of "Voronoi's Impact on Modern Science, Book I", P. Engel, H. Syta (eds), Institute of Mathematics, Kyiv, 1998 = Vol.21 of Proc. Inst. Math. Nat. Acad. Sci. Ukraine, math.CO/9905194.

Martin Gardner, Wheels, Life, and other Mathematical Amusements. W. H. Freeman and Company, 1983.

R. Wm. Gosper, Exploiting Regularities in Large Cellular Spaces. Physica 10D (1984) 75-80.

N. M. Gotts and P. B. Callahan, Emergent structures in sparse fields of Conway's 'Game of Life', in Artificial Life VI: Proceedings of the Sixth International Conference on Artificial Life, MIT Press, 1998.

Mark D Niemiec, Life Algorithms. BYTE, January 1979.

William Poundstone, The Recursive Universe. William Morrow and Company Inc., 1985.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_j.htm0000644000175000017500000001370512536111364014332 00000000000000 Life Lexicon (J)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:J = Herschel

:jack (p4) Found by Robert Wainwright, April 1984.


...O.....O...
...OO...OO...
O..OO...OO..O
OOO..O.O..OOO
.....O.O.....
OOO..O.O..OOO
O..OO...OO..O
...OO...OO...
...O.....O...

:jagged lines A pattern constructed by Dean Hickerson in May 2005 that uses puffers to produce a line of bi-blocks that weaves back and forth in a complicated way.

:jam (p3) Found by Achim Flammenkamp in 1988, but not widely known about until its independent discovery (and naming) by Dean Hickerson in September 1989. Compare with mold. In fact this is really very like caterer. In terms of its 7x7 bounding box it ties with trice tongs as the smallest p3 oscillator.


...OO.
..O..O
O..O.O
O...O.
O.....
...O..
.OO...

:Jaws A breeder constructed by Nick Gotts in February 1997. In the original version Jaws had an initial population of 150, which at the time was the smallest for any known pattern with superlinear growth. In November 1997 Gotts produced a 130-cell Jaws using some switch engine predecessors found by Paul Callahan. Jaws has since been beaten by the even smaller mosquitoes, teeth, catacryst and metacatacryst.

Jaws consists of eight pairs of switch engines which produce a new block-laying switch engine (plus masses of junk) every 10752 generations. It is therefore an MMS breeder.

:JC = dead spark coil

:JHC John Horton Conway. Also another name for monogram.

:J-heptomino = Herschel

:Jolson (p15) Two blocks hassled by two pentadecathlons. Found by Robert Wainwright in November 1984 and named by Bill Gosper. A p9 version using snackers instead of pentadecathlons is also possible.


.OO......OO..
O..O....O..O.
O..O....O..O.
O..O....O..O.
.OO......OO..
.............
.............
.......O.....
.....O..O.OO.
......OO..OO.
.............
.............
......OOOO...
.....OOOOOO..
....OOOOOOOO.
...OO......OO
....OOOOOOOO.
.....OOOOOO..
......OOOO...

:Justyna (stabilizes at time 26458) The following methuselah found by Andrzej Okrasinski in May 2004.


.................O....
................O..O..
.................OOO..
.................O..O.
......................
OO................O...
.O................O...
..................O...
......................
......................
......................
......................
......................
......................
......................
...................OOO
...........OOO........

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_d.htm0000644000175000017500000004100612536111364014317 00000000000000 Life Lexicon (D)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:dart (c/3 orthogonally, p3) Found by David Bell, May 1992.


.......O.......
......O.O......
.....O...O.....
......OOO......
...............
....OO...OO....
..O...O.O...O..
.OO...O.O...OO.
O.....O.O.....O
.O.OO.O.O.OO.O.

:dead spark coil (p1) Compare spark coil.


OO...OO
O.O.O.O
..O.O..
O.O.O.O
OO...OO

:de Bruijn diagram = de Bruijn graph

:de Bruijn graph As applied to Life, a de Bruijn graph is a graph showing which pieces can be linked to which other pieces to form a valid part of a Life pattern of a particular kind.

For example, if we are interested in still lifes, then we could consider 2x3 rectangular pieces and the de Bruijn graph would show which pairs of these can be overlapped to form 3x3 squares in which the centre cell remains unchanged in the next generation.

David Eppstein's search program gfind is based on de Bruijn graphs.

:Deep Cell A pattern by Jared James Prince, based on David Bell's unit Life cell, in which each unit cell simulates two Life cells, in such a way that a Life universe filled with Deep Cells simulates two independent Life universes running in parallel.

In fact, a Life universe filled with Deep Cells can simulate infinitely many Life universes, as follows. Let P1, P2, P3, ... be a sequence of Life patterns. Set the Deep Cells to run a simulation of P1 in parallel with a simulation of a universe filled with Deep Cells, with these simulated Deep Cells running a simulation of P2 in parallel with another simulation of a universe filled with Deep Cells, with these doubly simulated Deep Cells simulating P3 in parallel with yet another universe of Deep Cells, and so on.

Deep Cell is available from http://psychoticdeath.com/life.htm.

:density The density of a pattern is the limit of the proportion of live cells in a (2n+1)x(2n+1) square centred on a particular cell as n tends to infinity, when this limit exists. (Note that it does not make any difference what cell is chosen as the centre cell. Also note that if the pattern is finite then the density is zero.) There are other definitions of density, but this one will do here.

In 1994 Noam Elkies proved that the maximum density of a stable pattern is 1/2, which had been the conjectured value. See the paper listed in the bibliography. Marcus Moore provided a simpler proof in 1995, and in fact proves that a still life with an m x n bounding box has at most (mn+m+n)/2 cells.

But what is the maximum average density of an oscillating pattern? The answer is conjectured to be 1/2 again, but this remains unproved. The best upper bound so far obtained is 8/13 (Hartmut Holzwart, September 1992).

The maximum possible density for a phase of an oscillating pattern is also unknown. An example with a density of 3/4 is known (see agar), but densities arbitrarily close to 1 may perhaps be possible.

:D-heptomino = Herschel

:diamond = tub

:diamond ring (p3) Found by Dave Buckingham in 1972.


......O......
.....O.O.....
....O.O.O....
....O...O....
..OO..O..OO..
.O....O....O.
O.O.OO.OO.O.O
.O....O....O.
..OO..O..OO..
....O...O....
....O.O.O....
.....O.O.....
......O......

:diehard Any pattern that vanishes, but only after a long time. The following example vanishes in 130 generations, which is probably the limit for patterns of 7 or fewer cells. Note that there is no limit for higher numbers of cells - e.g., for 8 cells we could have a glider heading towards an arbitrarily distant blinker.


......O.
OO......
.O...OOO

:dinner table (p12) Found by Robert Wainwright in 1972.


.O...........
.OOO.......OO
....O......O.
...OO....O.O.
.........OO..
.............
.....OOO.....
.....OOO.....
..OO.........
.O.O....OO...
.O......O....
OO.......OOO.
...........O.

:dirty Opposite of clean. A reaction which produces a large amount of complicated junk which is difficult to control or use is said to be dirty. Many basic puffer engines are dirty and need to be tamed by accompanying spaceships in order to produce clean output.

:diuresis (p90) Found by David Eppstein in October 1998. His original stabilization used pentadecathlons. The stabilization with complicated still lifes shown here (in two slightly different forms) was found by Dean Hickerson the following day. The name is due to Bill Gosper (see kidney).


.....OO................OO....
......O................O.....
......O.O............O.O.....
.......OO............OO......
.............................
....OO..................OO...
....O.O..........OO....O.O...
.....O..........O.O.....O....
..O.............OO.........O.
..OOOOOO........O.....OOOOOO.
.......O..............O......
....OO..................OO...
....O....................O...
.....O..................O....
..OOO..O..............O..OOO.
..O..OOO........O.....OOO...O
...O............OO.......OOO.
....OO..........O.O.....O....
......O..........OO....O..OO.
....OO..................OO.O.
.O..O....................O...
O.O.O..OO............OO..O...
.O..O.O.O............O.O.OO..
....O.O................O..O..
.....OO................OO....

:dock The following induction coil.


.OOOO.
O....O
OO..OO

:domino The 2-cell polyomino. A number of objects, such as the HWSS and pentadecathlon, produce domino sparks.

:do-see-do The following reaction, found by David Bell in 1996, in which two gliders appear to circle around each other as they are reflected 90 degrees by a twin bees shuttle. Four copies of the reaction can be used to create a p92 glider loop which repeats the do-see-do reaction forever.


.....................................................O.O
.....................................................OO.
......................................................O.
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
................................................OO......
................................................O.......
..............................................O.O.......
..............................................OO........
..............................O.O.......................
..............................OO........................
...............................O........................
........................................................
.......................OOO..............................
OO........OOO........OO.O.OO............................
OO........O...O.....O.....OO............................
..........O....O.....OO.O.OO............................
...........O...O.......OOO..............................
........................................................
...........O...O........................................
..........O....O........................................
OO........O...O............OO...........................
OO........OOO..............OO...........................

:double-barrelled Of a gun, emitting two streams of spaceships (or rakes). See B-52 bomber for an example.

:double block reaction A certain reaction that can be used to stabilize the twin bees shuttle (qv). This was discovered by David Bell in October 1996.

The same reaction sometimes works in other situations, as shown in the following diagram where a pair of blocks eats an R-pentomino and a LWSS. (The LWSS version was known at least as early 1994, when Paul Callahan saw it form spontaneously as a result of firing a LWSS stream at some random junk.)


.OOOO.....OO....
O...O......OO.OO
....O......O..OO
O..O............
................
.............OO.
.............OO.

:double caterer (p3) Found by Dean Hickerson, October 1989. Compare caterer and triple caterer.


.....OO...O........
....O..O..OOO......
....OO.O.....O.....
......O.OOOO.O.....
..OOO.O.O...O.OO...
.O..O..O...O..O.O..
O.O..O...O.OO....O.
.O..........OO.OOO.
..OO.OO.OO...O.....
...O...O.....O.OOO.
...O...O......OO..O
.................OO

:double ewe (p3) Found by Robert Wainwright before September 1971.


......OO............
.......O............
......O.............
......OO............
.........OO.........
......OOO.O.........
O.OO.O..............
OO.O.O..............
.....O...O..........
....O...OO....OO....
....OO....OO...O....
..........O...O.....
..............O.O.OO
..............O.OO.O
.........O.OOO......
.........OO.........
............OO......
.............O......
............O.......
............OO......

:double wing = moose antlers

:dove The following induction coil.


.OO..
O..O.
.O..O
..OOO

:down boat with tail = cis-boat with tail

:dragon (c/6 orthogonally, p6) This spaceship, discovered by Paul Tooke in April 2000, was the first known c/6 spaceship. All other known orthogonal c/6 spaceships are flotillas involving at least two dragons.


.............O..OO......O..OOO
.....O...OOOO.OOOOOO....O..OOO
.OOOOO....O....O....OOO.......
O......OO.O......OO.OOO..O.OOO
.OOOOO.OOO........OOOO...O.OOO
.....O..O..............O......
........OO..........OO.OO.....
........OO..........OO.OO.....
.....O..O..............O......
.OOOOO.OOO........OOOO...O.OOO
O......OO.O......OO.OOO..O.OOO
.OOOOO....O....O....OOO.......
.....O...OOOO.OOOOOO....O..OOO
.............O..OO......O..OOO

:drain trap = paperclip

:drifter A perturbation moving within a stable pattern. Dean Hickerson has written a program to search for drifters, with the hope of finding one which could be moved around a track. Because drifters can be very small, they could be packed more tightly than Herschels, and so allow the creation of oscillators of periods not yet attained, and possibly prove that Life is omniperiodic. Hickerson has found a number of components towards this end, but it has proved difficult to change the direction of movement of a drifter, and so far no complete track has been found. However, Hickerson has had success using the same search program to find eaters with novel properties, such as that used in diuresis.

:dual 1-2-3-4 = Achim's p4


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_z.htm0000644000175000017500000000602012536111364014342 00000000000000 Life Lexicon (Z)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Z-hexomino The following hexomino. The Z-hexomino features in the pentoad, and also in Achim's p144.


OO.
.O.
.O.
.OO

:Z-pentomino Conway's name for the following pentomino, which rapidly dies.


OO.
.O.
.OO

:zweiback (p30) An oscillator in which two HW volcanoes hassle a loaf. This was found by Mark Niemiec in February 1995 and is too big to show here.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_e.htm0000644000175000017500000004626012536111364014327 00000000000000 Life Lexicon (E)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:early universe Conway's somewhat confusing term for sparse Life.

:eater Any still life that has the ability to interact with certain patterns without suffering any permanent damage. (If it doesn't suffer even temporary damage then it may be referred to as a rock.) The eater1 is a very common eater, and the term "eater" is often used specifically for this object. Other eaters include eater2, eater3, eater4 and even the humble block. (In fact the block was the first known eater, being found capable of eating beehives from a queen bee.) Another useful eater is shown below, feasting on a glider.


...O.....
...O.O...
...OO....
.........
.......OO
...O...OO
..O.O....
.O.O.....
.O.......
OO.......

:eater1 (p1) Usually simply called an eater, and also called a fishhook. Its ability to eat various objects was discovered by Bill Gosper in 1971.


OO..
O.O.
..O.
..OO

:eater2 (p1) This eater was found by Dave Buckingham in the 1970s. Mostly it works like the ordinary eater (see eater1) but with two slight differences that make it useful despite its size: it takes longer to recover from each bite and it acts like an eater in two directions. The first property means that, among other things, it can eat a glider in a position that would destroy a fishhook. This novel glider-eating action is occasionally of use in itself, and combined with the symmetry means that an eater2 can eat gliders along four different paths.


...O.OO
.OOO.OO
O......
.OOO.OO
...O.O.
...O.O.
....O..
The following eater2 variant (Stephen Silver, May 1998) can be useful for obtaining smaller bounding boxes. A more compact variant with the same purpose can be seen under gliderless.

OO....
O.....
..O.OO
.OO.OO
......
.OO.OO
..O.O.
..O.O.
...O..

:eater3 (p1) This large symmetric eater, found by Dave Buckingham, has a very different eating action from the eater1 and eater2. The loaf can take bites out things, being flipped over in the process. The rest of the object merely flips it back again.


.........OO.
....OO..O..O
.O..O....O.O
O.O.O.....O.
.O..O.OO....
....O..O....
.....O....O.
......OOOOO.
............
........O...
.......O.O..
........O...

:eater4 (p1) Another eater by Dave Buckingham, which he found in 1971, but did not recognize as an eater until 1975 or 1976. It can't eat gliders, but it can be used for various other purposes. The four NE-most centre cells regrow in a few generations after being destroyed by taking a bite out of something.


...OO.........
...O..........
OO.O..........
O..OO.........
.OO....O......
...OOOOO......
...O....OO....
....OO..O.....
......O.O.....
......O.O.O..O
.......OO.OOOO
.........O....
.........O.O..
..........OO..

:eater/block frob (p4) Found by Dave Buckingham in 1976 or earlier.


.OO.......
..O.......
..O.O.....
...O.O....
.....OO.OO
........OO
..OO......
...O......
OOO.......
O.........

:eater-bound pond = biting off more than they can chew

:eater-bound Z-hexomino = pentoad

:eater eating eater = two eaters

:eater plug (p2) Found by Robert Wainwright, February 1973.


.......O
.....OOO
....O...
.....O..
..O..O..
.O.OO...
.O......
OO......

:eaters + = French kiss

:eaters plus = French kiss

:ecologist (c/2 orthogonally, p20) This consists of the classic puffer train with a LWSS added to suppress the debris. See also space rake.


OOOO.....OO........
O...O...OO.OO......
O........OOOO......
.O..O.....OO.......
...................
.....O.........OO..
...OOO........OOOOO
..O...O.....O....OO
..O....OOOOO.....OO
..OO.O.OOOO....OO..
....O...OO.OOO.....
.....O.O...........
...................
...................
OOOO...............
O...O..............
O..................
.O..O..............

:edge-repair spaceship A spaceship which has an edge that possesses no spark and yet is able to perturb things because of its ability to repair certain types of damage to itself. The most useful examples are the following two small p3 c/3 spaceships:


..................................O.....
........O.......................OOO.OOO.
.......OOOO....................OO......O
..O...O...OO.OO...........O...O..O...OO.
.OOOO.....O..OO..........OOOO...........
O...O.......O..O........O...O...........
.O.O..O..................O.O..O.........
.....O.......................O..........
These were found by David Bell in 1992, but the usefulness of the edge-repair property wasn't recognised until July 1997. The following diagram (showing an edge-repair spaceship deleting a Herschel) demonstrates the self-repairing action.

................O.......
O..............OOOO.....
O.O.......O...O...OO.OO.
OOO......OOOO.....O..OO.
..O.....O...O.......O..O
.........O.O..O.........
.............O..........
In October 2000, David Bell found that a T-tetromino component of a c/4 spaceship can also be self-repairing. Stephen Silver noticed that it could be used to delete beehives and, in November 2000, found the smallest known c/4 spaceship with this edge-repair component - in fact, two copies of the component:

.OO..........................
O..O.........................
.OO..........................
.............................
.......O.O...................
.......O.....................
.......O.O..O..O.............
..........O..................
...........O.OO.O............
............OOO.O............
...........O....O..O.OO......
........O...OO...O.OOOO......
........OO..O..O.OO....O....O
........O........OO....O..OOO
.............OO...OO...O..OO.
.OO..........................
O..O.........................
.OO..........................

:edge shooter A gun which fires its gliders (or whatever) right at the edge of the pattern, so that it can be used to fire them closely parallel to others. This is useful for constructing complex guns. Compare glider pusher, which can in fact be used for making edge shooters.

The following diagram shows a p46 edge shooter found by Paul Callahan in June 1994.


OO............OO..O....OO..OO.............
OO............O.OO......OO.OO.............
...............O......O.O.................
...............OOO....OO..................
..........................................
...............OOO....OO..................
...............O......O.O.................
OO............O.OO......OO................
OO............OO..O....OO.................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
...............................OOO...OOO..
..............................O...O.O...O.
.............................O...OO.OO...O
.............................O.OO.....OO.O
...............................O.......O..
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
...............................OO.....OO..
...............................OO.....OO..

:edge spark A spark at the side of a spaceship that can be used to perturb things as the spaceship passes by.

:edge sparker A spaceship that produces one or more edge sparks.

:egg = non-spark

:E-heptomino Name given by Conway to the following heptomino.


.OOO
OO..
.OO.

:elbow ladder Scot Ellison's name for the type of pattern he created in which one or more gliders shuttle back and forth (using the kickback reaction) deleting the output gliders from a pair of slide guns.

:electric fence (p5) A stabilization of ants. Dean Hickerson, February 1993.


..........O..................................................
.........O.O........................OO.......................
..O....OOO.O.....O...................O...O..O......O.....OO..
.O.O..O....OO...O.O..................O.OOO..OOO...O.O....O...
.O.O..O.OO.......O....................O...OO...O.O..O......O.
OO.OO.O.O.OOOOO.....O..................OO...O..O.O.OO.OO..OO.
.O.O..O...O..O..O.......OO...OO...OO....OO.OO..O.O..O.O.O....
.O..OO....OO......OOO.OO...OO...OO...OOO.....OOOO.OOO.O...OO.
..O..OOO..O..O.OOOO...OO...OO...OO...OOO.OO..O....O.O....O..O
...OO...O.O..O.....OO...OO...OO...OO......O............O...OO
.....OO.O.OO.O.OO..O......................O........OO.O......
.....O.OO.O..O.OO....O.................OO.O.O................
...........OO.......OO..................O..OO................
......................................O.O....................
......................................OO.....................

:elevener (p1)


OO....
O.O...
..O...
..OOO.
.....O
....OO

:Elkies' p5 (p5) Found by Noam Elkies in 1997.


.O.......
O..OOO...
..O......
...O.O..O
..OO.OOOO
....O....
....O.O..
.....OO..

:emu Dave Buckingham's term for a Herschel loop that does not emit gliders (and so is "flightless"). All known Herschel loops of periods 57, 58, 59 and 61 are emus. See also Quetzal.

:emulator Any one of three p4 oscillators that produce sparks similar to those produced by LWSS, MWSS and HWSS. See LW emulator, MW emulator and HW emulator. Larger emulators are also possible, but they require stabilizing objects to suppress their non-sparks and so are of little use. The emulators were discovered by Robert Wainwright in June 1980.

:engine The active portion of an object (usually a puffer or gun) which is considered to actually produce its output, and which generally permits no variation in how it works. The other parts of the object are just there to support the engine. For examples, see puffer train, Schick engine, blinker puffer, frothing puffer and line puffer.

:en retard (p3) Found by Dave Buckingham, August 1972.


.....O.....
....O.O....
OO.O.O.O.OO
.O.O...O.O.
O..O.O.O..O
.OO.....OO.
...OO.OO...
...O.O.O...
....O.O....
..O.O.O.O..
..OO...OO..

:Enterprise (c/4 diagonally, p4) Found by Dean Hickerson, March 1993.


.......OOO...........
.....O.OO............
....OOOO.............
...OO.....O..........
..OOO..O.O.O.........
.OO...O.O..O.........
.O.O.OOOOO...........
OO.O.O...O...........
O........OO..........
.OO..O...O.O.........
....OO..O.OO......O..
...........OO.....OOO
............O..OOO..O
............O..O..OO.
.............O.OO....
............OO.......
............OO.......
...........O.........
............O.O......
...........O..O......
.............O.......

:Eureka (p30) A pre-pulsar shuttle found by Dave Buckingham in August 1980. A variant is obtained by shifting the top half two spaces to either side.


.O..............O.
O.O....O.......O.O
.O...OO.OO......O.
.......O..........
..................
..................
..................
.......O..........
.O...OO.OO......O.
O.O....O.......O.O
.O..............O.

:evolutionary factor For an unstable pattern, the time to stabilization divided by the initial population. For example, the R-pentomino has an evolutionary factor of 220.6, while bunnies has an evolutionary factor of 1925.777... The term is no longer in use.

:exposure = underpopulation

:extensible A pattern is said to be extensible if arbitrarily large patterns of the same type can be made by repeating parts of the original pattern in a regular way.

:extra extra long = long^4

:extra long = long^3

:extremely impressive (p6) Found by Dave Buckingham, August 1976.


....OO......
...O.OOO....
...O....O...
OO.O...OO...
OO.O.....OO.
....OOOOO..O
..........OO
......O.....
.....O.O....
......O.....

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_i.htm0000644000175000017500000002654312536111364014335 00000000000000 Life Lexicon (I)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:I-heptomino Name given by Conway to the following heptomino. After one generation this is the same as the H-heptomino.


OO..
.O..
.OO.
..OO

:IMG = intermitting glider gun

:Immigration A form of colorized Life in which there are two types of ON cell, a newly-born cell taking the type of the majority of its three parent cells and surviving cells remaining of the same type as in the previous generation.

:induction coil Any object used to stabilize an edge (or edges) without touching. The tubs used in the Gray counter are examples, as are the blocks and snakes used in the Hertz oscillator and the heptomino at the bottom of the mathematician.

:inductor Any oscillator with a row of dead cells down the middle and whose two halves are mirror images of one another, both halves being required for the oscillator to work. The classic examples are the pulsar and the tumbler. If still lifes are considered as p1 oscillators then there are numerous simple examples such as table on table, dead spark coil and cis-mirrored R-bee. Some spaceships, such as the brain, the snail and the spider use the same principle.

:infinite glider hotel A pattern by David Bell, named after Hilbert's "infinite hotel" scenario in which a hotel with an infinite number of rooms has room for more guests even if it is already full, simply by shuffling the old guests around.

In this pattern, two pairs of Corderships moving at c/12 are pulling apart such that there is an ever-lengthening glider track between them. Every 128 generations another glider is injected into the glider track, joining the gliders already circulating there. The number of gliders in the track therefore increases without limit.

The tricky part of this construction is that even though all the previously injected gliders are repeatedly flying through the injection point, that point is guaranteed to be empty when it is time for the next glider to be injected.

:infinite growth Growth of a finite pattern such that the population tends to infinity, or at least is unbounded. Sometimes the term is used for growth of something other than population (for example, length), but here we will only consider infinite population growth. The first known pattern with infinite growth in this sense was the Gosper glider gun.

An interesting question is: What is the minimum population of a pattern that exhibits infinite growth? In 1971 Charles Corderman found that a switch engine could be stabilized by a pre-block in a number of different ways, giving 11-cell patterns with infinite growth. This record stood for more than quarter of a century until Paul Callahan found, in November 1997, two 10-cell patterns with infinite growth. The following month he found the one shown below, which is much neater, being a single cluster. This produces a stabilized switch engine of the block-laying type.


......O.
....O.OO
....O.O.
....O...
..O.....
O.O.....
Nick Gotts and Paul Callahan have also shown that there is no infinite growth pattern with fewer than 10 cells, so that the question has now been answered.

Also of interest is the following pattern (again found by Callahan), which is the only 5x5 pattern with infinite growth. This too emits a block-laying switch engine.


OOO.O
O....
...OO
.OO.O
O.O.O

Following a conjecture of Nick Gotts, Stephen Silver produced, in May 1998, a pattern of width 1 which exhibits infinite growth. This pattern was very large (12470x1 in the first version, reduced to 5447x1 the following day). In October 1998 Paul Callahan did an exhaustive search, finding the smallest example, the 39x1 pattern shown below. This produces two block-laying switch engines, stability being achieved at generation 1483.


OOOOOOOO.OOOOO...OOO......OOOOOOO.OOOOO

Although the simplest infinite growth patterns grow at a rate that is (asymptotically) linear, many other types of growth rate are possible, quadratic growth (see breeder) being the fastest. Dean Hickerson has found many patterns with unusual growth rates, such as sawtooths and a caber tosser.

See also Fermat prime calculator.

:initials = monogram

:inline inverter The following reaction in which a p30 gun can be used to invert the presence or absence of gliders in a p30 stream, with the output glider stream being in the same direction as the input glider stream.


................O...................
.................O..................
...............OOO..................
....................................
.......................O.O..........
.....................O...O..........
.............O.......O..............
............OOOO....O....O........OO
...........OO.O.O....O............OO
OO........OOO.O..O...O...O..........
OO.........OO.O.O......O.O..........
............OOOO....................
.............O......................

:integral = integral sign

:integral sign (p1)


...OO
..O.O
..O..
O.O..
OO...

:intentionless = elevener

:interchange (p2) A common formation of six blinkers.


..OOO....OOO..
..............
O............O
O............O
O............O
..............
..OOO....OOO..

:intermitting glider gun Despite the name, an intermitting glider gun (IMG) is more often an oscillator than a gun. There are two basic types. A type 1 IMG consists of two guns firing at one another in such a way that each gun is temporarily disabled on being hit by a glider from the other gun. A type 2 IMG consists of a single gun firing at a 180-degree glider reflector in such a way that returning gliders temporarily disable the gun.

Both types of IMG can be used to make glider guns of periods that are multiples of the base period. This is done by firing another gun across the two-way intermittent glider stream of the IMG in such a way that gliders only occasionally escape.

:island The individual polyplets of which a stable pattern consists are sometimes called islands. So, for example, a boat has only one island, while an aircraft carrier has two, a honey farm has four and the standard form of the eater3 has five.

:Iwona (stabilizes at time 28786) The following methuselah found by Andrzej Okrasinski in August 2004.


..............OOO...
....................
....................
....................
....................
....................
..O.................
...OO...............
...O..............O.
..................O.
..................O.
...................O
..................OO
.......OO...........
........O...........
....................
....................
....................
....................
OO..................
.O..................

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/lex_g.htm0000644000175000017500000006371112536111364014331 00000000000000 Life Lexicon (G)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Gabriel's p138 (p138) The following oscillator found by Gabriel Nivasch in October 2002.


.......OOO.....
......O..O.....
.......O...O...
..O.....OOO....
...O.....O.....
OO.OO..........
O..O.........O.
O.O.........O.O
.O.........O..O
..........OO.OO
.....O.....O...
....OOO.....O..
...O...O.......
.....O..O......
.....OOO.......

:galaxy = Kok's galaxy

:Game of Life = Life

:Game of Life News A blog reporting on new Life discoveries, started by Heinrich Koenig in December 2004. Dave Greene is also a frequent contributor to the blog, which can be found at http://gameoflife-news.blogspot.com.

:Garden of Eden A configuration of ON and OFF cells that can only occur in generation 0. (This term was first used in connection with cellular automata by John W. Tukey, many years before Life.) It was known from the start that there are Gardens of Eden in Life, because of a theorem by Edward Moore that guarantees their existence in a wide class of cellular automata. Explicit examples have since been constructed, the first by Roger Banks, et al. at MIT in 1971. This example was 9 x 33. In 1974 J. Hardouin-Duparc et al. at the University of Bordeaux 1 produced a 6 x 122 example. The following shows a 12 x 12 example found by Nicolay Beluchenko in February 2006, based on a 13 x 12 one found by Achim Flammenkamp in June 2004.


..O.OOO.....
OO.O.OOOOO.O
O.O.OO.O.O..
.OOOO.O.OOO.
O.O.OO.OOO.O
.OOO.OO.O.O.
..O...OOO..O
.O.OO.O.O.O.
OOO.OOOO.O.O
OO.OOOO...O.
.O.O.OO..O..
.OO.O..OO.O.

:generation The fundamental unit of time. The starting pattern is generation 0.

:germ (p3) Found by Dave Buckingham, September 1972.


....OO....
.....O....
...O......
..O.OOOO..
..O....O..
.OO.O.....
..O.O.OOOO
O.O.O....O
OO...OOO..
.......OO.

:gfind A program by David Eppstein which uses de Bruijn graphs to search for new spaceships. It was with gfind that Eppstein found the weekender, and Paul Tooke later used it to find the dragon. It is available at http://www.ics.uci.edu/~eppstein/ca/gfind.c (C source code only).

Compare lifesrc.

:GIG A glider injection gate. This is a device for injecting a glider into a glider stream. The injected glider is synthesized from one or more incoming spaceships assisted by the presence of the GIG. (This contrasts with some other glider injection reactions which do not require a GIG.) Gliders already in the glider stream pass through the GIG without interfering with it. A GIG usually consists of a small number of oscillators.

Glider injection gates are useful for building glider guns with pseudo-periods that are of the form nd, where n is a positive integer, and d is a proper divisor of some convenient base gun period (such as 30 or 46), with d > 13.

:glasses (p2) Compare scrubber and spark coil.


....O........O....
..OOO........OOO..
.O..............O.
.O..OOO....OOO..O.
OO.O...O..O...O.OO
...O...OOOO...O...
...O...O..O...O...
....OOO....OOO....
..................
....OO.O..O.OO....
....O.OO..OO.O....

:glider (c/4 diagonally, p4) The smallest, most common and first discovered spaceship. This was found by Richard Guy in 1970 while Conway's group was attempting to track the evolution of the R-pentomino. The name is due in part to the fact that it is glide symmetric. (It is often stated that Conway discovered the glider, but he himself has said it was Guy. See also the cryptic reference ("some guy") in Winning Ways.)


OOO
O..
.O.
The term "glider" is also occasionally (mis)used to mean "spaceship".

:glider-block cycle An infinite oscillator based on the following reaction (a variant of the rephaser). The oscillator consists of copies of this reaction displaced 2n spaces from one another (for some n>6) with blocks added between the copies in order to cause the reaction to occur again halfway through the period. The period of the resulting infinite oscillator is 8n-20. (Alternatively, in a cylindrical universe of width 2n the oscillator just consists of two gliders and two blocks.)


...OO...
...OO...
........
........
..O..O..
O.O..O.O
.OO..OO.

:glider construction = glider synthesis

:glider duplicator Any reaction in which one input glider is converted into two output gliders. This can be done either by oscillators or by spaceships. The most useful glider duplicators are those with low periods.

The following period 30 glider duplicator demonstrates a simple glider duplicating mechanism found by Dieter Leithner. The input glider stream comes in from the upper left, and the output glider streams leave at the upper and lower right. One of the output glider streams is inverted, so an inline inverter is required to complete the duplicator.


..........O.O.......................
...........OO.......................
...........O........................
....................................
....................................
....................................
........................OO....O.....
..................O.....OO....OO....
...................OO........O.O....
..................OO................
....................................
....................................
....................................
....................................
......................OO............
.......................OO...........
............O.........O.............
............O.O.....................
.............O.O.........OO.........
OO...........O..O.......OOO.........
OO...........O.O.....O.OO...........
............O.O......O..O...........
............O........O.OO...........
........................OOO.....OO..
.........................OO.....O.O.
..................................O.
..................................OO

Spaceship convoys which can duplicate gliders are very useful since they (along with glider turners) provide a means to clean up many dirty puffers by duplicating and turning output gliders so as to impact into the exhaust to clean it up.

Glider duplicators (and turners) are known for backward gliders using p2 c/2 spaceships, and for forward gliders using p3 c/3 spaceships. These are the most general duplicators for these speeds.

:glider gun A gun which fires gliders.

:glider injection gate = GIG

:gliderless A gun is said to be gliderless if it does not use gliders. The purist definition would insist that a glider does not appear anywhere, even incidentally. For a long time the only known way to construct LWSS, MWSS and HWSS guns involved gliders, and it was not until April 1996 that Dieter Leithner constructed the first gliderless gun (a p46 LWSS gun).

The following diagram shows the p44 MWSS gun that Dieter Leithner discovered (in a somewhat larger form) in April 1997. This is the smallest known gliderless gun, and also the smallest known MWSS gun. It is based on an important p44 oscillator discovered by Dave Buckingham in early 1992, shown here in an improved form found in January 2005 by Jason Summers using a new p4 sparker by Nicolay Beluchenko. Note that a glider shape appears in this gun for three consecutive generations, but always as part of a larger cluster, so even a purist would regard this gun as gliderless.


.......O..........................................
..OO...O.O....O...................................
..O..OO..O.O.OO.O..OOO..OO........................
....OO.......OO.O.O.OO..OO........................
...OOO.......O.......OOO.........O................
.......................O.......OOO................
.......................O......O........OOO........
..............................OO.......O..O.......
.........OO..............O.............O..........
.........OO.............O..............O...O......
.........................OO............O..........
........................O.O.............O.O.......
..................................................
.......................O.O.....OOO................
........................O.....O..O..............OO
OO............OOO.......O......OO...........OO.O.O
OO...........O...O..........................OO.O..
.............OO.OO..............................O.
.................................OO.........OO.OO.
..............................OO.............O.O..
.............................................O.O..
..............................................O...
.............OO.OO.............O.O................
OO...........O...O.............OO.................
OO............OOO.................................
...........................OO.....................
...........................O.O....................
.............................O....................
.............................OO...................
..................................................
.........OO.......................................
.........OO.......................................
..................................................
.......................O..........................
.......................O..........................
...OOO.......O.......OOO..........................
....OO.......OO.O.O.OO..OO........................
..O..OO..O.O.OO.O..OOO..OO........................
..OO...O.O....O...................................
.......O..........................................

:glider pusher An arrangement of a queen bee shuttle and a pentadecathlon that can push the path of a passing glider out by one half-diagonal space. This was found by Dieter Leithner in December 1993 and is shown below. It is useful for constructing complex guns where it may be necessary to produce a number of gliders travelling on close parallel paths. See also edge shooter.


.........OO..............
.........OO..............
.........................
..........O..............
.........O.O.............
.........O.O.............
..........O..............
.........................
.........................
.......OO.O.OO...........
.......O.....O...........
........O...O............
.O.......OOO.............
..O......................
OOO......................
.........................
.........................
.................O....O..
...............OO.OOOO.OO
.................O....O..

:gliders by the dozen (stabilizes at time 184) In early references this is usually shown in a larger form whose generation 1 is generation 8 of the form shown here.


OO..O
O...O
O..OO

:glider synthesis Construction of an object by means of glider collisions. It is generally assumed that the gliders should be arranged so that they could come from infinity - that is, gliders should not have had to pass through one another to achieve the initial arrangement.

Glider syntheses for all still lifes and known oscillators with at most 14 cells were found by Dave Buckingham.

Perhaps the most interesting glider syntheses are those of spaceships, because these can be used to create corresponding guns and rakes. Many of the c/2 spaceships that are based on standard spaceships have been synthesized, mostly by Mark Niemiec. In June 1998 Stephen Silver found syntheses for some of the Corderships (although it was not until July 1999 that Jason Summers used this to build a Cordership gun). In May 2000, Noam Elkies suggested that a 2c/5 spaceship found by Tim Coe in May 1996 might be a candidate for glider synthesis. Initial attempts to construct a synthesis for this spaceship got fairly close, but it was only in March 2003 that Summers and Elkies managed to find a way perform the crucial last step. Summers then used the new synthesis to build a c/2 forward rake for the 2c/5 spaceship; this was the first example in Life of a rake which fires spaceships that travel in the same direction as the rake but more slowly.

A 3-glider synthesis of a pentadecathlon is shown in the diagram below. This was found in April 1997 by Heinrich Koenig and came as a surprise, as it was widely assumed that anything using just three gliders would already be known.


......O...
......O.O.
......OO..
..........
OOO.......
..O.......
.O.....OO.
........OO
.......O..

:glider train A certain puffer that produces two rows of blocks and two backward glider waves. Ten of these were used to make the first breeder.

:glider turner An reaction in which a glider is turned by an oscillator or a spaceship. In the former case, the glider turner is usually called a reflector.

Glider turners are easily built using standard spaceships. The following diagram shows a convoy which turns a forward glider 90 degrees, with the new glider also moving forwards.


.........OO.........
........OO.OOOO.....
.O.......OOOOOO.....
O.........OOOO......
OOO.................
....................
....................
....................
....................
...O................
.O...O..............
O...................
O....O..............
OOOOO...............
....................
....................
.............OOOOOO.
.............O.....O
.............O......
..............O....O
................OO..
Small rearrangements of the back two spaceships can alternatively send the output glider into any of the other three directions.

See also glider duplicator and reflector.

:glide symmetric Undergoing simultaneous reflection and translation. A glide symmetric spaceship is sometimes called a flipper.

:gnome = fox

:GoE = Garden of Eden

:GoL = Game of Life

:Golly A cross-platform open source Life program by Andrew Trevorrow and Tomas Rokicki. Unlike most Life programs it includes the ability to run patterns using the hashlife algorithm. It is available from http://golly.sourceforge.net.

:Gosper glider gun The first known gun, and indeed the first known finite pattern with unbounded growth, found by Bill Gosper in November 1970. It remains by far the smallest known gun. Gosper has since found other guns, see new gun and the p144 gun shown under factory.


........................O...........
......................O.O...........
............OO......OO............OO
...........O...O....OO............OO
OO........O.....O...OO..............
OO........O...O.OO....O.O...........
..........O.....O.......O...........
...........O...O....................
............OO......................

:gourmet (p32) Found by Dave Buckingham in March 1978. Compare with pi portraitor and popover.


..........OO........
..........O.........
....OO.OO.O....OO...
..O..O.O.O.....O....
..OO....O........O..
................OO..
....................
................OO..
O.........OOO..O.O..
OOO.......O.O...O...
...O......O.O....OOO
..O.O..............O
..OO................
....................
..OO................
..O........O....OO..
....O.....O.O.O..O..
...OO....O.OO.OO....
.........O..........
........OO..........

:grammar A set of rules for connecting components together to make an object such as a spaceship, oscillator or still life.

:grandfather = grandparent

:grandparent A pattern is said to be a grandparent of the pattern it gives rise to after two generations. See also parent.

:Gray counter (p4) Found in 1971. If you look at this in the right way you will see that it cycles through the Gray codes from 0 to 3. Compare with R2D2.


......O......
.....O.O.....
....O.O.O....
.O..O...O..O.
O.O.O...O.O.O
.O..O...O..O.
....O.O.O....
.....O.O.....
......O......

:gray ship = grey ship

:great on-off (p2)


..OO....
.O..O...
.O.O....
OO.O..O.
....OO.O
.......O
....OOO.
....O...

:grey counter = Gray counter (This form is erroneous, as Gray is surname, not a colour.)

:grey ship A spaceship that contains a region with a density of 1/2, and which is extensible in such a way that the region of density 1/2 can be made larger than any given square region.

See also with-the-grain grey ship, against-the-grain grey ship and hybrid grey ship.

:grin The following common parent of the block. This name relates to the infamous Cheshire cat. See also pre-block.


O..O
.OO.

:grow-by-one object A pattern whose population increases by one cell every generation. The smallest known grow-by-one object is the following 44-cell pattern (David Bell's one-cell improvement of a pattern found by Nicolay Beluchenko, September 2005).


........OO.......
.......OO........
.........O.......
...........OO....
..........O......
.................
.........O..OO...
.OO.....OO....O..
OO.....O.....O...
..O....O.O...OO..
....O..O....OO.O.
....OO.......OO..
........O....O.OO
.......O.O..O.OO.
........O........

:growing/shrinking line ship A line ship in which the line repeatedly grows and shrinks, resulting in a high-period spaceship.

:growing spaceship An object that moves like a spaceship, except that its front part moves faster than its back part and a wick extends between the two. Put another way, a growing spaceship is a puffer whose output is burning cleanly at a slower rate than the puffer is producing it. Examples include blinker ships and pi ships.

:gull = elevener

:gun Any stationary pattern that emits spaceships (or rakes) forever. For examples see double-barrelled, edge shooter, factory, gliderless, Gosper glider gun, new gun and true.

:gunstar Any of a series of glider guns of period 144+72n (for all non-negative integers n) constructed by Dave Buckingham in 1990 based on his transparent block reaction and Robert Wainwright's p72 oscillator (shown under factory).


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/Help/Lexicon/modify.pl0000755000175000017500000000273112536111364014343 00000000000000#!/usr/bin/perl @files = glob "*.htm" ; for $file (@files) { open F, "$file" or die "Can't open $file\n" ; @f = ; close F ; $f = join('', @f) ; for (($f)) { s///g ; s!
Life Lexicon Home Page!
Introduction \| Bibliography
!g ; s|
Life Lexicon
||g ; s:^Introduction \|::gm ; s:^Introduction \|::gm ; s:Z \|:Z:g ; s:Z \|:Z:g ; s|^Bibliography||gm ; s|^Bibliography||gm ; s||
|gm ;
      s|^
|
|gm ; # fix problems in lex_[hps].htm s|\n-|\n-|g ; s|-\n|-\n|g ; # fix problem in lex_l.htm s|\nMar|\nMar|g ; s|1973\n|1973\n|g ; } open F, ">$file" or die "Can't write $file\n" ; print F $f ; close F ; } golly-2.7-src/Help/changes.html0000644000175000017500000011704112536111364013412 00000000000000 Golly Help: Changes

Changes in version 2.7 (released May 2015)

  • The middle mouse button can now be used for panning, regardless of the current cursor mode.
  • Fixed potential crash when pasting a text pattern into any hash-based algorithm.
  • Fixed crash on Mac OS 10.9 when opening a modal dialog like Save Pattern.
  • Fixed crash on Windows 8 when opening the Set Rule dialog.
  • Fixed bug in QuickLife algorithm that could cause cells at the bottom/left edges of the viewport to disappear every odd generation.
  • Fixed bug in QuickLife algorithm that could cause the selection rectangle to appear offset by one pixel (left or right).
  • The shift.pl/py scripts save the given parameters for the next run.
  • The evolve command aborts the current script with an error message if the given number of generations is negative.
  • Fixed minor problem with the Fit Pattern/Selection menu commands not centering a pattern/selection accurately in some cases. Ditto for the fit and fitsel script commands. The visrect script command is also more accurate.
  • Fixed bug that could cause Undo to fail due to a temporary macrocell file containing comment lines not prefixed with #C.
  • Start-up message now shows if this version of Golly is 32-bit or 64-bit.

Changes in version 2.6 (released December 2013)

  • Fixed menu problems on Ubuntu when using Unity.
  • Fixed a nasty bug that could cause Golly to crash when doing a paste.
  • Fixed a bug that could cause the paste image to disappear after a flip/rotate.
  • Fixed bugs in Mac app caused by non-ASCII characters in some file paths.
  • Fixed a problem that prevented Golly starting up on Mac OS 10.9.
  • Tool bar buttons are no longer disabled when the main window is inactive.
  • The save settings in Preferences > Layer are now obeyed by scripts. For example, let's assume you've ticked the option to be asked to save changes on creating a new pattern. If the current layer has changes and you run a script that calls new() then you'll get the standard dialog asking if you want to save those changes. If you cancel the dialog then the script is aborted.
  • To avoid potential data loss, you now get a warning if you save a non-starting generation and earlier changes exist. The warning can be disabled in Preferences > Layer.
  • Created an online archive for very large patterns.

Changes in version 2.5 (released June 2013)

  • This version introduces a new rule format. A file in the new format has a .rule extension and contains all the information about the rule: its name, description, table/tree data, and any color/icon information. More details here.
  • The RuleTable and RuleTree algorithms have been replaced by a new algorithm called RuleLoader. If asked to load a rule called "Foo", RuleLoader will look for Foo.rule first, then Foo.table, then Foo.tree.
  • The Control menu has a new command called Convert Old Rules that can be used to convert all your old .table/tree/colors/icons files into new .rule files (it won't overwrite any existing .rule files). After the conversion finishes you're given the option of deleting all the old files.
  • If File > Open Clipboard or Edit > Paste sees clipboard text starting with "@RULE rulename" then Golly will save the text as rulename.rule in your rules folder and switch to that rule.
  • All Python scripts that created a .tree file (and possibly .colors/icons files) now create a .rule file containing the same tree data (and any color/icon info).
  • Two new scripts allow Golly to be used as an icon editor. First, run icon-importer.py to import any icons for the current rule and display their bitmaps in a new layer for you to edit. When you've finished, run icon-exporter.py to extract the icon images and create or update the @ICONS section in the appropriate .rule file, then display the icons in a separate test layer.
  • A script has been added: goto_expression.py. It works like goto.py, except that it also accepts expressions. An example of an "expression" is "17*(2^(3*143)+2^(2*3*27))".
  • The status bar now displays quantities larger than 10308 in scientific notation. Golly can easily exceed this in both the Generation and Population statistics. For example, open the pattern puffer-train.rle, then run the script goto_expression.py and enter "f10^2000".
  • Added a new pattern: partial-constructor.mc.gz.
  • Patterns can now be displayed at scale 1:32. If you want to use that scale when creating a new pattern then choose the appropriate pop-up menu option in Preferences > File.
  • Support for monochrome icons has been extended to allow grayscale icons, where shades of gray can be used to do anti-aliasing. See the icons in WireWorld.rule for a good example. Most of the default icons are now grayscale bitmaps.
  • The current directory is now inserted at the start of sys.path for Python scripts.
  • The "Load Icons" button in Preferences > Color has been removed (it's no longer possible to change an algorithm's default icons).
  • The RuleTableToTree program is no longer included (you can use the RuleTableToTree.py script instead).
  • Fixed bug in Linux app: the shift key wasn't toggling cursor mode.
  • Fixed bug in Linux app: the space key wouldn't stop a pattern generating.
  • Fixed bug in Mac app: resizing the window could cause the sash position to change unexpectedly.
  • Fixed bug in Mac app: the first keyboard shortcut after a Paste command might be ignored.

Changes in version 2.4 (released June 2012)

  • Fixed bug that prevented 64-bit Windows app using more than 4GB of hash memory.
  • Fixed bug that caused corrupted macrocell files if saved with timeline data.
  • Fixed bug in Langtons-Ant.tree that had ants colliding incorrectly.
  • Fixed Mac app crashing if user's language setting is non-English.
  • Clipboard data on the Mac now uses LF as the end-of-line character rather than CR.
  • A pending paste is aborted if the main window becomes inactive.
  • Error messages from each algorithm are shown if a pattern file can't be loaded.

Changes in version 2.3 (released November 2011)

  • QuickLife and HashLife support rules using the von Neumann neighborhood or the hexagonal neighborhood. More details here.
  • The default icon for most rules is now a circular dot rather than a diamond. A diamond is the default icon for rules using the von Neumann neighborhood and a slanted hexagon is the default icon for rules using the hexagonal neighborhood.
  • A number of new script commands have been added to allow mouse interaction and better keyboard interaction: getevent, doevent and getxy. The getkey and dokey commands still work but are deprecated. In particular, there is no longer any need for scripts to call dokey(getkey()). See the description of getevent for more details.
  • Some scripts have been added to take advantage of the new commands: draw-lines.py, flood-fill.py, move-object.py and move-selection.py.
  • New patterns: ComputerArt.rle, CrittersCircle.rle, CrittersOscillators.rle, HPP.rle, HPP_large.rle, Sand-Test.rle, TMGas.rle, TMGas_largeWithHole.rle, TripATron.rle, TripATron_BlockAligned.rle.
  • Scripts that create table/tree files have been moved into Scripts/Python/Rule-Generators.
  • Langtons-Ant-gen.py now accepts turns 'U' and 'N' (U-turn and no-turn) as well as 'L' and 'R'.
  • The hash() command uses a better hash function in a two-state universe.
  • Pattern rendering is faster at scales 1:16 and 1:8, especially in the Linux app.
  • The mouse wheel now zooms in/out from the current cursor location rather than the middle of the viewport.
  • Patterns can be saved as gzipped files (*.rle.gz or *.mc.gz).
  • If an algorithm can save patterns in macrocell format (currently all except QuickLife) then the Save Pattern dialog now prefers that format over RLE; ie. the file type order is *.mc, *.mc.gz, *.rle, *.rle.gz.
  • While waiting for a paste click, the keyboard shortcuts for flipping or rotating a selection now modify the paste pattern rather than the current selection.
  • Fixed a bug in Win and Linux apps that prevented keyboard shortcuts being used while waiting for paste click.
  • Pasted patterns are no longer truncated if the RLE header info is incorrect.
  • Quitting Win app no longer clears clipboard.
  • Fixed unwanted cursor changes while running a script.
  • Fixed bug if layer was changed while recording a timeline.
  • Fixed bug in EmulateMargolus.py when using square4_* neighborhoods.
  • Removed emulate-Margolus-table.py script (use RuleTableToTree.py instead).
  • Fixed bug that could result in all buttons and menus being disabled after hitting the tool bar's Reset button.
  • Fixed cursor problems if shift key is used in a keyboard shortcut.
  • The Mac app now runs on Lion (10.7). There are two Mac apps: a 64-bit version for 10.6 and later (based on Cocoa), and a 32-bit version for 10.4 and 10.5 (based on Carbon).

Changes in version 2.2 (released November 2010)

  • Golly supports bounded grids with various topologies (plane, torus, Klein bottle, etc.). Such grids are created by adding a special suffix to the usual rule string. The details are in Help > Bounded Grids.
  • Two new script commands, getwidth and getheight, return the size of the current grid.
  • The new scripts, make-torus.py and make-torus.pl, can be used to convert the current selection into a toroidal universe.
  • Any BOARD and WRAP settings in an MCell file are now obeyed (e.g. Bloomerang.mcl).
  • Golly can record and play back a pattern's "timeline", a sequence of steps saved by the new Start Recording item in the Control menu. Use the Delete Timeline item to delete a timeline. Timelines are supported by all the hashlife-based algorithms (ie. all except QuickLife).
  • Show Timeline in the View menu toggles the new timeline bar below the viewport window.
  • If a timeline exists when you save a .mc file then all the steps will be stored in the file. On opening such a file, Golly will load the timeline and automatically show the timeline bar.
  • Multi-color icons are supported and allow both icon and color information to be stored in the one file (more details here).
  • Rule tables now support hexagonal and oneDimensional neighborhoods and the permute symmetry.
  • Added a section on naming conventions for .table and .tree files.
  • Added a new Python script, make-ruletree.py, that allows you to write rules in Python and have them installed in the form of .tree files. See the comments at the top of the script.
  • Added RuleTableToTree.py for converting rule tables to trees. It provides emulation for several neighborhoods not natively supported by Golly: triangularVonNeumann, triangularMoore, Margolus, etc. More details here.
  • New Turmite scripts, e.g. Turmite-gen.py, for generating rule trees and icons for relative- and absolute-movement turmites on square, hexagonal and triangular grids.
  • The goto.py script is much faster (thanks to PM 2Ring).
  • Hitting escape aborts a script that has called a lengthy run() or step() command.
  • Langtons-Ant.table has been replaced with Langtons-Ant.tree. The new rule is faster, handles multiple ants correctly, and matches most other implementations of this CA.
  • Reorganized the Patterns folder: moved Conway's Life patterns into Life subfolder, moved rule subfolders out of Other-Rules to top level under Patterns, added Life-Like folder.
  • Added new Turmite patterns, e.g. WormTrails.rle.
  • Other new patterns: golly-ants.rle, Langtons-Ant.rle, JvN-loop-replicator.rle.gz, Herschel-conduit-stamp-collection.rle, Boustrophedon-replicator.rle.
  • Increased the maximum base step from 10,000 to 2,000,000,000.
  • Help > Keyboard Shortcuts lists unassigned actions at the end.
  • The drawing state can be changed by creating keyboard shortcuts for two new actions called Next Higher State and Next Lower State (see Preferences > Keyboard).
  • You can turn off the beep sound by unticking the option at the bottom of Preferences > Edit.
  • Loading a pattern won't proceed if the "save changes" dialog appears and you select Save but then decide to cancel the "save pattern" dialog.
  • Fixed bug that caused cells to be created in the wrong location when editing very large patterns.
  • Fixed bug drawing incorrect selection rectangle if very large.
  • Fixed cursor problem if the shift key is used in a keyboard shortcut to open a dialog/window.
  • Fixed weird bug on Mac that could cause the viewport to lose keyboard focus after clicking in the layer bar's "delete layer" button.
  • Fixed undo history getting out of sync if you tried to reset to a saved starting pattern that had been deleted.
  • Fixed a bug drawing incorrect icons when layers are stacked.
  • Fixed a bug not updating the paste image when colors are inverted.
  • Fixed a problem with the hash() command in a multi-state universe.
  • Fixed problems using a keyboard shortcut or menu command while a script is running.
  • Dropped support for Mac OS 10.3.9.

Changes in version 2.1 (released September 2009)

  • Golly can download patterns, rules and scripts from various online archives. You can change the location of downloaded files using the new button at the bottom of Preferences > File.
  • Zip files can be opened and processed as described here.
  • If the mouse moves over a link in the help window then the link reference is displayed at the bottom of the window. Ditto for links in the Set Rule dialog.
  • The algorithm info in the Set Rule dialog can now be accessed from the new Algorithms help item.
  • Translucent buttons for speed/scale/scroll functions now appear in a corner of the viewport whenever the mouse moves over that corner. The initial location is the top left corner, but you can use Preferences > View to specify any other corner or disable the buttons.
  • Layer bar buttons now show each layer's name rather than its numeric position.
  • New rules: Codd2, Devore, DLA, Ed-rep, LifeHistory, Perrier, Sand.
  • New patterns in Other-Rules/, Other-Rules/Codd/, Other-Rules/Codd/Devore/, Other-Rules/Margolus/, Loops/.
  • New scripts: FredkinModN-gen.py, make-Devore-tape.py, Margolus/emulate-Margolus-table.py, Margolus/convert-MCell-string.py.
  • All Python scripts now need to explicitly import the golly module. This wasn't strictly necessary in previous versions, but only because it was an undesirable side-effect of the way Golly ran scripts.
  • The open command can now be used to run a given Perl/Python script.
  • New scripting commands: opendialog, savedialog, getclipstr, setclipstr, getdir, setdir.
  • The appdir and datadir commands are deprecated; use the new getdir command.
  • The color of dead cells (state 0) is now handled like all other states, so it's possible for each algorithm/rule to have a different background color.
  • The setcolors and getcolors commands can be used to set/get the color of state 0.
  • Golly restores a layer's default colors whenever you create a new pattern or open a pattern file (and not just if the algorithm or rule changes). If you have any scripts that use setcolors then make sure it is called after calling new/open.
  • The base step can now be changed temporarily via the new Set Base Step dialog in the Control menu. Golly will restore the default base step (set in Preferences > Control) when you create a new pattern, open a pattern file, or switch to a different algorithm.
  • The setbase command also changes the base step temporarily, so if you have any scripts that use setbase then make sure it is called after calling new/open/setrule/setalgo.
  • The setoption/getoption commands can use "drawingstate" to set/get the edit bar's current drawing state, and they can use "restoreview" to set/get the state of the "Reset/Undo will restore view" option set in Preferences > View.
  • Paste now supports "And" mode.
  • The RLE reader allows alphabetic characters other than "o" to represent live cells.
  • Menu items can show single-character keyboard shortcuts.
  • When a lexicon pattern is loaded, Golly automatically switches the current rule to B3/S23 (and changes the algorithm to QuickLife, if necessary).
  • Fixed a bug with Random Fill. Golly wasn't initializing the seed, so the internal rand() calls were returning the same sequence of "random" integers each time!
  • Fixed a bug that prevented the getkey command from returning uppercase letters.
  • Fixed oscar.pl/py to handle B0-and-not-S8 rules correctly (they no longer report some spaceships to be stable patterns).
  • Fixed a couple of bugs when duplicating a layer's undo/redo history.
  • Fixed crash in Mac app if a script saved a pattern and the progress dialog appeared.

Changes in version 2.0 (released December 2008)

  • Golly now supports multiple algorithms and multi-state universes (up to 256 states).
  • The Generations algorithm supports an entire family of new rules, including Brian's Brain (/2/3), Star Wars (345/2/4), and Transers (345/26/5).
  • The JvN algorithm implements John von Neumann's classic 29-state CA, plus a couple of 32-state variants created by Renato Nobili and Tim Hutton. See Patterns/JvN for a variety of self-replicators.
  • The RuleTable and RuleTree algorithms allow you to add new rules by creating .table and .tree files and storing them in the Rules folder or your rules folder. A number of example rules are supplied, including Langtons-Loops, Evoloop, LifeOnTheEdge and WireWorld.
  • The tool bar has a new button for switching algorithms, or you can use the Set Algorithm submenu in the Control menu. The Use Hashing option has been removed.
  • The Control > Set Rule dialog also has a menu for changing the current algorithm. A help button can be used to expand the dialog and display information about the current algorithm, along with examples of the rules it supports.
  • Golly can read some MCell files (if an algorithm supports the given rule).
  • The ten layer-specific colors have been replaced by a more flexible approach to cope with multi-state universes. Each algorithm has a default color scheme that can be changed in Preferences > Color.
  • Each algorithm also has a default set of icons, small bitmaps that are only drawn at scales 1:8 and 1:16, and only if the Show Cell Icons option (in the View menu) is ticked. The default icons can be changed by using the Load Icons button in Preferences > Color.
  • Rule-specific colors and icons can be created by adding suitably named .colors and .icons files to the Rules folder or your rules folder. Golly looks for these files whenever it switches to a new rule.
  • The Layer > Set Layer Colors dialog can change one or more colors used by the current layer (and its clones). These changes are temporary and only remain in effect while the layer exists, or until the layer's algorithm or rule changes.
  • The View > Swap Cell Colors option has been changed to Invert Colors.
  • New script commands have been added to support the above changes: setalgo, getalgo, numalgos, numstates, join, setcolors and getcolors.
  • Some script commands have been modified to handle multi-state patterns. Perl users should read the section on cell arrays. Python users should read the section on cell lists.
  • The getrule command now returns a canonical rule string.
  • The setcursor/getcursor commands now accept/return strings.
  • Modified oscar.pl to use arbitrarily big integers.
  • It's now possible to open a pattern or run a script from the Help window by clicking on special links. For example, open golly-ticker.rle or run bricklayer.py.
  • Diagonal scrolling is supported. Open Preferences > Keyboard and assign keys to the new scrolling actions: Scroll NE/NW/SE/SW.
  • A new check box in Preferences > View can tell Reset/Undo not to restore the view.
  • View > Show Edit Bar toggles the new edit bar. The cursor mode buttons have been moved from the tool bar into the edit bar.
  • View > Show All States toggles the display of colors and icons for all states in the current universe. A box is drawn around the current drawing state.
  • Help > File Formats describes the various file formats used by Golly.
  • Rendering speed in the Mac and Linux apps has been improved.
  • Fixed a problem with ampersands not being displayed in the recent pattern/script menus.
  • Fixed a bug in the Linux/GTK app if a recent pattern/script path contained an underscore.
  • The Linux and Win apps require Perl 5.10 or later to run .pl scripts (older Perl versions are not binary compatible).
  • The Linux/X11 app is no longer supported due to limitations in wxX11.

Changes in version 1.4 (released May 2008)

  • Editing and other actions are now allowed while generating a pattern.
  • Golly saves files in the standard user-specific data directory on each platform rather than in the application directory. However, you can still keep the GollyPrefs file in the application directory if you prefer that option.
  • Right-click or control-click on a pattern/script file to open the file in a text editor. Use the new button in Preferences > File to select your preferred text editor.
  • Pasting a clipboard pattern can now change to the specified rule, depending on the option set in Preferences > Edit.
  • The Preferences dialog can be opened from the help window by clicking on special links like the examples above.
  • Added Reset button to tool bar and Duplicate Layer button to layer bar.
  • A duplicated layer now gets a copy of the original layer's undo/redo history.
  • Improved the automatic detection of Perl/Python code used by Run Clipboard.
  • Added help command to open given HTML file in help window.
  • A warning is displayed if a bad rule string is detected while loading a pattern.
  • Added support for reading WinLifeSearch output.
  • An error message is displayed if you try to load a JPEG file.
  • Fixed some problems if you quit Golly while running a script.
  • Fixed problem shrinking selection while generating a pattern.
  • Fixed "Rules differ" warning when undoing/redoing generating changes using hashing.
  • Fixed problems with incorrect file selections in Win app's directory pane.
  • Fixed bug in Mac app's activate event handler.
  • Fixed bug in Linux/GTK app that prevented using shift-space as a keyboard shortcut.
  • Mac app allows option-E/I/N/U/` to be used as keyboard shortcuts.
  • Golly can be built for 64-bit platforms.

Changes in version 1.3 (released November 2007)

  • Added unlimited undo/redo; see the Edit Menu help for details. For consistency with Undo, the Reset item now restores the starting selection and layer name.
  • Keyboard shortcuts are now configurable using Preferences > Keyboard. Note that you can also specify key combinations to open a pattern, run a script, or show any HTML file in the help window.
  • Golly can be scripted using Perl; see the new Perl Scripting help.
  • Added pop-plot.pl/py to the Scripts folder for creating population plots.
  • The metafier.py script now creates the metafied pattern in a separate layer.
  • Added getstring command for getting user input via a dialog box (glife's getstring function still exists but is deprecated).
  • Added hash command to speed up oscar.pl/py.
  • The parse and transform commands have optional parameters.
  • A script is aborted if a progress dialog appears and you hit Cancel.
  • The Open/Run Recent submenus show relative paths for files inside the Golly folder.
  • Added a Clear Missing Files item to the Open/Run Recent submenus.
  • The Control menu's Go and Stop items have been replaced by a single Start/Stop item for consistency with the tool bar's start/stop button.
  • The Control menu has a Set Generation item for changing the generation count, or you can click in the "Generation=..." text in the status bar. Scripts can use the new setgen command.
  • Flip operations are much faster.
  • The About box uses Brice Due's Golly ticker.
  • Reduced chances of out-of-memory error while loading a large .mc file.
  • Fixed crash if a pattern update occurred while saving a .mc file.
  • Fixed bug pasting a macrocell pattern.
  • Fixed bug reading an empty macrocell pattern.
  • Fixed bug not marking a layer as modified after clearing the entire pattern.
  • Fixed bug if apostrophe was in Python script path or file name.
  • Fixed drawing problems on Mac OS 10.3.9.

Changes in version 1.2 (released April 2007)

  • Golly supports multiple layers; see the new Layer Menu help for details.
  • Added layer-related scripting commands. See heisenburp.py and envelope.py in the Scripts folder for how these commands can be used.
  • Added other useful scripting commands: exit, check and note.
  • The putcells command has optional parameters, including a new mode parameter.
  • Clicked lexicon patterns are loaded into a separate "lexicon" layer (and the clipboard is no longer changed).
  • If a pattern has been modified then its layer name is prefixed with an asterisk and a "save changes" dialog will appear before certain actions, such as opening a pattern file or quitting Golly. The dialog can be disabled via check boxes in Preferences > Layer.
  • Scrolling is optional if the pencil/cross/hand cursor is dragged outside the view window; see Preferences > Edit.
  • The hand cursor no longer has a pointing finger.
  • A .py file selected via Open Pattern is run as a script.
  • If golly-start.py exists in the same folder as the application then it is automatically executed when Golly starts up.
  • New tool bar buttons, including a single start/stop button.
  • Reset and Use Hashing can be selected while a pattern is generating.
  • Renamed Flip Up-Down to Flip Top-Bottom.
  • GTK app no longer does unnecessary buffered drawing.
  • X11 app has a vertical tool bar which can be toggled.
  • Mac app has a creator code (GoLy) and .mc/rle files are saved with an appropriate type and creator.
  • Fixed a bug if Win app given a long-running script on command line.
  • Fixed a bug in the advance and evolve commands if using hashing with Wolfram rule.
  • Fixed a delay bug.

Changes in version 1.1 (released November 2006)

  • Added Save Extended RLE option (initially ticked) to the File menu. An extended RLE file stores the pattern position and generation count (if > 0) so they can be restored when the file is loaded.
  • Macrocell files also store the generation count if > 0.
  • Non-extended RLE files are now loaded so that 0,0 is at the top left corner of the pattern rather than in the middle of the pattern.
  • Golly can read BMP/GIF/PNG/TIFF files and paste bitmap data. All non-white pixels become live cells.
  • Golly can read pattern files using David Bell's dblife format.
  • Starting patterns are saved in a temporary file rather than in memory. This is much faster when hashing (saving a macrocell file is very quick).
  • Random Fill is much faster in typical cases.
  • Escape key can be used to stop generating.
  • Numerous additions and updates to the pattern collection.
  • Added fuse-watcher.py, metafier.py and shift.py to the Scripts folder.
  • More mouse interaction is allowed while a script is running. A script can be aborted by clicking the stop button in the tool bar or by selecting Stop in the Control menu.
  • Resizing the help window no longer changes the scroll position.
  • Fixed a bug loading huge macrocell files.
  • Fixed an obscure bug in the non-hashing algorithm.
  • Path to Scripts folder is only added to Python's sys.path once.
  • Fixed rect bug in Scripts/glife/__init__.py (thanks to Dan Hoey).
  • Golly's code can be compiled with a Unicode build of wxWidgets.

Changes in version 1.0 (released June 2006)

  • Added Python script support; see the new Python Scripting help.
  • Golly is available for Linux/GTK.
  • Mac app is a Universal Binary (4 times faster on an Intel Mac).
  • Added ability to change various colors via Preferences > Color. The Black on White option has been replaced by Swap Cell Colors.
  • Increased the base step limit from 100 to 10,000.
  • Added Show Hash Info option to the Control menu.
  • Added Show Exact Numbers option to the View menu.
  • Save Pattern preserves comments when writing to an existing file.
  • Added tool bar buttons for toggling patterns and scripts.
  • Included the latest release of the Life Lexicon.
  • Renamed Flip Horizontally/Vertically to Flip Up-Down/Left-Right.
  • Fixed disabled menu item bug after closing a modal dialog on Mac OS 10.4.
  • Fixed a couple of rule-related bugs in the non-hashing algorithm.
  • Fixed crash due to very long rule strings.
  • Fixed paste positioning bugs at scale 1:2.
  • Fixed error if Win app is closed while script is running.
  • Fixed problem if Win app is closed when window(s) minimized.

Changes in version 0.95 (released January 2006)

  • Stephen Silver's Life Lexicon has been integrated into the help. Note that clicking on a lexicon pattern loads it into the Golly window.
  • Added an Open Recent submenu to the File menu.
  • Added Show Patterns and Change Folder to the File menu.
  • Added a Preferences dialog to the File menu (app menu on Mac).
  • Added more items to the Edit menu: Clear Outside, Shrink Selection, Random Fill, Flip Vertically, Flip Horizontally, Rotate Clockwise and Rotate Anticlockwise.
  • The clipboard pattern is displayed when pasting.
  • Pasting large, sparse patterns is much faster when using Or mode.
  • Added more items to the View menu: Fit Selection, Restore Origin and Set Scale.
  • The thumb scroll range is adjustable (see Preferences > View).
  • The Reset item now restores the rule, scale, location, step size and hashing option to the values they had at generation 0.
  • Removed Max Hash Memory from Control menu (now set in Preferences > Control).
  • The Rule dialog lets you select/add/delete named rules. If a rule has a name then it's shown in the main window's title bar.
  • Hit control-space to advance the selection, or shift-space to advance everything outside the selection. The generation count will not change.
  • The delete key is a shortcut for Clear, or shift-delete for Clear Outside.
  • F5 to F9 can be used to set cursor modes.
  • Hit "s" to shrink the selection and fit it in the current view.
  • Hit "0" to change the origin to the cell under the cursor.
  • Hit "9" to restore the true origin.
  • Hit "6" to set the scale to 1:16.
  • Hit "," to open the Preferences dialog.
  • If the help window is in front, hit "+" and "-" to change the font size.
  • While dragging the mouse to make (or modify) a selection, the escape key can be used to cancel the operation and restore the original selection.
  • The escape key can no longer be used to stop generating.
  • In zoom in/out mode, right-click or control-click zooms in the opposite direction.
  • The mouse wheel can be used for zooming, regardless of cursor mode.
  • Commas are used to make large status bar numbers more readable.
  • Fixed a hashing bug that could cause advancing by the wrong step.
  • Fixed a bug in Mac app when returning from full screen mode.
  • Fixed a bug in Win app that prevented space bar being used to stop generating.
  • Fixed Win app's cross cursor (now visible on a black background).

Changes in version 0.91 (released October 2005)

  • Return key can be used to start/stop generating.
  • Space bar can be used to stop generating.
  • Win app puts CR+LF in clipboard data.
  • Fixed occasional bug when +/- pressed while hashing.

Changes in version 0.9 (released October 2005)

  • Implemented pattern saving (as RLE or macrocell format).
  • Implemented cell editing and selecting.
  • Implemented scrolling via hand cursor.
  • Edit menu has a Cursor Mode submenu (items match new tool bar buttons).
  • Hit "c" to cycle through all cursors.
  • Win app can now read gzipped pattern files.
  • Can now display comments in pattern files.
  • Added Patterns folder to distribution.
  • Toggling the hashing option doesn't change the pattern or generation count.
  • The Reset item is smarter about restoring the starting pattern.
  • Fixed colored frame after dropping pattern file onto Mac app's main window.
  • Fixed horizontal scroll bar problem in Mac app's help window.
  • The help window's cursor now gets updated while generating.
  • Fixed problem with location of help window in X11 app.
  • Added limited clipboard support to X11 app.
  • Golly has a new app icon based on Galaxy, a period-8 oscillator.

Changes in version 0.2 (released July 2005)

  • Added support for B0 rules.
  • Golly comes to the front after dropping a pattern file onto main window.
  • The help window can move behind the main window in Win/X11 apps.
  • Text in the help window can be selected and copied to the clipboard.
  • Fixed keyboard shortcuts in the help window.
  • Fixed RLE rule problem in Mac app.
  • Fixed menu and tool bar update problems in Mac/Win apps.
  • Fixed some cosmetic problems in Win app.

Initial version 0.1 released July 2005 golly-2.7-src/Help/edit.html0000644000175000017500000001375212536111364012733 00000000000000 Golly Help: Edit Menu

Undo

Lets you undo one or more recent changes, including all editing changes and generating changes, as well as changes to the selection, rule, hashing state and layer name. The number of changes you can undo is limited only by available memory and disk space. Multiple changes made by a script are treated like a single change and will be undone all at once.

Each layer maintains its own undo/redo history (but cloned layers share the same undo/redo history). The current layer's undo/redo history is automatically cleared after creating a new pattern or opening a pattern file.

Redo

Lets you redo one or more recently undone changes. Note that the redo history is automatically cleared after you make a new change; i.e., if you do something like rotate the current selection, undo the rotation, then edit some cells or change the selection, you can no longer redo the rotation.

Disable Undo/Redo

If ticked then the Undo and Redo items are disabled, and any existing undo/redo history for the current layer is cleared. When editing or generating a very large pattern you may want to temporarily disable undo/redo to speed up some operations. But be careful using this feature — if you switch to another layer when this item is ticked then that layer's undo/redo history is also cleared.

Cut

Copies the pattern in the current selection to the clipboard (in RLE format) and then kills all cells in the selection.

Copy

Copies the pattern in the current selection to the clipboard. The clipboard data is in RLE format.

Clear

Kills all cells in the current selection.

Clear Outside

Kills all cells outside the current selection. This is often the quickest way to delete escaping gliders.

Paste

Pastes a pattern stored in the clipboard into the existing pattern. After selecting this item you'll be asked to click where you want the paste to occur. Before clicking you can use keyboard shortcuts to scroll, change scale, etc. The keyboard shortcuts normally used to flip/rotate the selection will instead modify the paste pattern. You can also type "M" to change the paste mode or "L" to change the paste location (see below). To cancel the paste, just click anywhere outside the view area or hit the escape key.

Settings in Preferences > Edit specify how to handle rule information in the clipboard pattern. You can tell Golly not to change the current rule, or only change the rule if the universe is empty, or always change to the given rule. Note that a rule change might cause the current algorithm to change.

The References section has links to a number of good sources for clipboard patterns.

If the clipboard text starts with "@RULE rulename" then Golly will save the text as rulename.rule in your rules folder (set in Preferences > Control) and switch to that rule.

Paste Mode

This submenu lets you choose the logical function used when pasting in a clipboard pattern. The choices are Copy, Or and Xor. Typing "M" will cycle through all these modes, even after selecting the Paste command.

Paste Location

This submenu lets you choose the location of the cursor within the paste rectangle that appears after selecting the Paste command. You can choose any corner or the middle of the rectangle. Typing "L" will cycle through all possible locations, even after selecting the Paste command.

Paste to Selection

Pastes a clipboard pattern into the current selection, but only if it will fit. The paste always occurs at the top left corner of the selection. This command can be used as a quick check to see if the pattern in the clipboard matches the pattern in the selection — if Xor paste mode is used then all the resulting cells will be dead if the patterns match.

Select All

Selects the entire pattern, assuming there are one or more live cells. If there are no live cells then any existing selection is removed.

Remove Selection

Removes the current selection (without changing any cell states).

Shrink Selection

Reduces the size of the current selection to the smallest rectangle containing all of the selection's live cells. You can hit "s" to shrink the selection and fit it in the current view.

Random Fill (n%)

Randomly fills the current selection with the indicated percentage of live cells. Use Preferences > Edit to change the percentage (from 1 to 100).

Flip Top-Bottom

The cells in the current selection are reflected about its central horizontal axis.

Flip Left-Right

The cells in the current selection are reflected about its central vertical axis.

Rotate Clockwise

The current selection is rotated 90 degrees clockwise about its center.

Rotate Anticlockwise

As above, but the rotation is anticlockwise.

Cursor Mode

This submenu lets you choose a cursor mode for various editing operations: drawing cells, picking cell states, selecting cells, moving the view, and zooming into or out from a clicked cell. There are other (quicker) ways to change the cursor mode:

  • Click on the corresponding buttons in the edit bar.
  • Hit the corresponding function keys (F2 to F7).
  • Hit "c" to cycle through all the cursor modes.
  • Press the shift key to temporarily toggle the draw/pick cursors or the zoom in/out cursors.
golly-2.7-src/Help/problems.html0000644000175000017500000000164712536111364013631 00000000000000 Golly Help: Known Problems

This section lists all known bugs and limitations. If you come across any problems not mentioned below then please report them to Andrew Trevorrow (andrew@trevorrow.com) or Tom Rokicki (rokicki@gmail.com).

Problems on all platforms

  • All editing operations are restricted to cells whose coordinates are within +/- 1 billion.
  • Pattern rendering needs to be optimized, especially in the Mac and Linux apps. The solution will probably require using OpenGL rather than wxDC calls.

Mac problems

  • None.

Windows problems

  • None.

Linux problems

  • None.
golly-2.7-src/Help/credits.html0000644000175000017500000000513412536111364013436 00000000000000 Golly Help: Credits

The pioneers

First and foremost, a big thanks to John Conway for creating the Game of Life, and to Martin Gardner for popularizing the topic in his Scientific American column.

The programmers

Tom Rokicki wrote most of the complicated stuff. Golly is essentially the merging of two of Tom's programs (hlife and qlife). The HashLife algorithm is based on an idea by Bill Gosper. The QuickLife algorithm uses some ideas from Alan Hensel. David Eppstein provided the idea on how to emulate B0 rules.

Andrew Trevorrow wrote the cross-platform GUI code using wxWidgets. Much thanks to Julian Smart and all the other wxWidgets developers.

Golly's scripting capabilities were inspired by the generosity and efforts of Eugene Langvagen (author of PLife), Larry Wall (creator of Perl) and Guido van Rossum (creator of Python).

Tim Hutton wrote the RuleTable algorithm (now merged into the RuleLoader algorithm) and created the excellent Rule Table Repository.

Various code improvements have been contributed by Dave Greene, Jason Summers, Maks Verver and Robert Munafo.

If you'd like to join us and help make Golly the best Life/CA app in the known universe then please get in touch.

The beta testers

Thanks to all the bug hunters for their reports and suggestions, especially Dave Greene, Gabriel Nivasch, Dean Hickerson, Brice Due, David Eppstein, Tony Smith, Alan Hensel, Dennis Langdeau, Bill Gosper, Mark Jeronimus and Eric Goldstein.

Other contributors

Dave Greene and Alan Hensel helped put together the pattern collection. Thanks to everybody who allowed us to distribute their fantastic patterns, especially Nick Gotts, Gabriel Nivasch, David Eppstein, Jason Summers, Stephen Morley, Dean Hickerson, Brice Due, William R. Buckley, David Moore, Mark Owen, Tim Hutton, Renato Nobili and Adam P. Goucher.

Thanks to Stephen Silver for compiling the wonderful Life Lexicon.

Thanks to Nathaniel Johnston for creating the brilliant LifeWiki and for making its patterns available to Golly users via an online archive. golly-2.7-src/Help/intro.html0000644000175000017500000000354412536111364013137 00000000000000 Golly Help: Introduction

What is Golly?

Golly is a cross-platform application for exploring John Conway's Game of Life and other cellular automata. It's also free and open source. More details, including links to the source and binary distributions, are available at the Golly web site:

http://golly.sourceforge.net/

What is Life?

The Game of Life is a simple example of a set of rules more broadly known as a "cellular automaton", or CA for short. CAs were first studied in the mid-1950s by Stanislaw Ulam and John von Neumann but became much more widely known in 1970 when Conway's Life was described by Martin Gardner in his Scientific American column.

Life is played on an arbitrary-sized grid of square cells. Each cell has two states: "dead" or "alive". The state of every cell changes from one "generation" to the next according to the states of its 8 nearest neighbors: a dead cell becomes alive (a "birth") if it has exactly 3 live neighbors; a live cell dies out if it has less than 2 or more than 3 live neighbors. The "game" of Life simply involves starting off with a pattern of live cells and seeing what happens.

Even though the rules for Life are completely deterministic, it is impossible to predict whether an arbitrary starting pattern will die out, or start oscillating, or expand forever. Life and other CAs provide a powerful demonstration of how a very simple system can generate extremely complicated results.

If you'd like to learn more about Life and other cellular automata then check out the links and books mentioned in the References, or start exploring the Life Lexicon. golly-2.7-src/Help/refs.html0000644000175000017500000000744712536111364012751 00000000000000 Golly Help: References

Good web sites

Good books and magazine articles

  • "Wheels, Life and Other Mathematical Amusements" by Martin Gardner. W. H. Freeman and Company, 1983. The last three chapters are an updated collection of his superb columns from Scientific American (see below). The last chapter has an excellent bibliography.
  • "The Recursive Universe" by William Poundstone. William Morrow & Company, 1985. An entire book devoted to a discussion of cellular automata and other fascinating topics in physics and mathematics.
  • "Winning Ways", Volume 2 by Elwyn Berlekamp, John Conway and Richard Guy. Academic Press, 1982. Chapter 25 has the title "What is Life?".
  • "Cellular Automata Machines" by Tommaso Toffoli and Norman Margolus. MIT Press, 1987. Describes CAM, a machine for doing sophisticated experiments with cellular automata.
  • "A New Kind of Science" by Stephen Wolfram. Wolfram Media, 2002. Bloated and egotistical, but there is plenty of fascinating stuff.
  • Scientific American articles:
    "Mathematical Games" columns by Martin Gardner: Oct, Nov 1970, Jan, Feb, Mar, Apr, Nov 1971, Jan 1972.
    "Computer Recreations" by Brian Hayes, Mar 1984.
  • BYTE articles:
    "Some Facts of Life" by David Buckingham, Dec 1978.
    "Life Algorithms" by Mark Niemiec, Jan 1979.
golly-2.7-src/Help/algos.html0000644000175000017500000000107212536111364013103 00000000000000 Golly Help: Algorithms

Golly can generate patterns using a number of different algorithms:

QuickLife
HashLife
Generations
JvN
RuleLoader

The same information is also available in the Control menu's Set Rule dialog. golly-2.7-src/Help/archives.html0000644000175000017500000000367712536111364013617 00000000000000 Golly Help: Online Archives

Golly can download patterns, rules and scripts from these online archives:

LifeWiki Pattern Archive

Gliders in Life-Like Cellular Automata

Alan Hensel's Pattern Collections

Jason Summers' Pattern Collections

Very Large Patterns

Rule Table Repository

Golly Scripts Database

Note that Golly stores downloaded files in a directory that can be changed via a button at the bottom of Preferences > File. You might like to change the download location to a directory visible in the Show Patterns panel (to the left of the viewport), then you can easily re-open a pattern or zip file without having to download it again. Also, downloaded patterns and zip files are remembered in the Open Recent submenu, and downloaded scripts are remembered in the Run Recent submenu. golly-2.7-src/Help/bounded.html0000644000175000017500000005565012536111364013431 00000000000000 Golly Help: Bounded Grids

Bounded grids with various topologies can be created by adding a special suffix to the usual rule string. For example, B3/S23:T30,20 creates a toroidal Life universe 30 cells wide and 20 cells high. The suffix syntax is best illustrated by these examples:

:P30,20 — plane with width 30 and height 20
:P30,0 — plane with width 30 and infinite height
:T0,20 — tube with infinite width and height 20
:T30,20 — torus with width 30 and height 20
:T30+5,20 — torus with a shift of +5 on the horizontal edges
:T30,20-2 — torus with a shift of -2 on the vertical edges
:K30*,20 — Klein bottle with the horizontal edges twisted
:K30,20* — Klein bottle with the vertical edges twisted
:K30*+1,20 — Klein bottle with a shift on the horizontal edges
:C30,20 — cross-surface (horizontal and vertical edges are twisted)
:S30 — sphere with width 30 and height 30 (must be equal)

Some notes:

  • The first letter indicating the topology can be entered in lowercase but is always uppercase in the canonical string returned by the getrule() script command.
  • If a bounded grid has width w and height h then the cell in the top left corner has coordinates -int(w/2),-int(h/2).
  • The maximum width or height of a bounded grid is 2,000,000,000.
  • Use 0 to specify an infinite width or height (but not possible for a Klein bottle, cross-surface or sphere). Shifting is not allowed if either dimension is infinite.
  • Pattern generation in a bounded grid is slower than in an unbounded grid. This is because all the current algorithms have been designed to work with unbounded grids, so Golly has to do extra work to create the illusion of a bounded grid.

The different topologies are described in the following sections.

Plane

A bounded plane is a simple, flat surface with no curvature. When generating patterns in a plane, Golly ensures that all the cells neighboring the edges are set to state 0 before applying the transition rules, as in this example of a 4 by 3 plane:

 0  0  0  0  0  0 
 0  A  B  C  D  0 
 0  E  F  G  H  0 
 0  I  J  K  L  0 
 0  0  0  0  0  0 
   rule suffix is :P4,3

Torus

If the opposite edges of a bounded plane are joined then the result is a donut-shaped surface called a torus. Before applying the transition rules at each generation, Golly copies the states of edge cells into appropriate neighboring cells outside the grid. The following diagram of a 4 by 3 torus shows how the edges are joined:

 L  I  J  K  L  I 
 D  A  B  C  D  A 
 H  E  F  G  H  E 
 L  I  J  K  L  I 
 D  A  B  C  D  A 
   rule suffix is :T4,3

A torus can have a shift on the horizontal edges or the vertical edges, but not both. These two examples show how shifted edges are joined:

 K  L  I  J  K  L 
 D  A  B  C  D  A 
 H  E  F  G  H  E 
 L  I  J  K  L  I 
 A  B  C  D  A  B 
   :T4+1,3
 H  I  J  K  L  A 
 L  A  B  C  D  E 
 D  E  F  G  H  I 
 H  I  J  K  L  A 
 L  A  B  C  D  E 
   :T4,3+1

Klein bottle

If one pair of opposite edges are twisted 180 degrees (ie. reversed) before being joined then the result is a Klein bottle. Here are examples of a horizontal twist and a vertical twist:

 I  L  K  J  I  L 
 D  A  B  C  D  A 
 H  E  F  G  H  E 
 L  I  J  K  L  I 
 A  D  C  B  A  D 
   :K4*,3   
 D  I  J  K  L  A 
 L  A  B  C  D  I 
 H  E  F  G  H  E 
 D  I  J  K  L  A 
 L  A  B  C  D  I 
   :K4,3*

A Klein bottle can only have a shift on the twisted edges and only if that dimension has an even number of cells. Also, all shift amounts are equivalent to a shift of 1. Here are two examples:

 J  I  L  K  J  I 
 D  A  B  C  D  A 
 H  E  F  G  H  E 
 L  I  J  K  L  I 
 B  A  D  C  B  A 
   :K4*+1,3
 F  J  K  L  D 
 C  A  B  C  A 
 L  D  E  F  J 
 I  G  H  I  G 
 F  J  K  L  D 
 C  A  B  C  A 
   :K3,4*+1

Cross-surface

If both pairs of opposite edges are twisted and joined then the result is a cross-surface (also known as a real projective plane, but Conway prefers the term cross-surface). Here's an example showing how the edges are joined:

 A  L  K  J  I  D 
 L  A  B  C  D  I 
 H  E  F  G  H  E 
 D  I  J  K  L  A 
 I  D  C  B  A  L 
   :C4,3

Note that the corner cells have themselves as one of their neighbors. Shifting is not possible.

Sphere

If adjacent edges are joined rather than opposite edges then the result is a sphere. By convention we join the top edge to the left edge and the right edge to the bottom edge, as shown in this 3 by 3 example:

 A  A  D  G  C 
 A  A  B  C  G 
 B  D  E  F  H 
 C  G  H  I  I 
 G  C  F  I  I 
   :S3

Note that the cells in the top left and bottom right corners (the "poles") have different neighborhoods to the cells in the top right and bottom left corners. Shifting is not possible.

Example patterns using the above topologies can be found in Patterns/Generations and Patterns/Life/Bounded-Grids. golly-2.7-src/Help/file.html0000644000175000017500000001474012536111364012723 00000000000000 Golly Help: File Menu

New Pattern

Creates a new, empty universe and switches to a scale suitable for editing cells. Use Preferences > File to set the scale (initially 1:32), the cursor mode, and whether any selection should be removed.

Open Pattern...

Opens the standard file browser so you can select a pattern file. Golly can read all the common pattern formats: RLE, PC Life 1.05/1.06, dblife, some MCell files, and text patterns like "ooo...ooo". It can also read patterns in a "macrocell" format which allows huge, highly repetitive patterns to be stored in a very compact way. Such files usually have a .mc extension. If a .mc file contains timeline data then Golly will load all the frames and automatically show the timeline bar.

All the above formats are text based and can have DOS/Mac/Unix line endings, or they can be compressed in a .gz file.

Golly can also read graphic files in a number of popular formats: BMP, GIF, PNG and TIFF. The file name must end with an appropriate extension: .bmp, .gif, .png, .tif or .tiff. All the pure white pixels (RGB = 255,255,255) are treated as cells of state 0. All other pixels are treated as cells of state 1. This can be handy if you prefer to use a sophisticated drawing program to create your patterns.

Use Preferences > File to set the cursor mode, and whether any selection should be removed.

Open Clipboard

Opens a pattern stored in the clipboard. The References section has links to a number of good sources for clipboard patterns.

If the clipboard text starts with "@RULE rulename" then Golly will save the text as rulename.rule in your rules folder (set in Preferences > Control) and switch to that rule.

Open Recent

This submenu lets you open a recently loaded pattern file. The most recent file is always at the top. The maximum number of pattern files remembered is determined by a setting (initially 20) which you can change in Preferences > File.

Show Patterns

if ticked then a scrollable pattern folder is displayed next to the viewport. Clicking on a pattern file will load it in. The initial pattern folder is the Patterns collection supplied with Golly. If you have your own collection then use Set Pattern Folder (see below) to select a different folder.

Set Pattern Folder...

Lets you change the pattern folder displayed by Show Patterns (see above).

Save Pattern...

Opens the standard file saving dialog so you can save the current pattern in RLE format (but only if all live cells are within coordinates of +/- 1 billion), or in macrocell format if the current algorithm supports hashing (all algorithms except QuickLife). Note that if a timeline exists when you save a .mc file then all the frames will be stored in the file.

You also have the option of saving patterns as compressed files (.rle.gz or .mc.gz).

Save Extended RLE

If ticked, Golly will include additional information whenever it saves a pattern in an RLE file via the above Save Pattern item or the save/store script commands. The pattern's position is recorded, along with the current generation count if it's greater than zero. This allows Golly to restore the pattern's position and generation count when the file is loaded at a later date. The extra information is stored in a special "#CXRLE" comment line at the start of the file. Because it's a comment, other RLE-reading programs should have no problem loading such files.

Note that if the current grid is bounded (ie. has a finite width or height) then Golly ignores this item's setting and always records the pattern's position so it can be restored when the file is loaded.

Run Script...

Opens the standard file browser so you can run a selected Perl or Python script. Such scripts can be used to automate or extend Golly's user interface, or to construct complex patterns. A number of sample scripts are provided in the Scripts folder. More details about Golly's scripting capabilities can be found in the Perl Scripting and Python Scripting help topics.

Run Clipboard

Runs the Perl or Python script stored in the clipboard.

Run Recent

This submenu lets you run a recently executed script file. The most recent script is always at the top. The maximum number of scripts remembered is determined by a setting (initially 20) which you can change in Preferences > File.

Show Scripts

if ticked then a scrollable script folder is displayed next to the viewport. Clicking on a Perl or Python script file will execute it. The initial script folder is the Scripts folder supplied with Golly. If you want to write your own scripts then best to do so in a new folder and use Set Script Folder (see below) to select that folder.

Set Script Folder...

Lets you change the script folder displayed by Show Scripts (see above).

Preferences...

Opens the Preferences dialog so you can change various settings. All your settings are stored in a file called GollyPrefs. This file is initially saved in a user-specific data directory:

On Linux: ~/.golly/
On Mac: ~/Library/Application Support/Golly/
On Windows: C:\Documents and Settings\username\Application Data\Golly\

You might prefer to move GollyPrefs into the same folder as the application. This allows multiple copies of Golly to have their own set of preferences.

Notes for Mac users: On the Mac, the Preferences item is in the application menu, not the File menu. On newer Macs the ~/Library folder might be invisible, so to get access to GollyPrefs just use the "Go to Folder..." command in the Finder's Go menu and type in "~/Library/Application Support/Golly". golly-2.7-src/gollybase/0000755000175000017500000000000012536111546012263 500000000000000golly-2.7-src/gollybase/qlifealgo.h0000644000175000017500000003153312536111364014322 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /** * This is the fast "conventional" life algorithm code. */ #ifndef QLIFEALGO_H #define QLIFEALGO_H #include "lifealgo.h" #include "liferules.h" #include /* * The smallest unit of the universe is the `slice', which is a * 4 (horizontal) by 8 (vertical) chunk of the world. Each slice * is stored in a 32-bit word. The most significant bit of the * word is the upper left bit; the remaining bits go across * horizontally then down vertically. * * We always recompute in units of a slice. This is smaller than the * 8x8 in some programs, and in this particular case adds to the * efficiency. * * This arrangment of bits was selected to minimize the bit * twiddling needed for lookup; in general, we use a lookup table * that takes a 4x4 current-generation and figures out the values * of the inner 2x2 cells. * * A `brick' is composed of eight slices for the even generation and * eight slices for the odd generation. This is a total of 16 * 32-bit words. The slices are concatenated horizontally so each * brick contains two generations of a 32x8 section of the universe. * * No other data is stored directly into the bricks; various flags are * stored in the next level up. We try and minimize the size of the * data for a given universe so that we can minimize the number of * data cache misses and TLB misses. For almost all universes, the * bulk of the allocated data is in these 64-byte bricks. * * We use a stagger-step type algorithm to minimize the number of * neighbors that need to be examined (thanks, Alan!) for each slice. * Thus, a brick that holds (0,0)-(31,7) for the even generation would * hold (1,1)-(32,8) in the odd generations. */ struct brick { /* 64 bytes */ unsigned int d[16] ; } ; /* * A tile contains the flags for four bricks, and pointers to the bricks * themselves. These pointers are never null; if the portion of the * universe is completely empty, they point to a unique allocated * `emptybrick'. This means that we do not need to check if the pointers * are null; we can simply always dereference and get valid data. Thus, * each tile corresponds to a 32x32 section of the universe. * * The c flags indicate that, in the previous computation, * the data was found to change in some slice or * subslice. The least significant bit in each c01 flag corresponds * to the last (8th) slice for phase 0->1, and to the first slice for * phase 1->0. * * There are ten valid bits in c flags 1-4, one for each slice, * one most significant one that indicates that the rightmost (leftmost) * two columns of the first (eighth) slice changed in phase 0->1 (1->0) * (and thus, the next brick to the left (right) needs to be recomputed). * The tenth bit is just the ninth bit from the previous generation. * * For c flags 0 and 5, we only have the first nine bits as above. * * We need six flags; four for the slices themselves, and one indicating * that the top two rows of a particular slice has changed, and thus * the next brick up needs to be recomputed, and one indicating that the * bottom two rows of a particular slice has changed. * * In all cases, tiles only contain data about what has happened completely * within their borders; indicating that the next slice over needs to be * recomputed is handled by always inspecting the neighboring slices * *before* a recomputation. * * The flags int is divided into two 12-bit fields, each holding a population * count, and one eight-bit field, holding dirty flags. * * Note that tiles only point `down' to bricks, never to each other or to * higher-level supertiles. * * Tiles are numbered as level `0' of the universe tree. * * The tiles are 32 bytes each; they can hold up to four bricks, so the * memory consumption of the tiles tends to be small. */ struct tile { /* 32 bytes */ struct brick *b[4] ; short c[6] ; long flags ; } ; /* * Supertiles hold pointers to eight subtiles, which can either be * tiles or supertiles themselves. Supertiles are numbered as levels `1' on * up of the universe tree. * * Odd levels stack their subtiles horizontally; even levels stack their * subtiles vertically. Thus, each supertile at level 1 corresponds to * a 256x32 section of the universe. Each supertile at level 2 corresponds * to a 256x256 section of the universe. And so on. * * Levels are never skipped (that is, each pointer in a supertile at * level `n' points to a valid supertile or tile at level `n-1'). * * The c flag indicates that changes have happened in the subtiles. * The least significant eight bits indicate that changes have occurred * anywhere in the subtile; the least significant bit (bit 0) is associated * with the first subtile for phase 0->1 and the eighth subtile for phase * 1->0, and bit 7 is associated with other. Bit number 8 indicates that * some bits on the right (left) edge of the eighth (first) subtile have * changed for phase 0->1 (1->0). Bits numbered 9 through 16 indicate that * bits on the bottom (top) of the corresponding subtile have changed, and * bit number 17 indicates that a bit in the lower right (upper left) corner * of the eighth (first) subtile has changed. * * Bit 18 through 27 correspond to the previous generation's bits 8 through * 17. Bits 28 through 31 are the dirty bits; we currently use three of * them. * * The above description corresponds to odd levels. For even levels, * since tiles are stacked vertically instead of horizontally, change * `lower' to `right' and `right' to `lower'. * * The dirty flags again are used to indicate that this tile needed to * be recomputed since the last time the dirty bit was cleared. * * The two pop values hold a population count, if the appropriate dirty * bit is clear. These counts will never hold values greater than * 500M, so that a sum of the eight in unsigned arithmetic is guaranteed * to never overflow. * * This completes the universe data structures. Note that there is no * limit (other than the size of a pointer and memory constraints) on * the size of the universe. For instance, using these data structures * we can easily build a universe with elements separated by 2^200 * pixels. * * The supertiles are 44 bytes each; they correspond to at least a * 256x32 chunk of the universe, so the total memory consumption due to * supertiles tends to be small. */ struct supertile { /* 44 bytes */ struct supertile *d[8] ; int flags ; int pop[2] ; } ; /* * This is a common header for chunks of memory linked together. */ struct linkedmem { struct linkedmem *next ; } ; /* * This structure contains all of our variables that pertain to a * particular universe. (Thus, we support multiple universes.) * * The minx, miny, maxx, and maxy values describe the borders of * the universe dictated by the level of the root supertile. If * ever during computation these bounds are found to be too tight, * another supertile is added on top of the root, expanding these * bounds. * * These bounds currently limit the size of the universe to 2^32 in * each direction; however, they are only used during the set call * (when initially setting up the universe). Changing them to * doubles or 64-bit ints will relax this limitation. For now we * leave them as is. * * The rootlev variable contains the supertile level of the root node. * * The tilelist, supertilelist, and bricklist are freelists for the * appropriate type of structure. * * The memused is a linked list of all memory blocks allocated; this * enables us to free the universe and all of its memory without actually * walking the entire life tree. * * The emptybrick pointer points to the unique brick that is guaranteed * to always be empty. The emptytile pointer is similar. * * Finally, root is the top of the current life tree. Nullroot is the * topmost empty supertile allocated, and nullroots[] holds the empty * supertiles at each level. Setting this to 40 limits the number of * levels to 40, which is sufficient for a 2^65x2^62 universe. */ class qlifealgo : public lifealgo { public: qlifealgo() ; virtual ~qlifealgo() ; virtual void clearall() ; virtual int setcell(int x, int y, int newstate) ; virtual int getcell(int x, int y) ; virtual int nextcell(int x, int y, int &v) ; // call after setcell/clearcell calls virtual void endofpattern() { // AKT: unnecessary (and prevents shrinking selection while generating) // poller->bailIfCalculating() ; popValid = 0 ; } virtual void setIncrement(bigint inc) { increment = inc ; } virtual void setIncrement(int inc) { increment = inc ; } virtual void setGeneration(bigint gen) { generation = gen ; } virtual const bigint &getPopulation() ; virtual int isEmpty() ; // can we do the gen count doubling? only hashlife virtual int hyperCapable() { return 0 ; } virtual void setMaxMemory(int m) ; virtual int getMaxMemory() { return (int)(maxmemory >> 20) ; } virtual const char *setrule(const char *s) ; virtual const char *getrule() { return qliferules.getrule() ; } virtual void step() ; virtual void* getcurrentstate() { return 0 ; } virtual void setcurrentstate(void *) {} virtual void draw(viewport &view, liferender &renderer) ; virtual void fit(viewport &view, int force) ; virtual void lowerRightPixel(bigint &x, bigint &y, int mag) ; virtual void findedges(bigint *t, bigint *l, bigint *b, bigint *r) ; virtual const char *writeNativeFormat(std::ostream &, char *) { return "No native format for qlifealgo yet." ; } static void doInitializeAlgoInfo(staticAlgoInfo &) ; private: linkedmem *filllist(int size) ; brick *newbrick() ; tile *newtile() ; supertile *newsupertile(int lev) ; void uproot() ; int doquad01(supertile *zis, supertile *edge, supertile *par, supertile *cor, int lev) ; int doquad10(supertile *zis, supertile *edge, supertile *par, supertile *cor, int lev) ; int p01(tile *p, tile *pr, tile *pd, tile *prd) ; int p10(tile *plu, tile *pu, tile *pl, tile *p) ; G_INT64 find_set_bits(supertile *p, int lev, int gm1) ; int isEmpty(supertile *p, int lev, int gm1) ; supertile *mdelete(supertile *p, int lev) ; G_INT64 popcount() ; int uproot_needed() ; void dogen() ; void renderbm(int x, int y) ; void renderbm(int x, int y, int xsize, int ysize) ; void BlitCells(supertile *p, int xoff, int yoff, int wd, int ht, int lev) ; void ShrinkCells(supertile *p, int xoff, int yoff, int wd, int ht, int lev) ; void clearrect(int minx, int miny, int w, int h) ; int nextcell(int x, int y, supertile *n, int lev) ; void drawshpixel(int x, int y) ; void fill_ll(int d) ; int lowsub(vector &src, vector &dst, int lev) ; int highsub(vector &src, vector &dst, int lev) ; void allsub(vector &src, vector &dst, int lev) ; int gethbitsfromleaves(vector v) ; int getvbitsfromleaves(vector v) ; int markglobalchange(supertile *, int) ; void markglobalchange() ; // call if the rule changes /* data elements */ int min, max, rootlev ; int minlow32 ; bigint bmin, bmax ; bigint population ; int popValid ; linkedmem *tilelist, *supertilelist, *bricklist ; linkedmem *memused ; brick *emptybrick ; tile *emptytile ; supertile *root, *nullroot, *nullroots[40] ; int cleandowncounter ; g_uintptr_t maxmemory, usedmemory ; char *ruletable ; // when drawing, these are used liferender *renderer ; viewport *view ; int uviewh, uvieww, viewh, vieww, mag, pmag, kadd ; int oddgen ; int bmleft, bmtop, bmlev, shbmsize, logshbmsize ; int quickb, deltaforward ; int llbits, llsize ; char *llxb, *llyb ; liferules qliferules ; } ; #endif golly-2.7-src/gollybase/ghashbase.cpp0000644000175000017500000014604112536111364014640 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /* * jvn 0.99 by Radical Eye Software. * * All good ideas here were originated by Gosper or Bell or others, I'm * sure, and all bad ones by yours truly. * * The main reason I wrote this program was to attempt to push out the * evaluation of metacatacryst as far as I could. So this program * really does very little other than compute life as far into the * future as possible, using as little memory as possible (and reusing * it if necessary). No UI, few options. */ #include "ghashbase.h" #include "util.h" #include #include using namespace std ; /* * Prime hash sizes tend to work best. */ static g_uintptr_t nextprime(g_uintptr_t i) { g_uintptr_t j ; i |= 1 ; for (;; i+=2) { for (j=3; j*j<=i; j+=2) if (i % j == 0) break ; if (j*j > i) return i ; } } /* * We do now support garbage collection, but there are some routines we * call frequently to help us. */ #define ghnode_hash(a,b,c,d) (65537*(g_uintptr_t)(d)+257*(g_uintptr_t)(c)+17*(g_uintptr_t)(b)+5*(g_uintptr_t)(a)) #define ghleaf_hash(a,b,c,d) (65537*(d)+257*(c)+17*(b)+5*(a)) /* * Resize the hash. */ void ghashbase::resize() { g_uintptr_t i, nhashprime = nextprime(2 * hashprime) ; ghnode *p, **nhashtab ; if (alloced > maxmem || nhashprime * sizeof(ghnode *) > (maxmem - alloced)) { hashlimit = G_MAX ; return ; } /* * Don't let the hash table buckets take more than 4% of the * memory. If we're starting to strain memory, let the buckets * fill up a bit more. */ if (nhashprime > (maxmem/(25*sizeof(int *)))) { nhashprime = nextprime(maxmem/(25*sizeof(int *))) ; if (nhashprime == hashprime) { hashlimit = G_MAX ; return ; } } if (verbose) { strcpy(statusline, "Resizing hash...") ; lifestatus(statusline) ; } nhashtab = (ghnode **)calloc(nhashprime, sizeof(ghnode *)) ; if (nhashtab == 0) { lifewarning("Out of memory; running in a somewhat slower mode; " "try reducing the hash memory limit after restarting.") ; hashlimit = G_MAX ; return ; } alloced += sizeof(ghnode *) * (nhashprime - hashprime) ; for (i=0; inext ; g_uintptr_t h ; if (is_ghnode(p)) { h = ghnode_hash(p->nw, p->ne, p->sw, p->se) ; } else { ghleaf *l = (ghleaf *)p ; h = ghleaf_hash(l->nw, l->ne, l->sw, l->se) ; } h %= nhashprime ; p->next = nhashtab[h] ; nhashtab[h] = p ; p = np ; } } free(hashtab) ; hashtab = nhashtab ; hashprime = nhashprime ; hashlimit = hashprime ; if (verbose) { strcpy(statusline+strlen(statusline), " done.") ; lifestatus(statusline) ; } } /* * These next two routines are (nearly) our only hash table access * routines; we simply look up the passed in information. If we * find it in the hash table, we return it; otherwise, we build a * new ghnode and store it in the hash table, and return that. */ ghnode *ghashbase::find_ghnode(ghnode *nw, ghnode *ne, ghnode *sw, ghnode *se) { ghnode *p ; g_uintptr_t h = ghnode_hash(nw,ne,sw,se) ; ghnode *pred = 0 ; h = h % hashprime ; for (p=hashtab[h]; p; p = p->next) { /* make sure to compare nw *first* */ if (nw == p->nw && ne == p->ne && sw == p->sw && se == p->se) { if (pred) { /* move this one to the front */ pred->next = p->next ; p->next = hashtab[h] ; hashtab[h] = p ; } return save(p) ; } pred = p ; } p = newghnode() ; p->nw = nw ; p->ne = ne ; p->sw = sw ; p->se = se ; p->res = 0 ; p->next = hashtab[h] ; hashtab[h] = p ; hashpop++ ; if (hashpop > hashlimit) resize() ; return save(p) ; } void ghashbase::unhash_ghnode(ghnode *n) { ghnode *p ; g_uintptr_t h = ghnode_hash(n->nw,n->ne,n->sw,n->se) ; ghnode *pred = 0 ; h = h % hashprime ; for (p=hashtab[h]; p; p = p->next) { if (p == n) { if (pred) pred->next = p->next ; else hashtab[h] = p->next ; return ; } pred = p ; } lifefatal("Didn't find ghnode to unhash") ; } void ghashbase::rehash_ghnode(ghnode *n) { g_uintptr_t h = ghnode_hash(n->nw,n->ne,n->sw,n->se) ; h = h % hashprime ; n->next = hashtab[h] ; hashtab[h] = n ; } ghleaf *ghashbase::find_ghleaf(state nw, state ne, state sw, state se) { ghleaf *p ; ghleaf *pred = 0 ; g_uintptr_t h = ghleaf_hash(nw, ne, sw, se) ; h = h % hashprime ; for (p=(ghleaf *)hashtab[h]; p; p = (ghleaf *)p->next) { if (nw == p->nw && ne == p->ne && sw == p->sw && se == p->se && !is_ghnode(p)) { if (pred) { pred->next = p->next ; p->next = hashtab[h] ; hashtab[h] = (ghnode *)p ; } return (ghleaf *)save((ghnode *)p) ; } pred = p ; } p = newghleaf() ; p->nw = nw ; p->ne = ne ; p->sw = sw ; p->se = se ; p->leafpop = (nw != 0) + (ne != 0) + (sw != 0) + (se != 0) ; p->isghnode = 0 ; p->next = hashtab[h] ; hashtab[h] = (ghnode *)p ; hashpop++ ; if (hashpop > hashlimit) resize() ; return (ghleaf *)save((ghnode *)p) ; } /* * The following routine does the same, but first it checks to see if * the cached result is any good. If it is, it directly returns that. * Otherwise, it figures out whether to call the ghleaf routine or the * non-ghleaf routine by whether two ghnodes down is a ghleaf ghnode or not. * (We'll understand why this is a bit later.) All the sp stuff is * stack pointer and garbage collection stuff. */ ghnode *ghashbase::getres(ghnode *n, int depth) { if (n->res) return n->res ; ghnode *res = 0 ; /** * This routine be the only place we assign to res. We use * the fact that the poll routine is *sticky* to allow us to * manage unwinding the stack without munging our data * structures. Note that there may be many find_ghnodes * and getres called before we finally actually exit from * here, because the stack is deep and we don't want to * put checks throughout the code. Instead we need two * calls here, one to prevent us going deeper, and another * to prevent us from destroying the cache field. */ if (poller->poll()) return zeroghnode(depth-1) ; int sp = gsp ; depth-- ; if (ngens >= depth) { if (is_ghnode(n->nw)) { res = dorecurs(n->nw, n->ne, n->sw, n->se, depth) ; } else { res = (ghnode *)dorecurs_ghleaf((ghleaf *)n->nw, (ghleaf *)n->ne, (ghleaf *)n->sw, (ghleaf *)n->se) ; } } else { if (halvesdone < 1000) halvesdone++ ; if (is_ghnode(n->nw)) { res = dorecurs_half(n->nw, n->ne, n->sw, n->se, depth) ; } else { lifefatal("! can't happen") ; } } pop(sp) ; if (poller->isInterrupted()) // don't assign this to the cache field! res = zeroghnode(depth) ; else n->res = res ; return res ; } /* * So let's say the cached way failed. How do we do it the slow way? * Recursively, of course. For an n-square (composed of the four * n/2-squares passed in, compute the n/2-square that is n/4 * generations ahead. * * This routine works exactly the same as the ghleafres() routine, only * instead of working on an 8-square, we're working on an n-square, * returning an n/2-square, and we build that n/2-square by first building * 9 n/4-squares, use those to calculate 4 more n/4-squares, and * then put these together into a new n/2-square. Simple, eh? */ ghnode *ghashbase::dorecurs(ghnode *n, ghnode *ne, ghnode *t, ghnode *e, int depth) { int sp = gsp ; ghnode *t00 = getres(n, depth), *t01 = getres(find_ghnode(n->ne, ne->nw, n->se, ne->sw), depth), *t02 = getres(ne, depth), *t12 = getres(find_ghnode(ne->sw, ne->se, e->nw, e->ne), depth), *t11 = getres(find_ghnode(n->se, ne->sw, t->ne, e->nw), depth), *t10 = getres(find_ghnode(n->sw, n->se, t->nw, t->ne), depth), *t20 = getres(t, depth), *t21 = getres(find_ghnode(t->ne, e->nw, t->se, e->sw), depth), *t22 = getres(e, depth), *t44 = getres(find_ghnode(t11, t12, t21, t22), depth), *t43 = getres(find_ghnode(t10, t11, t20, t21), depth), *t33 = getres(find_ghnode(t00, t01, t10, t11), depth), *t34 = getres(find_ghnode(t01, t02, t11, t12), depth) ; n = find_ghnode(t33, t34, t43, t44) ; pop(sp) ; return save(n) ; } /* * Same as above, but we only do one step instead of 2. */ ghnode *ghashbase::dorecurs_half(ghnode *n, ghnode *ne, ghnode *t, ghnode *e, int depth) { int sp = gsp ; if (depth > 1) { ghnode *t00 = find_ghnode(n->nw->se, n->ne->sw, n->sw->ne, n->se->nw), *t01 = find_ghnode(n->ne->se, ne->nw->sw, n->se->ne, ne->sw->nw), *t02 = find_ghnode(ne->nw->se, ne->ne->sw, ne->sw->ne, ne->se->nw), *t10 = find_ghnode(n->sw->se, n->se->sw, t->nw->ne, t->ne->nw), *t11 = find_ghnode(n->se->se, ne->sw->sw, t->ne->ne, e->nw->nw), *t12 = find_ghnode(ne->sw->se, ne->se->sw, e->nw->ne, e->ne->nw), *t20 = find_ghnode(t->nw->se, t->ne->sw, t->sw->ne, t->se->nw), *t21 = find_ghnode(t->ne->se, e->nw->sw, t->se->ne, e->sw->nw), *t22 = find_ghnode(e->nw->se, e->ne->sw, e->sw->ne, e->se->nw) ; n = find_ghnode(getres(find_ghnode(t00, t01, t10, t11), depth), getres(find_ghnode(t01, t02, t11, t12), depth), getres(find_ghnode(t10, t11, t20, t21), depth), getres(find_ghnode(t11, t12, t21, t22), depth)) ; } else { ghnode *t00 = getres(n, depth), *t01 = getres(find_ghnode(n->ne, ne->nw, n->se, ne->sw), depth), *t10 = getres(find_ghnode(n->sw, n->se, t->nw, t->ne), depth), *t11 = getres(find_ghnode(n->se, ne->sw, t->ne, e->nw), depth), *t02 = getres(ne, depth), *t12 = getres(find_ghnode(ne->sw, ne->se, e->nw, e->ne), depth), *t20 = getres(t, depth), *t21 = getres(find_ghnode(t->ne, e->nw, t->se, e->sw), depth), *t22 = getres(e, depth) ; n = find_ghnode((ghnode *)find_ghleaf(((ghleaf *)t00)->se, ((ghleaf *)t01)->sw, ((ghleaf *)t10)->ne, ((ghleaf *)t11)->nw), (ghnode *)find_ghleaf(((ghleaf *)t01)->se, ((ghleaf *)t02)->sw, ((ghleaf *)t11)->ne, ((ghleaf *)t12)->nw), (ghnode *)find_ghleaf(((ghleaf *)t10)->se, ((ghleaf *)t11)->sw, ((ghleaf *)t20)->ne, ((ghleaf *)t21)->nw), (ghnode *)find_ghleaf(((ghleaf *)t11)->se, ((ghleaf *)t12)->sw, ((ghleaf *)t21)->ne, ((ghleaf *)t22)->nw)) ; } pop(sp) ; return save(n) ; } /* * If the ghnode is a 16-ghnode, then the constituents are leaves, so we * need a very similar but still somewhat different subroutine. Since * we do not (yet) garbage collect leaves, we don't need all that * save/pop mumbo-jumbo. */ ghleaf *ghashbase::dorecurs_ghleaf(ghleaf *nw, ghleaf *ne, ghleaf *sw, ghleaf *se) { return find_ghleaf( slowcalc(nw->nw, nw->ne, ne->nw, nw->sw, nw->se, ne->sw, sw->nw, sw->ne, se->nw), slowcalc(nw->ne, ne->nw, ne->ne, nw->se, ne->sw, ne->se, sw->ne, se->nw, se->ne), slowcalc(nw->sw, nw->se, ne->sw, sw->nw, sw->ne, se->nw, sw->sw, sw->se, se->sw), slowcalc(nw->se, ne->sw, ne->se, sw->ne, se->nw, se->ne, sw->se, se->sw, se->se)) ; } /* * We keep free ghnodes in a linked list for allocation, and we allocate * them 1000 at a time. */ ghnode *ghashbase::newghnode() { ghnode *r ; if (freeghnodes == 0) { int i ; freeghnodes = (ghnode *)calloc(1001, sizeof(ghnode)) ; if (freeghnodes == 0) lifefatal("Out of memory; try reducing the hash memory limit.") ; alloced += 1001 * sizeof(ghnode) ; freeghnodes->next = ghnodeblocks ; ghnodeblocks = freeghnodes++ ; for (i=0; i<999; i++) { freeghnodes[1].next = freeghnodes ; freeghnodes++ ; } totalthings += 1000 ; } if (freeghnodes->next == 0 && alloced + 1000 * sizeof(ghnode) > maxmem && okaytogc) { do_gc(0) ; } r = freeghnodes ; freeghnodes = freeghnodes->next ; return r ; } /* * Leaves are the same. */ ghleaf *ghashbase::newghleaf() { return (ghleaf *)newghnode() ; } /* * Sometimes we want the new ghnode or ghleaf to be automatically cleared * for us. */ ghnode *ghashbase::newclearedghnode() { return (ghnode *)memset(newghnode(), 0, sizeof(ghnode)) ; } ghleaf *ghashbase::newclearedghleaf() { return (ghleaf *)memset(newghleaf(), 0, sizeof(ghleaf)) ; } ghashbase::ghashbase() { hashprime = nextprime(1000) ; hashlimit = hashprime ; hashpop = 0 ; hashtab = (ghnode **)calloc(hashprime, sizeof(ghnode *)) ; if (hashtab == 0) lifefatal("Out of memory (1).") ; alloced += hashprime * sizeof(ghnode *) ; ngens = 0 ; stacksize = 0 ; halvesdone = 0 ; nzeros = 0 ; stack = 0 ; gsp = 0 ; alloced = 0 ; maxmem = 256 * 1024 * 1024 ; freeghnodes = 0 ; okaytogc = 0 ; totalthings = 0 ; ghnodeblocks = 0 ; zeroghnodea = 0 ; /* * We initialize our universe to be a 16-square. We are in drawing * mode at this point. */ root = (ghnode *)newclearedghnode() ; population = 0 ; generation = 0 ; increment = 1 ; setincrement = 1 ; nonpow2 = 1 ; pow2step = 1 ; llsize = 0 ; depth = 1 ; hashed = 0 ; popValid = 0 ; needPop = 0 ; inGC = 0 ; cacheinvalid = 0 ; gccount = 0 ; gcstep = 0 ; } /** * Destructor frees memory. */ ghashbase::~ghashbase() { free(hashtab) ; while (ghnodeblocks) { ghnode *r = ghnodeblocks ; ghnodeblocks = ghnodeblocks->next ; free(r) ; } if (zeroghnodea) free(zeroghnodea) ; if (stack) free(stack) ; if (llsize) { delete [] llxb ; delete [] llyb ; } } /** * Set increment. */ void ghashbase::setIncrement(bigint inc) { increment = inc ; } /** * Do a step. */ void ghashbase::step() { poller->bailIfCalculating() ; // we use while here because the increment may be changed while we are // doing the hashtable sweep; if that happens, we may need to sweep // again. int cleareddownto = 1000000000 ; while (increment != setincrement) { bigint pendingincrement = increment ; int newpow2 = 0 ; bigint t = pendingincrement ; while (t > 0 && t.even()) { newpow2++ ; t.div2() ; } nonpow2 = t.low31() ; if (t != nonpow2) lifefatal("bad increment") ; int downto = newpow2 ; if (ngens < newpow2) downto = ngens ; if (newpow2 != ngens && cleareddownto > downto) { new_ngens(newpow2) ; cleareddownto = downto ; } else { ngens = newpow2 ; } setincrement = pendingincrement ; pow2step = 1 ; while (newpow2--) pow2step += pow2step ; } gcstep = 0 ; for (int i=0; iisInterrupted()) // we *were* interrupted break ; popValid = 0 ; root = newroot ; } depth = ghnode_depth(root) ; extendtimeline() ; } void ghashbase::setcurrentstate(void *n) { if (root != (ghnode *)n) { root = (ghnode *)n ; depth = ghnode_depth(root) ; popValid = 0 ; } } /* * Set the max memory */ void ghashbase::setMaxMemory(int newmemlimit) { if (newmemlimit < 10) newmemlimit = 10 ; #ifndef GOLLY64BIT else if (newmemlimit > 4000) newmemlimit = 4000 ; #endif g_uintptr_t newlimit = ((g_uintptr_t)newmemlimit) << 20 ; if (alloced > newlimit) { lifewarning("Sorry, more memory currently used than allowed.") ; return ; } maxmem = newlimit ; hashlimit = hashprime ; } /** * Clear everything. */ void ghashbase::clearall() { lifefatal("clearall not implemented yet") ; } /* * This routine expands our universe by a factor of two, maintaining * centering. We use four new ghnodes, and *reuse* the root so this cannot * be called after we've started hashing. */ void ghashbase::pushroot_1() { ghnode *t ; t = newclearedghnode() ; t->se = root->nw ; root->nw = t ; t = newclearedghnode() ; t->sw = root->ne ; root->ne = t ; t = newclearedghnode() ; t->ne = root->sw ; root->sw = t ; t = newclearedghnode() ; t->nw = root->se ; root->se = t ; depth++ ; } /* * Return the depth of this ghnode (2 is 8x8). */ int ghashbase::ghnode_depth(ghnode *n) { int depth = 0 ; while (is_ghnode(n)) { depth++ ; n = n->nw ; } return depth ; } /* * This routine returns the canonical clear space ghnode at a particular * depth. */ ghnode *ghashbase::zeroghnode(int depth) { while (depth >= nzeros) { int nnzeros = 2 * nzeros + 10 ; zeroghnodea = (ghnode **)realloc(zeroghnodea, nnzeros * sizeof(ghnode *)) ; if (zeroghnodea == 0) lifefatal("Out of memory (2).") ; alloced += (nnzeros - nzeros) * sizeof(ghnode *) ; while (nzeros < nnzeros) zeroghnodea[nzeros++] = 0 ; } if (zeroghnodea[depth] == 0) { if (depth == 0) { zeroghnodea[depth] = (ghnode *)find_ghleaf(0, 0, 0, 0) ; } else { ghnode *z = zeroghnode(depth-1) ; zeroghnodea[depth] = find_ghnode(z, z, z, z) ; } } return zeroghnodea[depth] ; } /* * Same, but with hashed ghnodes. */ ghnode *ghashbase::pushroot(ghnode *n) { int depth = ghnode_depth(n) ; ghnode *z = zeroghnode(depth-1) ; return find_ghnode(find_ghnode(z, z, z, n->nw), find_ghnode(z, z, n->ne, z), find_ghnode(z, n->sw, z, z), find_ghnode(n->se, z, z, z)) ; } /* * Here is our recursive routine to set a bit in our universe. We * pass in a depth, and walk the space. Again, a lot of bit twiddling, * but really not all that complicated. We allocate new ghnodes and * leaves on our way down. * * Note that at this point our universe lives outside the hash table * and has not been canonicalized, and that many of the pointers in * the ghnodes can be null. We'll patch this up in due course. */ ghnode *ghashbase::setbit(ghnode *n, int x, int y, int newstate, int depth) { if (depth == 0) { ghleaf *l = (ghleaf *)n ; if (hashed) { state nw = l->nw ; state sw = l->sw ; state ne = l->ne ; state se = l->se ; if (x < 0) if (y < 0) sw = (state)newstate ; else nw = (state)newstate ; else if (y < 0) se = (state)newstate ; else ne = (state)newstate ; return save((ghnode *)find_ghleaf(nw, ne, sw, se)) ; } if (x < 0) if (y < 0) l->sw = (state)newstate ; else l->nw = (state)newstate ; else if (y < 0) l->se = (state)newstate ; else l->ne = (state)newstate ; return (ghnode *)l ; } else { unsigned int w = 0, wh = 0 ; if (depth >= 31) { if (depth == this->depth) wh = 0x80000000 ; } else { w = 1 << depth ; wh = 1 << (depth - 1) ; } if (depth > 31) w = 0 ; depth-- ; ghnode **nptr ; if (x < 0) { if (y < 0) nptr = &(n->sw) ; else nptr = &(n->nw) ; } else { if (y < 0) nptr = &(n->se) ; else nptr = &(n->ne) ; } if (*nptr == 0) { if (depth == 0) *nptr = (ghnode *)newclearedghleaf() ; else *nptr = newclearedghnode() ; } ghnode *s = setbit(*nptr, (x & (w - 1)) - wh, (y & (w - 1)) - wh, newstate, depth) ; if (hashed) { ghnode *nw = n->nw ; ghnode *sw = n->sw ; ghnode *ne = n->ne ; ghnode *se = n->se ; if (x < 0) { if (y < 0) sw = s ; else nw = s ; } else { if (y < 0) se = s ; else ne = s ; } n = save(find_ghnode(nw, ne, sw, se)) ; } else { *nptr = s ; } return n ; } } /* * Here is our recursive routine to get a bit in our universe. We * pass in a depth, and walk the space. Again, a lot of bit twiddling, * but really not all that complicated. */ int ghashbase::getbit(ghnode *n, int x, int y, int depth) { if (depth == 0) { ghleaf *l = (ghleaf *)n ; if (x < 0) if (y < 0) return l->sw ; else return l->nw ; else if (y < 0) return l->se ; else return l->ne ; } else { unsigned int w = 0, wh = 0 ; if (depth >= 31) { if (depth == this->depth) wh = 0x80000000 ; } else { w = 1 << depth ; wh = 1 << (depth - 1) ; } ghnode *nptr ; depth-- ; if (x < 0) { if (y < 0) nptr = n->sw ; else nptr = n->nw ; } else { if (y < 0) nptr = n->se ; else nptr = n->ne ; } if (nptr == 0 || nptr == zeroghnode(depth)) return 0 ; return getbit(nptr, (x & (w - 1)) - wh, (y & (w - 1)) - wh, depth) ; } } /* * Here is our recursive routine to get the next bit in our universe. We * pass in a depth, and walk the space. Again, a lot of bit twiddling, * but really not all that complicated. */ int ghashbase::nextbit(ghnode *n, int x, int y, int depth, int &v) { if (n == 0 || n == zeroghnode(depth)) return -1 ; if (depth == 0) { ghleaf *l = (ghleaf *)n ; if (y < 0) { if (x < 0 && l->sw) { v = l->sw ; return 0 ; } if (l->se) { v = l->se ; return -x ; } } else { if (x < 0 && l->nw) { v = l->nw ; return 0 ; } if (l->ne) { v = l->ne ; return -x ; } } return -1 ; // none found } else { unsigned int w = 1 << depth ; unsigned int wh = w >> 1 ; ghnode *lft, *rght ; depth-- ; if (y < 0) { lft = n->sw ; rght = n->se ; } else { lft = n->nw ; rght = n->ne ; } int r = 0 ; if (x < 0) { int t = nextbit(lft, (x & (w-1)) - wh, (y & (w - 1)) - wh, depth, v) ; if (t >= 0) return t ; r = -x ; x = 0 ; } int t = nextbit(rght, (x & (w-1)) - wh, (y & (w - 1)) - wh, depth, v) ; if (t >= 0) return r + t ; return -1 ; } } /* * Our nonrecurse top-level bit setting routine simply expands the * universe as necessary to encompass the passed-in coordinates, and * then invokes the recursive setbit. Right now it works hashed or * unhashed (but it's faster when unhashed). We also turn on the inGC * flag to inhibit popcount. */ int ghashbase::setcell(int x, int y, int newstate) { if (newstate < 0 || newstate >= maxCellStates) return -1 ; if (hashed) { clearstack() ; save(root) ; okaytogc = 1 ; } inGC = 1 ; y = - y ; int sx = x ; int sy = y ; if (depth <= 31) { sx >>= depth ; sy >>= depth ; } else { sx >>= 31 ; sy >>= 31 ; } while (sx > 0 || sx < -1 || sy > 0 || sy < -1) { if (hashed) { root = save(pushroot(root)) ; depth++ ; } else { pushroot_1() ; } sx >>= 1 ; sy >>= 1 ; } root = setbit(root, x, y, newstate, depth) ; if (hashed) { okaytogc = 0 ; } return 0 ; } /* * Our nonrecurse top-level bit getting routine. */ int ghashbase::getcell(int x, int y) { y = - y ; int sx = x ; int sy = y ; if (depth <= 31) { sx >>= depth ; sy >>= depth ; } else { sx >>= 31 ; sy >>= 31 ; } if (sx > 0 || sx < -1 || sy > 0 || sy < -1) return 0 ; return getbit(root, x, y, depth) ; } /* * A recursive bit getting routine, but this one returns the * number of pixels to the right to the next set cell in the * current universe, or -1 if none set to the right, or if * the next set pixel is out of range. */ int ghashbase::nextcell(int x, int y, int &v) { y = - y ; int sx = x ; int sy = y ; if (depth <= 31) { sx >>= depth ; sy >>= depth ; } else { sx >>= 31 ; sy >>= 31 ; } while (sx > 0 || sx < -1 || sy > 0 || sy < -1) { if (hashed) { root = save(pushroot(root)) ; depth++ ; } else { pushroot_1() ; } sx >>= 1 ; sy >>= 1 ; } if (depth > 30) { struct ghnode tghnode = *root ; int mdepth = depth ; while (mdepth > 30) { tghnode.nw = tghnode.nw->se ; tghnode.ne = tghnode.ne->sw ; tghnode.sw = tghnode.sw->ne ; tghnode.se = tghnode.se->nw ; mdepth-- ; } return nextbit(&tghnode, x, y, mdepth, v) ; } return nextbit(root, x, y, depth, v) ; } /* * Canonicalize a universe by filling in the null pointers and then * invoking find_ghnode on each ghnode. Drops the original universe on * the floor [big deal, it's probably small anyway]. */ ghnode *ghashbase::hashpattern(ghnode *root, int depth) { ghnode *r ; if (root == 0) { r = zeroghnode(depth) ; } else if (depth == 0) { ghleaf *n = (ghleaf *)root ; r = (ghnode *)find_ghleaf(n->nw, n->ne, n->sw, n->se) ; n->next = freeghnodes ; freeghnodes = root ; } else { depth-- ; r = find_ghnode(hashpattern(root->nw, depth), hashpattern(root->ne, depth), hashpattern(root->sw, depth), hashpattern(root->se, depth)) ; root->next = freeghnodes ; freeghnodes = root ; } return r ; } void ghashbase::endofpattern() { poller->bailIfCalculating() ; if (!hashed) { root = hashpattern(root, depth) ; hashed = 1 ; } popValid = 0 ; needPop = 0 ; inGC = 0 ; } void ghashbase::ensure_hashed() { if (!hashed) endofpattern() ; } /* * Pop off any levels we don't need. */ ghnode *ghashbase::popzeros(ghnode *n) { int depth = ghnode_depth(n) ; while (depth > 1) { ghnode *z = zeroghnode(depth-2) ; if (n->nw->nw == z && n->nw->ne == z && n->nw->sw == z && n->ne->nw == z && n->ne->ne == z && n->ne->se == z && n->sw->nw == z && n->sw->sw == z && n->sw->se == z && n->se->ne == z && n->se->sw == z && n->se->se == z) { depth-- ; n = find_ghnode(n->nw->se, n->ne->sw, n->sw->ne, n->se->nw) ; } else { break ; } } return n ; } /* * A lot of the routines from here on down traverse the universe, hanging * information off the ghnodes. The way they generally do so is by using * (or abusing) the cache (res) field, and the least significant bit of * the hash next field (as a visited bit). */ #define marked(n) (1 & (g_uintptr_t)(n)->next) #define mark(n) ((n)->next = (ghnode *)(1 | (g_uintptr_t)(n)->next)) #define clearmark(n) ((n)->next = (ghnode *)(~1 & (g_uintptr_t)(n)->next)) #define clearmarkbit(p) ((ghnode *)(~1 & (g_uintptr_t)(p))) /* * Sometimes we want to use *res* instead of next to mark. You cannot * do this to leaves, though. */ #define marked2(n) (1 & (g_uintptr_t)(n)->res) #define mark2(n) ((n)->res = (ghnode *)(1 | (g_uintptr_t)(n)->res)) #define clearmark2(n) ((n)->res = (ghnode *)(~1 & (g_uintptr_t)(n)->res)) static void sum4(bigint &dest, const bigint &a, const bigint &b, const bigint &c, const bigint &d) { dest = a ; dest += b ; dest += c ; dest += d ; } /* * This recursive routine calculates the population by hanging the * population on marked ghnodes. */ const bigint &ghashbase::calcpop(ghnode *root, int depth) { if (root == zeroghnode(depth)) return bigint::zero ; if (depth == 0) { root->nw = 0 ; bigint &r = *(bigint *)&(root->nw) ; ghleaf *n = (ghleaf *)root ; r = n->leafpop ; return r ; } else if (marked2(root)) { return *(bigint*)&(root->next) ; } else { depth-- ; unhash_ghnode(root) ; /** * We use the memory in root->next as a value bigint. But we want to * make sure the copy constructor doesn't "clean up" something that * doesn't exist. So we clear it to zero here. */ root->next = (ghnode *)0 ; // I wish I could come up with a cleaner way sum4(*(bigint *)&(root->next), calcpop(root->nw, depth), calcpop(root->ne, depth), calcpop(root->sw, depth), calcpop(root->se, depth)) ; mark2(root) ; return *(bigint *)&(root->next) ; } } /* * Call this after doing something that unhashes ghnodes in order to * use the next field as a temp pointer. */ void ghashbase::aftercalcpop2(ghnode *root, int depth, int cleanbigints) { if (root == zeroghnode(depth)) return ; if (depth == 0) { root->nw = 0 ; // all these bigints are guaranteed to be small return ; } if (marked2(root)) { clearmark2(root) ; depth-- ; aftercalcpop2(root->nw, depth, cleanbigints) ; aftercalcpop2(root->ne, depth, cleanbigints) ; aftercalcpop2(root->sw, depth, cleanbigints) ; aftercalcpop2(root->se, depth, cleanbigints) ; if (cleanbigints) *(bigint *)&(root->next) = bigint::zero ; // clean up; yuck! rehash_ghnode(root) ; } } /* * This top level routine calculates the population of a universe. */ void ghashbase::calcPopulation(ghnode *root) { int depth ; ensure_hashed() ; depth = ghnode_depth(root) ; population = calcpop(root, depth) ; aftercalcpop2(root, depth, 1) ; } /* * Is the universe empty? */ int ghashbase::isEmpty() { ensure_hashed() ; return root == zeroghnode(depth) ; } /* * This routine marks a ghnode as needed to be saved. */ ghnode *ghashbase::save(ghnode *n) { if (gsp >= stacksize) { int nstacksize = stacksize * 2 + 100 ; alloced += sizeof(ghnode *)*(nstacksize-stacksize) ; stack = (ghnode **)realloc(stack, nstacksize * sizeof(ghnode *)) ; if (stack == 0) lifefatal("Out of memory (3).") ; stacksize = nstacksize ; } stack[gsp++] = n ; return n ; } /* * This routine pops the stack back to a previous depth. */ void ghashbase::pop(int n) { gsp = n ; } /* * This routine clears the stack altogether. */ void ghashbase::clearstack() { gsp = 0 ; } /* * Do a gc. Walk down from all ghnodes reachable on the stack, saveing * them by setting the odd bit on the next link. Then, walk the hash, * eliminating the res from everything that's not saveed, and moving * the ghnodes from the hash to the freelist as appropriate. Finally, * walk the hash again, clearing the low order bits in the next pointers. */ void ghashbase::gc_mark(ghnode *root, int invalidate) { if (!marked(root)) { mark(root) ; if (is_ghnode(root)) { gc_mark(root->nw, invalidate) ; gc_mark(root->ne, invalidate) ; gc_mark(root->sw, invalidate) ; gc_mark(root->se, invalidate) ; if (root->res) { if (invalidate) root->res = 0 ; else gc_mark(root->res, invalidate) ; } } } } /** * If the invalidate flag is set, we want to kill *all* cache entries * and recalculate all leaves. */ void ghashbase::do_gc(int invalidate) { int i ; g_uintptr_t freed_ghnodes=0 ; ghnode *p, *pp ; inGC = 1 ; gccount++ ; gcstep++ ; if (verbose) { if (gcstep > 1) sprintf(statusline, "GC #%d(%d) ", gccount, gcstep) ; else sprintf(statusline, "GC #%d ", gccount) ; lifestatus(statusline) ; } for (i=nzeros-1; i>=0; i--) if (zeroghnodea[i] != 0) break ; if (i >= 0) gc_mark(zeroghnodea[i], 0) ; // never invalidate zeroghnode for (i=0; ipoll() ; gc_mark((ghnode *)stack[i], invalidate) ; } for (i=0; inext) { poller->poll() ; for (pp=p+1, i=1; i<1001; i++, pp++) { if (marked(pp)) { g_uintptr_t h = 0 ; if (pp->nw) { /* yes, it's a ghnode */ h = ghnode_hash(pp->nw, pp->ne, pp->sw, pp->se) % hashprime ; } else { ghleaf *lp = (ghleaf *)pp ; h = ghleaf_hash(lp->nw, lp->ne, lp->sw, lp->se) % hashprime ; } pp->next = hashtab[h] ; hashtab[h] = pp ; hashpop++ ; } else { pp->next = freeghnodes ; freeghnodes = pp ; freed_ghnodes++ ; } } } inGC = 0 ; if (verbose) { int perc = (int)(freed_ghnodes / (totalthings / 100)) ; sprintf(statusline+strlen(statusline), " freed %d percent.", perc) ; lifestatus(statusline) ; } if (needPop) { calcPopulation(root) ; popValid = 1 ; needPop = 0 ; poller->updatePop() ; } } /* * Clear the cache bits down to the appropriate level, marking the * ghnodes we've handled. */ void ghashbase::clearcache(ghnode *n, int depth, int clearto) { if (!marked(n)) { mark(n) ; if (depth > 1) { depth-- ; poller->poll() ; clearcache(n->nw, depth, clearto) ; clearcache(n->ne, depth, clearto) ; clearcache(n->sw, depth, clearto) ; clearcache(n->se, depth, clearto) ; if (n->res) clearcache(n->res, depth, clearto) ; } if (depth >= clearto) n->res = 0 ; } } /* * Clear the entire cache of everything, and recalculate all leaves. * This can be very expensive. */ void ghashbase::clearcache() { cacheinvalid = 1 ; } /* * Change the ngens value. Requires us to walk the hash, clearing * the cache fields of any ghnodes that do not have the appropriate * values. */ void ghashbase::new_ngens(int newval) { g_uintptr_t i ; ghnode *p, *pp ; int clearto = ngens ; if (newval > ngens && halvesdone == 0) { ngens = newval ; return ; } if (verbose) { strcpy(statusline, "Changing increment...") ; lifestatus(statusline) ; } if (newval < clearto) clearto = newval ; clearto++ ; /* clear this depth and above */ if (clearto < 1) clearto = 1 ; ngens = newval ; inGC = 1 ; for (i=0; inext)) if (is_ghnode(p) && !marked(p)) clearcache(p, ghnode_depth(p), clearto) ; for (p=ghnodeblocks; p; p=p->next) { poller->poll() ; for (pp=p+1, i=1; i<1001; i++, pp++) clearmark(pp) ; } halvesdone = 0 ; inGC = 0 ; if (needPop) { calcPopulation(root) ; popValid = 1 ; needPop = 0 ; poller->updatePop() ; } if (verbose) { strcpy(statusline+strlen(statusline), " done.") ; lifestatus(statusline) ; } } /* * Return log2. */ int ghashbase::log2(unsigned int n) { int r = 0 ; while ((n & 1) == 0) { n >>= 1 ; r++ ; } if (n != 1) { lifefatal("Expected power of two!") ; } return r ; } static bigint negone = -1 ; const bigint &ghashbase::getPopulation() { // note: if called during gc, then we cannot call calcPopulation // since that will mess up the gc. if (!popValid) { if (inGC) { needPop = 1 ; return negone ; } else { calcPopulation(root) ; popValid = 1 ; needPop = 0 ; } } return population ; } /* * Finally, we get to run the pattern. We first ensure that all * clearspace ghnodes and the input pattern is never garbage * collected; we turn on garbage collection, and then we invoke our * magic top-level routine passing in clearspace borders that are * guaranteed large enough. */ ghnode *ghashbase::runpattern() { ghnode *n = root ; save(root) ; // do this in case we interrupt generation ensure_hashed() ; okaytogc = 1 ; if (cacheinvalid) { do_gc(1) ; // invalidate the entire cache and recalc leaves cacheinvalid = 0 ; } int depth = ghnode_depth(n) ; ghnode *n2 ; n = pushroot(n) ; depth++ ; n = pushroot(n) ; depth++ ; while (ngens + 2 > depth) { n = pushroot(n) ; depth++ ; } save(zeroghnode(nzeros-1)) ; save(n) ; n2 = getres(n, depth) ; okaytogc = 0 ; clearstack() ; if (halvesdone == 1) { n->res = 0 ; halvesdone = 0 ; } if (poller->isInterrupted()) return 0 ; // indicate it was interrupted n = popzeros(n2) ; generation += pow2step ; return n ; } const char *ghashbase::readmacrocell(char *line) { int n=0 ; g_uintptr_t i=1, nw=0, ne=0, sw=0, se=0, indlen=0 ; int r, d ; ghnode **ind = 0 ; root = 0 ; while (getline(line, 10000)) { if (i >= indlen) { g_uintptr_t nlen = i + indlen + 10 ; ind = (ghnode **)realloc(ind, sizeof(ghnode*) * nlen) ; if (ind == 0) lifefatal("Out of memory (4).") ; while (indlen < nlen) ind[indlen++] = 0 ; } if (line[0] == '#') { switch (line[1]) { char *p, *pp ; // AKT: need to check for explicit rule const char *err ; case 'R': p = line + 2 ; while (*p && *p <= ' ') p++ ; pp = p ; while (*pp > ' ') pp++ ; *pp = 0 ; err = setrule(p); if (err) return err; break ; case 'G': p = line + 2 ; while (*p && *p <= ' ') p++ ; pp = p ; while (*pp >= '0' && *pp <= '9') pp++ ; *pp = 0 ; generation = bigint(p) ; break ; // either: // #FRAMES count base inc // or // #FRAME index node case 'F': if (strncmp(line, "#FRAMES ", 8) == 0) { p = line + 8 ; while (*p && *p <= ' ') p++ ; int cnt = atol(p) ; if (cnt < 0 || cnt > MAX_FRAME_COUNT) return "Bad FRAMES line" ; destroytimeline() ; while ('0' <= *p && *p <= '9') p++ ; while (*p && *p <= ' ') p++ ; pp = p ; while ((*pp >= '0' && *pp <= '9') || *pp == ',') pp++ ; if (*pp == 0) return "Bad FRAMES line" ; *pp = 0 ; timeline.start = bigint(p) ; timeline.end = timeline.start ; timeline.next = timeline.end ; p = pp + 1 ; while (*p && *p <= ' ') p++ ; pp = p ; while (*pp > ' ') pp++ ; *pp = 0 ; if (strchr(p, '^')) { int tbase=0, texpo=0 ; if (sscanf(p, "%d^%d", &tbase, &texpo) != 2 || tbase < 2 || texpo < 0) return "Bad FRAMES line" ; timeline.base = tbase ; timeline.expo = texpo ; timeline.inc = 1 ; while (texpo--) timeline.inc.mul_smallint(tbase) ; } else { timeline.inc = bigint(p) ; // if it's a power of two, we're good int texpo = timeline.inc.lowbitset() ; int tbase = 2 ; bigint test = 1 ; for (int i=0; i MAX_FRAME_COUNT || frameind < 0 || nodeind > i || timeline.framecount != frameind) return "Bad FRAME line" ; timeline.frames.push_back(ind[nodeind]) ; timeline.framecount++ ; timeline.end = timeline.next ; timeline.next += timeline.inc ; } break ; } } else { n = sscanf(line, "%d %" PRIuPTR " %" PRIuPTR " %" PRIuPTR " %" PRIuPTR " %d", &d, &nw, &ne, &sw, &se, &r) ; if (n < 0) // blank line; permit continue ; if (n == 0) { // conversion error in first argument; we allow only if the only // content on the line is whitespace. char *ws = line ; while (*ws && *ws <= ' ') ws++ ; if (*ws > 0) return "Parse error in macrocell format." ; continue ; } if (n < 5) // best not to use lifefatal here because user won't see any // error message when reading clipboard data starting with "[..." return "Parse error in readmacrocell." ; if (d < 1) return "Oops; bad depth in readmacrocell." ; if (d == 1) { if (nw >= (g_uintptr_t)maxCellStates || ne >= (g_uintptr_t)maxCellStates || sw >= (g_uintptr_t)maxCellStates || se >= (g_uintptr_t)maxCellStates) return "Cell state values too high for this algorithm." ; root = ind[i++] = (ghnode *)find_ghleaf((state)nw, (state)ne, (state)sw, (state)se) ; depth = d - 1 ; } else { ind[0] = zeroghnode(d-2) ; /* allow zeros to work right */ if (nw >= i || ind[nw] == 0 || ne >= i || ind[ne] == 0 || sw >= i || ind[sw] == 0 || se >= i || ind[se] == 0) { return "Node out of range in readmacrocell." ; } clearstack() ; root = ind[i++] = find_ghnode(ind[nw], ind[ne], ind[sw], ind[se]) ; depth = d - 1 ; } } } if (ind) free(ind) ; if (root == 0) { // allow empty macrocell pattern; note that endofpattern() // will be called soon so don't set hashed here // return "Invalid macrocell file: no ghnodes." ; return 0 ; } hashed = 1 ; return 0 ; } const char *ghashbase::setrule(const char *) { poller->bailIfCalculating() ; clearcache() ; return 0 ; } /** * Write out the native macrocell format. This is the one we use when * we're not interactive and displaying a progress dialog. */ g_uintptr_t ghashbase::writecell(std::ostream &os, ghnode *root, int depth) { g_uintptr_t thiscell = 0 ; if (root == zeroghnode(depth)) return 0 ; if (depth == 0) { if (root->nw != 0) return (g_uintptr_t)(root->nw) ; } else { if (marked2(root)) return (g_uintptr_t)(root->next) ; unhash_ghnode(root) ; mark2(root) ; } thiscell = ++cellcounter ; if (depth == 0) { ghleaf *n = (ghleaf *)root ; root->nw = (ghnode *)thiscell ; os << 1 << ' ' << int(n->nw) << ' ' << int(n->ne) << ' ' << int(n->sw) << ' ' << int(n->se) << '\n' ; } else { g_uintptr_t nw = writecell(os, root->nw, depth-1) ; g_uintptr_t ne = writecell(os, root->ne, depth-1) ; g_uintptr_t sw = writecell(os, root->sw, depth-1) ; g_uintptr_t se = writecell(os, root->se, depth-1) ; root->next = (ghnode *)thiscell ; os << depth+1 << ' ' << nw << ' ' << ne << ' ' << sw << ' ' << se << '\n' ; } return thiscell ; } /** * This new two-pass method works by doing a prepass that numbers the * ghnodes and counts the number of ghnodes that should be sent, so we can * display an accurate progress dialog. */ g_uintptr_t ghashbase::writecell_2p1(ghnode *root, int depth) { g_uintptr_t thiscell = 0 ; if (root == zeroghnode(depth)) return 0 ; if (depth == 0) { if (root->nw != 0) return (g_uintptr_t)(root->nw) ; } else { if (marked2(root)) return (g_uintptr_t)(root->next) ; unhash_ghnode(root) ; mark2(root) ; } if (depth == 0) { thiscell = ++cellcounter ; // note: we *must* not abort this prescan if ((cellcounter & 4095) == 0) lifeabortprogress(0, "Scanning tree") ; root->nw = (ghnode *)thiscell ; } else { writecell_2p1(root->nw, depth-1) ; writecell_2p1(root->ne, depth-1) ; writecell_2p1(root->sw, depth-1) ; writecell_2p1(root->se, depth-1) ; thiscell = ++cellcounter ; // note: we *must* not abort this prescan if ((cellcounter & 4095) == 0) lifeabortprogress(0, "Scanning tree") ; root->next = (ghnode *)thiscell ; } return thiscell ; } /** * This one writes the cells, but assuming they've already been * numbered, and displaying a progress dialog. */ static char progressmsg[80] ; g_uintptr_t ghashbase::writecell_2p2(std::ostream &os, ghnode *root, int depth) { g_uintptr_t thiscell = 0 ; if (root == zeroghnode(depth)) return 0 ; if (depth == 0) { if (cellcounter + 1 != (g_uintptr_t)(root->nw)) return (g_uintptr_t)(root->nw) ; thiscell = ++cellcounter ; if ((cellcounter & 4095) == 0) { std::streampos siz = os.tellp() ; sprintf(progressmsg, "File size: %.2f MB", double(siz) / 1048576.0) ; lifeabortprogress(thiscell/(double)writecells, progressmsg) ; } ghleaf *n = (ghleaf *)root ; root->nw = (ghnode *)thiscell ; os << 1 << ' ' << int(n->nw) << ' ' << int(n->ne) << ' ' << int(n->sw) << ' ' << int(n->se) << '\n'; } else { if (cellcounter + 1 > (g_uintptr_t)(root->next) || isaborted()) return (g_uintptr_t)(root->next) ; g_uintptr_t nw = writecell_2p2(os, root->nw, depth-1) ; g_uintptr_t ne = writecell_2p2(os, root->ne, depth-1) ; g_uintptr_t sw = writecell_2p2(os, root->sw, depth-1) ; g_uintptr_t se = writecell_2p2(os, root->se, depth-1) ; if (!isaborted() && cellcounter + 1 != (g_uintptr_t)(root->next)) { // this should never happen lifefatal("Internal in writecell_2p2") ; return (g_uintptr_t)(root->next) ; } thiscell = ++cellcounter ; if ((cellcounter & 4095) == 0) { std::streampos siz = os.tellp() ; sprintf(progressmsg, "File size: %.2f MB", double(siz) / 1048576.0) ; lifeabortprogress(thiscell/(double)writecells, progressmsg) ; } root->next = (ghnode *)thiscell ; os << depth+1 << ' ' << nw << ' ' << ne << ' ' << sw << ' ' << se << '\n' ; } return thiscell ; } #define STRINGIFY(arg) STR2(arg) #define STR2(arg) #arg const char *ghashbase::writeNativeFormat(std::ostream &os, char *comments) { int depth = ghnode_depth(root) ; os << "[M2] (golly " STRINGIFY(VERSION) ")\n" ; // AKT: always write out explicit rule os << "#R " << getrule() << '\n' ; if (generation > bigint::zero) { // write non-zero gen count os << "#G " << generation.tostring('\0') << '\n' ; } if (comments) { // write given comment line(s), but we can't just do "os << comments" because the // lines might not start with #C (eg. if they came from the end of a .rle file), // so we must ensure that each comment line in the .mc file starts with #C char *p = comments; while (*p != '\0') { char *line = p; // note that readcomments() in readpattern.cpp ensures each line ends with \n while (*p != '\n') p++; if (line[0] != '#' || line[1] != 'C') { os << "#C "; } if (line != p) { *p = '\0'; os << line; *p = '\n'; } os << '\n'; p++; } } inGC = 1 ; /* this is the old way: cellcounter = 0 ; writecell(os, root, depth) ; */ /* this is the new two-pass way */ cellcounter = 0 ; vector depths(timeline.framecount) ; int framestosave = timeline.framecount ; if (timeline.savetimeline == 0) framestosave = 0 ; if (framestosave) { for (int i=0; inext << '\n' ; } } writecell_2p2(os, root, depth) ; /* end new two-pass way */ if (framestosave) { for (int i=0; i #include #include #include using namespace std ; const int logbmsize = 7 ; // 6=64x64 7=128x128 8=256x256 const int bmsize = (1<> 3)] |= (128 >> (x & 7)) ; } /* * Draw a 4x4 area yielding 1x1, 2x2, or 4x4 pixels. */ void draw4x4_1(unsigned short sw, unsigned short se, unsigned short nw, unsigned short ne, int llx, int lly) { unsigned char *p = bigbuf + ((bmsize-1+lly) << (logbmsize-3)) + ((-llx) >> 3) ; int bit = 128 >> ((-llx) & 0x7) ; if (sw) *p |= bit ; if (se) *p |= (bit >> 1) ; p -= byteoff ; if (nw) *p |= bit ; if (ne) *p |= (bit >> 1) ; } void draw4x4_1(node *n, node *z, int llx, int lly) { unsigned char *p = bigbuf + ((bmsize-1+lly) << (logbmsize-3)) + ((-llx) >> 3) ; int bit = 128 >> ((-llx) & 0x7) ; if (n->sw != z) *p |= bit ; if (n->se != z) *p |= (bit >> 1) ; p -= byteoff ; if (n->nw != z) *p |= bit ; if (n->ne != z) *p |= (bit >> 1) ; } static unsigned char compress4x4[256] ; static bool inited = false; void draw4x4_2(unsigned short bits1, unsigned short bits2, int llx, int lly) { unsigned char *p = bigbuf + ((bmsize-1+lly) << (logbmsize-3)) + ((-llx) >> 3) ; int mask = (((-llx) & 0x4) ? 0x0f : 0xf0) ; int db = ((bits1 | (bits1 << 4)) & 0xf0f0) + ((bits2 | (bits2 >> 4)) & 0x0f0f) ; p[0] |= mask & compress4x4[db & 255] ; p[-byteoff] |= mask & compress4x4[db >> 8] ; } void draw4x4_4(unsigned short bits1, unsigned short bits2, int llx, int lly) { unsigned char *p = bigbuf + ((bmsize-1+lly) << (logbmsize-3)) + ((-llx) >> 3) ; p[0] = (unsigned char)(((bits1 << 4) & 0xf0) + (bits2 & 0xf)) ; p[-byteoff] = (unsigned char)((bits1 & 0xf0) + ((bits2 >> 4) & 0xf)) ; p[-2*byteoff] = (unsigned char)(((bits1 >> 4) & 0xf0) + ((bits2 >> 8) & 0xf)) ; p[-3*byteoff] = (unsigned char)(((bits1 >> 8) & 0xf0) + ((bits2 >> 12) & 0xf)) ; } void hlifealgo::clearrect(int minx, int miny, int w, int h) { // minx,miny is lower left corner if (w <= 0 || h <= 0) return ; if (pmag > 1) { minx *= pmag ; miny *= pmag ; w *= pmag ; h *= pmag ; } miny = uviewh - miny - h ; renderer->killrect(minx, miny, w, h) ; } void hlifealgo::renderbm(int x, int y) { // x,y is lower left corner int rx = x ; int ry = y ; int rw = bmsize ; int rh = bmsize ; if (pmag > 1) { rx *= pmag ; ry *= pmag ; rw *= pmag ; rh *= pmag ; } ry = uviewh - ry - rh ; // AKT: eventually we'll draw directly into pixbuf rather than bigbuf!!! if (pmag > 1) { // convert each bigbuf byte into 8 bytes of state data int j = 0; for (int i = 0; i < ibufsize * 4; i++) { int byte = bigbuf[i]; for (int bit = 128; bit > 0; bit >>= 1) { pixbuf[j++] = (byte & bit) ? 1 : 0; } } } else { // convert each bigbuf byte into 24 bytes of pixel data (8 * rgb) int j = 0; for (int i = 0; i < ibufsize * 4; i++) { int byte = bigbuf[i]; for (int bit = 128; bit > 0; bit >>= 1) { if (byte & bit) { pixbuf[j++] = liver; pixbuf[j++] = liveg; pixbuf[j++] = liveb; } else { pixbuf[j++] = deadr; pixbuf[j++] = deadg; pixbuf[j++] = deadb; } } } } renderer->pixblit(rx, ry, rw, rh, (char *)pixbuf, pmag); memset(bigbuf, 0, sizeof(ibigbuf)) ; } /* * Here, llx and lly are coordinates in screen pixels describing * where the lower left pixel of the screen is. Draw one node. * This is our main recursive routine. */ void hlifealgo::drawnode(node *n, int llx, int lly, int depth, node *z) { int sw = 1 << (depth - mag + 1) ; if (sw >= bmsize && (llx + vieww <= 0 || lly + viewh <= 0 || llx >= sw || lly >= sw)) return ; if (n == z) { if (sw >= bmsize) clearrect(-llx, -lly, sw, sw) ; } else if (depth > 2 && sw > 2) { z = z->nw ; sw >>= 1 ; depth-- ; if (sw == (bmsize >> 1)) { drawnode(n->sw, 0, 0, depth, z) ; drawnode(n->se, -(bmsize/2), 0, depth, z) ; drawnode(n->nw, 0, -(bmsize/2), depth, z) ; drawnode(n->ne, -(bmsize/2), -(bmsize/2), depth, z) ; renderbm(-llx, -lly) ; } else { drawnode(n->sw, llx, lly, depth, z) ; drawnode(n->se, llx-sw, lly, depth, z) ; drawnode(n->nw, llx, lly-sw, depth, z) ; drawnode(n->ne, llx-sw, lly-sw, depth, z) ; } } else if (depth > 2 && sw == 2) { draw4x4_1(n, z->nw, llx, lly) ; } else if (sw == 1) { drawpixel(-llx, -lly) ; } else { struct leaf *l = (struct leaf *)n ; sw >>= 1 ; if (sw == 1) { draw4x4_1(l->sw, l->se, l->nw, l->ne, llx, lly) ; } else if (sw == 2) { draw4x4_2(l->sw, l->se, llx, lly) ; draw4x4_2(l->nw, l->ne, llx, lly-sw) ; } else { draw4x4_4(l->sw, l->se, llx, lly) ; draw4x4_4(l->nw, l->ne, llx, lly-sw) ; } } } /* * Fill in the llxb and llyb bits from the viewport information. * Allocate if necessary. This arithmetic should be done carefully. */ void hlifealgo::fill_ll(int d) { pair coor = view->at(0, view->getymax()) ; coor.second.mul_smallint(-1) ; bigint s = 1 ; s <<= d ; coor.first += s ; coor.second += s ; int bitsreq = coor.first.bitsreq() ; int bitsreq2 = coor.second.bitsreq() ; if (bitsreq2 > bitsreq) bitsreq = bitsreq2 ; if (bitsreq <= d) bitsreq = d + 1 ; // need to access llxyb[d] if (bitsreq > llsize) { if (llsize) { delete [] llxb ; delete [] llyb ; } llxb = new char[bitsreq] ; llyb = new char[bitsreq] ; llsize = bitsreq ; } llbits = bitsreq ; coor.first.tochararr(llxb, llbits) ; coor.second.tochararr(llyb, llbits) ; } static void init_compress4x4() { int i; for (i=0; i<8; i++) compress4x4[((size_t)1)<> 1)) ; for (i=0; i<256; i++) if (i & (i-1)) compress4x4[i] = compress4x4[i & (i-1)] | compress4x4[i & -i] ; } /* * This is the top-level draw routine that takes the root node. * It maintains four nodes onto which the screen fits and uses the * high bits of llx/lly to project those four nodes as far down * the tree as possible, so we know we can get away with just * 32-bit arithmetic in the above recursive routine. This way * we don't need any high-precision addition or subtraction to * display an image. */ void hlifealgo::draw(viewport &viewarg, liferender &rendererarg) { if (!inited) { init_compress4x4() ; inited = true; } memset(bigbuf, 0, sizeof(ibigbuf)) ; ensure_hashed() ; renderer = &rendererarg ; // AKT: get cell colors unsigned char *r, *g, *b; renderer->getcolors(&r, &g, &b); deadr = r[0]; deadg = g[0]; deadb = b[0]; liver = r[1]; liveg = g[1]; liveb = b[1]; view = &viewarg ; uvieww = view->getwidth() ; uviewh = view->getheight() ; if (view->getmag() > 0) { pmag = 1 << (view->getmag()) ; mag = 0 ; viewh = ((uviewh - 1) >> view->getmag()) + 1 ; vieww = ((uvieww - 1) >> view->getmag()) + 1 ; uviewh += (-uviewh) & (pmag - 1) ; } else { mag = (-view->getmag()) ; pmag = 1 ; viewh = uviewh ; vieww = uvieww ; } int d = depth ; fill_ll(d) ; int maxd = vieww ; int i ; node *z = zeronode(d) ; node *sw = root, *nw = z, *ne = z, *se = z ; if (viewh > maxd) maxd = viewh ; int llx=-llxb[llbits-1], lly=-llyb[llbits-1] ; /* Skip down to top of tree. */ for (i=llbits-1; i>d && i>=mag; i--) { /* go down to d, but not further than mag */ llx = (llx << 1) + llxb[i] ; lly = (lly << 1) + llyb[i] ; if (llx > 2*maxd || lly > 2*maxd || llx < -2*maxd || lly < -2*maxd) { clearrect(0, 0, vieww, viewh) ; goto bail ; } } /* Find the lowest four we need to examine */ while (d > 2 && d - mag >= 0 && (d - mag > 28 || (1 << (d - mag)) > 2 * maxd)) { llx = (llx << 1) + llxb[d] ; lly = (lly << 1) + llyb[d] ; if (llx >= 1) { if (lly >= 1) { ne = ne->sw ; nw = nw->se ; se = se->nw ; sw = sw->ne ; lly-- ; } else { ne = se->nw ; nw = sw->ne ; se = se->sw ; sw = sw->se ; } llx-- ; } else { if (lly >= 1) { ne = nw->se ; nw = nw->sw ; se = sw->ne ; sw = sw->nw ; lly-- ; } else { ne = sw->ne ; nw = sw->nw ; se = sw->se ; sw = sw->sw ; } } if (llx > 2*maxd || lly > 2*maxd || llx < -2*maxd || lly < -2*maxd) { clearrect(0, 0, vieww, viewh) ; goto bail ; } d-- ; } /* At this point we know we can use 32-bit arithmetic. */ for (i=d; i>=mag; i--) { llx = (llx << 1) + llxb[i] ; lly = (lly << 1) + llyb[i] ; } /* clear the border *around* the universe if necessary */ if (d + 1 <= mag) { node *z = zeronode(d) ; if (llx > 0 || lly > 0 || llx + vieww <= 0 || lly + viewh <= 0 || (sw == z && se == z && nw == z && ne == z)) { clearrect(0, 0, vieww, viewh) ; } else { clearrect(0, 1-lly, vieww, viewh-1+lly) ; clearrect(0, 0, vieww, -lly) ; clearrect(0, -lly, -llx, 1) ; clearrect(1-llx, -lly, vieww-1+llx, 1) ; drawpixel(0, 0) ; renderbm(-llx, -lly) ; } } else { z = zeronode(d) ; maxd = 1 << (d - mag + 2) ; clearrect(0, maxd-lly, vieww, viewh-maxd+lly) ; clearrect(0, 0, vieww, -lly) ; clearrect(0, -lly, -llx, maxd) ; clearrect(maxd-llx, -lly, vieww-maxd+llx, maxd) ; if (maxd <= bmsize) { maxd >>= 1 ; drawnode(sw, 0, 0, d, z) ; drawnode(se, -maxd, 0, d, z) ; drawnode(nw, 0, -maxd, d, z) ; drawnode(ne, -maxd, -maxd, d, z) ; renderbm(-llx, -lly) ; } else { maxd >>= 1 ; drawnode(sw, llx, lly, d, z) ; drawnode(se, llx-maxd, lly, d, z) ; drawnode(nw, llx, lly-maxd, d, z) ; drawnode(ne, llx-maxd, lly-maxd, d, z) ; } } bail: renderer = 0 ; view = 0 ; } int getbitsfromleaves(const vector &v) { unsigned short nw=0, ne=0, sw=0, se=0 ; int i; for (i=0; i<(int)v.size(); i++) { leaf *p = (leaf *)v[i] ; nw |= p->nw ; ne |= p->ne ; sw |= p->sw ; se |= p->se ; } int r = 0 ; // horizontal bits are least significant ones unsigned short w = nw | sw ; unsigned short e = ne | se ; // vertical bits are next 8 unsigned short n = nw | ne ; unsigned short s = sw | se ; for (i=0; i<4; i++) { if (w & (0x1111 << i)) r |= 0x1000 << i ; if (e & (0x1111 << i)) r |= 0x100 << i ; if (n & (0xf << (4 * i))) r |= 0x10 << i ; if (s & (0xf << (4 * i))) r |= 0x1 << i ; } return r ; } /** * Copy the vector, but sort it and uniquify it so we don't have a ton * of duplicate nodes. */ void sortunique(vector &dest, vector &src) { swap(src, dest) ; // note: this is superfast sort(dest.begin(), dest.end()) ; vector::iterator new_end = unique(dest.begin(), dest.end()) ; dest.erase(new_end, dest.end()) ; src.clear() ; } void hlifealgo::findedges(bigint *ptop, bigint *pleft, bigint *pbottom, bigint *pright) { // AKT: following code is from fit() but all goal/size stuff // has been removed so it finds the exact pattern edges ensure_hashed() ; bigint xmin = -1 ; bigint xmax = 1 ; bigint ymin = -1 ; bigint ymax = 1 ; int currdepth = depth ; int i; if (root == zeronode(currdepth)) { // AKT: return impossible edges to indicate empty pattern; // not really a problem because caller should check first *ptop = 1 ; *pleft = 1 ; *pbottom = 0 ; *pright = 0 ; return ; } vector top, left, bottom, right ; top.push_back(root) ; left.push_back(root) ; bottom.push_back(root) ; right.push_back(root) ; int topbm = 0, bottombm = 0, rightbm = 0, leftbm = 0 ; while (currdepth >= 0) { currdepth-- ; if (currdepth == 1) { // we have leaf nodes; turn them into bitmasks topbm = getbitsfromleaves(top) & 0xff ; bottombm = getbitsfromleaves(bottom) & 0xff ; leftbm = getbitsfromleaves(left) >> 8 ; rightbm = getbitsfromleaves(right) >> 8 ; } if (currdepth <= 1) { int sz = 1 << (currdepth + 2) ; int maskhi = (1 << sz) - (1 << (sz >> 1)) ; int masklo = (1 << (sz >> 1)) - 1 ; ymax += ymax ; if ((topbm & maskhi) == 0) { ymax.add_smallint(-2) ; } else { topbm >>= (sz >> 1) ; } ymin += ymin ; if ((bottombm & masklo) == 0) { ymin.add_smallint(2) ; bottombm >>= (sz >> 1) ; } xmax += xmax ; if ((rightbm & masklo) == 0) { xmax.add_smallint(-2) ; rightbm >>= (sz >> 1) ; } xmin += xmin ; if ((leftbm & maskhi) == 0) { xmin.add_smallint(2) ; } else { leftbm >>= (sz >> 1) ; } } else { node *z = 0 ; if (hashed) z = zeronode(currdepth) ; vector newv ; int outer = 0 ; for (i=0; i<(int)top.size(); i++) { node *t = top[i] ; if (!outer && (t->nw != z || t->ne != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->nw != z) newv.push_back(t->nw) ; if (t->ne != z) newv.push_back(t->ne) ; } else { if (t->sw != z) newv.push_back(t->sw) ; if (t->se != z) newv.push_back(t->se) ; } } sortunique(top, newv) ; ymax += ymax ; if (!outer) { ymax.add_smallint(-2) ; } outer = 0 ; for (i=0; i<(int)bottom.size(); i++) { node *t = bottom[i] ; if (!outer && (t->sw != z || t->se != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->sw != z) newv.push_back(t->sw) ; if (t->se != z) newv.push_back(t->se) ; } else { if (t->nw != z) newv.push_back(t->nw) ; if (t->ne != z) newv.push_back(t->ne) ; } } sortunique(bottom, newv) ; ymin += ymin ; if (!outer) { ymin.add_smallint(2) ; } outer = 0 ; for (i=0; i<(int)right.size(); i++) { node *t = right[i] ; if (!outer && (t->ne != z || t->se != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->ne != z) newv.push_back(t->ne) ; if (t->se != z) newv.push_back(t->se) ; } else { if (t->nw != z) newv.push_back(t->nw) ; if (t->sw != z) newv.push_back(t->sw) ; } } sortunique(right, newv) ; xmax += xmax ; if (!outer) { xmax.add_smallint(-2) ; } outer = 0 ; for (i=0; i<(int)left.size(); i++) { node *t = left[i] ; if (!outer && (t->nw != z || t->sw != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->nw != z) newv.push_back(t->nw) ; if (t->sw != z) newv.push_back(t->sw) ; } else { if (t->ne != z) newv.push_back(t->ne) ; if (t->se != z) newv.push_back(t->se) ; } } sortunique(left, newv) ; xmin += xmin ; if (!outer) { xmin.add_smallint(2) ; } } } xmin >>= 1 ; xmax >>= 1 ; ymin >>= 1 ; ymax >>= 1 ; xmin <<= (currdepth + 1) ; ymin <<= (currdepth + 1) ; xmax <<= (currdepth + 1) ; ymax <<= (currdepth + 1) ; xmax -= 1 ; ymax -= 1 ; ymin.mul_smallint(-1) ; ymax.mul_smallint(-1) ; // set pattern edges *ptop = ymax ; // due to y flip *pbottom = ymin ; // due to y flip *pleft = xmin ; *pright = xmax ; } void hlifealgo::fit(viewport &view, int force) { ensure_hashed() ; bigint xmin = -1 ; bigint xmax = 1 ; bigint ymin = -1 ; bigint ymax = 1 ; int xgoal = view.getwidth() ; int ygoal = view.getheight() ; if (xgoal < 8) xgoal = 8 ; if (ygoal < 8) ygoal = 8 ; int xsize = 2 ; int ysize = 2 ; int currdepth = depth ; int i; if (root == zeronode(currdepth)) { view.center() ; view.setmag(MAX_MAG) ; return ; } vector top, left, bottom, right ; top.push_back(root) ; left.push_back(root) ; bottom.push_back(root) ; right.push_back(root) ; int topbm = 0, bottombm = 0, rightbm = 0, leftbm = 0 ; while (currdepth >= 0) { currdepth-- ; if (currdepth == 1) { // we have leaf nodes; turn them into bitmasks topbm = getbitsfromleaves(top) & 0xff ; bottombm = getbitsfromleaves(bottom) & 0xff ; leftbm = getbitsfromleaves(left) >> 8 ; rightbm = getbitsfromleaves(right) >> 8 ; } if (currdepth <= 1) { int sz = 1 << (currdepth + 2) ; int maskhi = (1 << sz) - (1 << (sz >> 1)) ; int masklo = (1 << (sz >> 1)) - 1 ; ymax += ymax ; if ((topbm & maskhi) == 0) { ymax.add_smallint(-2) ; ysize-- ; } else { topbm >>= (sz >> 1) ; } ymin += ymin ; if ((bottombm & masklo) == 0) { ymin.add_smallint(2) ; ysize-- ; bottombm >>= (sz >> 1) ; } xmax += xmax ; if ((rightbm & masklo) == 0) { xmax.add_smallint(-2) ; xsize-- ; rightbm >>= (sz >> 1) ; } xmin += xmin ; if ((leftbm & maskhi) == 0) { xmin.add_smallint(2) ; xsize-- ; } else { leftbm >>= (sz >> 1) ; } xsize <<= 1 ; ysize <<= 1 ; } else { node *z = 0 ; if (hashed) z = zeronode(currdepth) ; vector newv ; int outer = 0 ; for (i=0; i<(int)top.size(); i++) { node *t = top[i] ; if (!outer && (t->nw != z || t->ne != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->nw != z) newv.push_back(t->nw) ; if (t->ne != z) newv.push_back(t->ne) ; } else { if (t->sw != z) newv.push_back(t->sw) ; if (t->se != z) newv.push_back(t->se) ; } } top = newv ; newv.clear() ; ymax += ymax ; if (!outer) { ymax.add_smallint(-2) ; ysize-- ; } outer = 0 ; for (i=0; i<(int)bottom.size(); i++) { node *t = bottom[i] ; if (!outer && (t->sw != z || t->se != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->sw != z) newv.push_back(t->sw) ; if (t->se != z) newv.push_back(t->se) ; } else { if (t->nw != z) newv.push_back(t->nw) ; if (t->ne != z) newv.push_back(t->ne) ; } } bottom = newv ; newv.clear() ; ymin += ymin ; if (!outer) { ymin.add_smallint(2) ; ysize-- ; } ysize *= 2 ; outer = 0 ; for (i=0; i<(int)right.size(); i++) { node *t = right[i] ; if (!outer && (t->ne != z || t->se != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->ne != z) newv.push_back(t->ne) ; if (t->se != z) newv.push_back(t->se) ; } else { if (t->nw != z) newv.push_back(t->nw) ; if (t->sw != z) newv.push_back(t->sw) ; } } right = newv ; newv.clear() ; xmax += xmax ; if (!outer) { xmax.add_smallint(-2) ; xsize-- ; } outer = 0 ; for (i=0; i<(int)left.size(); i++) { node *t = left[i] ; if (!outer && (t->nw != z || t->sw != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->nw != z) newv.push_back(t->nw) ; if (t->sw != z) newv.push_back(t->sw) ; } else { if (t->ne != z) newv.push_back(t->ne) ; if (t->se != z) newv.push_back(t->se) ; } } left = newv ; newv.clear() ; xmin += xmin ; if (!outer) { xmin.add_smallint(2) ; xsize-- ; } xsize *= 2 ; } if (xsize > xgoal || ysize > ygoal) break ; } xmin >>= 1 ; xmax >>= 1 ; ymin >>= 1 ; ymax >>= 1 ; xmin <<= (currdepth + 1) ; ymin <<= (currdepth + 1) ; xmax <<= (currdepth + 1) ; ymax <<= (currdepth + 1) ; xmax -= 1 ; ymax -= 1 ; ymin.mul_smallint(-1) ; ymax.mul_smallint(-1) ; if (!force) { // if all four of the above dimensions are in the viewport, don't change if (view.contains(xmin, ymin) && view.contains(xmax, ymax)) return ; } int mag = - currdepth - 1 ; while (xsize <= xgoal && ysize <= ygoal && mag < MAX_MAG) { mag++ ; xsize *= 2 ; ysize *= 2 ; } view.setpositionmag(xmin, xmax, ymin, ymax, mag) ; } void hlifealgo::lowerRightPixel(bigint &x, bigint &y, int mag) { if (mag >= 0) return ; x >>= -mag ; x <<= -mag ; y -= 1 ; y >>= -mag ; y <<= -mag ; y += 1 ; } golly-2.7-src/gollybase/viewport.h0000644000175000017500000000611212536111364014231 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef VIEWPORT_H #define VIEWPORT_H #include "bigint.h" #include using std::pair; using std::make_pair; class lifealgo ; /** * This class holds information on where in space the user's window is. * It provides the functions to zoom, unzoom, move, etc. * * The reason we need a whole class is because doing this in a universe * that may be billions of billions of cells on a side, but we still * want single cell precision, is a bit tricky. * * This class is not finished yet; I still need to be more precise about * cases where mag>0 and precisely what will be displayed in this case * and precisely how the coordinate transformations will occur. */ class viewport { public: viewport(int width, int height) { init() ; resize(width, height) ; } void zoom() ; void zoom(int x, int y) ; void unzoom() ; void unzoom(int x, int y) ; void center() ; pair at(int x, int y) ; pair atf(int x, int y) ; pair screenPosOf(bigint x, bigint y, lifealgo *algo) ; void resize(int newwidth, int newheight) ; void move(int dx, int dy) ; // dx and dy are given in pixels int getmag() const { return mag ; } void setmag(int magarg) { mag = magarg ; reposition() ; } void setpositionmag(const bigint &xarg, const bigint &yarg, int magarg) ; void setpositionmag(const bigint &xlo, const bigint &xhi, const bigint &ylo, const bigint &yhi, int magarg) ; int getwidth() const { return width ; } int getheight() const { return height ; } int getxmax() const { return width-1 ; } int getymax() const { return height-1 ; } int contains(const bigint &x, const bigint &y) ; bigint x, y ; // cell at center of viewport private: void init() ; void reposition() ; // recalculate *0* and *m* values int width, height ; int mag ; // plus is zoom in; neg is zoom out bigint x0, y0 ; double x0f, y0f ; double xymf ; // always = 2**-mag } ; extern int MAX_MAG; // maximum cell size is 2^MAX_MAG (default is 2^4, but mobile devices // will probably want a bigger cell size) #endif golly-2.7-src/gollybase/util.h0000644000175000017500000000441412536111364013332 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /** * Basic utility classes for things like fatal errors. */ #ifndef UTIL_H #define UTIL_H #include // for FILE * void lifefatal(const char *s) ; void lifewarning(const char *s) ; void lifestatus(const char *s) ; void lifebeginprogress(const char *dlgtitle) ; bool lifeabortprogress(double fracdone, const char *newmsg) ; void lifeendprogress() ; const char *lifegetuserrules() ; const char *lifegetrulesdir() ; bool isaborted() ; FILE *getdebugfile() ; /** * Sick of line ending woes. This class takes care of this for us. */ class linereader { public: linereader(FILE *f) ; char *fgets(char *buf, int maxlen) ; void setfile(FILE *f) ; void setcloseonfree() ; int close() ; ~linereader() ; private: int lastchar ; int closeonfree ; FILE *fp ; } ; /** * To substitute your own routines, use the following class. */ class lifeerrors { public: virtual void fatal(const char *s) = 0 ; virtual void warning(const char *s) = 0 ; virtual void status(const char *s) = 0 ; virtual void beginprogress(const char *dlgtitle) = 0 ; virtual bool abortprogress(double fracdone, const char *newmsg) = 0 ; virtual void endprogress() = 0 ; virtual const char *getuserrules() = 0 ; virtual const char *getrulesdir() = 0 ; static void seterrorhandler(lifeerrors *obj) ; bool aborted ; } ; #endif golly-2.7-src/gollybase/ruletable_algo.h0000644000175000017500000000540712536111364015341 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef RULETABLE_ALGO_H #define RULETABLE_ALGO_H #include "ghashbase.h" #include #include #include /** * An algo that takes a rule table. */ class ruletable_algo : public ghashbase { public: ruletable_algo() ; virtual ~ruletable_algo() ; virtual state slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) ; virtual const char* setrule(const char* s) ; virtual const char* getrule() ; virtual const char* DefaultRule() ; virtual int NumCellStates() ; static void doInitializeAlgoInfo(staticAlgoInfo &) ; // these two methods are needed for RuleLoader algo bool IsDefaultRule(const char* rulename); const char* LoadTable(FILE* rulefile, int lineno, char endchar, const char* s); protected: std::string LoadRuleTable(std::string filename); void PackTransitions(const std::string& symmetries, int n_inputs, const std::vector< std::pair< std::vector< std::vector >, state> > & transition_table); void PackTransition(const std::vector< std::vector > & inputs, state output); protected: std::string current_rule; unsigned int n_states; enum TNeighborhood { vonNeumann, Moore, hexagonal, oneDimensional } neighborhood; static const int N_SUPPORTED_NEIGHBORHOODS = 4; static const std::string neighborhood_value_keywords[N_SUPPORTED_NEIGHBORHOODS]; // we use a lookup table to match inputs to outputs: typedef unsigned long long int TBits; // we can use unsigned int if we hit portability issues (not much slower) std::vector< std::vector< std::vector > > lut; // TBits lut[neighbourhood_size][n_states][n_compressed_rules]; unsigned int n_compressed_rules; std::vector output; // state output[n_rules]; }; #endif golly-2.7-src/gollybase/hlifealgo.h0000644000175000017500000003204112536111364014304 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef HLIFEALGO_H #define HLIFEALGO_H #include "lifealgo.h" #include "liferules.h" /* * Into instances of this node structure is where almost all of the * memory allocated by this program goes. Thus, it is imperative we * keep it as small as possible so we can explore patterns as large * and as deep as possible. * * But first, how does this program even work? Well, there are * two major tricks that are used. * * The first trick is to represent the 2D space `symbolically' * (in the sense that a binary decision diagram is a symbolic * representation of a boolean predicate). This can be thought * of as a sort of compression. We break up space into a grid of * squares, each containing 8x8 cells. And we `canonicalize' * each square; that is, all the squares with no cells set are * represented by a single actual instance of an empty square; * all squares with only the upper-left-most cell set are * represented by yet another instance, and so on. A single pointer * to the single instance of each square takes less space than * representing the actual cell bits themselves. * * Where do we store these pointers? At first, one might envision * a large two-dimensional array of pointers, each one pointing * to one of the square instances. But instead, we group the * squares (we'll call them 8-squares) into larger squares 16 * cells on a side; these are 16-squares. Each 16-square contains * four 8-squares, so each 16-square is represented by four * pointers, each to an 8-square. And we canonicalize these as * well, so for a particular set of values for a 16 by 16 array * of cells, we'll only have a single 16-square. * * And so on up; we canonicalize 32-squares out of 16-squares, and * on up to some limit. Now the limit need not be very large; * having just 20 levels of nodes gives us a universe that is * 4 * 2**20 or about 4M cells on a side. Having 100 levels of * nodes (easily within the limits of this program) gives us a * universe that is 4 * 2**100 or about 5E30 cells on a side. * I've run universes that expand well beyond 1E50 on a side with * this program. * * [A nice thing about this representation is that there are no * coordinate values anywhere, which means that there are no * limits to the coordinate values or complex multidimensional * arithmetic needed.] * * [Note that this structure so far is very similar to the octtrees * used in 3D simulation and rendering programs. It's different, * however, in that we canonicalize the nodes, and also, of course, * in that it is 2D rather than 3D.] * * I mentioned there were two tricks, and that's only the first. * The second trick is to cache the `results' of the LIFE calculation, * but in a way that looks ahead farther in time as you go higher * in the tree, much like the tree nodes themselves scan larger * distances in space. This trick is just a little subtle, but it * is where the bulk of the power of the program comes from. * * Consider once again the 8-squares. We want to cache the result * of executing LIFE on that area. We could cache the result of * looking ahead just one generation; that would yield a 6x6 square. * (Note that we cannot calculate an 8-square, because we are * using the single instance of the 8-square to represent all the * different places that 8x8 arrangement occurs, and those different * places might be surrounded by different border cells. But we * can say for sure that the central 6-square will evolve in a * unique way in the next generation.) * * We could also calculate the 4-square that is two generations * hence, and the 3-square that is three generations hence, and * the 2-square that is four generations hence. We choose the * 4-square that is two generations hence; why will be clear in * a moment. * * Now let's consider the 16-square. We would like to look farther * ahead for this square (if we always only looked two generations * ahead, our runtime would be at *least* linear in the number of * generations, and we want to beat that.) So let's look 4 generations * ahead, and cache the resulting 8-square. So we do. * * Where do we cache the results? Well, we cache the results in the * same node structure we are using to store the pointers to the * smaller squares themselves. And since we're hashing them all * together, we want a next pointer for the hash chain. Put all of * this together, and you get the following structure for the 16-squares * and larger: */ struct node { node *next ; /* hash link */ node *nw, *ne, *sw, *se ; /* constant; nw != 0 means nonleaf */ node *res ; /* cache */ } ; /* * For the 8-squares, we do not have `children', we have actual data * values. We still break up the 8-square into 4-squares, but the * 4-squares only have 16 cells in them, so we represent them directly * by an unsigned short (in this case, the direct value itself takes * less memory than the pointer we might replace it with). * * One minor trick about the following structure. We did lie above * somewhat; sometimes the struct node * points to an actual struct * node, and sometimes it points to a struct leaf. So we need a way * to tell if the thing we are pointing at is a node or a leaf. We * could add another bit to the node structure, but this would grow * it, and we want it to stay as small as possible. Now, notice * that, in all valid struct nodes, all four pointers (nw, ne, sw, * and se) must contain a live non-zero value. We simply ensure * that the struct leaf contains a zero where the first (nw) pointer * field would be in a struct node. * * Each short represents a 4-square in normal, left-to-right then top-down * order from the most significant bit. So bit 0x8000 is the upper * left (or northwest) bit, and bit 0x1000 is the upper right bit, and * so on. */ struct leaf { node *next ; /* hash link */ node *isnode ; /* must always be zero for leaves */ unsigned short nw, ne, sw, se ; /* constant */ unsigned short res1, res2 ; /* constant */ unsigned short leafpop ; /* how many set bits */ } ; /* * If it is a struct node, this returns a non-zero value, otherwise it * returns a zero value. */ #define is_node(n) (((node *)(n))->nw) /** * Our hlifealgo class. */ class hlifealgo : public lifealgo { public: hlifealgo() ; virtual ~hlifealgo() ; // note that for hlifealgo, clearall() releases no memory; it retains // the full cache information but just sets the current pattern to // the empty pattern. virtual void clearall() ; // not implemented virtual int setcell(int x, int y, int newstate) ; virtual int getcell(int x, int y) ; virtual int nextcell(int x, int y, int &state) ; virtual void endofpattern() ; virtual void setIncrement(bigint inc) ; virtual void setIncrement(int inc) { setIncrement(bigint(inc)) ; } virtual void setGeneration(bigint gen) { generation = gen ; } virtual const bigint &getPopulation() ; virtual int isEmpty() ; virtual int hyperCapable() { return 1 ; } virtual void setMaxMemory(int m) ; virtual int getMaxMemory() { return (int)(maxmem >> 20) ; } virtual const char *setrule(const char *s) ; virtual const char *getrule() { return hliferules.getrule() ; } virtual void step() ; virtual void* getcurrentstate() { return root ; } virtual void setcurrentstate(void *n) ; /* * The contract of draw() is that it render every pixel in the * viewport precisely once. This allows us to eliminate all * flashing. Later we'll make this be damage-specific. */ virtual void draw(viewport &view, liferender &renderer) ; virtual void fit(viewport &view, int force) ; virtual void lowerRightPixel(bigint &x, bigint &y, int mag) ; virtual void findedges(bigint *t, bigint *l, bigint *b, bigint *r) ; virtual const char *readmacrocell(char *line) ; virtual const char *writeNativeFormat(std::ostream &os, char *comments) ; static void doInitializeAlgoInfo(staticAlgoInfo &) ; private: /* * Some globals representing our universe. The root is the * real root of the universe, and the depth is the depth of the * tree where 2 means that root is a leaf, and 3 means that the * children of root are leaves, and so on. The center of the * root is always coordinate position (0,0), so at startup the * x and y coordinates range from -4..3; in general, * -(2**depth)..(2**depth)-1. The zeronodea is an * array of canonical `empty-space' nodes at various depths. * The ngens is an input parameter which is the second power of * the number of generations to run. */ node *root ; int depth ; node **zeronodea ; int nzeros ; /* * Finally, our gc routine. We keep a `stack' of all the `roots' * we want to preserve. Nodes not reachable from here, we allow to * be freed. Same with leaves. */ node **stack ; int stacksize ; g_uintptr_t hashpop, hashlimit, hashprime ; node **hashtab ; int halvesdone ; int gsp ; g_uintptr_t alloced, maxmem ; node *freenodes ; int okaytogc ; g_uintptr_t totalthings ; node *nodeblocks ; char *ruletable ; bigint population ; bigint setincrement ; bigint pow2step ; // greatest power of two in increment int nonpow2 ; // increment / pow2step int ngens ; // log2(pow2step) int popValid, needPop, inGC ; /* * When rendering we store the relevant bits here rather than * passing them deep into recursive subroutines. */ liferender *renderer ; viewport *view ; int uviewh, uvieww, viewh, vieww, mag, pmag ; int llbits, llsize ; char *llxb, *llyb ; int hashed ; int cacheinvalid ; g_uintptr_t cellcounter ; // used when writing g_uintptr_t writecells ; // how many to write int gccount ; // how many gcs total this pattern int gcstep ; // how many gcs this step static char statusline[] ; // void leafres(leaf *n) ; void resize() ; node *find_node(node *nw, node *ne, node *sw, node *se) ; void unhash_node(node *n) ; void rehash_node(node *n) ; leaf *find_leaf(unsigned short nw, unsigned short ne, unsigned short sw, unsigned short se) ; node *getres(node *n, int depth) ; node *dorecurs(node *n, node *ne, node *t, node *e, int depth) ; node *dorecurs_half(node *n, node *ne, node *t, node *e, int depth) ; leaf *dorecurs_leaf(leaf *n, leaf *ne, leaf *t, leaf *e) ; leaf *dorecurs_leaf_half(leaf *n, leaf *ne, leaf *t, leaf *e) ; leaf *dorecurs_leaf_quarter(leaf *n, leaf *ne, leaf *t, leaf *e) ; node *newnode() ; leaf *newleaf() ; node *newclearednode() ; leaf *newclearedleaf() ; void pushroot_1() ; int node_depth(node *n) ; node *zeronode(int depth) ; node *pushroot(node *n) ; node *setbit(node *n, int x, int y, int newstate, int depth) ; int getbit(node *n, int x, int y, int depth) ; int nextbit(node *n, int x, int y, int depth) ; node *hashpattern(node *root, int depth) ; node *popzeros(node *n) ; const bigint &calcpop(node *root, int depth) ; void aftercalcpop2(node *root, int depth, int cleanbigints) ; void calcPopulation(node *root) ; node *save(node *n) ; void pop(int n) ; void clearstack() ; void clearcache() ; void gc_mark(node *root, int invalidate) ; void do_gc(int invalidate) ; void clearcache(node *n, int depth, int clearto) ; void new_ngens(int newval) ; int log2(unsigned int n) ; node *runpattern() ; void clearrect(int x, int y, int w, int h) ; void renderbm(int x, int y) ; void fill_ll(int d) ; void drawnode(node *n, int llx, int lly, int depth, node *z) ; void ensure_hashed() ; g_uintptr_t writecell(std::ostream &os, node *root, int depth) ; g_uintptr_t writecell_2p1(node *root, int depth) ; g_uintptr_t writecell_2p2(std::ostream &os, node *root, int depth) ; void unpack8x8(unsigned short nw, unsigned short ne, unsigned short sw, unsigned short se, unsigned int *top, unsigned int *bot) ; liferules hliferules ; } ; #endif golly-2.7-src/gollybase/liferules.h0000644000175000017500000000577112536111364014356 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /** * This class implements the rules supported by QuickLife and HashLife. * A rule lookup table is used for computing a new 2x2 grid from * a provided 4x4 grid (two tables are used to emulate B0-not-Smax rules). * The input is a 16-bit integer, with the most significant bit the * upper left corner, bits going horizontally and then down. The output * is a 6-bit integer, with the top two bits indicating the top row of * the 2x2 output grid and the least significant two bits indicating the * bottom row. The middle two bits are always zero. */ #ifndef LIFERULES_H #define LIFERULES_H #include "lifealgo.h" const int MAXRULESIZE = 200 ; class liferules { public: liferules() ; ~liferules() ; // string returned by setrule is any error const char *setrule(const char *s, lifealgo *algo) ; const char *getrule() ; // AKT: we need 2 tables to support B0-not-Smax rule emulation // where max is 8, 6 or 4 depending on the neighborhood char rule0[65536]; // rule table for even gens if rule has B0 but not Smax, // or for all gens if rule has no B0, or it has B0 *and* Smax char rule1[65536]; // rule table for odd gens if rule has B0 but not Smax bool alternate_rules; // set by setrule; true if rule has B0 but not Smax // AKT: support for various neighborhoods enum neighborhood_masks { MOORE = 0x777, // all 8 neighbors HEXAGONAL = 0x673, // ignore NE and SW neighbors VON_NEUMANN = 0x272 // 4 orthogonal neighbors } ; bool isRegularLife() ; // is this B3/S23? bool isHexagonal() const { return neighbormask == HEXAGONAL ; } bool isVonNeumann() const { return neighbormask == VON_NEUMANN ; } bool isWolfram() const { return wolfram >= 0 ; } private: void initruletable(char *rptr, int rulebits, int nmask, int wolfram) ; // canonical version of valid rule passed into setrule char canonrule[MAXRULESIZE] ; neighborhood_masks neighbormask ; int rulebits ; int wolfram ; // >= 0 if Wn rule (n is even and <= 254) } ; #endif golly-2.7-src/gollybase/lifepoll.cpp0000755000175000017500000000326412536111364014523 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "lifepoll.h" #include "util.h" lifepoll::lifepoll() { interrupted = 0 ; calculating = 0 ; countdown = POLLINTERVAL ; } int lifepoll::checkevents() { return 0 ; } int lifepoll::inner_poll() { // AKT: bailIfCalculating() ; if (isCalculating()) { // AKT: better to simply ignore user event??? // lifefatal("recursive poll called.") ; return interrupted ; } countdown = POLLINTERVAL ; calculating++ ; if (!interrupted) interrupted = checkevents() ; calculating-- ; return interrupted ; } void lifepoll::bailIfCalculating() { if (isCalculating()) // AKT: lifefatal("recursive poll called.") ; lifefatal("Illegal operation while calculating.") ; } void lifepoll::updatePop() {} lifepoll default_poller ; golly-2.7-src/gollybase/util.cpp0000644000175000017500000000766512536111364013700 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "util.h" #include #include /** * For now error just uses stderr. */ class baselifeerrors : public lifeerrors { public: virtual void fatal(const char *s) { fprintf(stderr, "%s\n", s) ; exit(10) ; } virtual void warning(const char *s) { fprintf(stderr, "%s\n", s) ; } virtual void status(const char *s) { fprintf(stderr, "%s\n", s) ; } virtual void beginprogress(const char *) { aborted = false ; } virtual bool abortprogress(double, const char *) { return false ; } virtual void endprogress() { // do nothing } virtual const char *getuserrules() { return "" ; } virtual const char *getrulesdir() { return "" ; } } ; baselifeerrors baselifeerrors ; lifeerrors *errorhandler = &baselifeerrors ; void lifeerrors::seterrorhandler(lifeerrors *o) { if (o == 0) errorhandler = &baselifeerrors ; else errorhandler = o ; } void lifefatal(const char *s) { errorhandler->fatal(s) ; } void lifewarning(const char *s) { errorhandler->warning(s) ; } void lifestatus(const char *s) { errorhandler->status(s) ; } void lifebeginprogress(const char *dlgtitle) { errorhandler->beginprogress(dlgtitle) ; } bool lifeabortprogress(double fracdone, const char *newmsg) { return errorhandler->aborted |= errorhandler->abortprogress(fracdone, newmsg) ; } bool isaborted() { return errorhandler->aborted ; } void lifeendprogress() { errorhandler->endprogress() ; } const char *lifegetuserrules() { return errorhandler->getuserrules() ; } const char *lifegetrulesdir() { return errorhandler->getrulesdir() ; } static FILE *f ; FILE *getdebugfile() { if (f == 0) f = fopen("trace.txt", "w") ; return f ; } /** * Manage reading lines from a FILE* without worrying about * line terminates. Note that the fgets() routine does not * insert any line termination characters at all. */ linereader::linereader(FILE *f) { setfile(f) ; } void linereader::setfile(FILE *f) { fp = f ; lastchar = 0 ; closeonfree = 0 ; // AKT: avoid crash on Linux } void linereader::setcloseonfree() { closeonfree = 1 ; } int linereader::close() { if (fp) { int r = fclose(fp) ; fp = 0 ; return r ; } return 0 ; } linereader::~linereader() { if (closeonfree) close() ; } const int LF = 10 ; const int CR = 13 ; char *linereader::fgets(char *buf, int maxlen) { int i = 0 ; for (;;) { if (i+1 >= maxlen) { buf[i] = 0 ; return buf ; } int c = getc(fp) ; switch (c) { case EOF: if (i == 0) return 0 ; buf[i] = 0 ; return buf ; case LF: if (lastchar != CR) { lastchar = LF ; buf[i] = 0 ; return buf ; } break ; case CR: lastchar = CR ; buf[i] = 0 ; return buf ; default: lastchar = c ; buf[i++] = (char)c ; break ; } } } golly-2.7-src/gollybase/jvnalgo.cpp0000644000175000017500000021172112536111364014351 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "jvnalgo.h" // for case-insensitive string comparison #include #ifndef WIN32 #define stricmp strcasecmp #endif #include using namespace std ; // this algorithm supports three rules: const char* RULE_STRINGS[] = { "JvN29", "Nobili32", "Hutton32" }; const int N_STATES[] = { 29, 32, 32 }; int jvnalgo::NumCellStates() { return N_STATES[current_rule]; } const char* jvnalgo::setrule(const char *s) { const char* colonptr = strchr(s,':'); string rule_name(s); if(colonptr) rule_name.assign(s,colonptr); // check the requested string against the named rules, and deprecated versions if (stricmp(rule_name.c_str(), RULE_STRINGS[JvN29]) == 0 || stricmp(rule_name.c_str(), "JvN-29") == 0) current_rule = JvN29; else if (stricmp(rule_name.c_str(), RULE_STRINGS[Nobili32]) == 0 || stricmp(rule_name.c_str(), "JvN-32") == 0) current_rule = Nobili32; else if (stricmp(rule_name.c_str(), RULE_STRINGS[Hutton32]) == 0 || stricmp(rule_name.c_str(), "modJvN-32") == 0) current_rule = Hutton32; else { return "This algorithm only supports these rules:\nJvN29, Nobili32, Hutton32."; } // check for rule suffix like ":T200,100" to specify a bounded universe if (colonptr) { const char* err = setgridsize(colonptr); if (err) return err; } else { // universe is unbounded gridwd = 0; gridht = 0; } maxCellStates = N_STATES[current_rule]; ghashbase::setrule(RULE_STRINGS[current_rule]); return NULL; } const char* jvnalgo::getrule() { // return canonical rule string static char canonrule[MAXRULESIZE]; sprintf(canonrule, "%s", RULE_STRINGS[current_rule]); if (gridwd > 0 || gridht > 0) { // setgridsize() was successfully called above, so append suffix int len = (int)strlen(canonrule); const char* bounds = canonicalsuffix(); int i = 0; while (bounds[i]) canonrule[len++] = bounds[i++]; canonrule[len] = 0; } return canonrule; } const char* jvnalgo::DefaultRule() { return RULE_STRINGS[JvN29]; } const int NORTH = 1 ; const int SOUTH = 3 ; const int EAST = 0 ; const int WEST = 2 ; const int FLIPDIR = 2 ; const int DIRMASK = 3 ; const int CONF = 0x10 ; const int OTRANS = 0x20 ; const int STRANS = 0x40 ; const int TEXC = 0x80 ; const int CDEXC = 0x80 ; const int CROSSEXC = 6 ; const int CEXC = 1 ; const int BIT_ONEXC = 1 ; const int BIT_OEXC_EW = 2 ; const int BIT_OEXC_NS = 4 ; const int BIT_OEXC = BIT_OEXC_NS | BIT_OEXC_EW ; const int BIT_SEXC = 8 ; const int BIT_CEXC = 16 ; const int BIT_NS_IN = 32 ; const int BIT_EW_IN = 64 ; const int BIT_NS_OUT = 128 ; const int BIT_EW_OUT = 256 ; const int BIT_CROSS = (BIT_NS_IN | BIT_EW_IN | BIT_NS_OUT | BIT_EW_OUT) ; const int BIT_ANY_OUT = (BIT_NS_OUT | BIT_EW_OUT) ; const int BIT_OEXC_OTHER = 512 ; const int BIT_SEXC_OTHER = 1024 ; static state compress[256] ; /** * These are the legal *internal* states. */ static state uncompress[] = { 0, /* dead */ 1, 2, 3, 4, 5, 6, 7, 8, /* construction states */ 32, 33, 34, 35, /* ordinary */ 160, 161, 162, 163, /* ordinary active */ 64, 65, 66, 67, /* special */ 192, 193, 194, 195, /* special active */ 16, 144, /* confluent states */ 17, 145, /* more confluent states */ 146, 148, 150 /* crossing confluent states */ } ; /** * The behavior of the confluent states under the extended * rules was verified empirically by the wjvn executable, * because I could not interpret the paper sufficiently to * cover some cases I thought were ambiguous, or where the * simulator seemed to contradict the transition rules in the * paper. -tgr */ static int bits(state mcode, state code, state dir) { if ((code & (TEXC | OTRANS | STRANS | CONF | CEXC)) == 0) return 0 ; if (code & CONF) { if ((mcode & (OTRANS | STRANS)) && ((mcode & DIRMASK) ^ FLIPDIR) == dir) return 0 ; if ((code & 2) && !(dir & 1)) return BIT_CEXC ; if ((code & 4) && (dir & 1)) return BIT_CEXC ; if (code & 1) return BIT_CEXC ; return 0 ; } if ((code & (OTRANS | STRANS)) == 0) return 0 ; int r = 0 ; if ((code & DIRMASK) == dir) { if (code & OTRANS) { if (dir & 1) { r |= BIT_NS_IN ; if (code & TEXC) r |= BIT_OEXC_NS ; else r |= BIT_ONEXC ; } else { r |= BIT_EW_IN ; if (code & TEXC) r |= BIT_OEXC_EW ; else r |= BIT_ONEXC ; } } else if ((code & (STRANS | TEXC)) == (STRANS | TEXC)) r |= BIT_SEXC ; if ((mcode & (OTRANS | STRANS)) && (dir ^ (mcode & DIRMASK)) == 2) { // don't permit these bits to propogate; head to head } else { if (r & BIT_OEXC) r |= BIT_OEXC_OTHER ; if (r & BIT_SEXC) r |= BIT_SEXC_OTHER ; } } else { if (dir & 1) r |= BIT_NS_OUT ; else r |= BIT_EW_OUT ; } return r ; } static state cres[] = {0x22, 0x23, 0x40, 0x41, 0x42, 0x43, 0x10, 0x20, 0x21} ; jvnalgo::jvnalgo() { for (int i=0; i<256; i++) compress[i] = 255 ; for (unsigned int i=0; i 8) c = cres[c-9] ; } else if (c & CONF) { if (mbits & BIT_SEXC) c = 0 ; else if (current_rule == Nobili32 && (mbits & BIT_CROSS) == BIT_CROSS) { if (mbits & BIT_OEXC) c = (state)((mbits & BIT_OEXC) + CONF + 0x80) ; else c = CONF ; } else { if (c & CROSSEXC) {// was a cross, is no more c = (c & ~(CROSSEXC | CDEXC)) ; } if ((mbits & BIT_OEXC) && !(mbits & BIT_ONEXC)) c = ((c & CDEXC) >> 7) + (CDEXC | CONF) ; else if ((mbits & BIT_ANY_OUT) || current_rule == JvN29) c = ((c & CDEXC) >> 7) + CONF ; else /* no change */ ; } } else { if (((c & OTRANS) && (mbits & BIT_SEXC)) || ((c & STRANS) && (mbits & BIT_OEXC))) c = 0 ; else if (mbits & (BIT_SEXC_OTHER | BIT_OEXC_OTHER | BIT_CEXC)) c |= 128 ; else c &= 127 ; } return compress[c] ; } else // Hutton32 return slowcalc_Hutton32(c,n,s,e,w); } // XPM data for the 31 7x7 icons used in JvN algo static const char* jvn7x7[] = { // width height ncolors chars_per_pixel "7 217 4 1", // colors ". c #000000", // black will be transparent "D c #404040", "E c #E0E0E0", "W c #FFFFFF", // white // pixels ".DEWED.", "DWWWWWD", "EWWWWWE", "WWWWWWW", "EWWWWWE", "DWWWWWD", ".DEWED.", "..WWW..", ".WWWWW.", "WWWWWWW", ".......", "WWW.WWW", ".WW.WW.", "..W.W..", "..W.W..", ".WW.WW.", "WWW.WWW", ".......", "WWWWWWW", ".WWWWW.", "..WWW..", "..W.W..", ".WW.WW.", "WWW.WWW", ".......", "WWW.WWW", "WWW.WWW", "WWW.WWW", "..W.WWW", ".WW.WWW", "WWW.WWW", ".......", "WWW.WWW", "WWW.WW.", "WWW.W..", "WWW.W..", "WWW.WW.", "WWW.WWW", ".......", "WWW.WWW", ".WW.WWW", "..W.WWW", "WWW.WWW", "WWW.WWW", "WWW.WWW", ".......", "WWW.WWW", ".WW.WW.", "..W.W..", "..W.W..", ".WW.WW.", "WWW.WWW", ".......", "WWW.WWW", ".WW.WW.", "..W.W..", ".......", "....W..", "....WW.", "WWWWWWW", "....WW.", "....W..", ".......", "...W...", "..WWW..", ".WWWWW.", "...W...", "...W...", "...W...", "...W...", ".......", "..W....", ".WW....", "WWWWWWW", ".WW....", "..W....", ".......", "...W...", "...W...", "...W...", "...W...", ".WWWWW.", "..WWW..", "...W...", ".......", "....W..", "....WW.", "WWWWWWW", "....WW.", "....W..", ".......", "...W...", "..WWW..", ".WWWWW.", "...W...", "...W...", "...W...", "...W...", ".......", "..W....", ".WW....", "WWWWWWW", ".WW....", "..W....", ".......", "...W...", "...W...", "...W...", "...W...", ".WWWWW.", "..WWW..", "...W...", ".......", "....W..", "....WW.", "WWWWWWW", "....WW.", "....W..", ".......", "...W...", "..WWW..", ".WWWWW.", "...W...", "...W...", "...W...", "...W...", ".......", "..W....", ".WW....", "WWWWWWW", ".WW....", "..W....", ".......", "...W...", "...W...", "...W...", "...W...", ".WWWWW.", "..WWW..", "...W...", ".......", "....W..", "....WW.", "WWWWWWW", "....WW.", "....W..", ".......", "...W...", "..WWW..", ".WWWWW.", "...W...", "...W...", "...W...", "...W...", ".......", "..W....", ".WW....", "WWWWWWW", ".WW....", "..W....", ".......", "...W...", "...W...", "...W...", "...W...", ".WWWWW.", "..WWW..", "...W...", "...W...", "..WWW..", ".WW.WW.", "WW...WW", ".WW.WW.", "..WWW..", "...W...", "...W...", "..WWW..", ".WW.WW.", "WW...WW", ".WW.WW.", "..WWW..", "...W...", "...W...", "..WWW..", ".WWWWW.", "WWW.WWW", ".WWWWW.", "..WWW..", "...W...", "...W...", "..WWW..", ".WWWWW.", "WWWWWWW", ".WWWWW.", "..WWW..", "...W...", "...W...", "..W.W..", ".WW.WW.", "WWW.WWW", ".WW.WW.", "..W.W..", "...W...", "...W...", "..WWW..", ".WWWWW.", "W.....W", ".WWWWW.", "..WWW..", "...W...", "...W...", "..WWW..", ".W.W.W.", "WWW.WWW", ".W.W.W.", "..WWW..", "...W..."}; // XPM data for the 31 15x15 icons used in JvN algo static const char* jvn15x15[] = { // width height ncolors chars_per_pixel "15 465 5 1", // colors ". c #000000", // black will be transparent "D c #404040", "C c #808080", "B c #C0C0C0", "W c #FFFFFF", // white // pixels "...............", "....DBWWWBD....", "...BWWWWWWWB...", "..BWWWWWWWWWB..", ".DWWWWWWWWWWWD.", ".BWWWWWWWWWWWB.", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", ".BWWWWWWWWWWWB.", ".DWWWWWWWWWWWD.", "..BWWWWWWWWWB..", "...BWWWWWWWB...", "....DBWWWBD....", "...............", "...............", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWWWWWWWWW..", ".WWWWWWWWWWWWW.", "...............", ".WWWWWW.WWWWWW.", "..WWWWW.WWWWW..", "...WWWW.WWWW...", "....WWW.WWW....", ".....WW.WW.....", "......W.W......", "...............", "...............", "......W.W......", ".....WW.WW.....", "....WWW.WWW....", "...WWWW.WWWW...", "..WWWWW.WWWWW..", ".WWWWWW.WWWWWW.", "...............", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", "...............", "...............", "......W.W......", ".....WW.WW.....", "....WWW.WWW....", "...WWWW.WWWW...", "..WWWWW.WWWWW..", ".WWWWWW.WWWWWW.", "...............", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", "...............", "...............", "......W.WWWWWW.", ".....WW.WWWWWW.", "....WWW.WWWWWW.", "...WWWW.WWWWWW.", "..WWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", "...............", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWW..", ".WWWWWW.WWWW...", ".WWWWWW.WWW....", ".WWWWWW.WW.....", ".WWWWWW.W......", "...............", "...............", ".WWWWWW.W......", ".WWWWWW.WW.....", ".WWWWWW.WWW....", ".WWWWWW.WWWW...", ".WWWWWW.WWWWW..", ".WWWWWW.WWWWWW.", "...............", ".WWWWWW.WWWWWW.", "..WWWWW.WWWWWW.", "...WWWW.WWWWWW.", "....WWW.WWWWWW.", ".....WW.WWWWWW.", "......W.WWWWWW.", "...............", "...............", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", ".WWWWWW.WWWWWW.", "...............", ".WWWWWW.WWWWWW.", "..WWWWW.WWWWW..", "...WWWW.WWWW...", "....WWW.WWW....", ".....WW.WW.....", "......W.W......", "...............", "...............", "......W.W......", ".....WW.WW.....", "....WWW.WWW....", "...WWWW.WWWW...", "..WWWWW.WWWWW..", ".WWWWWW.WWWWWW.", "...............", ".WWWWWW.WWWWWW.", "..WWWWW.WWWWW..", "...WWWW.WWWW...", "....WWW.WWW....", ".....WW.WW.....", "......W.W......", "...............", "...............", ".......W.......", ".......WW......", ".......WWW.....", ".......WWWW....", ".......WWWWW...", ".WWWWWWWWWWWW..", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWW..", ".......WWWWW...", ".......WWWW....", ".......WWW.....", ".......WW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWWWWWWWWW..", ".WWWWWWWWWWWWW.", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "...............", "...............", ".......W.......", "......WW.......", ".....WWW.......", "....WWWW.......", "...WWWWW.......", "..WWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWWW.", "...WWWWW.......", "....WWWW.......", ".....WWW.......", "......WW.......", ".......W.......", "...............", "...............", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", ".......WW......", ".......WWW.....", ".......WWWW....", ".......WWWWW...", ".WWWWWWWWWWWW..", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWW..", ".......WWWWW...", ".......WWWW....", ".......WWW.....", ".......WW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWWWWWWWWW..", ".WWWWWWWWWWWWW.", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "...............", "...............", ".......W.......", "......WW.......", ".....WWW.......", "....WWWW.......", "...WWWWW.......", "..WWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWWW.", "...WWWWW.......", "....WWWW.......", ".....WWW.......", "......WW.......", ".......W.......", "...............", "...............", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", ".......WW......", ".......WWW.....", ".......WWWW....", ".......WWWWW...", ".WWWWWWWWWWWW..", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWW..", ".......WWWWW...", ".......WWWW....", ".......WWW.....", ".......WW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWWWWWWWWW..", ".WWWWWWWWWWWWW.", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "...............", "...............", ".......W.......", "......WW.......", ".....WWW.......", "....WWWW.......", "...WWWWW.......", "..WWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWWW.", "...WWWWW.......", "....WWWW.......", ".....WWW.......", "......WW.......", ".......W.......", "...............", "...............", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", ".......WW......", ".......WWW.....", ".......WWWW....", ".......WWWWW...", ".WWWWWWWWWWWW..", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWW..", ".......WWWWW...", ".......WWWW....", ".......WWW.....", ".......WW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWWWWWWWWW..", ".WWWWWWWWWWWWW.", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "...............", "...............", ".......W.......", "......WW.......", ".....WWW.......", "....WWWW.......", "...WWWWW.......", "..WWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWWW.", "...WWWWW.......", "....WWWW.......", ".....WWW.......", "......WW.......", ".......W.......", "...............", "...............", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", "......WWW......", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWW.WWWW...", "..WWWW...WWWW..", ".WWWW.....WWWW.", "..WWWW...WWWW..", "...WWWW.WWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWW.WWWW...", "..WWWW...WWWW..", ".WWWW.....WWWW.", "..WWWW...WWWW..", "...WWWW.WWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWW...WWWW..", ".WWWWW...WWWWW.", "..WWWW...WWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWWWWWWWWW..", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....W...W.....", "....WW...WW....", "...WWW...WWW...", "..WWWW...WWWW..", ".WWWWW...WWWWW.", "..WWWW...WWWW..", "...WWW...WWW...", "....WW...WW....", ".....W...W.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..W.........W..", ".WW.........WW.", "..W.........W..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "...............", "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....W.WWW.W....", "...W...W...W...", "..WWW.....WWW..", ".WWWWW...WWWWW.", "..WWW.....WWW..", "...W...W...W...", "....W.WWW.W....", ".....WWWWW.....", "......WWW......", ".......W.......", "..............."}; // XPM data for the 31 31x31 icons used in JvN algo static const char* jvn31x31[] = { // width height ncolors chars_per_pixel "31 961 5 1", // colors ". c #000000", // black will be transparent "D c #404040", "C c #808080", "B c #C0C0C0", "W c #FFFFFF", // white // pixels "...............................", "...............................", "..........DCBWWWWWBCD..........", ".........CWWWWWWWWWWWC.........", ".......DWWWWWWWWWWWWWWWD.......", "......BWWWWWWWWWWWWWWWWWB......", ".....BWWWWWWWWWWWWWWWWWWWB.....", "....DWWWWWWWWWWWWWWWWWWWWWD....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...CWWWWWWWWWWWWWWWWWWWWWWWC...", "..DWWWWWWWWWWWWWWWWWWWWWWWWWD..", "..CWWWWWWWWWWWWWWWWWWWWWWWWWC..", "..BWWWWWWWWWWWWWWWWWWWWWWWWWB..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..BWWWWWWWWWWWWWWWWWWWWWWWWWB..", "..CWWWWWWWWWWWWWWWWWWWWWWWWWC..", "..DWWWWWWWWWWWWWWWWWWWWWWWWWD..", "...CWWWWWWWWWWWWWWWWWWWWWWWC...", "....WWWWWWWWWWWWWWWWWWWWWWW....", "....DWWWWWWWWWWWWWWWWWWWWWD....", ".....BWWWWWWWWWWWWWWWWWWWB.....", "......BWWWWWWWWWWWWWWWWWB......", ".......DWWWWWWWWWWWWWWWD.......", ".........CWWWWWWWWWWWC.........", "..........DCBWWWWWBCD..........", "...............................", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...............................", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...WWWWWWWWWWWW.WWWWWWWWWWWW...", "....WWWWWWWWWWW.WWWWWWWWWWW....", ".....WWWWWWWWWW.WWWWWWWWWW.....", "......WWWWWWWWW.WWWWWWWWW......", ".......WWWWWWWW.WWWWWWWW.......", "........WWWWWWW.WWWWWWW........", ".........WWWWWW.WWWWWW.........", "..........WWWWW.WWWWW..........", "...........WWWW.WWWW...........", "............WWW.WWW............", ".............WW.WW.............", "..............W.W..............", "...............................", "...............................", "...............................", "...............................", "..............W.W..............", ".............WW.WW.............", "............WWW.WWW............", "...........WWWW.WWWW...........", "..........WWWWW.WWWWW..........", ".........WWWWWW.WWWWWW.........", "........WWWWWWW.WWWWWWW........", ".......WWWWWWWW.WWWWWWWW.......", "......WWWWWWWWW.WWWWWWWWW......", ".....WWWWWWWWWW.WWWWWWWWWW.....", "....WWWWWWWWWWW.WWWWWWWWWWW....", "...WWWWWWWWWWWW.WWWWWWWWWWWW...", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...............................", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "....WWWWWWWWWWWWWWWWWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............................", "..............W.W..............", ".............WW.WW.............", "............WWW.WWW............", "...........WWWW.WWWW...........", "..........WWWWW.WWWWW..........", ".........WWWWWW.WWWWWW.........", "........WWWWWWW.WWWWWWW........", ".......WWWWWWWW.WWWWWWWW.......", "......WWWWWWWWW.WWWWWWWWW......", ".....WWWWWWWWWW.WWWWWWWWWW.....", "....WWWWWWWWWWW.WWWWWWWWWWW....", "...WWWWWWWWWWWW.WWWWWWWWWWWW...", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...............................", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...............................", "...............................", "...............................", "...............................", "..............W.WWWWWWWWWWWWW..", ".............WW.WWWWWWWWWWWWW..", "............WWW.WWWWWWWWWWWWW..", "...........WWWW.WWWWWWWWWWWWW..", "..........WWWWW.WWWWWWWWWWWWW..", ".........WWWWWW.WWWWWWWWWWWWW..", "........WWWWWWW.WWWWWWWWWWWWW..", ".......WWWWWWWW.WWWWWWWWWWWWW..", "......WWWWWWWWW.WWWWWWWWWWWWW..", ".....WWWWWWWWWW.WWWWWWWWWWWWW..", "....WWWWWWWWWWW.WWWWWWWWWWWWW..", "...WWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...............................", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWW...", "..WWWWWWWWWWWWW.WWWWWWWWWWW....", "..WWWWWWWWWWWWW.WWWWWWWWWW.....", "..WWWWWWWWWWWWW.WWWWWWWWW......", "..WWWWWWWWWWWWW.WWWWWWWW.......", "..WWWWWWWWWWWWW.WWWWWWW........", "..WWWWWWWWWWWWW.WWWWWW.........", "..WWWWWWWWWWWWW.WWWWW..........", "..WWWWWWWWWWWWW.WWWW...........", "..WWWWWWWWWWWWW.WWW............", "..WWWWWWWWWWWWW.WW.............", "..WWWWWWWWWWWWW.W..............", "...............................", "...............................", "...............................", "...............................", "..WWWWWWWWWWWWW.W..............", "..WWWWWWWWWWWWW.WW.............", "..WWWWWWWWWWWWW.WWW............", "..WWWWWWWWWWWWW.WWWW...........", "..WWWWWWWWWWWWW.WWWWW..........", "..WWWWWWWWWWWWW.WWWWWW.........", "..WWWWWWWWWWWWW.WWWWWWW........", "..WWWWWWWWWWWWW.WWWWWWWW.......", "..WWWWWWWWWWWWW.WWWWWWWWW......", "..WWWWWWWWWWWWW.WWWWWWWWWW.....", "..WWWWWWWWWWWWW.WWWWWWWWWWW....", "..WWWWWWWWWWWWW.WWWWWWWWWWWW...", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...............................", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...WWWWWWWWWWWW.WWWWWWWWWWWWW..", "....WWWWWWWWWWW.WWWWWWWWWWWWW..", ".....WWWWWWWWWW.WWWWWWWWWWWWW..", "......WWWWWWWWW.WWWWWWWWWWWWW..", ".......WWWWWWWW.WWWWWWWWWWWWW..", "........WWWWWWW.WWWWWWWWWWWWW..", ".........WWWWWW.WWWWWWWWWWWWW..", "..........WWWWW.WWWWWWWWWWWWW..", "...........WWWW.WWWWWWWWWWWWW..", "............WWW.WWWWWWWWWWWWW..", ".............WW.WWWWWWWWWWWWW..", "..............W.WWWWWWWWWWWWW..", "...............................", "...............................", "...............................", "...............................", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...............................", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...WWWWWWWWWWWW.WWWWWWWWWWWW...", "....WWWWWWWWWWW.WWWWWWWWWWW....", ".....WWWWWWWWWW.WWWWWWWWWW.....", "......WWWWWWWWW.WWWWWWWWW......", ".......WWWWWWWW.WWWWWWWW.......", "........WWWWWWW.WWWWWWW........", ".........WWWWWW.WWWWWW.........", "..........WWWWW.WWWWW..........", "...........WWWW.WWWW...........", "............WWW.WWW............", ".............WW.WW.............", "..............W.W..............", "...............................", "...............................", "...............................", "...............................", "..............W.W..............", ".............WW.WW.............", "............WWW.WWW............", "...........WWWW.WWWW...........", "..........WWWWW.WWWWW..........", ".........WWWWWW.WWWWWW.........", "........WWWWWWW.WWWWWWW........", ".......WWWWWWWW.WWWWWWWW.......", "......WWWWWWWWW.WWWWWWWWW......", ".....WWWWWWWWWW.WWWWWWWWWW.....", "....WWWWWWWWWWW.WWWWWWWWWWW....", "...WWWWWWWWWWWW.WWWWWWWWWWWW...", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...............................", "..WWWWWWWWWWWWW.WWWWWWWWWWWWW..", "...WWWWWWWWWWWW.WWWWWWWWWWWW...", "....WWWWWWWWWWW.WWWWWWWWWWW....", ".....WWWWWWWWWW.WWWWWWWWWW.....", "......WWWWWWWWW.WWWWWWWWW......", ".......WWWWWWWW.WWWWWWWW.......", "........WWWWWWW.WWWWWWW........", ".........WWWWWW.WWWWWW.........", "..........WWWWW.WWWWW..........", "...........WWWW.WWWW...........", "............WWW.WWW............", ".............WW.WW.............", "..............W.W..............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "...............WW..............", "...............WWW.............", "...............WWWW............", "...............WWWWW...........", "...............WWWWWW..........", "...............WWWWWWW.........", "...............WWWWWWWW........", "...............WWWWWWWWW.......", "...............WWWWWWWWWW......", "...............WWWWWWWWWWW.....", "..WWWWWWWWWWWWWWWWWWWWWWWWW....", "..WWWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWW....", "...............WWWWWWWWWWW.....", "...............WWWWWWWWWW......", "...............WWWWWWWWW.......", "...............WWWWWWWW........", "...............WWWWWWW.........", "...............WWWWWW..........", "...............WWWWW...........", "...............WWWW............", "...............WWW.............", "...............WW..............", "...............W...............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "..............WW...............", ".............WWW...............", "............WWWW...............", "...........WWWWW...............", "..........WWWWWW...............", ".........WWWWWWW...............", "........WWWWWWWW...............", ".......WWWWWWWWW...............", "......WWWWWWWWWW...............", ".....WWWWWWWWWWW...............", "....WWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWWW..", "....WWWWWWWWWWWWWWWWWWWWWWWWW..", ".....WWWWWWWWWWW...............", "......WWWWWWWWWW...............", ".......WWWWWWWWW...............", "........WWWWWWWW...............", ".........WWWWWWW...............", "..........WWWWWW...............", "...........WWWWW...............", "............WWWW...............", ".............WWW...............", "..............WW...............", "...............W...............", "...............................", "...............................", "...............................", "...............................", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "....WWWWWWWWWWWWWWWWWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "...............WW..............", "...............WWW.............", "...............WWWW............", "...............WWWWW...........", "...............WWWWWW..........", "...............WWWWWWW.........", "...............WWWWWWWW........", "...............WWWWWWWWW.......", "...............WWWWWWWWWW......", "...............WWWWWWWWWWW.....", "..WWWWWWWWWWWWWWWWWWWWWWWWW....", "..WWWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWW....", "...............WWWWWWWWWWW.....", "...............WWWWWWWWWW......", "...............WWWWWWWWW.......", "...............WWWWWWWW........", "...............WWWWWWW.........", "...............WWWWWW..........", "...............WWWWW...........", "...............WWWW............", "...............WWW.............", "...............WW..............", "...............W...............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "..............WW...............", ".............WWW...............", "............WWWW...............", "...........WWWWW...............", "..........WWWWWW...............", ".........WWWWWWW...............", "........WWWWWWWW...............", ".......WWWWWWWWW...............", "......WWWWWWWWWW...............", ".....WWWWWWWWWWW...............", "....WWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWWW..", "....WWWWWWWWWWWWWWWWWWWWWWWWW..", ".....WWWWWWWWWWW...............", "......WWWWWWWWWW...............", ".......WWWWWWWWW...............", "........WWWWWWWW...............", ".........WWWWWWW...............", "..........WWWWWW...............", "...........WWWWW...............", "............WWWW...............", ".............WWW...............", "..............WW...............", "...............W...............", "...............................", "...............................", "...............................", "...............................", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "....WWWWWWWWWWWWWWWWWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "...............WW..............", "...............WWW.............", "...............WWWW............", "...............WWWWW...........", "...............WWWWWW..........", "...............WWWWWWW.........", "...............WWWWWWWW........", "...............WWWWWWWWW.......", "...............WWWWWWWWWW......", "...............WWWWWWWWWWW.....", "..WWWWWWWWWWWWWWWWWWWWWWWWW....", "..WWWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWW....", "...............WWWWWWWWWWW.....", "...............WWWWWWWWWW......", "...............WWWWWWWWW.......", "...............WWWWWWWW........", "...............WWWWWWW.........", "...............WWWWWW..........", "...............WWWWW...........", "...............WWWW............", "...............WWW.............", "...............WW..............", "...............W...............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "..............WW...............", ".............WWW...............", "............WWWW...............", "...........WWWWW...............", "..........WWWWWW...............", ".........WWWWWWW...............", "........WWWWWWWW...............", ".......WWWWWWWWW...............", "......WWWWWWWWWW...............", ".....WWWWWWWWWWW...............", "....WWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWWW..", "....WWWWWWWWWWWWWWWWWWWWWWWWW..", ".....WWWWWWWWWWW...............", "......WWWWWWWWWW...............", ".......WWWWWWWWW...............", "........WWWWWWWW...............", ".........WWWWWWW...............", "..........WWWWWW...............", "...........WWWWW...............", "............WWWW...............", ".............WWW...............", "..............WW...............", "...............W...............", "...............................", "...............................", "...............................", "...............................", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "....WWWWWWWWWWWWWWWWWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "...............WW..............", "...............WWW.............", "...............WWWW............", "...............WWWWW...........", "...............WWWWWW..........", "...............WWWWWWW.........", "...............WWWWWWWW........", "...............WWWWWWWWW.......", "...............WWWWWWWWWW......", "...............WWWWWWWWWWW.....", "..WWWWWWWWWWWWWWWWWWWWWWWWW....", "..WWWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWW....", "...............WWWWWWWWWWW.....", "...............WWWWWWWWWW......", "...............WWWWWWWWW.......", "...............WWWWWWWW........", "...............WWWWWWW.........", "...............WWWWWW..........", "...............WWWWW...........", "...............WWWW............", "...............WWW.............", "...............WW..............", "...............W...............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", "...............................", "...............................", "...............................", "...............................", "...............W...............", "..............WW...............", ".............WWW...............", "............WWWW...............", "...........WWWWW...............", "..........WWWWWW...............", ".........WWWWWWW...............", "........WWWWWWWW...............", ".......WWWWWWWWW...............", "......WWWWWWWWWW...............", ".....WWWWWWWWWWW...............", "....WWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWWW..", "....WWWWWWWWWWWWWWWWWWWWWWWWW..", ".....WWWWWWWWWWW...............", "......WWWWWWWWWW...............", ".......WWWWWWWWW...............", "........WWWWWWWW...............", ".........WWWWWWW...............", "..........WWWWWW...............", "...........WWWWW...............", "............WWWW...............", ".............WWW...............", "..............WW...............", "...............W...............", "...............................", "...............................", "...............................", "...............................", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", ".............WWWWW.............", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "....WWWWWWWWWWWWWWWWWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWW.WWWWWWWW.......", "......WWWWWWWW...WWWWWWWW......", ".....WWWWWWWW.....WWWWWWWW.....", "....WWWWWWWW.......WWWWWWWW....", "...WWWWWWWW.........WWWWWWWW...", "..WWWWWWWW...........WWWWWWWW..", ".WWWWWWWW.............WWWWWWWW.", "..WWWWWWWW...........WWWWWWWW..", "...WWWWWWWW.........WWWWWWWW...", "....WWWWWWWW.......WWWWWWWW....", ".....WWWWWWWW.....WWWWWWWW.....", "......WWWWWWWW...WWWWWWWW......", ".......WWWWWWWW.WWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWW.WWWWWWWW.......", "......WWWWWWWW...WWWWWWWW......", ".....WWWWWWWW.....WWWWWWWW.....", "....WWWWWWWW.......WWWWWWWW....", "...WWWWWWWW.........WWWWWWWW...", "..WWWWWWWW...........WWWWWWWW..", ".WWWWWWWW.............WWWWWWWW.", "..WWWWWWWW...........WWWWWWWW..", "...WWWWWWWW.........WWWWWWWW...", "....WWWWWWWW.......WWWWWWWW....", ".....WWWWWWWW.....WWWWWWWW.....", "......WWWWWWWW...WWWWWWWW......", ".......WWWWWWWW.WWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWW.......WWWWWWWW....", "...WWWWWWWWW.......WWWWWWWWW...", "..WWWWWWWWWW.......WWWWWWWWWW..", ".WWWWWWWWWWW.......WWWWWWWWWWW.", "..WWWWWWWWWW.......WWWWWWWWWW..", "...WWWWWWWWW.......WWWWWWWWW...", "....WWWWWWWW.......WWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", ".WWWWWWWWWWWWWWWWWWWWWWWWWWWWW.", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "....WWWWWWWWWWWWWWWWWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWW.......WWWW........", ".......WWWWW.......WWWWW.......", "......WWWWWW.......WWWWWW......", ".....WWWWWWW.......WWWWWWW.....", "....WWWWWWWW.......WWWWWWWW....", "...WWWWWWWWW.......WWWWWWWWW...", "..WWWWWWWWWW.......WWWWWWWWWW..", ".WWWWWWWWWWW.......WWWWWWWWWWW.", "..WWWWWWWWWW.......WWWWWWWWWW..", "...WWWWWWWWW.......WWWWWWWWW...", "....WWWWWWWW.......WWWWWWWW....", ".....WWWWWWW.......WWWWWWW.....", "......WWWWWW.......WWWWWW......", ".......WWWWW.......WWWWW.......", "........WWWW.......WWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWW...............WWWW....", "...WWWWW...............WWWWW...", "..WWWWWW...............WWWWWW..", ".WWWWWWW...............WWWWWWW.", "..WWWWWW...............WWWWWW..", "...WWWWW...............WWWWW...", "....WWWW...............WWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWW.WWWWWWW.WWW........", ".......WWW...WWWWW...WWW.......", "......WWW.....WWW.....WWW......", ".....WWW.......W.......WWW.....", "....WWWWW.............WWWWW....", "...WWWWWWW...........WWWWWWW...", "..WWWWWWWWW.........WWWWWWWWW..", ".WWWWWWWWWWW.......WWWWWWWWWWW.", "..WWWWWWWWW.........WWWWWWWWW..", "...WWWWWWW...........WWWWWWW...", "....WWWWW.............WWWWW....", ".....WWW.......W.......WWW.....", "......WWW.....WWW.....WWW......", ".......WWW...WWWWW...WWW.......", "........WWW.WWWWWWW.WWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "..............................."}; // colors for each cell state (we try to match colors used in icons) static unsigned char jvncolors[] = { 48, 48, 48, // 0 dark gray 255, 0, 0, // 1 red 255, 125, 0, // 2 orange (to match red and yellow) 255, 150, 25, // 3 lighter 255, 175, 50, // 4 lighter 255, 200, 75, // 5 lighter 255, 225, 100, // 6 lighter 255, 250, 125, // 7 lighter 251, 255, 0, // 8 yellow 89, 89, 255, // 9 blue 106, 106, 255, // 10 lighter 122, 122, 255, // 11 lighter 139, 139, 255, // 12 lighter 27, 176, 27, // 13 green 36, 200, 36, // 14 lighter 73, 255, 73, // 15 lighter 106, 255, 106, // 16 lighter 235, 36, 36, // 17 red 255, 56, 56, // 18 lighter 255, 73, 73, // 19 lighter 255, 89, 89, // 20 lighter 185, 56, 255, // 21 purple 191, 73, 255, // 22 lighter 197, 89, 255, // 23 lighter 203, 106, 255, // 24 lighter 0, 255, 128, // 25 light green 255, 128, 64, // 26 light orange 255, 255, 128, // 27 light yellow 33, 215, 215, // 28 cyan 27, 176, 176, // 29 darker 24, 156, 156, // 30 darker 21, 137, 137 // 31 darker }; static lifealgo *creator() { return new jvnalgo() ; } void jvnalgo::doInitializeAlgoInfo(staticAlgoInfo &ai) { ghashbase::doInitializeAlgoInfo(ai) ; ai.setAlgorithmName("JvN") ; ai.setAlgorithmCreator(&creator) ; ai.minstates = 29 ; ai.maxstates = 32 ; // init default color scheme ai.defgradient = false; ai.defr1 = ai.defg1 = ai.defb1 = 255; // start color = white ai.defr2 = ai.defg2 = ai.defb2 = 128; // end color = gray int numcolors = sizeof(jvncolors) / (sizeof(jvncolors[0])*3); unsigned char* rgbptr = jvncolors; for (int i = 0; i < numcolors; i++) { ai.defr[i] = *rgbptr++; ai.defg[i] = *rgbptr++; ai.defb[i] = *rgbptr++; } // init default icon data ai.defxpm7x7 = jvn7x7; ai.defxpm15x15 = jvn15x15; ai.defxpm31x31 = jvn31x31; } // ------------------- beginning of Hutton32 section ----------------------- /*** Motivation: In the original von Neumann transition rules, lines of transmission states can extend themselves by writing out binary signal trains, e.g. 10000 for extend with a right-directed ordinary transmission state (OTS). But for construction, a dual-stranded construction arm (c-arm) is needed, simply because the arm must be retracted after each write. I noticed that there was room to add the needed write-and-retract operation by modifying the transition rules slightly. This allows the machine to be greatly reduced in size and speed of replication. Another modification was made when it was noticed that the construction could be made rotationally invariant simply by basing the orientation of the written cell on the orientation of the one writing it. Instead of "write an up arrow" we have "turn left". This allows us to spawn offspring in different directions and to fill up the space with more and more copies in a manner inspired by Langton's Loops. A single OTS line can now act as a c-arm in any direction. Below are the signal trains: 100000 : move forward (write an OTS arrow in the same direction) 100010 : turn left 10100 : turn right 100001 : write a forward-directed OTS and retract 100011 : write a left-directed OTS and retract 10011 : write a reverse-directed OTS and retract 10101 : write a right-directed OTS and retract 101101 : write a forward-directed special transmission state (STS) and retract 110001 : write a left-directed STS and retract 110101 : write a reverse-directed STS and retract 111001 : write a right-directed STS and retract 1111 : write a confluent state and retract 101111 : retract Achieving these features without adding new states required making some slight changes elsewhere, though hopefully these don't affect the computation- or construction-universality of the CA. The most important effects are listed here: 1) OTS's cannot destroy STS's. This functionality was used in von Neumann's construction and read-write arms but isn't needed for the logic organs, as far as I know. The opposite operation is still enabled. 2) STS lines can only construct one cell type: an OTS in the forward direction. Some logic organs will need to be redesigned. Under this modified JvN rule, a self-replicator can be much smaller, consisting only of a tape contained within a repeater-emitter loop. One early example consisted of 5521 cells in total, and replicates in 44,201 timesteps, compared with 8 billion timesteps for the smallest known JvN-32 replicator. This became possible because the construction process runs at the same speed as a moving signal, allowing the tape to be simply stored in a repeater-emitter loop. The machine simply creates a loop of the right size (by counting tape circuits) before allowing the tape contents to fill up their new home. The rotational invariance allows the machine to make multiple copies oriented in different directions. The population growth starts off as exponential but soons slows down as the long tapes obstruct the new copies. Some context for these modifications to von Neumann's rule table: Codd simplified vN's CA to a rotationally-invariant 8 states. Langton modified this to make a self-replicating repeater-emitter, his 'loops'. Other loops were made by Sayama, Perrier, Tempesti, Byl, Chou-Reggia, and others. So there are other CA derived from vN's that support faster replication than that achieveable here, and some of them retain the computation- and construction-universality that von Neumann was considering. Our modifications are mostly a historical exploration of the possibility space around vN's CA, to explore the questions of why he made the design decisions he did. In particular, why didn't von Neumann design for a tape loop stored within a repeater-emitter? It would have made his machine much simpler from the beginning. Why didn't he consider write-and-retraction instead of designing a complicated c-arm procedure? Of course this is far from criticism of vN - his untimely death interrupted his work in this area. Some explanation of the details of the modifications is given below: The transition rules are as in Nobili32 (or JvN29), except the following: 1) The end of an OTS wire, when writing a new cell, adopts one of two states: excited OTS and excited STS, standing for bits 1 and 0 respectively. After writing the cell reverts to being an OTS. 2) A sensitized cell that is about to revert to an arrow bases its direction upon that of the excited arrow that is pointing to it. 3) A TS 'c', with a sensitized state 's' on its output that will become an OTS next (based on the state of 'c'), reverts to the ground state if any of 'c's input is 1, else it quiesces. 4) A TS 'c', with a sensitized state 's' on its output that will become a confluent state next (based on the state of 'c'), reverts to the first sensitized state S is any of 'c's input is one, else it reverts to the ground state. 5) A TS 'c', with an STS on its output, reverts to the ground state if any of 'c's input is 1. Tim Hutton , 2008 ***/ bool is_OTS(state c) { return c>=9 && c<=16; } bool is_STS(state c) { return c>=17 && c<=24; } bool is_TS(state c) { return is_OTS(c) || is_STS(c); } bool is_sensitized(state c) { return c>=1 && c<=8; } bool is_east(state c) { return c==9 || c==13 || c==17 || c==21; } bool is_north(state c) { return c==10 || c==14 || c==18 || c==22; } bool is_west(state c) { return c==11 || c==15 || c==19 || c==23; } bool is_south(state c) { return c==12 || c==16 || c==20 || c==24; } bool is_excited(state c) { return (c>=13 && c<=16) || (c>=21 && c<=24); } state dir(state c) { // return 0,1,2,3 encoding the direction of 'c': right,up,left,down return (c-9)%4; } state output(state c,state n,state s,state e,state w) // what is the state of the cell we are pointing to? { if(is_east(c)) return e; else if(is_north(c)) return n; else if(is_west(c)) return w; else if(is_south(c)) return s; else return 0; // error } state input(state n,state s,state e,state w) // what is the state of the excited cell pointing at us? { if(is_east(w) && is_excited(w)) return w; else if(is_north(s) && is_excited(s)) return s; else if(is_west(e) && is_excited(e)) return e; else if(is_south(n) && is_excited(n)) return n; else return 0; // error } bool output_will_become_OTS(state c,state n,state s,state e,state w) { return output(c,n,s,e,w)==8 || (output(c,n,s,e,w)==4 && is_excited(c)) || (output(c,n,s,e,w)==5 && !is_excited(c)); } bool output_will_become_confluent(state c,state n,state s,state e,state w) { return output(c,n,s,e,w)==7 && is_excited(c); } bool output_will_become_sensitized(state c,state n,state s,state e,state w) { int out=output(c,n,s,e,w); return ((out==0 && is_excited(c)) || out==1 || out==2 || out==3 || (out==4 && !is_OTS(c))); } bool excited_arrow_to_us(state n,state s,state e,state w) { return n==16 || n==24 || s==14 || s==22 || e==15 || e==23 || w==13 || w==21; } bool excited_OTS_to_us(state c,state n,state s,state e,state w) { // is there an excited OTS state that will hit us next? return ((n==16 || n==27 || n==28 || n==30 || n==31) && !(c==14 || c==10)) || ((s==14 || s==27 || s==28 || s==30 || s==31) && !(c==16 || c==12)) || ((e==15 || e==27 || e==28 || e==29 || e==31) && !(c==13 || c==9)) || ((w==13 || w==27 || w==28 || w==29 || w==31) && !(c==15 || c==11)); } bool excited_OTS_arrow_to_us(state c,state n,state s,state e,state w) { // is there an excited OTS arrow pointing at us? return (n==16 && !(c==14 || c==10)) || (s==14 && !(c==16 || c==12)) || (e==15 && !(c==13 || c==9)) || (w==13 && !(c==15 || c==11)); } bool OTS_arrow_to_us(state n,state s,state e,state w) { // is there an OTS arrow pointing at us? return (is_OTS(n) && is_south(n)) || (is_OTS(s) && is_north(s)) || (is_OTS(e) && is_west(e)) || (is_OTS(w) && is_east(w)); } bool excited_STS_to_us(state c,state n,state s,state e,state w) { // is there an excited STS state that will hit us next? return ((n==24 || n==27 || n==28 || n==30 || n==31) && !(c==22 || c==18)) || ((s==22 || s==27 || s==28 || s==30 || s==31) && !(c==24 || c==20)) || ((e==23 || e==27 || e==28 || e==29 || e==31) && !(c==21 || c==17)) || ((w==21 || w==27 || w==28 || w==29 || w==31) && !(c==23 || c==19)); } bool excited_STS_arrow_to_us(state c,state n,state s,state e,state w) { // is there an excited STS arrow pointing at us? return (n==24 && !(c==22 || c==18)) || (s==22 && !(c==24 || c==20)) || (e==23 && !(c==21 || c==17)) || (w==21 && !(c==23 || c==19)); } bool all_inputs_on(state n,state s,state e,state w) { return (!(n==12 || s==10 || e==11 || w==9)) && (n==16 || s==14 || e==15 || w==13); } bool is_crossing(state n,state s,state e,state w) { int n_inputs=0; if(is_south(n)) n_inputs++; if(is_east(w)) n_inputs++; if(is_west(e)) n_inputs++; if(is_north(s)) n_inputs++; int n_outputs=0; if(is_TS(n) && !is_south(n)) n_outputs++; if(is_TS(w) && !is_east(w)) n_outputs++; if(is_TS(e) && !is_west(e)) n_outputs++; if(is_TS(s) && !is_north(s)) n_outputs++; return n_inputs==2 && n_outputs==2; } state quiesce(state c) { if(((c>=13 && c<=16) || (c>=21 && c<=24))) return c-4; else if(c>=26 && c<=31) return 25; else return c; } // the update function itself state slowcalc_Hutton32(state c,state n,state s,state e,state w) { if(is_OTS(c)) { if(excited_STS_arrow_to_us(c,n,s,e,w)) return 0; // we get destroyed by the incoming excited STS else if(excited_OTS_to_us(c,n,s,e,w)) { if(output_will_become_OTS(c,n,s,e,w) || (is_STS(output(c,n,s,e,w)) && !is_excited(output(c,n,s,e,w)))) return 0; // we become the ground state (retraction) else if(output_will_become_confluent(c,n,s,e,w)) return 1; // we become sensitized by the next input (after retraction) else return quiesce(c)+4; // we become excited (usual OTS transmission) } else if(output_will_become_confluent(c,n,s,e,w)) return 0; // we become the ground state (retraction) else if(is_excited(c) && output_will_become_sensitized(c,n,s,e,w)) return quiesce(c)+12; // we become excited STS (special for end-of-wire: // means quiescent OTS, used to mark which cell is the sensitized cell's input) else return quiesce(c); } else if(is_STS(c)) { if(is_excited(c) && is_sensitized(output(c,n,s,e,w)) && OTS_arrow_to_us(n,s,e,w)) { // this cell is the special mark at the end of an OTS wire, so it behaves differently // if output is about to finalize, we revert to ground or quiescent OTS, depending on next signal // if output will remain sensitized, we change to excited OTS if next signal is 1 if(output_will_become_sensitized(c,n,s,e,w)) { if(excited_OTS_arrow_to_us(c,n,s,e,w)) return c-8; else return c; } else { if(excited_OTS_arrow_to_us(c,n,s,e,w)) return 0; // write-and-retract else return quiesce(c)-8; // revert to quiescent OTS } } else if(is_excited(c) && output(c,n,s,e,w)==0) if(excited_STS_arrow_to_us(c,n,s,e,w)) return c; // we remain excited else return quiesce(c); // we quiesce else if(excited_OTS_arrow_to_us(c,n,s,e,w)) return 0; // we get destroyed by the incoming excited OTS else if(excited_STS_to_us(c,n,s,e,w)) return quiesce(c)+4; // we become excited (usual STS transmission) else return quiesce(c); // we quiesce (usual STS transmission) } else if(c==0) { if(excited_OTS_arrow_to_us(c,n,s,e,w)) // (excludes e.g. excited confluent states) return 1; // we become sensitized else if(excited_STS_arrow_to_us(c,n,s,e,w)) return quiesce(input(n,s,e,w))-8; // directly become 'forward' OTS else return c; } else if(c==1) { if(!excited_OTS_arrow_to_us(c,n,s,e,w)) return 2; // 10 else return 3; // 11 } else if(c==2) { if(!excited_OTS_arrow_to_us(c,n,s,e,w)) return 4; // 100 else return 5; // 101 } else if(c==3) { if(!excited_OTS_arrow_to_us(c,n,s,e,w)) return 6; // 110 else return 7; // 111 } else if(c==4) { if(!excited_OTS_arrow_to_us(c,n,s,e,w)) return 8; // 1000 else return ( (quiesce(input(n,s,e,w))-9+2) % 4 )+9; // 1001: reverse } else if(c==5) { if(!excited_OTS_arrow_to_us(c,n,s,e,w)) return ( (quiesce(input(n,s,e,w))-9+3) % 4 )+9; // 1010: turn right else return quiesce(input(n,s,e,w))+8; // 1011: STS forward } else if(c==6) { if(!excited_OTS_arrow_to_us(c,n,s,e,w)) return ( (quiesce(input(n,s,e,w))-9+1) % 4 )+17; // 1100: STS turn left else return ( (quiesce(input(n,s,e,w))-9+2) % 4 )+17; // 1101: STS reverse } else if(c==7) { if(!excited_OTS_arrow_to_us(c,n,s,e,w)) return ( (quiesce(input(n,s,e,w))-9+3) % 4 )+17; // 1110: STS turn left else return 25; // 1111 } else if(c==8) { if(!excited_OTS_arrow_to_us(c,n,s,e,w)) return 9+dir(input(n,s,e,w)); // 10000: move forward else return 9+dir(input(n,s,e,w)+1); // 10001: turn left } else if(c==25) // quiescent confluent state { if(excited_STS_arrow_to_us(c,n,s,e,w)) return 0; // we get destroyed by the incoming excited STS else if(is_crossing(n,s,e,w)) // for JvN-32 crossings { if((n==16||s==14)&&(e==15||w==13)) return 31; // double crossing else if(n==16||s==14) return 30; // vertical crossing else if(e==15||w==13) return 29; // horizontal crossing else return 25; // nothing happening } else if(all_inputs_on(n,s,e,w)) return 26; else return 25; } else if(c==26) { if(excited_STS_arrow_to_us(c,n,s,e,w)) return 0; // we get destroyed by the incoming excited STS else if(all_inputs_on(n,s,e,w)) return 28; else return 27; } else if(c==27) { if(excited_STS_arrow_to_us(c,n,s,e,w)) return 0; // we get destroyed by the incoming excited STS else if(all_inputs_on(n,s,e,w)) return 26; else return 25; } else if(c==28) { if(excited_STS_arrow_to_us(c,n,s,e,w)) return 0; // we get destroyed by the incoming excited STS else if(all_inputs_on(n,s,e,w)) return 28; else return 27; } else if(c==29 || c==30 || c==31) { if(excited_STS_arrow_to_us(c,n,s,e,w)) return 0; // we get destroyed by the incoming excited STS else if((n==16||s==14)&&(e==15||w==13)) return 31; // double crossing else if(n==16||s==14) return 30; // vertical crossing else if(e==15||w==13) return 29; // horizontal crossing else return 25; // revert to quiescent confluent state } else return c; // error - should be no more states } // ------------------ end of Hutton32 section ------------------------- golly-2.7-src/gollybase/liferules.cpp0000644000175000017500000002006712536111364014704 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "liferules.h" #include "util.h" #include #include #include liferules::liferules() { canonrule[0] = 0 ; alternate_rules = 0 ; neighbormask = MOORE ; rulebits = 0 ; wolfram = 0 ; memset(rule0, 0, sizeof(rule0)) ; memset(rule1, 0, sizeof(rule1)) ; } liferules::~liferules() { } // returns a count of the number of bits set in given int static int bitcount(int v) { int r = 0 ; while (v) { r++ ; v &= v - 1 ; } return r ; } // initialize current rule table (rptr points to rule0 or rule1) void liferules::initruletable(char *rptr, int rulebits, int nmask, int wolfram) { int i ; if (wolfram >= 0) { for (i=0; i<0x1000; i = ((i | 0x888) + 1) & 0x1777) rptr[i] = (char)(1 & ((i >> 5) | (wolfram >> (i >> 8)))) ; } else { for (i=0; i<=0x777; i = (((i | 0x888) + 1) & 0x1777)) if (rulebits & (1 << (((i & 0x20) >> 1) + bitcount(i & nmask)))) rptr[i] = 1 ; else rptr[i] = 0 ; } for (i=0xfff; i>=0; i--) rptr[i] = rptr[i & 0x777] + (rptr[(i >> 1) & 0x777] << 1) ; for (i=0xffff; i>=0; i--) rptr[i] = rptr[i & 0xfff] + (rptr[(i >> 4) & 0xfff] << 4) ; } const char *liferules::setrule(const char *rulestring, lifealgo *algo) { int slashcount = 0 ; int colonpos = 0 ; int addend = 17 ; int i ; // AKT: don't allow empty string if (rulestring[0] == 0) { return "Rule cannot be empty string." ; } wolfram = -1 ; rulebits = 0 ; neighbormask = MOORE ; // we might need to emulate B0 rule by using two different rules for odd/even gens alternate_rules = false; if (rulestring[0] == 'w' || rulestring[0] == 'W') { // parse Wolfram 1D rule wolfram = 0; i = 1; while (rulestring[i] >= '0' && rulestring[i] <= '9') { wolfram = 10 * wolfram + rulestring[i] - '0' ; i++ ; } if ( wolfram < 0 || wolfram > 254 || wolfram & 1 ) { return "Wolfram rule must be an even number from 0 to 254." ; } if (rulestring[i] == ':') { colonpos = i ; } else if (rulestring[i]) { return "Bad character in Wolfram rule." ; } } else { for (i=0; rulestring[i]; i++) { if (rulestring[i] == 'h' || rulestring[i] == 'H') { neighbormask = HEXAGONAL ; } else if (rulestring[i] == 'v' || rulestring[i] == 'V') { neighbormask = VON_NEUMANN ; } else if (rulestring[i] == 'b' || rulestring[i] == 'B' || rulestring[i] == '/') { if (rulestring[i]== '/' && slashcount++ > 0) return "Only one slash permitted in life rule." ; addend = 0 ; } else if (rulestring[i] == 's' || rulestring[i] == 'S') { addend = 17 ; } else if (rulestring[i] >= '0' && rulestring[i] <= '8') { rulebits |= 1 << (addend + rulestring[i] - '0') ; } else if (rulestring[i] == ':' && i > 0) { colonpos = i ; break ; } else { // nicer to show given rulestring in error msg static std::string badrule; badrule = "Unknown rule: "; badrule += rulestring; return badrule.c_str(); } } } // AKT: check for rule suffix like ":T200,100" to specify a bounded universe if (colonpos > 0) { const char* err = algo->setgridsize(rulestring + colonpos); if (err) return err; } else { // universe is unbounded algo->gridwd = 0; algo->gridht = 0; } // maximum # of neighbors is the # of 1 bits in neighbormask, minus the central cell int maxneighbors = bitcount(neighbormask) - 1; // check if rule contains B0 if (rulebits & 1) { /* Use David Eppstein's idea to change the current rule depending on gen parity. If original rule has B0 but not S8: For even generations, whenever the original rule has a Bx or Sx, omit that bit from the modified rule, and whenever the original rule is missing a Bx or Sx, add that bit to the modified rule. eg. B03/S23 => B1245678/S0145678. For odd generations, use Bx if and only if the original rule has S(8-x) and use Sx if and only if the original rule has B(8-x). eg. B03/S23 => B56/S58. If original rule has B0 and S8: Such rules don't strobe, so we just want to invert all the cells. The trick is to do both changes: invert the bits, and swap Bx for S(8-x). eg. B03/S238 => B123478/S0123467 (for ALL gens). */ if (rulebits & (1 << (17+maxneighbors))) { // B0-and-Smax rule // change rule for all gens; eg. B03/S238 => B123478/S0123467 int newrulebits = 0; for (i=0; i<=maxneighbors; i++) { if ( (rulebits & (1 << i )) == 0 ) newrulebits |= 1 << (17+maxneighbors-i); if ( (rulebits & (1 << (17+i))) == 0 ) newrulebits |= 1 << (maxneighbors-i); } initruletable(rule0, newrulebits, neighbormask, wolfram); } else { // B0-not-Smax rule alternate_rules = true; // change rule for even gens; eg. B03/S23 => B1245678/S0145678 int newrulebits = 0; for (i=0; i<=maxneighbors; i++) { if ( (rulebits & (1 << i )) == 0 ) newrulebits |= 1 << i; if ( (rulebits & (1 << (17+i))) == 0 ) newrulebits |= 1 << (17+i); } initruletable(rule0, newrulebits, neighbormask, wolfram); // change rule for odd gens; eg. B03/S23 => B56/S58 newrulebits = 0; for (i=0; i<=maxneighbors; i++) { if ( rulebits & (1 << (17+maxneighbors-i)) ) newrulebits |= 1 << i; if ( rulebits & (1 << ( maxneighbors-i)) ) newrulebits |= 1 << (17+i); } initruletable(rule1, newrulebits, neighbormask, wolfram); } } else { // not doing B0 emulation so use rule0 for all gens initruletable(rule0, rulebits, neighbormask, wolfram); } // AKT: store valid rule in canonical format for getrule() int p = 0 ; if (wolfram >= 0) { sprintf(canonrule, "W%d", wolfram) ; while (canonrule[p]) p++ ; } else { canonrule[p++] = 'B' ; for (i=0; i<=maxneighbors; i++) { if (rulebits & (1 << i)) canonrule[p++] = '0' + (char)i ; } canonrule[p++] = '/' ; canonrule[p++] = 'S' ; for (i=0; i<=maxneighbors; i++) { if (rulebits & (1 << (17+i))) canonrule[p++] = '0' + (char)i ; } if (neighbormask == HEXAGONAL) canonrule[p++] = 'H' ; if (neighbormask == VON_NEUMANN) canonrule[p++] = 'V' ; } if (algo->gridwd > 0 || algo->gridht > 0) { // algo->setgridsize() was successfully called above, so append suffix const char* bounds = algo->canonicalsuffix() ; int i = 0 ; while (bounds[i]) canonrule[p++] = bounds[i++] ; } canonrule[p] = 0 ; return 0 ; } const char* liferules::getrule() { return canonrule ; } // B3/S23 -> (1 << 3) + (1 << (17 + 2)) + (1 << (17 + 3)) = 0x180008 bool liferules::isRegularLife() { return (neighbormask == MOORE && rulebits == 0x180008 && wolfram < 0) ; } golly-2.7-src/gollybase/readpattern.cpp0000644000175000017500000007343512536111364015232 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "readpattern.h" #include "lifealgo.h" #include "liferules.h" // for MAXRULESIZE #include "util.h" // for lifewarning and *progress calls #include #ifdef ZLIB #include #endif #include #include #define LINESIZE 20000 #define CR 13 #define LF 10 bool getedges = false; // find pattern edges? bigint top, left, bottom, right; // the pattern edges #ifdef __APPLE__ #define BUFFSIZE 4096 // 4K is best for Mac OS X #else #define BUFFSIZE 8192 // 8K is best for Windows and other platforms??? #endif #ifdef ZLIB gzFile zinstream ; #else FILE *pattfile ; #endif char filebuff[BUFFSIZE]; int buffpos, bytesread, prevchar; long filesize; // length of file in bytes // use buffered getchar instead of slow fgetc // don't override the "getchar" name which is likely to be a macro int mgetchar() { if (buffpos == BUFFSIZE) { double filepos; #ifdef ZLIB bytesread = gzread(zinstream, filebuff, BUFFSIZE); #if ZLIB_VERNUM >= 0x1240 // gzoffset is only available in zlib 1.2.4 or later filepos = gzoffset(zinstream); #else // use an approximation of file position if file is compressed filepos = gztell(zinstream); if (filepos > 0 && gzdirect(zinstream) == 0) filepos /= 4; #endif #else bytesread = fread(filebuff, 1, BUFFSIZE, pattfile); filepos = ftell(pattfile); #endif buffpos = 0; lifeabortprogress(filepos / filesize, ""); } if (buffpos >= bytesread) return EOF; return filebuff[buffpos++]; } // use getline instead of fgets so we can handle DOS/Mac/Unix line endings char *getline(char *line, int maxlinelen) { int i = 0; while (i < maxlinelen) { int ch = mgetchar(); if (isaborted()) return NULL; switch (ch) { case CR: prevchar = CR; line[i] = 0; return line; case LF: if (prevchar != CR) { prevchar = LF; line[i] = 0; return line; } // if CR+LF (DOS) then ignore the LF break; case EOF: if (i == 0) return NULL; line[i] = 0; return line; default: prevchar = ch; line[i++] = (char) ch; break; } } line[i] = 0; // silently truncate long line return line; } const char *SETCELLERROR = "Impossible; set cell error for state 1" ; // Read a text pattern like "...ooo$$$ooo" where '.', ',' and chars <= ' ' // represent dead cells, '$' represents 10 dead cells, and all other chars // represent live cells. const char *readtextpattern(lifealgo &imp, char *line) { int x=0, y=0; char *p; do { for (p = line; *p; p++) { if (*p == '.' || *p == ',' || *p <= ' ') { x++; } else if (*p == '$') { x += 10; } else { if (imp.setcell(x, y, 1) < 0) { return SETCELLERROR ; } x++; } } y++ ; if (getedges && right.toint() < x - 1) right = x - 1; x = 0; } while (getline(line, LINESIZE)); if (getedges) bottom = y - 1; return 0 ; } /* * Parse "#CXRLE key=value key=value ..." line and extract values. */ void ParseXRLELine(char *line, int *xoff, int *yoff, bool *sawpos, bigint &gen) { char *key = line; while (key) { // set key to start of next key word while (*key && *key != ' ') key++; while (*key == ' ') key++; if (*key == 0) return; // set value to pos of char after next '=' char *value = key; while (*value && *value != '=') value++; if (*value == 0) return; value++; if (strncmp(key, "Pos", 3) == 0) { // extract Pos=int,int sscanf(value, "%d,%d", xoff, yoff); *sawpos = true; } else if (strncmp(key, "Gen", 3) == 0) { // extract Gen=bigint char *p = value; while (*p >= '0' && *p <= '9') p++; char savech = *p; *p = 0; gen = bigint(value); *p = savech; value = p; } key = value; } } /* * Read an RLE pattern into given life algorithm implementation. */ const char *readrle(lifealgo &imp, char *line) { int n=0, x=0, y=0 ; char *p ; char *ruleptr; const char *errmsg; int wd=0, ht=0, xoff=0, yoff=0; bigint gen = bigint::zero; bool sawpos = false; // xoff and yoff set in ParseXRLELine? bool sawrule = false; // saw explicit rule? // parse any #CXRLE line(s) at start while (strncmp(line, "#CXRLE", 6) == 0) { ParseXRLELine(line, &xoff, &yoff, &sawpos, gen); imp.setGeneration(gen); if (getline(line, LINESIZE) == NULL) return 0; } do { if (line[0] == '#') { if (line[1] == 'r') { ruleptr = line; ruleptr += 2; while (*ruleptr && *ruleptr <= ' ') ruleptr++; p = ruleptr; while (*p > ' ') p++; *p = 0; errmsg = imp.setrule(ruleptr); if (errmsg) return errmsg; sawrule = true; } // there's a slight ambiguity here for extended RLE when a line // starts with 'x'; we only treat it as a dimension line if the // next char is whitespace or '=', since 'x' will only otherwise // occur as a two-char token followed by an upper case alphabetic. } else if (line[0] == 'x' && (line[1] <= ' ' || line[1] == '=')) { // extract wd and ht p = line; while (*p && *p != '=') p++; p++; sscanf(p, "%d", &wd); while (*p && *p != '=') p++; p++; sscanf(p, "%d", &ht); while (*p && *p != 'r') p++; if (strncmp(p, "rule", 4) == 0) { p += 4; while (*p && (*p <= ' ' || *p == '=')) p++; ruleptr = p; while (*p > ' ') p++; // remove any comma at end of rule if (p[-1] == ',') p--; *p = 0; errmsg = imp.setrule(ruleptr); if (errmsg) return errmsg; sawrule = true; } if (!sawrule) { // if no rule given then try Conway's Life; if it fails then // return error so Golly will look for matching algo errmsg = imp.setrule("B3/S23"); if (errmsg) return errmsg; } // imp.setrule() has set imp.gridwd and imp.gridht if (!sawpos && (imp.gridwd > 0 || imp.gridht > 0)) { // position pattern at top left corner of bounded grid xoff = -int(imp.gridwd / 2); yoff = -int(imp.gridht / 2); } if (getedges) { top = yoff; left = xoff; bottom = yoff + ht - 1; right = xoff + wd - 1; } } else { n = 0 ; for (p=line; *p; p++) { char c = *p ; if ('0' <= c && c <= '9') { n = n * 10 + c - '0' ; } else { if (n == 0) n = 1 ; if (c == 'b' || c == '.') { x += n ; } else if (c == '$') { x = 0 ; y += n ; } else if (c == '!') { return 0; } else if (('o' <= c && c <= 'y') || ('A' <= c && c <= 'X')) { int state = -1 ; if (c == 'o') state = 1 ; else if (c < 'o') { state = c - 'A' + 1 ; } else { state = 24 * (c - 'p' + 1) ; p++ ; c = *p ; if ('A' <= c && c <= 'X') { state = state + c - 'A' + 1 ; } else { // return "Illegal multi-char state" ; // be more forgiving so we can read non-standard rle files like // those at http://home.interserv.com/~mniemiec/lifepage.htm state = 1 ; p-- ; } } while (n-- > 0) { if (imp.setcell(xoff + x++, yoff + y, state) < 0) return "Cell state out of range for this algorithm" ; } } n = 0 ; } } } } while (getline(line, LINESIZE)); return 0; } /* * This ugly bit of code will go undocumented. It reads Alan Hensel's * PC Life format, either 1.05 or 1.06. */ const char *readpclife(lifealgo &imp, char *line) { int x=0, y=0 ; int leftx = x ; char *p ; char *ruleptr; const char *errmsg; bool sawrule = false; // saw explicit rule? do { if (line[0] == '#') { if (line[1] == 'P') { if (!sawrule) { // if no rule given then try Conway's Life; if it fails then // return error so Golly will look for matching algo errmsg = imp.setrule("B3/S23"); if (errmsg) return errmsg; sawrule = true; // in case there are many #P lines } sscanf(line + 2, " %d %d", &x, &y) ; leftx = x ; } else if (line[1] == 'N') { errmsg = imp.setrule("B3/S23"); if (errmsg) return errmsg; sawrule = true; } else if (line[1] == 'R') { ruleptr = line; ruleptr += 2; while (*ruleptr && *ruleptr <= ' ') ruleptr++; p = ruleptr; while (*p > ' ') p++; *p = 0; errmsg = imp.setrule(ruleptr); if (errmsg) return errmsg; sawrule = true; } } else if (line[0] == '-' || ('0' <= line[0] && line[0] <= '9')) { sscanf(line, "%d %d", &x, &y) ; if (imp.setcell(x, y, 1) < 0) return SETCELLERROR ; } else if (line[0] == '.' || line[0] == '*') { for (p = line; *p; p++) { if (*p == '*') { if (imp.setcell(x, y, 1) < 0) return SETCELLERROR ; } x++ ; } x = leftx ; y++ ; } } while (getline(line, LINESIZE)); return 0; } /* * This routine reads David Bell's dblife format. */ const char *readdblife(lifealgo &imp, char *line) { int n=0, x=0, y=0; char *p; while (getline(line, LINESIZE)) { if (line[0] != '!') { // parse line like "23.O15.3O15.3O15.O4.4O" n = x = 0; for (p=line; *p; p++) { if ('0' <= *p && *p <= '9') { n = n * 10 + *p - '0'; } else { if (n == 0) n = 1; if (*p == '.') { x += n; } else if (*p == 'O') { while (n-- > 0) if (imp.setcell(x++, y, 1) < 0) return SETCELLERROR ; } else { // ignore dblife commands like "5k10h@" } n = 0; } } y++; } } return 0; } // // Read Mirek Wojtowicz's MCell format. // See http://psoup.math.wisc.edu/mcell/ca_files_formats.html for details. // const char *readmcell(lifealgo &imp, char *line) { int x = 0, y = 0; int wd = 0, ht = 0; // bounded if > 0 int wrapped = 0; // plane if 0, torus if 1 char *p; const char *errmsg; bool sawrule = false; // saw explicit rule? bool extendedHL = false; // special-case rule translation for extended HistoricalLife rules while (getline(line, LINESIZE)) { if (line[0] == '#') { if (line[1] == 'L' && line[2] == ' ') { if (!sawrule) { // if no rule given then try Conway's Life; if it fails then // return error so Golly will look for matching algo errmsg = imp.setrule("B3/S23"); if (errmsg) return errmsg; sawrule = true; } int n = 0; for (p=line+3; *p; p++) { char c = *p; if ('0' <= c && c <= '9') { n = n * 10 + c - '0'; } else if (c > ' ') { if (n == 0) n = 1; if (c == '.') { x += n; } else if (c == '$') { x = -(wd/2); y += n; } else { int state = 0; if ('a' <= c && c <= 'j') { state = 24 * (c - 'a' + 1); p++; c = *p; } if ('A' <= c && c <= 'X') { state = state + c - 'A' + 1; if (extendedHL) { // adjust marked states for LifeHistory if (state == 8) state = 4; else if (state == 3) state = 5; else if (state == 5) state = 3; } } else { return "Illegal multi-char state"; } while (n-- > 0) { if (imp.setcell(x++, y, state) < 0) return "Cell state out of range"; } } n = 0; } } // look for bounded universe } else if (strncmp(line, "#BOARD ", 7) == 0) { sscanf(line + 7, "%dx%d", &wd, &ht); // write pattern in top left corner initially // (pattern will be shifted to middle of grid below) x = -(wd/2); y = -(ht/2); // look for topology } else if (strncmp(line, "#WRAP ", 6) == 0) { sscanf(line + 6, "%d", &wrapped); // we allow lines like "#GOLLY WireWorld" } else if (!sawrule && (strncmp(line, "#GOLLY", 6) == 0 || strncmp(line, "#RULE", 5) == 0) ) { if (strncmp(line, "#RULE 1,0,1,0,0,0,1,0,0,0,0,0,0,2,2,1,1,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2", 69) == 0) { // standard HistoricalLife rule -- all states transfer directly to LifeHistory if (strncmp(line, "#RULE 1,0,1,0,0,0,1,0,0,0,0,0,0,2,2,1,1,2,2,2,2,2,0,2,2,2,1,2,2,2,2,2,", 70) == 0) { // special case: Brice Due's extended HistoricalLife rules have // non-contiguous states (State 8 but no State 4, 6, or 7) // that need translating to work in LifeHistory) extendedHL = true; } errmsg = imp.setrule("LifeHistory"); if (errmsg) return errmsg; sawrule = true; } else if (strncmp(line, "#RULE 1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1", 40) == 0) { errmsg = imp.setrule("B3/S23"); if (errmsg) errmsg = imp.setrule("Life"); if (errmsg) return errmsg; sawrule = true; } else { char *ruleptr = line; // skip "#GOLLY" or "#RULE" ruleptr += line[1] == 'G' ? 6 : 5; while (*ruleptr && *ruleptr <= ' ') ruleptr++; p = ruleptr; while (*p > ' ') p++; *p = 0; errmsg = imp.setrule(ruleptr); if (errmsg) return errmsg; sawrule = true; } } } } if (wd > 0 || ht > 0) { // grid is bounded, so append suitable suffix to rule char rule[MAXRULESIZE]; if (wrapped) sprintf(rule, "%s:T%d,%d", imp.getrule(), wd, ht); else sprintf(rule, "%s:P%d,%d", imp.getrule(), wd, ht); errmsg = imp.setrule(rule); if (errmsg) { // should never happen lifewarning("Bug in readmcell code!"); return errmsg; } // shift pattern to middle of bounded grid imp.endofpattern(); if (!imp.isEmpty()) { imp.findedges(&top, &left, &bottom, &right); // pattern is currently in top left corner so shift down and right // (note that we add 1 to wd and ht to get same position as MCell) int shiftx = (wd + 1 - (right.toint() - left.toint() + 1)) / 2; int shifty = (ht + 1 - (bottom.toint() - top.toint() + 1)) / 2; if (shiftx > 0 || shifty > 0) { for (y = bottom.toint(); y >= top.toint(); y--) { for (x = right.toint(); x >= left.toint(); x--) { int state = imp.getcell(x, y); if (state > 0) { imp.setcell(x, y, 0); imp.setcell(x+shiftx, y+shifty, state); } } } } } } return 0; } long getfilesize(const char *filename) { long flen = 0; FILE *f = fopen(filename, "r"); if (f != 0) { fseek(f, 0L, SEEK_END); flen = ftell(f); fclose(f); } return flen; } // This function guesses whether `line' is the start of a headerless Life RLE // pattern. It is used to distinguish headerless RLE from plain text patterns. static bool isplainrle(const char *line) { // Find end of line, or terminating '!' character, whichever comes first: const char *end = line; while (*end && *end != '!') ++end; // Verify that '!' (if present) is the final printable character: if (*end == '!') { for (const char *p = end + 1; *p; ++p) { if ((unsigned)*p > ' ') { return false; } } } // Ensure line consists of valid tokens: bool prev_digit = false, have_digit = false; for (const char *p = line; p != end; ++p) { if ((unsigned)*p <= ' ') { if (prev_digit) return false; // space inside token! } else if (*p >= '0' && *p <= '9') { prev_digit = have_digit = true; } else if (*p == 'b' || *p == 'o' || *p == '$') { prev_digit = false; } else { return false; // unsupported printable character encountered! } } if (prev_digit) return false; // end of line inside token! // Everything seems parseable; assume this is RLE if either we saw some // digits, or the pattern ends with a '!', both of which are unlikely to // occur in plain text patterns: return have_digit || *end == '!'; } const char *loadpattern(lifealgo &imp) { char line[LINESIZE + 1] ; const char *errmsg = 0; // set rule to Conway's Life (default if explicit rule isn't supplied, // such as a text pattern like "...ooo$$$ooo") const char *err = imp.setrule("B3/S23") ; if (err) { // try "Life" in case given algo is RuleLoader and a // Life.table/tree file exists (nicer for loading lexicon patterns) err = imp.setrule("Life"); if (err) { // if given algo doesn't support B3/S23 or Life then the only sensible // choice left is to use the algo's default rule imp.setrule( imp.DefaultRule() ) ; } } if (getedges) lifebeginprogress("Reading from clipboard"); else lifebeginprogress("Reading pattern file"); // skip any blank lines at start to avoid problem when copying pattern // from Internet Explorer while (getline(line, LINESIZE) && line[0] == 0) ; // test for 'i' to cater for #LLAB comment in LifeLab file if (line[0] == '#' && line[1] == 'L' && line[2] == 'i') { errmsg = readpclife(imp, line) ; if (errmsg == 0) { imp.endofpattern() ; if (getedges && !imp.isEmpty()) { imp.findedges(&top, &left, &bottom, &right) ; } } } else if (line[0] == '#' && line[1] == 'P' && line[2] == ' ') { // WinLifeSearch creates clipboard patterns similar to // Life 1.05 format but without the header line errmsg = readpclife(imp, line) ; if (errmsg == 0) { imp.endofpattern() ; if (getedges && !imp.isEmpty()) { imp.findedges(&top, &left, &bottom, &right) ; } } } else if (line[0] == '#' && line[1] == 'M' && line[2] == 'C' && line[3] == 'e' && line[4] == 'l' && line[5] == 'l' ) { errmsg = readmcell(imp, line) ; if (errmsg == 0) { imp.endofpattern() ; if (getedges && !imp.isEmpty()) { imp.findedges(&top, &left, &bottom, &right) ; } } } else if (line[0] == '#' || line[0] == 'x') { errmsg = readrle(imp, line) ; if (errmsg == 0) { imp.endofpattern() ; if (getedges && !imp.isEmpty()) { // readrle has set top,left,bottom,right based on the info given in // the header line and possibly a "#CXRLE Pos=..." line, but in case // that info is incorrect we find the true pattern edges and expand // top/left/bottom/right if necessary to avoid truncating the pattern bigint t, l, b, r ; imp.findedges(&t, &l, &b, &r) ; if (t < top) top = t ; if (l < left) left = l ; if (b > bottom) bottom = b ; if (r > right) right = r ; } } } else if (line[0] == '!') { errmsg = readdblife(imp, line) ; if (errmsg == 0) { imp.endofpattern() ; if (getedges && !imp.isEmpty()) { imp.findedges(&top, &left, &bottom, &right) ; } } } else if (line[0] == '[') { errmsg = imp.readmacrocell(line) ; if (errmsg == 0) { imp.endofpattern() ; if (getedges && !imp.isEmpty()) { imp.findedges(&top, &left, &bottom, &right) ; } } } else if (isplainrle(line)) { errmsg = readrle(imp, line) ; if (errmsg == 0) { imp.endofpattern() ; if (getedges && !imp.isEmpty()) { imp.findedges(&top, &left, &bottom, &right) ; } } } else { // read a text pattern like "...ooo$$$ooo" errmsg = readtextpattern(imp, line) ; if (errmsg == 0) { imp.endofpattern() ; // if getedges is true then readtextpattern has set top,left,bottom,right } } lifeendprogress(); return errmsg ; } const char *build_err_str(const char *filename) { static char file_err_str[2048]; sprintf(file_err_str, "Can't open pattern file:\n%s", filename); return file_err_str; } const char *readpattern(const char *filename, lifealgo &imp) { filesize = getfilesize(filename); #ifdef ZLIB zinstream = gzopen(filename, "rb") ; // rb needed on Windows if (zinstream == 0) return build_err_str(filename) ; #else pattfile = fopen(filename, "r") ; if (pattfile == 0) return build_err_str(filename) ; #endif buffpos = BUFFSIZE; // for 1st getchar call prevchar = 0; // for 1st getline call const char *errmsg = loadpattern(imp) ; #ifdef ZLIB gzclose(zinstream) ; #else fclose(pattfile) ; #endif return errmsg ; } const char *readclipboard(const char *filename, lifealgo &imp, bigint *t, bigint *l, bigint *b, bigint *r) { filesize = getfilesize(filename); #ifdef ZLIB zinstream = gzopen(filename, "rb") ; // rb needed on Windows if (zinstream == 0) return "Can't open clipboard file!" ; #else pattfile = fopen(filename, "r") ; if (pattfile == 0) return "Can't open clipboard file!" ; #endif buffpos = BUFFSIZE; // for 1st getchar call prevchar = 0; // for 1st getline call top = 0; left = 0; bottom = 0; right = 0; getedges = true; const char *errmsg = loadpattern(imp); getedges = false; *t = top; *l = left; *b = bottom; *r = right; // make sure we return a valid rect if (bottom < top) *b = top; if (right < left) *r = left; #ifdef ZLIB gzclose(zinstream) ; #else fclose(pattfile) ; #endif return errmsg ; } const char *readcomments(const char *filename, char **commptr) { // allocate a 128K buffer for storing comment data (big enough // for the comments in Dean Hickerson's stamp collection) const int maxcommlen = 128 * 1024; *commptr = (char *)malloc(maxcommlen); if (*commptr == NULL) { return "Not enough memory for comments!"; } char *cptr = *commptr; cptr[0] = 0; // safer to init to empty string filesize = getfilesize(filename); #ifdef ZLIB zinstream = gzopen(filename, "rb") ; // rb needed on Windows if (zinstream == 0) return build_err_str(filename) ; #else pattfile = fopen(filename, "r") ; if (pattfile == 0) return build_err_str(filename) ; #endif char line[LINESIZE + 1] ; buffpos = BUFFSIZE; // for 1st getchar call prevchar = 0; // for 1st getline call int commlen = 0; // loading comments is likely to be quite fast so no real need to // display the progress dialog, but getchar calls lifeabortprogress // so safer just to assume the progress dialog might appear lifebeginprogress("Loading comments"); // skip any blank lines at start to avoid problem when copying pattern // from Internet Explorer while (getline(line, LINESIZE) && line[0] == 0) ; // test for 'i' to cater for #LLAB comment in LifeLab file if (line[0] == '#' && line[1] == 'L' && line[2] == 'i') { // extract comment lines from Life 1.05/1.06 file int linecount = 0; while (linecount < 10000) { linecount++; if (line[0] == '#' && !(line[1] == 'P' && line[2] == ' ') && !(line[1] == 'N' && line[2] == 0)) { int linelen = (int)strlen(line); if (commlen + linelen + 1 > maxcommlen) break; strncpy(cptr + commlen, line, linelen); commlen += linelen; cptr[commlen] = '\n'; // getline strips off eol char(s) commlen++; } if (getline(line, LINESIZE) == NULL) break; } } else if (line[0] == '#' && line[1] == 'M' && line[2] == 'C' && line[3] == 'e' && line[4] == 'l' && line[5] == 'l' ) { // extract "#D ..." lines from MCell file while (getline(line, LINESIZE)) { if (line[0] != '#') break; if (line[1] == 'L' && line[2] == ' ') break; if (line[1] == 'D' && (line[2] == ' ' || line[2] == 0)) { int linelen = (int)strlen(line); if (commlen + linelen + 1 > maxcommlen) break; strncpy(cptr + commlen, line, linelen); commlen += linelen; cptr[commlen] = '\n'; // getline strips off eol char(s) commlen++; } } } else if (line[0] == '#' || line[0] == 'x') { // extract comment lines from RLE file while (line[0] == '#') { int linelen = (int)strlen(line); if (commlen + linelen + 1 > maxcommlen) break; strncpy(cptr + commlen, line, linelen); commlen += linelen; cptr[commlen] = '\n'; // getline strips off eol char(s) commlen++; if (getline(line, LINESIZE) == NULL) break; } // also look for any lines after "!" but only if file is < 1MB // (ZLIB doesn't seem to provide a fast way to go to eof) if (filesize < 1024*1024) { bool foundexcl = false; while (getline(line, LINESIZE)) { if (strrchr(line, '!')) { foundexcl = true; break; } } if (foundexcl) { while (getline(line, LINESIZE)) { int linelen = (int)strlen(line); if (commlen + linelen + 1 > maxcommlen) break; strncpy(cptr + commlen, line, linelen); commlen += linelen; cptr[commlen] = '\n'; // getline strips off eol char(s) commlen++; } } } } else if (line[0] == '!') { // extract "!..." lines from dblife file while (line[0] == '!') { int linelen = (int)strlen(line); if (commlen + linelen + 1 > maxcommlen) break; strncpy(cptr + commlen, line, linelen); commlen += linelen; cptr[commlen] = '\n'; // getline strips off eol char(s) commlen++; if (getline(line, LINESIZE) == NULL) break; } } else if (line[0] == '[') { // extract "#C..." lines from macrocell file while (getline(line, LINESIZE)) { if (line[0] != '#') break; if (line[1] == 'C') { int linelen = (int)strlen(line); if (commlen + linelen + 1 > maxcommlen) break; strncpy(cptr + commlen, line, linelen); commlen += linelen; cptr[commlen] = '\n'; // getline strips off eol char(s) commlen++; } } } else { // no comments in text pattern file??? } lifeendprogress(); if (commlen == maxcommlen) commlen--; cptr[commlen] = 0; #ifdef ZLIB gzclose(zinstream) ; #else fclose(pattfile) ; #endif return 0 ; } golly-2.7-src/gollybase/bigint.h0000644000175000017500000001541512536111364013634 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /** * Class bigint manages signed bigints using a very Lisp-ish approach. * Integers from -0x40000000 through 0x3fffffff are represented * by a direct instance of this four-byte class, with the lowest * bit set. Integers outside that range use a pointer to an * integer array; the first element is how many elements of * that array are used. The array itself is always a power of * two in size, the smallest power of two greater than * the number of used elements. * * The value of the bigint, when represented as a vector, is * always sum 1<=i<=v.p[0] 2^(31*(i-1))*v.p[i] * * You can use this as a value class, in which case it may do a * lot of allocation/deallocation during copy and assignment, or * (preferably, for efficiency) you can use it as a mutating * class, with +=, -=, and the like operators that will not * allocate/free unnecessarily. * * We'll add mempool support soon. * * If we are using an int array, each holds 31 bits of the number. * All elements except the last are in the range 0..2^31-1; the * last is always either 0 or -1. * (This is an invariant; note that we have only canonical forms.) * If it is a positive number, the last element is 0; if it is * a negative number, the last element is -1. You can consider * the last element as * the sign except that the other components are in two's * complement form. * * We use a binary form (the radix is 2^31) because that makes * bit extraction faster, at the expense of decimal conversion. * But decimal conversion is not *that* onerous, so this is * okay. * * This code is *very* carefully written so that things like * the comparisons can be done simply; specifically, we always * have a single canonical representation of each number. * * We never use an array size smaller than 4. * * Nonnegative numbers are represented as follows: * * 0..2^30-1 Directly, shifted left one with the low bit set * 2^30..2^31-1 siz=2, low 31 bits then 0; array size is 4 * 2^31..2^62-1 size=3, two 31-bit words then 0; array size is 4 * 2^62..2^93-1 size=4, three 31-bit words then 0; array size is 8 * ... * 2^155..2^186-1 size=7, six 31-bit words than 0; array size is 8 * 2^186..2^217-1 size=8, seven 31-bit words then 0; array size is 16 * * Negative numbers are analogous: * * -1..-2^30 Directly, shifted left one with the low bit set * -2^30-1..-2^31 siz=2, low 31 bits then -1; array size is 4 * -2^31-1..-2^62 size=3, two 31-bit words then -1; array size is 4 * -2^62-1..-2^93 size=4, three 31-bit words then -1; array size is 8 * ... * -2^155-1..-2^186 size=7, six 31-bit words than -1; array size is 8 * -2^186-1..-2^217 size=8, seven 31-bit words then -1; array size is 16 * * The only upper bound on the size of these numbers is memory. * * We only provide a limited number of arithmetic operations for the * moment. (Addition, subtraction, comparison, bit extraction, * radix conversion, parsing, copying, assignment, to float, to double, * to int, to long long, minbits). */ #ifndef BIGINT_H #define BIGINT_H #ifdef _MSC_VER #if _MSC_VER < 1300 // 12xx = VC6; 13xx = VC7 #define G_INT64 __int64 #define G_MAKEINT64(x) x ## i64 #define G_INT64_FMT "I64d" #endif #endif #ifndef G_INT64 #define G_INT64 long long #define G_MAKEINT64(x) x ## LL #define G_INT64_FMT "lld" #endif class bigint { public: bigint() ; bigint(int i) ; bigint(G_INT64 i) ; bigint(const char *s) ; bigint(const bigint &a) ; ~bigint() ; bigint& operator=(const bigint &a) ; bigint& operator+=(const bigint &a) ; bigint& operator-=(const bigint &a) ; bigint& operator>>=(int i) ; bigint& operator<<=(int i) ; void mulpow2(int p) ; int operator==(const bigint &b) const ; int operator!=(const bigint &b) const ; int operator<=(const bigint &b) const ; int operator>=(const bigint &b) const ; int operator<(const bigint &b) const ; int operator>(const bigint &b) const ; int even() const ; int odd() const ; int low31() const ; // return the low 31 bits quickly int lowbitset() const ; // return the index of the lowest set bit const char *tostring(char sep=sepchar) const ; int sign() const ; // note: a should be a small positive int, say 1..10,000 void mul_smallint(int a) ; // note: a should be a small positive int, say 1..10,000 void div_smallint(int a) ; // note: a should be a small positive int, say 1..10,000 int mod_smallint(int a) ; // note: a should be a small positive int, say 1..10,000 void div2() ; // note: a may only be a *31* bit int, not just 0 or 1 // note: may only be called on arrayed bigints void add_smallint(int a) ; double todouble() const ; double toscinot() const ; int toint() const ; // static values predefined static const bigint zero, one, two, three, minint, maxint ; // how many bits required to represent this (approximately)? int bitsreq() const ; // fill in one bit per char, up to n. void tochararr(char *ar, int siz) const ; private: // note: may only be called on arrayed bigints int size() const ; // do we need to shrink it to keep it canonical? void shrink(int pos) ; void grow(int osz, int nsz) ; // note: carry may be any legal 31-bit int // note: may only be called on arrayed bigints void ripple(int carry, int pos) ; void ripple(const bigint &a, int carry) ; void ripplesub(const bigint &a, int carry) ; // make sure it's in vector form; may leave it not canonical! void vectorize(int i) ; void fromint(int i) ; void ensurework(int sz) const ; union { int i ; int *p ; } v ; static char *printbuf ; static int *work ; static int printbuflen ; static int workarrlen ; static char sepchar ; static int sepcount ; } ; #endif golly-2.7-src/gollybase/ghashbase.h0000644000175000017500000002010112536111364014271 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef GHASHBASE_H #define GHASHBASE_H #include "lifealgo.h" #include "liferules.h" /* * This class forms the basis of all hashlife-type algorithms except * the highly-optimized hlifealgo (which is most appropriate for * simple two-state automata). This more generalized class is used * for multi-state algorithms. */ /** * The size of a state. Unsigned char works for now. */ typedef unsigned char state ; /** * Nodes, like the standard hlifealgo nodes. */ struct ghnode { ghnode *next ; /* hash link */ ghnode *nw, *ne, *sw, *se ; /* constant; nw != 0 means nonjleaf */ ghnode *res ; /* cache */ } ; /* * Leaves, like the standard hlifealgo leaves. */ struct ghleaf { ghnode *next ; /* hash link */ ghnode *isghnode ; /* must always be zero for leaves */ state nw, ne, sw, se ; /* constant */ unsigned short leafpop ; /* how many set bits */ } ; /* * If it is a struct ghnode, this returns a non-zero value, otherwise it * returns a zero value. */ #define is_ghnode(n) (((ghnode *)(n))->nw) /** * Our ghashbase class. Note that this is an abstract class; you need * to expand specific methods to specialize it for a particular multi-state * automata. */ class ghashbase : public lifealgo { public: ghashbase() ; virtual ~ghashbase() ; // This is the method that computes the next generation, slowly. // This should be overridden by a deriving class. virtual state slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) = 0 ; // note that for ghashbase, clearall() releases no memory; it retains // the full cache information but just sets the current pattern to // the empty pattern. virtual void clearall() ; virtual int setcell(int x, int y, int newstate) ; virtual int getcell(int x, int y) ; virtual int nextcell(int x, int y, int &v) ; virtual void endofpattern() ; virtual void setIncrement(bigint inc) ; virtual void setIncrement(int inc) { setIncrement(bigint(inc)) ; } virtual void setGeneration(bigint gen) { generation = gen ; } virtual const bigint &getPopulation() ; virtual int isEmpty() ; virtual int hyperCapable() { return 1 ; } virtual void setMaxMemory(int m) ; virtual int getMaxMemory() { return (int)(maxmem >> 20) ; } virtual const char *setrule(const char *) ; virtual const char *getrule() { return "" ; } virtual void step() ; virtual void* getcurrentstate() { return root ; } virtual void setcurrentstate(void *n) ; /* * The contract of draw() is that it render every pixel in the * viewport precisely once. This allows us to eliminate all * flashing. Later we'll make this be damage-specific. */ virtual void draw(viewport &view, liferender &renderer) ; virtual void fit(viewport &view, int force) ; virtual void lowerRightPixel(bigint &x, bigint &y, int mag) ; virtual void findedges(bigint *t, bigint *l, bigint *b, bigint *r) ; virtual const char *readmacrocell(char *line) ; virtual const char *writeNativeFormat(std::ostream &os, char *comments) ; static void doInitializeAlgoInfo(staticAlgoInfo &) ; private: /* * Some globals representing our universe. The root is the * real root of the universe, and the depth is the depth of the * tree where 2 means that root is a ghleaf, and 3 means that the * children of root are leaves, and so on. The center of the * root is always coordinate position (0,0), so at startup the * x and y coordinates range from -4..3; in general, * -(2**depth)..(2**depth)-1. The zeroghnodea is an * array of canonical `empty-space' ghnodes at various depths. * The ngens is an input parameter which is the second power of * the number of generations to run. */ ghnode *root ; int depth ; ghnode **zeroghnodea ; int nzeros ; /* * Finally, our gc routine. We keep a `stack' of all the `roots' * we want to preserve. Nodes not reachable from here, we allow to * be freed. Same with leaves. */ ghnode **stack ; int stacksize ; g_uintptr_t hashpop, hashlimit, hashprime ; ghnode **hashtab ; int halvesdone ; int gsp ; g_uintptr_t alloced, maxmem ; ghnode *freeghnodes ; int okaytogc ; g_uintptr_t totalthings ; ghnode *ghnodeblocks ; bigint population ; bigint setincrement ; bigint pow2step ; // greatest power of two in increment int nonpow2 ; // increment / pow2step int ngens ; // log2(pow2step) int popValid, needPop, inGC ; /* * When rendering we store the relevant bits here rather than * passing them deep into recursive subroutines. */ liferender *renderer ; viewport *view ; int uviewh, uvieww, viewh, vieww, mag, pmag ; int llbits, llsize ; char *llxb, *llyb ; int hashed ; int cacheinvalid ; g_uintptr_t cellcounter ; // used when writing g_uintptr_t writecells ; // how many to write int gccount ; // how many gcs total this pattern int gcstep ; // how many gcs this step static char statusline[] ; // void resize() ; ghnode *find_ghnode(ghnode *nw, ghnode *ne, ghnode *sw, ghnode *se) ; void unhash_ghnode(ghnode *n) ; void rehash_ghnode(ghnode *n) ; ghleaf *find_ghleaf(state nw, state ne, state sw, state se) ; ghnode *getres(ghnode *n, int depth) ; ghnode *dorecurs(ghnode *n, ghnode *ne, ghnode *t, ghnode *e, int depth) ; ghnode *dorecurs_half(ghnode *n, ghnode *ne, ghnode *t, ghnode *e, int depth) ; ghleaf *dorecurs_ghleaf(ghleaf *n, ghleaf *ne, ghleaf *t, ghleaf *e) ; ghnode *newghnode() ; ghleaf *newghleaf() ; ghnode *newclearedghnode() ; ghleaf *newclearedghleaf() ; void pushroot_1() ; int ghnode_depth(ghnode *n) ; ghnode *zeroghnode(int depth) ; ghnode *pushroot(ghnode *n) ; ghnode *setbit(ghnode *n, int x, int y, int newstate, int depth) ; int getbit(ghnode *n, int x, int y, int depth) ; int nextbit(ghnode *n, int x, int y, int depth, int &v) ; ghnode *hashpattern(ghnode *root, int depth) ; ghnode *popzeros(ghnode *n) ; const bigint &calcpop(ghnode *root, int depth) ; void aftercalcpop2(ghnode *root, int depth, int cleanbigints) ; void calcPopulation(ghnode *root) ; ghnode *save(ghnode *n) ; void pop(int n) ; void clearstack() ; void clearcache() ; void gc_mark(ghnode *root, int invalidate) ; void do_gc(int invalidate) ; void clearcache(ghnode *n, int depth, int clearto) ; void new_ngens(int newval) ; int log2(unsigned int n) ; ghnode *runpattern() ; void clearrect(int x, int y, int w, int h) ; void renderbm(int x, int y) ; void fill_ll(int d) ; void drawghnode(ghnode *n, int llx, int lly, int depth, ghnode *z) ; void ensure_hashed() ; g_uintptr_t writecell(std::ostream &os, ghnode *root, int depth) ; g_uintptr_t writecell_2p1(ghnode *root, int depth) ; g_uintptr_t writecell_2p2(std::ostream &os, ghnode *root, int depth) ; void drawpixel(int x, int y); void draw4x4_1(state sw, state se, state nw, state ne, int llx, int lly) ; void draw4x4_1(ghnode *n, ghnode *z, int llx, int lly) ; // AKT: set all pixels to background color void killpixels(); } ; #endif golly-2.7-src/gollybase/ruleloaderalgo.cpp0000644000175000017500000002057112536111364015713 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "ruleloaderalgo.h" #include "util.h" // for lifegetuserrules, lifegetrulesdir, lifefatal #include // for strcmp, strchr #include // for std::string const char* noTABLEorTREE = "No @TABLE or @TREE section found in .rule file."; int ruleloaderalgo::NumCellStates() { if (rule_type == TABLE) return LocalRuleTable->NumCellStates(); else // rule_type == TREE return LocalRuleTree->NumCellStates(); } static FILE* OpenRuleFile(std::string& rulename, const char* dir) { // try to open rulename.rule in given dir std::string path = dir; int istart = (int)path.size(); path += rulename + ".rule"; // change "dangerous" characters to underscores for (unsigned int i=istart; iNumCellStates(); grid_type = LocalRuleTable->getgridtype(); gridwd = LocalRuleTable->gridwd; gridht = LocalRuleTable->gridht; gridleft = LocalRuleTable->gridleft; gridright = LocalRuleTable->gridright; gridtop = LocalRuleTable->gridtop; gridbottom = LocalRuleTable->gridbottom; boundedplane = LocalRuleTable->boundedplane; sphere = LocalRuleTable->sphere; htwist = LocalRuleTable->htwist; vtwist = LocalRuleTable->vtwist; hshift = LocalRuleTable->hshift; vshift = LocalRuleTable->vshift; } else { // rule_type == TREE maxCellStates = LocalRuleTree->NumCellStates(); grid_type = LocalRuleTree->getgridtype(); gridwd = LocalRuleTree->gridwd; gridht = LocalRuleTree->gridht; gridleft = LocalRuleTree->gridleft; gridright = LocalRuleTree->gridright; gridtop = LocalRuleTree->gridtop; gridbottom = LocalRuleTree->gridbottom; boundedplane = LocalRuleTree->boundedplane; sphere = LocalRuleTree->sphere; htwist = LocalRuleTree->htwist; vtwist = LocalRuleTree->vtwist; hshift = LocalRuleTree->hshift; vshift = LocalRuleTree->vshift; } // need to clear cache ghashbase::setrule("not used"); } const char* ruleloaderalgo::LoadTableOrTree(FILE* rulefile, const char* rule) { const char *err; const int MAX_LINE_LEN = 4096; char line_buffer[MAX_LINE_LEN+1]; int lineno = 0; linereader lr(rulefile); // find line starting with @TABLE or @TREE while (lr.fgets(line_buffer,MAX_LINE_LEN) != 0) { lineno++; if (strcmp(line_buffer, "@TABLE") == 0) { err = LocalRuleTable->LoadTable(rulefile, lineno, '@', rule); // err is the result of setrule(rule) if (err == NULL) { SetAlgoVariables(TABLE); } // LoadTable has closed rulefile so don't do lr.close() return err; } if (strcmp(line_buffer, "@TREE") == 0) { err = LocalRuleTree->LoadTree(rulefile, lineno, '@', rule); // err is the result of setrule(rule) if (err == NULL) { SetAlgoVariables(TREE); } // LoadTree has closed rulefile so don't do lr.close() return err; } } lr.close(); return noTABLEorTREE; } const char* ruleloaderalgo::setrule(const char* s) { const char *err; const char *colonptr = strchr(s,':'); std::string rulename(s); if (colonptr) rulename.assign(s,colonptr); // first check if rulename is the default rule for RuleTable or RuleTree // in which case there is no need to look for a .rule/table/tree file if (LocalRuleTable->IsDefaultRule(rulename.c_str())) { LocalRuleTable->setrule(s); SetAlgoVariables(TABLE); return NULL; } if (LocalRuleTree->IsDefaultRule(rulename.c_str())) { LocalRuleTree->setrule(s); SetAlgoVariables(TREE); return NULL; } // look for .rule file in user's rules dir then in Golly's rules dir bool inuser = true; FILE* rulefile = OpenRuleFile(rulename, lifegetuserrules()); if (!rulefile) { inuser = false; rulefile = OpenRuleFile(rulename, lifegetrulesdir()); } if (rulefile) { err = LoadTableOrTree(rulefile, s); if (inuser && err && (strcmp(err, noTABLEorTREE) == 0)) { // if .rule file was found in user's rules dir but had no // @TABLE or @TREE section then we look in Golly's rules dir // (this lets user override the colors/icons in a supplied .rule // file without having to copy the entire file) rulefile = OpenRuleFile(rulename, lifegetrulesdir()); if (rulefile) err = LoadTableOrTree(rulefile, s); } return err; } // no .rule file so try to load .table file err = LocalRuleTable->setrule(s); if (err == NULL) { SetAlgoVariables(TABLE); return NULL; } // no .table file so try to load .tree file err = LocalRuleTree->setrule(s); if (err == NULL) { SetAlgoVariables(TREE); return NULL; } // make sure we show given rule string in final error msg (probably "File not found") static std::string badrule; badrule = err; badrule += "\nGiven rule: "; badrule += s; return badrule.c_str(); } const char* ruleloaderalgo::getrule() { if (rule_type == TABLE) return LocalRuleTable->getrule(); else // rule_type == TREE return LocalRuleTree->getrule(); } const char* ruleloaderalgo::DefaultRule() { // use RuleTree's default rule (B3/S23) return LocalRuleTree->DefaultRule(); } ruleloaderalgo::ruleloaderalgo() { LocalRuleTable = new ruletable_algo(); LocalRuleTree = new ruletreealgo(); if (LocalRuleTable == NULL) lifefatal("RuleLoader failed to create local RuleTable!"); if (LocalRuleTree == NULL) lifefatal("RuleLoader failed to create local RuleTree!"); // initialize rule_type LocalRuleTree->setrule( LocalRuleTree->DefaultRule() ); SetAlgoVariables(TREE); } ruleloaderalgo::~ruleloaderalgo() { delete LocalRuleTable; delete LocalRuleTree; } state ruleloaderalgo::slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) { if (rule_type == TABLE) return LocalRuleTable->slowcalc(nw, n, ne, w, c, e, sw, s, se); else // rule_type == TREE return LocalRuleTree->slowcalc(nw, n, ne, w, c, e, sw, s, se); } static lifealgo* creator() { return new ruleloaderalgo(); } void ruleloaderalgo::doInitializeAlgoInfo(staticAlgoInfo &ai) { ghashbase::doInitializeAlgoInfo(ai); ai.setAlgorithmName("RuleLoader"); ai.setAlgorithmCreator(&creator); ai.minstates = 2; ai.maxstates = 256; // init default color scheme ai.defgradient = true; // use gradient ai.defr1 = 255; // start color = red ai.defg1 = 0; ai.defb1 = 0; ai.defr2 = 255; // end color = yellow ai.defg2 = 255; ai.defb2 = 0; // if not using gradient then set all states to white for (int i=0; i<256; i++) { ai.defr[i] = ai.defg[i] = ai.defb[i] = 255; } } golly-2.7-src/gollybase/jvnalgo.h0000644000175000017500000000302312536111364014010 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef JVNALGO_H #define JVNALGO_H #include "ghashbase.h" /** * Our JvN algo class. */ class jvnalgo : public ghashbase { public: jvnalgo() ; virtual ~jvnalgo() ; virtual state slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) ; virtual const char* setrule(const char* s) ; virtual const char* getrule() ; virtual const char* DefaultRule() ; virtual int NumCellStates() ; static void doInitializeAlgoInfo(staticAlgoInfo &) ; private: enum { JvN29, Nobili32, Hutton32 } current_rule ; }; #endif golly-2.7-src/gollybase/liferender.h0000644000175000017500000000522512536111364014475 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /** * Encapsulate a class capable of rendering a life universe. * Note that we only use fill rectangle calls and blitbit calls * (no setpixel). Coordinates are in the same coordinate * system as the viewport min/max values. * * Also note that the render is responsible for deciding how * to scale bits up as necessary, whether using the graphics * hardware or the CPU. Blits will only be called with * reasonable bitmaps (32x32 or larger, probably) so the * overhead should not be horrible. Also, the bitmap must * have zeros for all pixels to the left and right of those * requested to be rendered (just for simplicity). * * If clipping is needed, it's the responsibility of these * routines, *not* the caller (although the caller should make * every effort to not call these routines with out of bound * values). */ #ifndef LIFERENDER_H #define LIFERENDER_H class liferender { public: liferender() {} virtual ~liferender() ; // killrect is used to draw background (ie. dead cells) virtual void killrect(int x, int y, int w, int h) = 0 ; // pixblit is used to draw a pixel map by passing data in two formats: // If pmscale == 1 then pm data contains 3*w*h bytes where each // byte triplet contains the rgb values for the corresponding pixel. // If pmscale > 1 then pm data contains (w/pmscale)*(h/pmscale) bytes // where each byte is a cell state (0..255). This allows the rendering // code to display either icons or colors. virtual void pixblit(int x, int y, int w, int h, char* pm, int pmscale) = 0 ; // drawing code needs access to current layer's colors virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b) = 0; } ; #endif golly-2.7-src/gollybase/qlifedraw.cpp0000644000175000017500000010121412536111364014662 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "qlifealgo.h" #include #include #include "util.h" const int logbmsize = 8 ; // *must* be 8 in this code const int bmsize = (1< 1) { rx *= pmag ; ry *= pmag ; rw *= pmag ; rh *= pmag ; } ry = uviewh - ry - rh ; // AKT: eventually we might draw directly into pixbuf rather than bigbuf if (pmag > 1) { // convert each bigbuf byte into 8 bytes of state data int j = 0; for (int i = 0; i < ibufsize * 4; i++) { int byte = bigbuf[i]; for (int bit = 128; bit > 0; bit >>= 1) { pixbuf[j++] = (byte & bit) ? 1 : 0; } } } else { // convert each bigbuf byte into 24 bytes of pixel data (8 * rgb) int j = 0; for (int i = 0; i < ibufsize * 4; i++) { int byte = bigbuf[i]; for (int bit = 128; bit > 0; bit >>= 1) { if (byte & bit) { pixbuf[j++] = liver; pixbuf[j++] = liveg; pixbuf[j++] = liveb; } else { pixbuf[j++] = deadr; pixbuf[j++] = deadg; pixbuf[j++] = deadb; } } } } renderer->pixblit(rx, ry, rw, rh, (char *)pixbuf, pmag); memset(bigbuf, 0, sizeof(ibigbuf)) ; } void qlifealgo::clearrect(int minx, int miny, int w, int h) { // minx,miny is lower left corner if (w <= 0 || h <= 0) return ; if (pmag > 1) { minx *= pmag ; miny *= pmag ; w *= pmag ; h *= pmag ; } miny = uviewh - miny - h ; renderer->killrect(minx, miny, w, h) ; } static int minlevel; /* * We cheat for now; we assume we can use 32-bit ints. We can below * a certain level; we'll deal with higher levels later. */ void qlifealgo::BlitCells(supertile *p, int xoff, int yoff, int wd, int ht, int lev) { int i, xinc=0, yinc=0, ypos, x, yy; int liveseen = 0 ; if (xoff >= vieww || xoff + wd < 0 || yoff >= viewh || yoff + ht < 0) // no part of this supertile is visible return; if (p == nullroots[lev]) { clearrect(xoff, yoff, wd, ht) ; return; } // do recursion until we get to level 2 (256x256 supertile) if (lev > 2) { if (lev & 1) { // odd level -- 8 subtiles are stacked horizontally xinc = wd = ht; } else { // even level -- 8 subtiles are stacked vertically yinc = ht = (ht >> 3); } for (i=0; i<8; i++) { BlitCells(p->d[i], xoff, yoff, wd, ht, lev-1); xoff += xinc; yoff += yinc; } return; } // walk a (probably) non-empty 256x256 supertile, finding all the 1 bits and // setting corresponding bits in the bitmap (bigbuf) liveseen = 0 ; ypos = yoff; // examine the 8 vertically stacked subtiles in this 256x256 supertile (at level 2) for (yy=0; yy<8; yy++) { if (p->d[yy] != nullroots[1] && ypos < viewh && ypos + 32 >= 0) { supertile *psub = p->d[yy]; x = xoff; // examine the 8 tiles in this 256x32 supertile (at level 1) for (i=0; i<8; i++) { if (psub->d[i] != nullroots[0] && x < vieww && x + 32 >= 0) { tile *t = (tile *)psub->d[i]; int j, k, y = ypos; // examine the 4 bricks in this 32x32 tile (at level 0) for (j=0; j<4; j++) { if (t->b[j] != emptybrick && y < viewh && y + 8 >= 0) { brick *b = t->b[j]; // examine the 8 slices (2 at a time) in the appropriate half-brick for (k=0; k<8; k+=2) { unsigned int v1 = b->d[k+kadd]; unsigned int v2 = b->d[k+kadd+1]; if (v1|v2) { // do an 8x8 set of bits (2 adjacent slices) int xd = (i<<2)+(k>>1); int yd = (7 - yy) << 10; // 1024 bytes in 256x32 supertile unsigned char *p = bigbuf + yd + xd + ((3 - j) << 8); unsigned int v3 = (((v1 & 0x0f0f0f0f) << 4) | (v2 & 0x0f0f0f0f)); v2 = ((v1 & 0xf0f0f0f0) | ((v2 >> 4) & 0x0f0f0f0f)); *p = (unsigned char)v3; p[32] = (unsigned char)v2; p[64] = (unsigned char)(v3 >> 8); p[96] = (unsigned char)(v2 >> 8); p[128] = (unsigned char)(v3 >> 16); p[160] = (unsigned char)(v2 >> 16); p[192] = (unsigned char)(v3 >> 24); p[224] = (unsigned char)(v2 >> 24); liveseen |= (1 << yy) ; } } } y += 8; // down to next brick } } x += 32; // across to next tile } } ypos += 32; // down to next subtile } if (liveseen == 0) { clearrect(xoff, yoff, wd, ht) ; return; // no live cells seen } // performance: if we want, liveseen now contains eight bits // corresponding to whether those respective 256x32 rectangles // contain set pixels or not. We should trim the bitmap // to only render those portions that need to be rendered // (using this information). -tom // // draw the non-empty bitmap, scaling up if pmag > 1 renderbm(xoff, yoff) ; } // This pattern drawing routine is used when mag > 0. // We go down to a level where what we're going to draw maps to one // of 256x256, 128x128, or 64x64. // // We no longer rely on popcount having been called; instead we invoke // the popcount child if needed. void qlifealgo::ShrinkCells(supertile *p, int xoff, int yoff, int wd, int ht, int lev) { int i ; if (lev >= bmlev) { if (xoff >= vieww || xoff + wd < 0 || yoff >= viewh || yoff + ht < 0) // no part of this supertile/tile is visible return ; if (p == nullroots[lev]) { clearrect(xoff, yoff, wd, ht) ; return ; } if (lev == bmlev) { bmleft = xoff ; bmtop = yoff ; } } else { if (p == nullroots[lev]) return ; } int bminc = -1 << (logshbmsize-3) ; unsigned char *bm = bigbuf + (((shbmsize-1)-yoff+bmtop) << (logshbmsize-3)) + ((xoff-bmleft) >> 3) ; int bit = 128 >> ((xoff-bmleft) & 7) ; // do recursion until we get to minimum level (which depends on mag) if (lev > minlevel) { int xinc = 0, yinc = 0 ; if (lev & 1) { // odd level -- 8 subtiles are stacked horizontally xinc = wd ; wd = ht ; } else { // even level -- 8 subtiles are stacked vertically yinc = ht ; ht = (ht >> 3); } int xxinc = 0 ; int yyinc = 0 ; if (yinc <= 8 && xinc == 0) { // This is a case where we need to traverse multiple nodes for a // single pixel. This can be really slow, especially if we have // to examine 4x4=16 nodes just for a single pixel! To help // mitigate that, we special-case this and do the entire square, // tracking which pixels are set and not traversing when we // would set a pixel again. xinc = yinc ; int sh = 0 ; if (xinc == 8) sh = 0 ; else if (xinc == 4) sh = 1 ; else if (xinc == 2) sh = 2 ; for (i=0; i<8; i++) { if (p->d[i] != nullroots[lev-1]) { supertile *pp = p->d[i] ; int bbit = bit ; for (int j=0; j<8; j++) { if (pp->d[j] != nullroots[lev-2]) { if (0 == (*bm & bbit)) { supertile *ppp = pp->d[j] ; if (lev > 2) { if ( ppp->pop[oddgen] != 0 ) *bm |= bbit ; } else { tile *t = (tile *)ppp ; if (t->flags & quickb) *bm |= bbit ; } } } if ((j ^ (j + 1)) >> sh) bbit >>= 1 ; } } if ((i ^ (i + 1)) >> sh) bm += bminc ; } return ; } else { for (i=0; i<8; i++) { ShrinkCells(p->d[i], xoff + (xxinc >> 3), yoff + (yyinc >> 3), wd, ht, lev-1); xxinc += xinc ; yyinc += yinc ; } if (lev == bmlev) renderbm(bmleft, bmtop, shbmsize, shbmsize) ; } } else if (mag > 4) { if (lev > 0) { // mag >= 8 if ( p->pop[oddgen] != 0 ) *bm |= bit ; } else { // mag = 5..7 tile *t = (tile *)p; if (t->flags & quickb) *bm |= bit ; } } else { switch (mag) { case 4: { // shrink 32x32 tile to 2x2 pixels tile *t = (tile *)p; if ((t->b[0] != emptybrick || t->b[1] != emptybrick) ) { brick *bt = t->b[0]; brick *bb = t->b[1]; // examine the top left 16x16 cells if ( bt->d[kadd+0] | bt->d[kadd+1] | bt->d[kadd+2] | bt->d[kadd+3] | bb->d[kadd+0] | bb->d[kadd+1] | bb->d[kadd+2] | bb->d[kadd+3] ) // shrink 16x16 cells to 1 pixel *bm |= bit ; // examine the top right 16x16 cells if ( bt->d[kadd+4] | bt->d[kadd+5] | bt->d[kadd+6] | bt->d[kadd+7] | bb->d[kadd+4] | bb->d[kadd+5] | bb->d[kadd+6] | bb->d[kadd+7] ) // shrink 16x16 cells to 1 pixel *bm |= bit >> 1 ; } bm += bminc ; if (t->b[2] != emptybrick || t->b[3] != emptybrick) { brick *bt = t->b[2]; brick *bb = t->b[3]; // examine the bottom left 16x16 cells if ( bt->d[kadd+0] | bt->d[kadd+1] | bt->d[kadd+2] | bt->d[kadd+3] | bb->d[kadd+0] | bb->d[kadd+1] | bb->d[kadd+2] | bb->d[kadd+3] ) // shrink 16x16 cells to 1 pixel *bm |= bit ; // examine the bottom right 16x16 cells if ( bt->d[kadd+4] | bt->d[kadd+5] | bt->d[kadd+6] | bt->d[kadd+7] | bb->d[kadd+4] | bb->d[kadd+5] | bb->d[kadd+6] | bb->d[kadd+7] ) // shrink 16x16 cells to 1 pixel *bm |= bit >> 1 ; } } break; case 3: { // mag = 3 so shrink 32x32 tile to 4x4 pixels tile *t = (tile *)p; int j ; // examine the 4 bricks in this 32x32 tile for (j=0; j<4; j++) { if (t->b[j] != emptybrick) { brick *b = t->b[j]; int k ; // examine the 8 slices (2 at a time) in the appropriate half-brick int bbit = bit; for (k=0; k<8; k += 2) { if ( (b->d[k+kadd] | b->d[k+kadd+1]) ) *bm |= bbit ; bbit >>= 1 ; } } bm += bminc ; } } break; case 2: { // mag = 2 so shrink 32x32 tile to 8x8 pixels tile *t = (tile *)p; int j ; // examine the 4 bricks in this 32x32 tile for (j=0; j<4; j++) { if (t->b[j] != emptybrick) { brick *b = t->b[j]; int k ; bit = 128 ; // examine the 8 slices in the appropriate half-brick for (k=0; k<8; k++) { unsigned int s = b->d[k+kadd]; // s represents a 4x8 slice so examine top and bottom halves if (s) { if (s & 0xFFFF0000) *bm |= bit ; if (s & 0x0000FFFF) bm[bminc] |= bit ; } bit >>= 1 ; } } bm += 2 * bminc ; } } break; case 1: { // mag = 1 so shrink 32x32 tile to 16x16 pixels tile *t = (tile *)p; int j ; // examine the 4 bricks in this 32x32 tile unsigned char *bmm = bm ; for (j=0; j<4; j++) { if (t->b[j] != emptybrick) { brick *b = t->b[j]; int k ; bit = 128 ; // examine the 8 slices in the appropriate half-brick for (k=0; k<8; k++) { unsigned int s = b->d[k+kadd]; if (s) { // s is a non-empty 4x8 slice so shrink each 2x2 section to 1 pixel if (s & 0xCC000000) *bmm |= bit ; if (s & 0x00CC0000) bmm[bminc] |= bit ; if (s & 0x0000CC00) bmm[bminc+bminc] |= bit ; if (s & 0x000000CC) bmm[bminc+bminc+bminc] |= bit ; bit >>= 1 ; if (s & 0x33000000) *bmm |= bit ; if (s & 0x00330000) bmm[bminc] |= bit ; if (s & 0x00003300) bmm[bminc+bminc] |= bit ; if (s & 0x00000033) bmm[bminc+bminc+bminc] |= bit ; bit >>= 1 ; } else { bit >>= 2 ; } if (bit < 1) { bmm++ ; bit = 128 ; } } bmm -= 2 ; } bmm += 4 * bminc ; } } break; } } } /* * Fill in the llxb and llyb bits from the viewport information. * Allocate if necessary. This arithmetic should be done carefully. */ void qlifealgo::fill_ll(int d) { pair coor = view->at(0, view->getymax()) ; coor.second.mul_smallint(-1) ; coor.first -= bmin ; coor.second -= bmin ; if (oddgen) { coor.first -= 1 ; coor.second -= 1 ; } int bitsreq = coor.first.bitsreq() ; int bitsreq2 = coor.second.bitsreq() ; if (bitsreq2 > bitsreq) bitsreq = bitsreq2 ; if (bitsreq <= d) bitsreq = d + 1 ; // need to access llxyb[d] if (bitsreq > llsize) { if (llsize) { delete [] llxb ; delete [] llyb ; } llxb = new char[bitsreq] ; llyb = new char[bitsreq] ; llsize = bitsreq ; } llbits = bitsreq ; coor.first.tochararr(llxb, llbits) ; coor.second.tochararr(llyb, llbits) ; } void qlifealgo::draw(viewport &viewarg, liferender &renderarg) { memset(bigbuf, 0, sizeof(ibigbuf)) ; renderer = &renderarg ; // AKT: get cell colors unsigned char *r, *g, *b; renderer->getcolors(&r, &g, &b); deadr = r[0]; deadg = g[0]; deadb = b[0]; liver = r[1]; liveg = g[1]; liveb = b[1]; view = &viewarg ; uvieww = view->getwidth() ; uviewh = view->getheight() ; oddgen = getGeneration().odd() ; kadd = oddgen ? 8 : 0 ; int xoff, yoff ; if (view->getmag() > 0) { pmag = 1 << (view->getmag()) ; mag = 0 ; viewh = ((uviewh - 1) >> view->getmag()) + 1 ; vieww = ((uvieww - 1) >> view->getmag()) + 1 ; uviewh += (-uviewh) & (pmag-1) ; } else { mag = (-view->getmag()) ; // cheat for now since unzoom is broken pmag = 1 ; viewh = uviewh ; vieww = uvieww ; } if (root == nullroots[rootlev]) { clearrect(0, 0, view->getwidth(), view->getheight()) ; renderer = 0 ; view = 0 ; return ; } int d = 5 + (rootlev + 1) / 2 * 3 ; fill_ll(d) ; int maxd = vieww ; supertile *sw = root, *nw = nullroots[rootlev], *ne = nullroots[rootlev], *se = nullroots[rootlev] ; if (viewh > maxd) maxd = viewh ; int llx=-llxb[llbits-1], lly=-llyb[llbits-1] ; /* Skip down to top of tree. */ int i; for (i=llbits-1; i>=d && i>=mag; i--) { /* go down to d, but not further than mag */ llx = (llx << 1) + llxb[i] ; lly = (lly << 1) + llyb[i] ; if (llx > 2*maxd || lly > 2*maxd || llx < -2*maxd || lly < -2*maxd) { clearrect(0, 0, vieww, viewh) ; renderer = 0 ; view = 0 ; return ; } } /* Find the lowest four we need to examine */ int curlev = rootlev ; while (d > 8 && d - mag > 2 && (d - mag > 28 || (1 << (d - mag)) > 32 * maxd)) { // d is 5 + 3 * i for some positive i llx = (llx << 3) + (llxb[d-1] << 2) + (llxb[d-2] << 1) + llxb[d-3] ; lly = (lly << 3) + (llyb[d-1] << 2) + (llyb[d-2] << 1) + llyb[d-3] ; int xp = llx ; if (xp < 0) xp = 0 ; else if (xp > 7) xp = 7 ; int yp = lly ; if (yp < 0) yp = 0 ; else if (yp > 7) yp = 7 ; if (xp == 7) { if (yp == 7) { ne = ne->d[0]->d[0] ; se = se->d[7]->d[0] ; nw = nw->d[0]->d[7] ; sw = sw->d[7]->d[7] ; } else { ne = se->d[yp+1]->d[0] ; se = se->d[yp]->d[0] ; nw = sw->d[yp+1]->d[7] ; sw = sw->d[yp]->d[7] ; } } else { if (yp == 7) { ne = nw->d[0]->d[xp+1] ; se = sw->d[7]->d[xp+1] ; nw = nw->d[0]->d[xp] ; sw = sw->d[7]->d[xp] ; } else { ne = sw->d[yp+1]->d[xp+1] ; se = sw->d[yp]->d[xp+1] ; nw = sw->d[yp+1]->d[xp] ; sw = sw->d[yp]->d[xp] ; } } llx -= xp ; lly -= yp ; if (llx > 2*maxd || lly > 2*maxd || llx < -2*maxd || lly < -2*maxd) { clearrect(0, 0, vieww, viewh) ; renderer = 0 ; view = 0 ; return ; } d -= 3 ; curlev -= 2 ; } find_set_bits(nw, curlev, oddgen) ; find_set_bits(ne, curlev, oddgen) ; find_set_bits(sw, curlev, oddgen) ; find_set_bits(se, curlev, oddgen) ; // getPopulation() ; /* At this point we know we can use 32-bit arithmetic. */ for (i=d-1; i>=mag; i--) { llx = (llx << 1) + llxb[i] ; lly = (lly << 1) + llyb[i] ; } /* now, we have four nodes to draw. the ll point in screen coordinates is given by llx/lly. the ur point in screen coordinates is given by that plus 2 << (d-mag). */ xoff = -llx ; yoff = -lly ; int wd = 2 ; if (d >= mag) wd = 2 << (d-mag) ; int yoffuht = yoff + wd ; int xoffuwd = xoff + wd ; if (yoff >= viewh || xoff >= vieww || yoffuht < 0 || xoffuwd < 0) { clearrect(0, 0, view->getwidth(), view->getheight()) ; renderer = 0 ; view = 0 ; return ; } if (yoff > 0) clearrect(0, 0, vieww, yoff) ; if (xoff > 0) clearrect(0, yoff, xoff, wd) ; if (yoffuht < viewh) clearrect(0, yoffuht, vieww, viewh-yoffuht) ; if (xoffuwd < vieww) clearrect(xoffuwd, yoff, vieww-xoffuwd, wd) ; int levsize = wd / 2 ; // do recursive drawing quickb = 0xfff << (8 + oddgen * 12) ; if (mag > 0) { bmlev = (1 + mag / 3) * 2 ; logshbmsize = 8 - (mag % 3) ; shbmsize = 1 << logshbmsize ; if (mag < 5) { // recurse down to 32x32 tiles minlevel = 0; } else { // if mag = 5..7 minlevel = 0 (32x32 tiles) // if mag = 8..10 minlevel = 2 (256x256 supertiles) // if mag = 11..13 minlevel = 4 (2048x2048 supertiles) etc... minlevel = ((mag - 5) / 3) * 2; } bmleft = xoff ; bmtop = yoff ; ShrinkCells(sw, xoff, yoff, levsize, levsize, curlev); ShrinkCells(se, xoff+levsize, yoff, levsize, levsize, curlev); ShrinkCells(nw, xoff, yoff+levsize, levsize, levsize, curlev); ShrinkCells(ne, xoff+levsize, yoff+levsize, levsize, levsize, curlev); if (bmlev > curlev) renderbm(bmleft, bmtop, shbmsize, shbmsize) ; } else { // recurse down to 256x256 supertiles and use bitmap blitting BlitCells(sw, xoff, yoff, levsize, levsize, curlev); BlitCells(se, xoff+levsize, yoff, levsize, levsize, curlev); BlitCells(nw, xoff, yoff+levsize, levsize, levsize, curlev); BlitCells(ne, xoff+levsize, yoff+levsize, levsize, levsize, curlev); } renderer = 0 ; view = 0 ; } /** * Find the subsupertiles with the smallest indices. */ int qlifealgo::lowsub(vector &src, vector &dst, int lev) { int lowlev = 7 ; dst.clear() ; supertile *z = nullroots[lev-1] ; if (lev > 1) { for (int i=0; i<(int)src.size(); i++) { supertile *p = src[i] ; for (int j=0; jd[j] != z && (p->d[j]->pop[oddgen])) { lowlev = j ; dst.clear() ; } if (p->d[lowlev] != z && (p->d[lowlev]->pop[oddgen])) dst.push_back(p->d[lowlev]) ; } } else { for (int i=0; i<(int)src.size(); i++) { supertile *p = src[i] ; for (int j=0; jd[j] != z && (((tile *)(p->d[j]))->flags & quickb)) { lowlev = j ; dst.clear() ; } if (p->d[lowlev] != z && (((tile *)(p->d[lowlev]))->flags & quickb)) dst.push_back(p->d[lowlev]) ; } } return lowlev ; } /** * Find the subsupertiles with the highest indices. */ int qlifealgo::highsub(vector &src, vector &dst, int lev) { int highlev = 0 ; dst.clear() ; supertile *z = nullroots[lev-1] ; if (lev > 1) { for (int i=0; i<(int)src.size(); i++) { supertile *p = src[i] ; for (int j=7; j>highlev; j--) if (p->d[j] != z && (p->d[j]->pop[oddgen])) { highlev = j ; dst.clear() ; } if (p->d[highlev] != z && (p->d[highlev]->pop[oddgen])) dst.push_back(p->d[highlev]) ; } } else { for (int i=0; i<(int)src.size(); i++) { supertile *p = src[i] ; for (int j=7; j>highlev; j--) if (p->d[j] != z && (((tile *)(p->d[j]))->flags & quickb)) { highlev = j ; dst.clear() ; } if (p->d[highlev] != z && (((tile *)(p->d[highlev]))->flags & quickb)) dst.push_back(p->d[highlev]) ; } } return highlev ; } /** * Find all nonzero sub-supertiles. */ void qlifealgo::allsub(vector &src, vector &dst, int lev) { dst.clear() ; supertile *z = nullroots[lev-1] ; if (lev > 1) { for (int i=0; i<(int)src.size(); i++) { supertile *p = src[i] ; for (int j=0; j<8; j++) if (p->d[j] != z && (p->d[j]->pop[oddgen])) dst.push_back(p->d[j]) ; } } else { for (int i=0; i<(int)src.size(); i++) { supertile *p = src[i] ; for (int j=0; j<8; j++) if (p->d[j] != z && (((tile *)(p->d[j]))->flags & quickb)) dst.push_back(p->d[j]) ; } } } int qlifealgo::gethbitsfromleaves(vector v) { int h[8] ; int i; for (i=0; i<8; i++) h[i] = 0 ; for (i=0; i<(int)v.size(); i++) { tile *p = (tile *)v[i] ; for (int j=0; j<4; j++) if (p->b[j] != emptybrick) for (int k=0; k<8; k++) h[k] |= p->b[j]->d[k+kadd] ; } int r = 0 ; for (i=0; i<8; i++) { int v = h[i] ; v |= (v >> 16) ; v |= (v >> 8) ; v |= (v >> 4) ; r = (r << 4) | (v & 15) ; } return r ; } int qlifealgo::getvbitsfromleaves(vector vec) { int v[4] ; int i; for (i=0; i<4; i++) v[i] = 0 ; for (i=0; i<(int)vec.size(); i++) { tile *p = (tile *)vec[i] ; for (int j=0; j<4; j++) if (p->b[j] != emptybrick) for (int k=0; k<8; k++) v[j] |= p->b[j]->d[k+kadd] ; } int r = 0 ; for (i=3; i>=0; i--) { int vv = v[i] ; for (int j=0; j<8; j++) { r += r ; if (vv & (0xf << (4 * j))) r++ ; } } return r ; } void qlifealgo::findedges(bigint *ptop, bigint *pleft, bigint *pbottom, bigint *pright) { // AKT: following code is from fit() but all goal/size stuff // has been removed so it finds the exact pattern edges bigint xmin = 0 ; bigint xmax = 1 ; bigint ymin = 0 ; bigint ymax = 1 ; getPopulation() ; // make sure pop values are valid oddgen = getGeneration().odd() ; kadd = oddgen ? 8 : 0 ; quickb = 0xfff << (8 + oddgen * 12) ; int currdepth = rootlev ; if (root == nullroots[currdepth] || root->pop[oddgen] == 0) { // AKT: return impossible edges to indicate empty pattern; // not really a problem because caller should check first *ptop = 1 ; *pleft = 1 ; *pbottom = 0 ; *pright = 0 ; return ; } vector top, left, bottom, right ; top.push_back(root) ; left.push_back(root) ; bottom.push_back(root) ; right.push_back(root) ; int topbm = 0, bottombm = 0, rightbm = 0, leftbm = 0 ; int bitval = (currdepth + 1) / 2 * 3 + 5 ; while (bitval > 0) { if (bitval == 5) { // we have leaf nodes; turn them into bitmasks topbm = getvbitsfromleaves(top) ; bottombm = getvbitsfromleaves(bottom) ; leftbm = gethbitsfromleaves(left) ; rightbm = gethbitsfromleaves(right) ; } if (bitval <= 5) { int sz = 1 << bitval ; int masklo = (1 << (sz >> 1)) - 1 ; int maskhi = ~masklo ; ymax += ymax ; xmax += xmax ; ymin += ymin ; xmin += xmin ; if ((topbm & maskhi) == 0) { ymax.add_smallint(-1) ; } else { topbm = (topbm >> (sz >> 1)) & masklo ; } if ((bottombm & masklo) == 0) { ymin.add_smallint(1) ; bottombm = (bottombm >> (sz >> 1)) & masklo ; } if ((rightbm & masklo) == 0) { xmax.add_smallint(-1) ; rightbm = (rightbm >> (sz >> 1)) & masklo ; } if ((leftbm & maskhi) == 0) { xmin.add_smallint(1) ; } else { leftbm = (leftbm >> (sz >> 1)) & masklo ; } bitval-- ; } else { vector newv ; int outer = highsub(top, newv, currdepth) ; allsub(newv, top, currdepth-1) ; ymax <<= 3 ; ymax -= (7 - outer) ; outer = lowsub(bottom, newv, currdepth) ; allsub(newv, bottom, currdepth-1) ; ymin <<= 3 ; ymin += outer ; allsub(left, newv, currdepth) ; outer = lowsub(newv, left, currdepth-1) ; xmin <<= 3 ; xmin += outer ; allsub(right, newv, currdepth) ; outer = highsub(newv, right, currdepth-1) ; xmax <<= 3 ; xmax -= (7-outer) ; currdepth -= 2 ; bitval -= 3 ; } } if (bitval > 0) { xmin <<= bitval ; ymin <<= bitval ; xmax <<= bitval ; ymax <<= bitval ; } if (oddgen) { xmin += 1 ; ymin += 1 ; xmax += 1 ; ymax += 1 ; } xmin += bmin ; ymin += bmin ; xmax += bmin ; ymax += bmin ; ymax -= 1 ; xmax -= 1 ; ymin.mul_smallint(-1) ; ymax.mul_smallint(-1) ; // set pattern edges *ptop = ymax ; // due to y flip *pbottom = ymin ; // due to y flip *pleft = xmin ; *pright = xmax ; } void qlifealgo::fit(viewport &view, int force) { bigint xmin = 0 ; bigint xmax = 1 ; bigint ymin = 0 ; bigint ymax = 1 ; getPopulation() ; // make sure pop values are valid oddgen = getGeneration().odd() ; kadd = oddgen ? 8 : 0 ; quickb = 0xfff << (8 + oddgen * 12) ; int xgoal = view.getwidth() ; int ygoal = view.getheight() ; if (xgoal < 8) xgoal = 8 ; if (ygoal < 8) ygoal = 8 ; int xsize = 1 ; int ysize = 1 ; int currdepth = rootlev ; if (root == nullroots[currdepth] || root->pop[oddgen] == 0) { view.center() ; view.setmag(MAX_MAG) ; return ; } vector top, left, bottom, right ; top.push_back(root) ; left.push_back(root) ; bottom.push_back(root) ; right.push_back(root) ; int topbm = 0, bottombm = 0, rightbm = 0, leftbm = 0 ; int bitval = (currdepth + 1) / 2 * 3 + 5 ; while (bitval > 0) { if (bitval == 5) { // we have leaf nodes; turn them into bitmasks topbm = getvbitsfromleaves(top) ; bottombm = getvbitsfromleaves(bottom) ; leftbm = gethbitsfromleaves(left) ; rightbm = gethbitsfromleaves(right) ; } if (bitval <= 5) { int sz = 1 << bitval ; int masklo = (1 << (sz >> 1)) - 1 ; int maskhi = ~masklo ; ymax += ymax ; xmax += xmax ; ymin += ymin ; xmin += xmin ; xsize <<= 1 ; ysize <<= 1 ; if ((topbm & maskhi) == 0) { ymax.add_smallint(-1) ; ysize-- ; } else { topbm = (topbm >> (sz >> 1)) & masklo ; } if ((bottombm & masklo) == 0) { ymin.add_smallint(1) ; ysize-- ; bottombm = (bottombm >> (sz >> 1)) & masklo ; } if ((rightbm & masklo) == 0) { xmax.add_smallint(-1) ; xsize-- ; rightbm = (rightbm >> (sz >> 1)) & masklo ; } if ((leftbm & maskhi) == 0) { xmin.add_smallint(1) ; xsize-- ; } else { leftbm = (leftbm >> (sz >> 1)) & masklo ; } bitval-- ; } else { vector newv ; ysize <<= 3 ; int outer = highsub(top, newv, currdepth) ; allsub(newv, top, currdepth-1) ; ymax <<= 3 ; ymax -= (7 - outer) ; ysize -= (7 - outer) ; outer = lowsub(bottom, newv, currdepth) ; allsub(newv, bottom, currdepth-1) ; ymin <<= 3 ; ymin += outer ; ysize -= outer ; xsize <<= 3 ; allsub(left, newv, currdepth) ; outer = lowsub(newv, left, currdepth-1) ; xmin <<= 3 ; xmin += outer ; xsize -= outer ; allsub(right, newv, currdepth) ; outer = highsub(newv, right, currdepth-1) ; xmax <<= 3 ; xmax -= (7-outer) ; xsize -= (7-outer) ; currdepth -= 2 ; bitval -= 3 ; } if (xsize > xgoal || ysize > ygoal) break ; } if (bitval > 0) { xmin <<= bitval ; ymin <<= bitval ; xmax <<= bitval ; ymax <<= bitval ; } if (oddgen) { xmin += 1 ; ymin += 1 ; xmax += 1 ; ymax += 1 ; } xmin += bmin ; ymin += bmin ; xmax += bmin ; ymax += bmin ; ymax -= 1 ; xmax -= 1 ; ymin.mul_smallint(-1) ; ymax.mul_smallint(-1) ; if (!force) { // if all four of the above dimensions are in the viewport, don't change if (view.contains(xmin, ymin) && view.contains(xmax, ymax)) return ; } int mag = - bitval ; while (2 * xsize <= xgoal && 2 * ysize <= ygoal && mag < MAX_MAG) { mag++ ; xsize *= 2 ; ysize *= 2 ; } while (xsize > xgoal || ysize > ygoal) { mag-- ; xsize /= 2 ; ysize /= 2 ; } view.setpositionmag(xmin, xmax, ymin, ymax, mag) ; } /** * Fixed for qlife. */ void qlifealgo::lowerRightPixel(bigint &x, bigint &y, int mag) { if (mag >= 0) return ; x -= oddgen ; x -= bmin ; x >>= -mag ; x <<= -mag ; x += bmin ; x += oddgen ; y -= 1 ; y += bmin ; y += oddgen ; y >>= -mag ; y <<= -mag ; y -= bmin ; y += 1 ; y -= oddgen ; } golly-2.7-src/gollybase/generationsalgo.cpp0000644000175000017500000001106712536111364016073 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "generationsalgo.h" #include using namespace std ; int generationsalgo::NumCellStates() { return maxCellStates ; } const char* generationsalgo::setrule(const char *s) { if ((int)strlen(s) + 10 > MAXRULESIZE) return "Rule too long for Generations" ; // a legal rule goes: // [0-8]+/[1-8]+/[1-9][0-9]* const char *p = s ; int tstaybits = 0, tbornbits = 0, tnumstates = 0 ; while ('0' <= *p && *p <= '8') { tstaybits |= 1<<(*p-'0') ; p++ ; } if (*p != '/') return "Missing expected slash in Generations rule" ; p++ ; while ('1' <= *p && *p <= '8') { tbornbits |= 1<<(*p-'0') ; p++ ; } if (*p != '/') return "Missing expected slash in Generations rule" ; p++ ; while ('0' <= *p && *p <= '9') { tnumstates = 10 * tnumstates + *p - '0' ; p++ ; if (tnumstates > 256) return "Number of states too high in Generations rule" ; } if (tnumstates < 2) return "Number of states too low in Generations rule" ; if (*p == ':') { // check for suffix like ":T200,100" to specify a bounded universe const char* err = setgridsize(p) ; if (err) return err ; } else { if (*p) return "Unexpected stuff at end of Generations rule" ; gridwd = 0 ; gridht = 0 ; } staybits = tstaybits ; bornbits = tbornbits ; maxCellStates = tnumstates ; // store rule in canonical format for getrule() int i, j = 0 ; char states[4] ; // room for "2".."256" and null for (i=0; i<=8; i++) { if (staybits & (1 << i)) canonrule[j++] = (char)('0' + i) ; } canonrule[j++] = '/' ; for (i=1; i<=8; i++) { if (bornbits & (1 << i)) canonrule[j++] = (char)('0' + i) ; } canonrule[j++] = '/' ; sprintf(states, "%d", tnumstates) ; i = 0 ; while (states[i]) { canonrule[j++] = states[i++] ; } if (gridwd > 0 || gridht > 0) { // setgridsize() was successfully called above const char* bounds = canonicalsuffix() ; i = 0 ; while (bounds[i]) { canonrule[j++] = bounds[i++] ; } } canonrule[j] = 0 ; ghashbase::setrule(canonrule) ; return 0 ; } const char* generationsalgo::getrule() { return canonrule ; } static const char *DEFAULTRULE = "12/34/3" ; const char* generationsalgo::DefaultRule() { return DEFAULTRULE ; } generationsalgo::generationsalgo() { // we may need this to be >2 here so it's recognized as multistate maxCellStates = 3 ; } generationsalgo::~generationsalgo() {} state generationsalgo::slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) { int nn = (nw==1)+(n==1)+(ne==1)+(w==1)+(e==1)+(sw==1)+(s==1)+(se==1) ; if (c==1 && (staybits & (1 << nn))) return 1 ; if (c==0 && (bornbits & (1 << nn))) return 1 ; if (c > 0 && c+1 < maxCellStates) return c + 1 ; return 0 ; } static lifealgo *creator() { return new generationsalgo() ; } void generationsalgo::doInitializeAlgoInfo(staticAlgoInfo &ai) { ghashbase::doInitializeAlgoInfo(ai) ; ai.setAlgorithmName("Generations") ; ai.setAlgorithmCreator(&creator) ; ai.minstates = 2 ; ai.maxstates = 256 ; // init default color scheme ai.defgradient = true; // use gradient ai.defr1 = 255; // start color = red ai.defg1 = 0; ai.defb1 = 0; ai.defr2 = 255; // end color = yellow ai.defg2 = 255; ai.defb2 = 0; // if not using gradient then set all states to white for (int i=0; i<256; i++) { ai.defr[i] = ai.defg[i] = ai.defb[i] = 255; } } golly-2.7-src/gollybase/viewport.cpp0000644000175000017500000001447312536111364014575 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "viewport.h" #include "lifealgo.h" #include int MAX_MAG = 4 ; // default maximum cell size is 2^4 using namespace std ; void viewport::init() { x = 0 ; y = 0 ; height = width = 8 ; mag = 0 ; x0 = 0 ; y0 = 0 ; x0f = 0 ; y0f = 0 ; xymf = 0 ; } void viewport::zoom() { if (mag >= MAX_MAG) return ; mag++ ; reposition() ; } void viewport::zoom(int xx, int yy) { if (mag >= MAX_MAG) return ; pair oldpos = at(xx, yy); // save cell pos for use below int x2c = xx * 2 - getxmax() ; bigint o = x2c ; o.mulpow2(-mag-2) ; x += o ; int y2c = yy * 2 - getymax() ; o = y2c ; o.mulpow2(-mag-2) ; y += o ; mag++ ; reposition() ; // adjust cell position if necessary to avoid any drift if (mag >= 0) { pair newpos = at(xx, yy); bigint xdrift = newpos.first; bigint ydrift = newpos.second; xdrift -= oldpos.first; ydrift -= oldpos.second; // drifts will be -1, 0 or 1 if (xdrift != 0) move(-xdrift.toint() << mag, 0); if (ydrift != 0) move(0, -ydrift.toint() << mag); } } void viewport::unzoom() { mag-- ; reposition() ; } void viewport::unzoom(int xx, int yy) { pair oldpos = at(xx, yy); // save cell pos for use below mag-- ; int x2c = xx * 2 - getxmax() ; bigint o = x2c ; o.mulpow2(-mag-2) ; x -= o ; int y2c = yy * 2 - getymax() ; o = y2c ; o.mulpow2(-mag-2) ; y -= o ; reposition() ; if (mag >= 0) { // adjust cell position if necessary to avoid any drift pair newpos = at(xx, yy); bigint xdrift = newpos.first; bigint ydrift = newpos.second; xdrift -= oldpos.first; ydrift -= oldpos.second; // drifts will be -1, 0 or 1 if (xdrift != 0) move(-xdrift.toint() << mag, 0); if (ydrift != 0) move(0, -ydrift.toint() << mag); } } pair viewport::at(int x, int y) { bigint rx = x ; bigint ry = y ; rx.mulpow2(-mag) ; ry.mulpow2(-mag) ; rx += x0 ; ry += y0 ; return pair(rx, ry) ; } pair viewport::atf(int x, int y) { return pair(x0f + x * xymf, y0f + y * xymf) ; } /** * Returns the screen position of a particular pixel. Note that this * is a tiny bit more complicated than you might expect, because it * has to take into account exactly how a life algorithm compresses * multiple pixels into a single pixel (which depends not only on the * lifealgo, but in the case of qlifealgo, *also* depends on the * generation count). In the case of mag < 0, it always returns * the upper left pixel; it's up to the caller to adjust when * mag<0. */ pair viewport::screenPosOf(bigint x, bigint y, lifealgo *algo) { if (mag < 0) { bigint xx0 = x0 ; bigint yy0 = y0 ; algo->lowerRightPixel(xx0, yy0, mag) ; y -= yy0 ; x -= xx0 ; } else { x -= x0 ; y -= y0 ; } x.mulpow2(mag) ; y.mulpow2(mag) ; int xx = 0 ; int yy = 0 ; /* AKT: don't do this clipping as it makes it harder to calculate an accurate paste rectangle if (x < 0) xx = -1 ; else if (x > getxmax()) xx = getxmax() + 1 ; else xx = x.toint() ; if (y < 0) yy = -1 ; else if (y > getymax()) yy = getymax() + 1 ; else yy = y.toint() ; */ if (x > bigint::maxint) xx = INT_MAX ; else if (x < bigint::minint) xx = INT_MIN ; else xx = x.toint() ; if (y > bigint::maxint) yy = INT_MAX ; else if (y < bigint::minint) yy = INT_MIN ; else yy = y.toint() ; return pair(xx,yy) ; } void viewport::move(int dx, int dy) { // dx and dy are in pixels if (mag > 0) { dx /= (1 << mag) ; dy /= (1 << mag) ; } bigint addx = dx ; bigint addy = dy ; if (mag < 0) { addx <<= -mag ; addy <<= -mag ; } x += addx ; y += addy ; reposition() ; } void viewport::resize(int newwidth, int newheight) { width = newwidth ; height = newheight ; reposition() ; } void viewport::center() { x = 0 ; y = 0 ; reposition() ; } void viewport::reposition() { xymf = pow(2.0, -mag) ; bigint w = 1 + getxmax() ; w.mulpow2(-mag) ; w >>= 1 ; x0 = x ; x0 -= w ; w = 1 + getymax() ; w.mulpow2(-mag) ; w >>= 1 ; y0 = y ; y0 -= w ; y0f = y0.todouble() ; x0f = x0.todouble() ; } void viewport::setpositionmag(const bigint &xarg, const bigint &yarg, int magarg) { x = xarg ; y = yarg ; mag = magarg ; reposition() ; } /* * This is only called by fit. We find an x/y location that * centers things optimally. */ void viewport::setpositionmag(const bigint &xmin, const bigint &xmax, const bigint &ymin, const bigint &ymax, int magarg) { mag = magarg ; x = xmax ; x += xmin ; x += 1 ; x >>= 1 ; y = ymax ; y += ymin ; y += 1 ; y >>= 1 ; reposition() ; } int viewport::contains(const bigint &xarg, const bigint &yarg) { if (xarg < x0 || yarg < y0) return 0 ; bigint t = getxmax() ; t += 1 ; t.mulpow2(-mag) ; t -= 1 ; t += x0 ; if (xarg > t) return 0 ; t = getymax() ; t += 1 ; t.mulpow2(-mag) ; t -= 1 ; t += y0 ; if (yarg > t) return 0 ; return 1 ; } golly-2.7-src/gollybase/platform.h0000644000175000017500000000443612536111364014205 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /** * This file holds things that are platform-dependent such as * dependencies on 64-bitness, help for when the platform does not * have inttypes.h, and things like that. * * We need to convert pointers to integers and back for two * reasons. First, hlife structures use the address of a node * as its label, and we need to hash these labels. Secondly, * we use bit tricks for garbage collection and need to set and * clear low-order bits in a pointer. Normally the typedef * below is all we need, but if your platform doesn't have * uintptr_t you can change that here. We also need this type * for anything that might hold the *count* of nodes, since * this might be larger than an int. If inttypes does not * exist, and you're compiling for a 64-bit platform, you may * need to make some changes here. */ #include #if defined(_WIN64) #define PRIuPTR "I64u" typedef uintptr_t g_uintptr_t ; #define G_MAX SIZE_MAX #define GOLLY64BIT (1) #elif defined(__LP64__) || defined(__amd64__) #define __STDC_FORMAT_MACROS #define __STDC_LIMIT_MACROS #include #include typedef uintptr_t g_uintptr_t ; #define G_MAX SIZE_MAX #define GOLLY64BIT (1) #else #define PRIuPTR "u" typedef unsigned int g_uintptr_t ; #define G_MAX UINT_MAX #undef GOLLY64BIT #endif golly-2.7-src/gollybase/qlifealgo.cpp0000644000175000017500000011627512536111364014664 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /* * Inspired by Alan Hensel's Life applet and also by xlife. Tries to * improve the cache, TLB, and branching behavior for modern CPUs. */ #include "qlifealgo.h" #include "liferules.h" #include "util.h" #include #include #include #include using namespace std ; /* * The ai array is used to figure out the index number of the bit set in * the set [1, 2, 4, 8, 16, 32, 64, 128]. Also, for the value 0, it * returns the result 4, to eliminate a conditional in some obscure piece * of code. */ static unsigned char ai[129] ; /* * This define is the size of memory to ask for at one time. 8K is a good * size; we drop 16 bits because malloc overhead is probably near this. * * Values much smaller than this will be impacted by malloc overhead (both * speed and space); values much larger than this will occupy excessive * memory for small universes. */ #define MEMCHUNK (8192-16) /* * When we need a bunch more structures of a particular size, we call this. * This code allocates the memory, adds it to our universe memory allocated * list, tries to maximize the cache alignment of the structures, and then * links all the substructures together into a linked list which is then * returned. */ /* * This preprocessor directive is used to work around a bug in * register allocation when using function inlining (-O3 or * better) and gcc 3.4.2, which is very common having shipped with * Fedora Core 3. */ #ifdef __GNUC__ __attribute__((noinline)) #endif linkedmem *qlifealgo::filllist(int size) { usedmemory += MEMCHUNK ; if (maxmemory != 0 && usedmemory > maxmemory) lifefatal("exceeded user-specified memory limit") ; linkedmem *p, *safep, *r = (linkedmem *)calloc(MEMCHUNK, 1) ; int i = size & - size ; if (r == 0) lifefatal("No memory.") ; r->next = memused ; memused = r ; safep = p = (linkedmem *)((((g_uintptr_t)(r+1))+i-1)&-i) ; while (((g_uintptr_t)p) + 2 * size <= MEMCHUNK+(g_uintptr_t)r) { p->next = (linkedmem *)(size + (g_uintptr_t)p) ; p = (linkedmem *)(size + (g_uintptr_t)p) ; } return safep ; } #ifdef STATS static int bricks, tiles, supertiles, rcc, dq, ds, rccs, dqs, dss ; #define STAT(a) a #else #define STAT(a) #endif /* * If we need a new empty brick, we call this. This structure is guaranteed * to be all zeros. */ brick *qlifealgo::newbrick() { brick *r ; if (bricklist == 0) bricklist = filllist(sizeof(brick)) ; r = (brick *)(bricklist) ; bricklist = bricklist->next ; memset(r, 0, sizeof(brick)) ; STAT(bricks++) ; return r ; } /* * If we need a new tile, we call this. The structure is also initialized * appropriately, with all the pointers pointing to the empty brick. */ tile *qlifealgo::newtile() { tile *r ; if (tilelist == 0) tilelist = filllist(sizeof(tile)) ; r = (tile *)(tilelist) ; tilelist = tilelist->next ; r->b[0] = r->b[1] = r->b[2] = r->b[3] = emptybrick ; r->flags = -1 ; STAT(tiles++) ; return r ; } /* * Finally, a new supertile is provided by this routine. It initializes * all the subtiles to point to the next level down's empty tile. */ supertile *qlifealgo::newsupertile(int lev) { supertile *r ; if (supertilelist == 0) supertilelist = filllist(sizeof(supertile)) ; r = (supertile *)supertilelist ; supertilelist = supertilelist->next ; r->d[0] = r->d[1] = r->d[2] = r->d[3] = r->d[4] = r->d[5] = r->d[6] = r->d[7] = nullroots[lev-1] ; STAT(supertiles++) ; return r ; } /* * This short little subroutine plays a very important role. It takes bits * set up according to the c01 or c10 fields of supertiles, and translates * these bits into the impact on the next level up. Essentially, it swaps * the parallel bits (bits 9 through 16), any of them set, with the edge * bit (bit 8), in a way that requires no conditional branches. On a * slower older processor without large branch penalties, it might be * faster to use a conditional variation that executes fewer instructions, * but actually this code is not totally performance critical. */ static int upchanging(int x) { int a = (x & 0x1feff) + 0x1feff ; return ((a >> 8) & 1) | ((a >> 16) & 2) | ((x << 1) & 0x200) | ((x >> 7) & 0x400) ; } /* * If it is determined that the universe is not large enough, this * subroutine adds another level to it, expanding it by a factor of 8 * in one dimension, depending on whether the level is even or odd. * * It also allocates a new emptytile at the appropriate level. * * The old root is always placed at position 4. This allows expansion * in both positive and negative directions. * * The sequence of sizes is as follows: * * 0 31 * -128 127 * -1,152 895 * -9,344 7,039 * -74,880 56,191 * -599,168 449,407 * -4,793,472 3,595,135 * -38,347,904 28,760,959 * -306,783,360 230,087,551 * INT_MIN 1,840,700,287 * INT_MIN INT_MAX * * Remember these are only relevant for set() calls and have nothing * to do with rendering or generation. */ void qlifealgo::uproot() { if (min < -100000000) min = INT_MIN ; else min = 8 * min - 128 ; if (max > 500000000) max = INT_MAX ; else max = 8 * max - 121 ; bmin <<= 3 ; bmin -= 128 ; bmax <<= 3 ; bmax -= 121 ; minlow32 = 8 * minlow32 - 4 ; if (rootlev >= 38) lifefatal("internal: push too deep for qlifealgo") ; for (int i=0; i<2; i++) { supertile *oroot = root ; rootlev++ ; root = newsupertile(rootlev) ; if (rootlev > 1) root->flags = 0xf0000000 | (upchanging(oroot->flags) << (3 + (generation.odd()))) ; root->d[4] = oroot ; if (oroot != nullroot) { nullroots[rootlev] = nullroot = newsupertile(rootlev) ; } else { nullroots[rootlev] = nullroot = root ; } } // Need to clear this because we don't have valid population values // in the new root. popValid = 0 ; } /* * This subroutine allocates a new empty universe. The universe starts * out as a 256x256 universe. */ qlifealgo::qlifealgo() { int test = (INT_MAX != 0x7fffffff) ; if (test) lifefatal("bad platform for this program") ; memused = 0 ; maxmemory = 0 ; clearall() ; } /* * Clear everything. This one also frees memory. */ static int bc[256] ; // popcount void qlifealgo::clearall() { poller->bailIfCalculating() ; while (memused) { linkedmem *nu = memused->next ; free(memused) ; memused = nu ; } generation = 0 ; increment = 1 ; tilelist = 0 ; supertilelist = 0 ; bricklist = 0 ; rootlev = 0 ; cleandowncounter = 63 ; usedmemory = 0 ; deltaforward = 0 ; ai[0] = 4 ; ai[1] = 0 ; ai[2] = 1 ; ai[4] = 2 ; ai[8] = 3 ; ai[16] = 4 ; ai[32] = 5 ; ai[64] = 6 ; ai[128] = 7 ; minlow32 = min = 0 ; max = 31 ; bmin = 0 ; bmax = 31 ; emptybrick = newbrick() ; nullroots[0] = nullroot = root = (supertile *)(emptytile = newtile()) ; uproot() ; popValid = 0 ; llxb = 0 ; llyb = 0 ; llbits = 0 ; llsize = 0 ; if (bc[255] == 0) for (int i=1; i<256; i++) bc[i] = bc[i & (i-1)] + 1 ; } /* * This subroutine frees a universe. */ qlifealgo::~qlifealgo() { while (memused) { linkedmem *nu = memused->next ; free(memused) ; memused = nu ; } } /* * Set the max memory */ void qlifealgo::setMaxMemory(int newmemlimit) { // AKT: allow setting maxmemory to 0 if (newmemlimit == 0) { maxmemory = 0 ; return; } if (newmemlimit < 10) newmemlimit = 10 ; #ifndef GOLLY64BIT else if (newmemlimit > 4000) newmemlimit = 4000 ; #endif g_uintptr_t newlimit = ((g_uintptr_t)newmemlimit) << 20 ; if (usedmemory > newlimit) { lifewarning("Sorry, more memory currently used than allowed.") ; return ; } maxmemory = newlimit ; } /* * Finally, our first generation subroutine! This one handles supertiles * for even to odd generation (0->1). What is passed in is the universe * itself, the tile (this) to focus on, its three neighbor tiles (the * one `parallel' to it [by the way the subtiles are stacked], the one * past it, and the corner one. * * The way we walk down the tree in this subroutine is one of the major * keys to cache and TLB performance. We walk the universe in a * spatially local way, always doing an entire 32x32 tile before * moving on, always doing a 256x32 supertile before moving on, always * doing a 256x256 supertile, etc. That is, if we need to access a * particular brick four times in recomputing four bricks, chances are * good that those four times will occur closely in time since we do * spatially adjacent bricks near each other. * * Another trick is to do the universe from bottom to top in phase 0->1 * and from top to bottom in phase 1->0; this also helps cut down on * those cache misses. */ int qlifealgo::doquad01(supertile *zis, supertile *edge, supertile *par, supertile *cor, int lev) { /* * First we figure out which subtiles we need to recalculate. There will * always be at least one if we got into this subroutine (except for the * case of a static universe and at the root level). To do this, we * use the edge bits from the parallel supertile, and one bit each from * the other two neighbor tiles, blending them into a single 8-bit * recalculate int. * * Note that the parallel and corner have already been recomputed so * their changing bits are shifted up 10 positions in c. */ poller->poll() ; int changing = (zis->flags | (par->flags >> 19) | (((edge->flags >> 18) | (cor->flags >> 27)) & 1)) & 0xff ; int x, b, nchanging = (zis->flags & 0x3ff00) << 10 ; supertile *p, *pf, *pu, *pfu ; STAT(ds++) ; /* * Only if the first subtile needs to be recomputed do we actually need to * `visit' the edge and corner neighbors. We always keep track of the * subtiles one level down. */ if (changing & 1) { x = 7 ; b = 1 ; pf = edge->d[0] ; pfu = cor->d[0] ; } else { /* * Otherwise, we compute which tile we need to examine first with the help * of the ai array. */ b = (changing & - changing) ; x = 7 - ai[b] ; pf = zis->d[x + 1] ; pfu = par->d[x + 1] ; } for (;;) { p = zis->d[x] ; pu = par->d[x] ; /* * Do we need to recompute this subtile? */ if (changing & b) { /* * If so, is it the canonical empty supertile for this level? If so, * allocate a new empty supertile and set the void bits appropriately. */ if (zis->d[x] == nullroots[lev-1]) p = zis->d[x] = (lev == 1 ? (supertile *)newtile() : newsupertile(lev-1)) ; /* * If it's level 1, call the tile handler, else call the next level down of * the supertile handler. The return value is the changing indicators that * should be propogated up. */ nchanging |= ((lev == 1) ? p01((tile *)p, (tile *)pf, (tile *)pu, (tile *)pfu) : doquad01(p, pu, pf, pfu, lev-1)) << x ; changing -= b ; } else if (changing == 0) break ; b <<= 1 ; x-- ; pfu = pu ; pf = p ; } zis->flags = nchanging | 0xf0000000 ; return upchanging(nchanging) ; } /* * This is for odd to even generations, and the documentation is pretty * much the same as for the previous subroutine. */ int qlifealgo::doquad10(supertile *zis, supertile *edge, supertile *par, supertile *cor, int lev) { poller->poll() ; int changing = (zis->flags | (par->flags >> 19) | (((edge->flags >> 18) | (cor->flags >> 27)) & 1)) & 0xff ; int x, b, nchanging = (zis->flags & 0x3ff00) << 10 ; supertile *p, *pf, *pu, *pfu ; STAT(ds++) ; if (changing & 1) { x = 0 ; b = 1 ; pf = edge->d[7] ; pfu = cor->d[7] ; } else { b = (changing & - changing) ; x = ai[b] ; pf = zis->d[x - 1] ; pfu = par->d[x - 1] ; } for (;;) { p = zis->d[x] ; pu = par->d[x] ; if (changing & b) { if (zis->d[x] == nullroots[lev-1]) p = zis->d[x] = (lev == 1 ? (supertile *)newtile() : newsupertile(lev-1)) ; nchanging |= ((lev == 1) ? p10((tile *)pfu, (tile *)pu, (tile *)pf, (tile *)p) : doquad10(p, pu, pf, pfu, lev-1)) << (7-x) ; changing -= b ; } else if (changing == 0) break ; b <<= 1 ; x++ ; pfu = pu ; pf = p ; } zis->flags = nchanging | 0xf0000000 ; return upchanging(nchanging) ; } /* * This is our monster subroutine that, with its mirror below, accounts for * about 90% of the runtime. It handles recomputation for a 32x32 tile. * Passed in are the neighbor tiles: pr (to the right), pd (down), and * prd (down and to the right). */ int qlifealgo::p01(tile *p, tile *pr, tile *pd, tile *prd) { brick *db = pd->b[0], *rdb = prd->b[0] ; /* * Do we need to recompute the fourth brick? This happens here because its * the only place we need to pull in changing from the down and corner * neighbor. */ int i, recomp = (p->c[4] | pd->c[0] | (pr->c[4] >> 9) | (prd->c[0] >> 8)) & 0xff ; STAT(dq++) ; p->c[5] = 0 ; p->flags |= 0xfff00000 ; /* * For each brick . . . */ for (i=3; i>=0; i--) { brick *b = p->b[i], *rb = pr->b[i] ; /* * Do we need to recompute? */ if (recomp) { unsigned int traildata, trailunderdata ; int j, cdelta = 0, maska, maskb, maskprev = 0 ; /* * If so, set the dirty bit. Also, if this brick is the canonical empty * brick, get a new one. */ p->flags |= 1 << i ; if (b == emptybrick) p->b[i] = b = newbrick() ; /* * If we need to recompute the end slice, now is a good time to get the * right neighbor's data. */ if (recomp & 1) { j = 7 ; traildata = rb->d[0] ; trailunderdata = rdb->d[0] ; } else { /* * Otherwise we use the ai[] array to figure out where to begin in this * brick. */ j = ai[recomp & - recomp] ; recomp >>= j ; j = 7 - j ; traildata = b->d[j+1] ; trailunderdata = db->d[j+1] ; } trailunderdata = (traildata << 8) + (trailunderdata >> 24) ; for (;;) { /* * At all times here, we have traildata (the data from the slice to the * right) and trailunderdata (24 bits of traildata and eight bits from * the slice under and to the right). * * Do we need to recompute this slice? */ if (recomp & 1) { /* * Our main recompute chunk recomputes a single slice. */ unsigned int zisdata = b->d[j] ; unsigned int underdata = (zisdata << 8) + (db->d[j] >> 24) ; unsigned int otherdata = ((zisdata << 2) & 0xcccccccc) + ((traildata >> 2) & 0x33333333) ; unsigned int otherunderdata = ((underdata << 2) & 0xcccccccc) + ((trailunderdata >> 2) & 0x33333333) ; int newv = (ruletable[zisdata >> 16] << 26) + (ruletable[underdata >> 16] << 18) + (ruletable[zisdata & 0xffff] << 10) + (ruletable[underdata & 0xffff] << 2) + (ruletable[otherdata >> 16] << 24) + (ruletable[otherunderdata >> 16] << 16) + (ruletable[otherdata & 0xffff] << 8) + ruletable[otherunderdata & 0xffff] ; /* * Has anything changed? * Keep track of what has changed in the entire cell, the rightmost * two columns, the lowest two rows, and the lowest rightmost 2x2 cell, into * the maskprev int. Do all of this without conditionals. */ int delta = (b->d[j + 8] ^ newv) | deltaforward ; STAT(rcc++) ; b->d[j + 8] = newv ; maska = cdelta | (delta & 0x33333333) ; maskb = maska | -maska ; maskprev = (maskprev << 1) | ((maskb >> 9) & 0x400000) | (maskb & 0x80) ; cdelta = delta ; traildata = zisdata ; trailunderdata = underdata ; } else { /* * No need to recompute? Well, maintain our necessary invariants and bail * if we're done. */ maskb = cdelta | -cdelta ; maskprev = (maskprev << 1) | ((maskb >> 9) & 0x400000) | (maskb & 0x80) ; if (recomp == 0) break ; ; cdelta = 0 ; traildata = b->d[j] ; trailunderdata = (traildata << 8) + (db->d[j] >> 24) ; } recomp >>= 1 ; j-- ; } /* * Finally done with that brick! Update our changing for the next * call to p10, and or-in any changes to the lower two rows that we saw * into the next brick down's changing variable. */ p->c[i+2] |= (maskprev >> (6 - j)) & 0x1ff ; p->c[i+1] = (short)(((p->c[i+1] & 0x100) << 1) | (maskprev >> (21 - j))) ; } else p->c[i+1] = 0 ; /* * Calculate recomp for the next row down. */ recomp = (p->c[i] | (pr->c[i] >> 9)) & 0xff ; db = b ; rdb = rb ; } /* * Propogate the changing information for this tile to the supertile on * the next level up. */ recomp = p->c[5] ; i = recomp | p->c[0] | p->c[1] | p->c[2] | p->c[3] | p->c[4] ; if (recomp) return 0x201 | ((recomp & 0x100) << 2) | ((i & 0x100) >> 7) ; else return i ? ((i & 0x100) >> 7) | 1 : 0 ; } /* * This subroutine is the mirror of the one above, used for odd to even * generations. */ int qlifealgo::p10(tile *plu, tile *pu, tile *pl, tile *p) { brick *ub = pu->b[3], *lub = plu->b[3] ; int i, recomp = (p->c[1] | pu->c[5] | (pl->c[1] >> 9) | (plu->c[5] >> 8)) & 0xff ; STAT(dq++) ; p->c[0] = 0 ; p->flags |= 0x000fff00 ; for (i=0; i<=3; i++) { brick *b = p->b[i], *lb = pl->b[i] ; if (recomp) { int maska, maskprev = 0, j, cdelta = 0 ; unsigned int traildata, trailoverdata ; p->flags |= 1 << i ; if (b == emptybrick) p->b[i] = b = newbrick() ; if (recomp & 1) { j = 0 ; traildata = lb->d[15] ; trailoverdata = lub->d[15] ; } else { j = ai[recomp & - recomp] ; traildata = b->d[j+7] ; trailoverdata = ub->d[j+7] ; recomp >>= j ; } trailoverdata = (traildata >> 8) + (trailoverdata << 24) ; for (;;) { if (recomp & 1) { unsigned int zisdata = b->d[j + 8] ; unsigned int overdata = (zisdata >> 8) + (ub->d[j + 8] << 24) ; unsigned int otherdata = ((zisdata >> 2) & 0x33333333) + ((traildata << 2) & 0xcccccccc) ; unsigned int otheroverdata = ((overdata >> 2) & 0x33333333) + ((trailoverdata << 2) & 0xcccccccc) ; int newv = (ruletable[otheroverdata >> 16] << 26) + (ruletable[otherdata >> 16] << 18) + (ruletable[otheroverdata & 0xffff] << 10) + (ruletable[otherdata & 0xffff] << 2) + (ruletable[overdata >> 16] << 24) + (ruletable[zisdata >> 16] << 16) + (ruletable[overdata & 0xffff] << 8) + ruletable[zisdata & 0xffff] ; int delta = (b->d[j] ^ newv) | deltaforward ; STAT(rcc++) ; maska = cdelta | (delta & 0xcccccccc) ; maskprev = (maskprev << 1) | (((maska | - maska) >> 9) & 0x400000) | ((((maska >> 24) | 0x100) - 1) & 0x100) ; b->d[j] = newv ; cdelta = delta ; traildata = zisdata ; trailoverdata = overdata ; } else { maskprev = (maskprev << 1) | (((cdelta | - cdelta) >> 9) & 0x400000) | ((((cdelta >> 24) | 0x100) - 1) & 0x100) ; if (recomp == 0) break ; cdelta = 0 ; traildata = b->d[j + 8] ; trailoverdata = (traildata >> 8) + (ub->d[j + 8] << 24) ; } recomp >>= 1 ; j++ ; } p->c[i+1] = (short)(((p->c[i+1] & 0x100) << 1) | (maskprev >> (14 + j))) ; p->c[i] |= (maskprev >> j) & 0x1ff ; } else p->c[i+1] = 0 ; recomp = (p->c[i+2] | (pl->c[i+2] >> 9)) & 0xff ; ub = b ; lub = lb ; } recomp = p->c[0] ; i = recomp | p->c[1] | p->c[2] | p->c[3] | p->c[4] | p->c[5] ; if (recomp) return 0x201 | ((recomp & 0x100) << 2) | ((i & 0x100) >> 7) ; else return i ? ((i & 0x100) >> 7) | 1 : 0 ; } /** * Mark a node and its subnodes as changed. We really * only mark those nodes that have any cells set at all. */ int qlifealgo::markglobalchange(supertile *p, int lev) { int i ; if (lev == 0) { tile *pp = (tile *)p ; if (pp != emptytile) { int s = 0 ; for (int i=0; i<4; i++) for (int j=0; j<16; j++) s |= pp->b[i]->d[j] ; if (s) { pp->c[0] = pp->c[5] = 0x1ff ; pp->c[1] = pp->c[2] = pp->c[3] = pp->c[4] = 0x3ff ; return 0x603 ; } } return 0 ; } else { if (p != nullroots[lev]) { int nchanging = 0 ; if (generation.odd()) for (i=0; i<8; i++) nchanging |= (markglobalchange(p->d[i], lev-1)) << i ; else for (i=0; i<8; i++) nchanging |= (markglobalchange(p->d[i], lev-1)) << (7 - i) ; p->flags |= nchanging | 0xf0000000 ; return upchanging(nchanging) ; } return 0 ; } } void qlifealgo::markglobalchange() { markglobalchange(root, rootlev) ; deltaforward = 0xffffffff ; } /* * This subroutine sets a bit at a particular location. * * We walk down the tree to the particular bit, setting changing flags as * we go. */ int qlifealgo::setcell(int x, int y, int newstate) { if (newstate & ~1) return -1 ; y = - y ; supertile *b ; tile *p ; int lev ; int odd = generation.odd() ; if (odd) { x-- ; y-- ; } while (x < min || x > max || y < min || y > max) uproot() ; int xdel = (x >> 5) - minlow32 ; int ydel = (y >> 5) - minlow32 ; int xc = x - (minlow32 << 5) ; int yc = y - (minlow32 << 5) ; if (root == nullroot) root = newsupertile(rootlev) ; b = root ; lev = rootlev ; while (lev > 0) { int i, d = 1 ; if (lev & 1) { int s = (lev >> 1) + lev - 1 ; i = (xdel >> s) & 7 ; s = (1 << (s + 5)) - 2 ; if ((xc & s) == ((odd) ? s : 0)) d += 2 ; if ((yc & s) == ((odd) ? s : 0)) d += d << 9 ; } else { int s = (lev >> 1) + lev - 3 ; i = (ydel >> s) & 7 ; s = (1 << (s + 5)) - 2 ; if ((yc & s) == ((odd) ? s : 0)) d += 2 ; s |= s << 3 ; if ((xc & s) == ((odd) ? s : 0)) d += d << 9 ; } if (odd) b->flags |= (d << i) | 0xf0000000 ; else b->flags |= (d << (7 - i)) | 0xf0000000 ; if (b->d[i] == nullroots[lev-1]) b->d[i] = (lev==1 ? (supertile *)newtile() : newsupertile(lev-1)) ; lev -= 1 ; b = b->d[i] ; } x &= 31 ; y &= 31 ; p = (tile *)b ; if (p->b[(y >> 3) & 0x3] == emptybrick) p->b[(y >> 3) & 0x3] = newbrick() ; if (odd) { int mor = ((x & 2) ? 3 : 1) << ((x >> 2) & 0x7) ; p->c[((y >> 3) & 0x3) + 1] |= mor ; p->flags = -1 ; if ((y & 6) == 6) p->c[((y >> 3) & 0x3) + 2] |= mor ; if (newstate) p->b[(y >> 3) & 0x3]->d[8 + ((x >> 2) & 0x7)] |= (1 << (31 - (y & 7) * 4 - (x & 3))) ; else p->b[(y >> 3) & 0x3]->d[8 + ((x >> 2) & 0x7)] &= ~(1 << (31 - (y & 7) * 4 - (x & 3))) ; } else { int mor = ((x & 2) ? 1 : 3) << (7 - ((x >> 2) & 0x7)) ; p->c[((y >> 3) & 0x3) + 1] |= mor ; p->flags = -1 ; if ((y & 6) == 0) p->c[((y >> 3) & 0x3)] |= mor ; if (newstate) p->b[(y >> 3) & 0x3]->d[(x >> 2) & 0x7] |= (1 << (31 - (y & 7) * 4 - (x & 3))) ; else p->b[(y >> 3) & 0x3]->d[(x >> 2) & 0x7] &= ~(1 << (31 - (y & 7) * 4 - (x & 3))) ; } deltaforward = 0xffffffff ; return 0 ; } /* * This subroutine gets a bit at a particular location. */ int qlifealgo::getcell(int x, int y) { y = - y ; supertile *b ; tile *p ; int lev ; int odd = generation.odd() ; if (odd) { x-- ; y-- ; } while (x < min || x > max || y < min || y > max) uproot() ; if (x < min || x > max || y < min || y > max) return 0 ; int xdel = (x >> 5) - minlow32 ; int ydel = (y >> 5) - minlow32 ; if (root == nullroot) return 0 ; b = root ; lev = rootlev ; while (lev > 0) { int i ; if (lev & 1) { int s = (lev >> 1) + lev - 1 ; i = (xdel >> s) & 7 ; } else { int s = (lev >> 1) + lev - 3 ; i = (ydel >> s) & 7 ; } if (b->d[i] == nullroots[lev-1]) return 0 ; lev -= 1 ; b = b->d[i] ; } x &= 31 ; y &= 31 ; p = (tile *)b ; if (p->b[(y >> 3) & 0x3] == emptybrick) return 0 ; if (odd) { if (p->b[(y >> 3) & 0x3]->d[8 + ((x >> 2) & 0x7)] & (1 << (31 - (y & 7) * 4 - (x & 3)))) return 1 ; else return 0 ; } else { if (p->b[(y >> 3) & 0x3]->d[(x >> 2) & 0x7] & (1 << (31 - (y & 7) * 4 - (x & 3)))) return 1 ; else return 0 ; } } /** * Similar but returns the distance to the next set cell horizontally. */ int qlifealgo::nextcell(int x, int y, int &v) { v = 1 ; y = - y ; int odd = generation.odd() ; if (odd) { x-- ; y-- ; } while (x < min || x > max || y < min || y > max) uproot() ; if (x > max || x < min || y < min || y > max) return -1 ; return nextcell(x, y, root, rootlev) ; } int qlifealgo::nextcell(int x, int y, supertile *n, int lev) { if (lev > 0) { if (n == nullroots[lev]) return -1 ; int xdel = (x >> 5) - minlow32 ; int ydel = (y >> 5) - minlow32 ; int i ; if (lev & 1) { int s = (lev >> 1) + lev - 1 ; i = (xdel >> s) & 7 ; int r = 0 ; int off = (x & 31) + ((xdel & ((1 << s) - 1)) << 5) ; while (i < 8) { int t = nextcell(x, y, n->d[i], lev-1) ; if (t < 0) { r += (32 << s) - off ; x += (32 << s) - off ; off = 0 ; } else { return r + t ; } i++ ; } return -1 ; } else { int s = (lev >> 1) + lev - 3 ; i = (ydel >> s) & 7 ; return nextcell(x, y, n->d[i], lev-1) ; } } x &= 31 ; y &= 31 ; tile *p = (tile *)n ; brick *br = (brick *)(p->b[(y>>3) & 3]) ; if (br == emptybrick) return -1 ; int i = ((x >> 2) & 7) ; int add = (generation.odd() ? 8 : 0) ; int sh = (7 - (y & 7)) * 4 ; int r = 0 ; x &= 3 ; int m = 15 >> x ; while (i < 8) { int t = (br->d[i+add] >> sh) & m ; if (t) { if (t & 8) return r - x ; if (t & 4) return r + 1 - x ; if (t & 2) return r + 2 - x ; return r + 3 - x ; } r += (4 - x) ; x = 0 ; m = 15 ; i++ ; } return -1 ; } /* * This subroutine calculates the population count of the universe. It * uses dirty bits number 1 and 2 of supertiles. */ G_INT64 qlifealgo::find_set_bits(supertile *p, int lev, int gm1) { G_INT64 pop = 0 ; int i, j, k, b ; if (lev == 0) { tile *pp = (tile *)p ; b = 8 + gm1 * 12 ; pop = (pp->flags >> b) & 0xfff ; if (pop > 0x800) { pop = 0 ; for (i=0; i<4; i++) { if (pp->b[i] != emptybrick) { for (j=0; j<8; j++) { k = pp->b[i]->d[j+gm1*8] ; if (k) pop += bc[k & 255] + bc[(k >> 8) & 255] + bc[(k >> 16) & 255] + bc[(k >> 24) & 255] ; } } } pp->flags = (long)((pp->flags & ~(0xfff << b)) | (pop << b)) ; } } else { if (p->flags & (0x20000000 << gm1)) { for (i=0; i<8; i++) if (p->d[i] != nullroots[lev-1]) pop += find_set_bits(p->d[i], lev-1, gm1) ; if (pop < 500000000) { p->pop[gm1] = (long)pop ; p->flags &= ~(0x20000000 << gm1) ; } else { p->pop[gm1] = 0xfffffff ; // placeholder; *some* bits are set } } else { pop = p->pop[gm1] ; } } return pop ; } /** * A variation that tries to quickly answer: *any* bits set? */ int qlifealgo::isEmpty(supertile *p, int lev, int gm1) { int i, j, k, b ; if (lev == 0) { tile *pp = (tile *)p ; b = 8 + gm1 * 12 ; int pop = (pp->flags >> b) & 0xfff ; if (pop > 0x800) { pop = 0 ; for (i=0; i<4; i++) { if (pp->b[i] != emptybrick) { for (j=0; j<8; j++) { k = pp->b[i]->d[j+gm1*8] ; if (k) return 0 ; } } } } return pop ? 0 : 1 ; } else { if (p->flags & (0x20000000 << gm1)) { for (i=0; i<8; i++) if (p->d[i] != nullroots[lev-1]) if (!isEmpty(p->d[i], lev-1, gm1)) return 0 ; return 1 ; } else { return p->pop[gm1] ? 0 : 1 ; } } } /* * Another critical subroutine, this one cleans up the empty bricks, * tiles, and supertiles as the generations go by. This speeds things * up by not using too much memory (minimizing cache misses and TLB * misses). We only try to delete bricks, tiles, and supertiles from * regions of the universe that have been active since we last attempted * to delete tiles. We delete all possible tiles, even those near active * regions; if necessary, * * We use dirty bit number 0 of supertiles, and dirty bits 0..3 of * tiles. */ supertile *qlifealgo::mdelete(supertile *p, int lev) { int i ; if (lev == 0) { tile *pp = (tile *)p ; if (pp->flags & 0xf) { int seen = 0 ; for (i=0; i<4; i++) { brick *b = pp->b[i] ; if (b != emptybrick) { if ((pp->flags & (1 << i))) { if (b->d[0] | b->d[1] | b->d[2] | b->d[3] | b->d[4] | b->d[5] | b->d[6] | b->d[7] | b->d[8] | b->d[9] | b->d[10] | b->d[11] | b->d[12] | b->d[13] | b->d[14] | b->d[15]) { seen++ ; } else { STAT(bricks--) ; ((linkedmem *)b)->next = bricklist ; bricklist = (linkedmem *)b ; pp->b[i] = emptybrick ; } } else seen++ ; } } if (seen || ((pp->c[1] | pp->c[2] | pp->c[3] | pp->c[4]) & 0xff) || ((generation.odd()) ? pp->c[5] : pp->c[0])) pp->flags &= 0xfffffff0 ; else { STAT(tiles--) ; memset(pp, 0, sizeof(tile)) ; ((linkedmem *)pp)->next = tilelist ; tilelist = (linkedmem *)pp ; return nullroots[lev] ; } } } else { if (p->flags & 0x10000000) { int keep = 0 ; for (i=0; i<8; i++) if (p->d[i] != nullroots[lev-1]) if ((p->d[i] = mdelete(p->d[i], lev-1)) != nullroots[lev-1]) keep++ ; if (keep || p == root || (p->flags & 0x3ffff)) p->flags &= 0xefffffff ; else { STAT(supertiles--) ; memset(p, 0, sizeof(supertile)) ; ((linkedmem *)p)->next = supertilelist ; supertilelist = (linkedmem *)p ; return nullroots[lev] ; } } } return p ; } G_INT64 qlifealgo::popcount() { return find_set_bits(root, rootlev, generation.odd()) ; } const bigint &qlifealgo::getPopulation() { if (!popValid) { population = bigint(popcount()) ; popValid = 1 ; poller->reset_countdown() ; } return population ; } int qlifealgo::isEmpty() { return isEmpty(root, rootlev, generation.odd()) ; } /* * Here we look at the root node and see if activity is getting * uncomfortably close to the current edges. If so, we add another * level onto the top. */ int qlifealgo::uproot_needed() { int i ; if (root->d[0] != nullroots[rootlev-1] || root->d[7] != nullroots[rootlev-1]) return 1 ; for (i=1; i<7; i++) if (root->d[i]->d[0] != nullroots[rootlev-2] || root->d[i]->d[7] != nullroots[rootlev-2]) return 1 ; return 0 ; } /* * The new generation code is simple. We uproot if needed. Then, we call * the appropriate top-level slice code depending on the generation number. * Finally, if we are generations 64, 128, 192, and so on, we clean up * the tree. * * Note that this 64 was carefully chosen to balance extraneous bricks left * behind by gliders against the computational cost of deletion. */ void qlifealgo::dogen() { poller->reset_countdown() ; #ifdef STATS ds = 0 ; dq = 0 ; rcc = 0 ; #endif // AKT: if grid is bounded then we should never need to call uproot() here // because setrule() has already expanded the universe to enclose the grid if (gridwd == 0 || gridht == 0) { while (uproot_needed()) uproot() ; } if (generation.odd()) doquad10(root, nullroot, nullroot, nullroot, rootlev) ; else doquad01(root, nullroot, nullroot, nullroot, rootlev) ; deltaforward = 0 ; generation += bigint::one ; popValid = 0 ; if (--cleandowncounter == 0) { cleandowncounter = 63 ; mdelete(root, rootlev) ; } #ifdef STATS dss += ds ; dqs += dq ; rccs += rcc ; #endif } /** * Step. Do increment generations. */ void qlifealgo::step() { poller->bailIfCalculating() ; bigint t = increment ; while (t != 0) { if (qliferules.alternate_rules) { // emulate B0-not-Smax rule by changing rule table depending on gen parity if (generation.odd()) ruletable = qliferules.rule1 ; else ruletable = qliferules.rule0 ; } else { ruletable = qliferules.rule0 ; } dogen() ; if (poller->isInterrupted()) break ; t -= 1 ; if (t > increment) // might change; make it happen now t = increment ; } } // Flip bits in given rule table. // This is a tad tricky because we want to turn both the input // and the output of this table upside down. static void fliprule(char *rptr) { for (int i=0; i<65536; i++) { int j = ((i & 0xf) << 12) + ((i & 0xf0) << 4) + ((i & 0xf00) >> 4) + ((i & 0xf000) >> 12) ; if (i <= j) { char fi = rptr[i] ; char fj = rptr[j] ; fi = ((fi & 0x30) >> 4) + ((fi & 0x3) << 4) ; fj = ((fj & 0x30) >> 4) + ((fj & 0x3) << 4) ; rptr[i] = fj ; rptr[j] = fi ; } } } /** * If we change the rule we need to mark everything dirty. */ const char *qlifealgo::setrule(const char *s) { const char* err = qliferules.setrule(s, this); if (err) return err; markglobalchange() ; // AKT: qlifealgo has an opposite interpretation of the orientation of // a rule table assumed by qliferules.setrule. For vertically symmetrical // rules such as the Moore or von Neumann neighborhoods this doesn't matter, // but for hexagonal rules and Wolfram rules we need to flip the rule table(s) // upside down. if ( qliferules.isHexagonal() || qliferules.isWolfram() ) { if (qliferules.alternate_rules) { // hex rule has B0 but not S6 so we'll be using rule1 for odd gens fliprule(qliferules.rule1); } fliprule(qliferules.rule0); } // ruletable is set in step(), but play safe ruletable = qliferules.rule0 ; if (qliferules.isHexagonal()) grid_type = HEX_GRID; else if (qliferules.isVonNeumann()) grid_type = VN_GRID; else grid_type = SQUARE_GRID; // AKT: if the grid is bounded then call uproot() if necessary so that // dogen() never needs to call it if (gridwd > 0 && gridht > 0) { // use the top left and bottom right corners of the grid, but expanded by 2 // to allow for growth in the borders when the grid edges are joined int xmin = -int(gridwd/2) - 2; int ymin = -int(gridht/2) - 2; int xmax = xmin + gridwd + 3; int ymax = ymin + gridht + 3; // duplicate the expansion code in setcell() ymin = -ymin; ymax = -ymax; if (generation.odd()) { xmin--; ymin--; xmax--; ymax--; } // min is -ve, max is +ve, xmin is -ve, xmax is +ve, ymin is +ve, ymax is -ve while (xmin < min || xmax > max || ymin > max || ymax < min) uproot(); } return 0; } static lifealgo *creator() { return new qlifealgo() ; } void qlifealgo::doInitializeAlgoInfo(staticAlgoInfo &ai) { ai.setAlgorithmName("QuickLife") ; ai.setAlgorithmCreator(&creator) ; ai.setDefaultBaseStep(10) ; ai.setDefaultMaxMem(0) ; ai.minstates = 2 ; ai.maxstates = 2 ; // init default color scheme ai.defgradient = false; ai.defr1 = ai.defg1 = ai.defb1 = 255; // start color = white ai.defr2 = ai.defg2 = ai.defb2 = 255; // end color = white ai.defr[0] = ai.defg[0] = ai.defb[0] = 48; // 0 state = dark gray ai.defr[1] = ai.defg[1] = ai.defb[1] = 255; // 1 state = white } golly-2.7-src/gollybase/ruletable_algo.cpp0000644000175000017500000010044012536111364015665 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "ruletable_algo.h" #include "util.h" // for lifegetuserrules, lifegetrulesdir, lifewarning // for case-insensitive string comparison #include #ifndef WIN32 #define stricmp strcasecmp #define strnicmp strncasecmp #endif #include #include #include using namespace std; const string ruletable_algo::neighborhood_value_keywords[N_SUPPORTED_NEIGHBORHOODS] = {"vonNeumann","Moore","hexagonal","oneDimensional"}; // (keep in sync with TNeighborhood) bool ruletable_algo::IsDefaultRule(const char* rulename) { return (strcmp(rulename, DefaultRule()) == 0); } static FILE* static_rulefile = NULL; static int static_lineno = 0; static char static_endchar = 0; const char* ruletable_algo::LoadTable(FILE* rulefile, int lineno, char endchar, const char* s) { // set static vars so LoadRuleTable() will load table data from .rule file static_rulefile = rulefile; static_lineno = lineno; static_endchar = endchar; const char* err = setrule(s); // calls LoadRuleTable // reset static vars static_rulefile = NULL; static_lineno = 0; static_endchar = 0; return err; } int ruletable_algo::NumCellStates() { return this->n_states; } bool starts_with(const string& line,const string& keyword) { return strnicmp(line.c_str(),keyword.c_str(),keyword.length())==0; } const char* ruletable_algo::setrule(const char* s) { const char *colonptr = strchr(s, ':'); string rule_name(s); if (colonptr) rule_name.assign(s,colonptr); static string ret; // NOTE: don't initialize this statically! ret = LoadRuleTable(rule_name.c_str()); if(!ret.empty()) { // if the file exists and we've got an error then it must be a file format issue if(!starts_with(ret,"Failed to open file: ")) lifewarning(ret.c_str()); return ret.c_str(); } // check for rule suffix like ":T200,100" to specify a bounded universe if (colonptr) { const char* err = setgridsize(colonptr); if (err) return err; } else { // universe is unbounded gridwd = 0; gridht = 0; } // set canonical rule string returned by getrule() this->current_rule = rule_name.c_str(); if (gridwd > 0 || gridht > 0) { // setgridsize() was successfully called above, so append suffix string bounds = canonicalsuffix(); this->current_rule += bounds; } maxCellStates = this->n_states; ghashbase::setrule(rule_name.c_str()); return NULL; } vector tokenize(const string& str,const string& delimiters) { vector tokens; // skip delimiters at beginning. string::size_type lastPos = str.find_first_not_of(delimiters, 0); // find first "non-delimiter". string::size_type pos = str.find_first_of(delimiters, lastPos); while (string::npos != pos || string::npos != lastPos) { // found a token, add it to the vector. tokens.push_back(str.substr(lastPos, pos - lastPos)); // skip delimiters. Note the "not_of" lastPos = str.find_first_not_of(delimiters, pos); // find next "non-delimiter" pos = str.find_first_of(delimiters, lastPos); } return tokens; } string trim_right(const string & s, const string & t = " \t\r\n") { string d (s); string::size_type i (d.find_last_not_of (t)); if (i == string::npos) return ""; else return d.erase (d.find_last_not_of (t) + 1); } string trim_left(const string & s, const string & t = " \t\r\n") { string d (s); return d.erase (0, s.find_first_not_of (t)); } string trim(const string & s, const string & t = " \t\r\n") { string d (s); return trim_left (trim_right (d, t), t); } const char *defaultRuleData[] = { "n_states:8", "neighborhood:vonNeumann", "symmetries:rotate4", "000000", "000012", "000020", "000030", "000050", "000063", "000071", "000112", "000122", "000132", "000212", "000220", "000230", "000262", "000272", "000320", "000525", "000622", "000722", "001022", "001120", "002020", "002030", "002050", "002125", "002220", "002322", "005222", "012321", "012421", "012525", "012621", "012721", "012751", "014221", "014321", "014421", "014721", "016251", "017221", "017255", "017521", "017621", "017721", "025271", "100011", "100061", "100077", "100111", "100121", "100211", "100244", "100277", "100511", "101011", "101111", "101244", "101277", "102026", "102121", "102211", "102244", "102263", "102277", "102327", "102424", "102626", "102644", "102677", "102710", "102727", "105427", "111121", "111221", "111244", "111251", "111261", "111277", "111522", "112121", "112221", "112244", "112251", "112277", "112321", "112424", "112621", "112727", "113221", "122244", "122277", "122434", "122547", "123244", "123277", "124255", "124267", "125275", "200012", "200022", "200042", "200071", "200122", "200152", "200212", "200222", "200232", "200242", "200250", "200262", "200272", "200326", "200423", "200517", "200522", "200575", "200722", "201022", "201122", "201222", "201422", "201722", "202022", "202032", "202052", "202073", "202122", "202152", "202212", "202222", "202272", "202321", "202422", "202452", "202520", "202552", "202622", "202722", "203122", "203216", "203226", "203422", "204222", "205122", "205212", "205222", "205521", "205725", "206222", "206722", "207122", "207222", "207422", "207722", "211222", "211261", "212222", "212242", "212262", "212272", "214222", "215222", "216222", "217222", "222272", "222442", "222462", "222762", "222772", "300013", "300022", "300041", "300076", "300123", "300421", "300622", "301021", "301220", "302511", "401120", "401220", "401250", "402120", "402221", "402326", "402520", "403221", "500022", "500215", "500225", "500232", "500272", "500520", "502022", "502122", "502152", "502220", "502244", "502722", "512122", "512220", "512422", "512722", "600011", "600021", "602120", "612125", "612131", "612225", "700077", "701120", "701220", "701250", "702120", "702221", "702251", "702321", "702525", "702720", 0 }; static FILE *OpenTableFile(string &rule, const char *dir, string &path) { // look for rule.table in given dir and set path path = dir; int istart = (int)path.size(); path += rule + ".table"; // change "dangerous" characters to underscores for (unsigned int i=istart; i > available_symmetries; { const string vonNeumann_available_symmetries[5] = {"none","rotate4","rotate4reflect","reflect_horizontal","permute"}; available_symmetries["vonNeumann"].assign(vonNeumann_available_symmetries,vonNeumann_available_symmetries+5); const string Moore_available_symmetries[7] = {"none","rotate4","rotate8","rotate4reflect","rotate8reflect","reflect_horizontal","permute"}; available_symmetries["Moore"].assign(Moore_available_symmetries,Moore_available_symmetries+7); const string hexagonal_available_symmetries[6] = {"none","rotate2","rotate3","rotate6","rotate6reflect","permute"}; available_symmetries["hexagonal"].assign(hexagonal_available_symmetries,hexagonal_available_symmetries+6); const string oneDimensional_available_symmetries[3] = {"none","reflect","permute"}; available_symmetries["oneDimensional"].assign(oneDimensional_available_symmetries,oneDimensional_available_symmetries+3); } string line; const int MAX_LINE_LEN=1000; char line_buffer[MAX_LINE_LEN]; FILE *in = 0; linereader line_reader(0); int lineno = 0; string full_filename; bool isDefaultRule = IsDefaultRule(rule.c_str()); if (isDefaultRule) { // no need to read table data from a file } else if (static_rulefile) { // read table data from currently open .rule file line_reader.setfile(static_rulefile); line_reader.setcloseonfree(); lineno = static_lineno; full_filename = rule + ".rule"; } else { // look for rule.table in user's rules dir then in Golly's rules dir in = OpenTableFile(rule, lifegetuserrules(), full_filename); if (!in) in = OpenTableFile(rule, lifegetrulesdir(), full_filename); if (!in) return "Failed to open file: "+full_filename; line_reader.setfile(in); line_reader.setcloseonfree(); // make sure it goes away if we return with an error } string symmetries = "rotate4"; // default TNeighborhood neighborhood = vonNeumann; // default unsigned int n_states = 8; // default map< string, vector > variables; vector< pair< vector< vector >, state > > transition_table; unsigned int n_inputs=0; // these line must have been read before the rest of the file bool n_states_parsed=false,neighborhood_parsed=false,symmetries_parsed=false; for (;;) { if (isDefaultRule) { if (defaultRuleData[lineno] == 0) break; line = defaultRuleData[lineno]; } else { if (!line_reader.fgets(line_buffer,MAX_LINE_LEN)) break; if (static_rulefile && line_buffer[0] == static_endchar) break; line = line_buffer; } lineno++; // snip off any trailing comment if(line.find('#')!=string::npos) line.assign(line.begin(),line.begin()+line.find('#')); // trim any leading/trailing whitespace line = trim(line); // try each of the allowed forms for this line: if(line.empty()) continue; // line was blank or just had a comment else if(starts_with(line,n_states_keyword)) { // parse the rest of the line if(sscanf(line.c_str()+n_states_keyword.length(),"%d",&n_states)!=1) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line; return oss.str(); } if(n_states<2 || n_states>256) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": n_states out of range (min 2, max 256)"; return oss.str(); } n_states_parsed = true; } else if(starts_with(line,neighborhood_keyword)) { // parse the rest of the line string remaining(line.begin()+neighborhood_keyword.length(),line.end()); remaining = trim(remaining); // (allow for space between : and value) const string* found = find(this->neighborhood_value_keywords, this->neighborhood_value_keywords+N_SUPPORTED_NEIGHBORHOODS,remaining); if(found == this->neighborhood_value_keywords+N_SUPPORTED_NEIGHBORHOODS) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": unsupported neighborhood"; return oss.str(); } neighborhood = (TNeighborhood)(found - this->neighborhood_value_keywords); switch(neighborhood) { default: case vonNeumann: n_inputs=5; grid_type=VN_GRID; break; case Moore: n_inputs=9; grid_type=SQUARE_GRID; break; case hexagonal: n_inputs=7; grid_type=HEX_GRID; break; case oneDimensional: n_inputs=3; grid_type=SQUARE_GRID; break; } neighborhood_parsed = true; } else if(starts_with(line,symmetries_keyword)) { if(!neighborhood_parsed) { ostringstream oss; oss << "Error reading " << full_filename << ": neighborhood must be declared before symmetries"; return oss.str(); } string remaining(line.begin()+symmetries_keyword.length(),line.end()); remaining = trim(remaining); // (allow for space between : and value) string neighborhood_as_string = this->neighborhood_value_keywords[neighborhood]; vector::const_iterator found = find( available_symmetries[neighborhood_as_string].begin(), available_symmetries[neighborhood_as_string].end(), remaining ); if(found == available_symmetries[neighborhood_as_string].end()) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": unsupported symmetries"; return oss.str(); } symmetries = remaining; symmetries_parsed = true; } else if(starts_with(line,variable_keyword)) { if(!n_states_parsed || !neighborhood_parsed || !symmetries_parsed) { ostringstream oss; oss << "Error reading " << full_filename << ": one or more of n_states, neighborhood or symmetries missing\nbefore first variable"; return oss.str(); } // parse the rest of the line for the variable vector tokens = tokenize(line,"= {,}"); string variable_name = tokens[1]; vector states; if(tokens.size()<3) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line; return oss.str(); } for(unsigned int i=2;i=n_states) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line << " - state value out of range"; return oss.str(); } states.push_back((state)s); } } variables[variable_name] = states; } else { // must be a transitions line if(!n_states_parsed || !neighborhood_parsed || !symmetries_parsed) { ostringstream oss; oss << "Error reading " << full_filename << ": one or more of n_states, neighborhood or symmetries missing\nbefore first transition"; return oss.str(); } if(n_states<=10 && variables.empty() && line.find(',')==string::npos) { // if there are only single-digit states and no variables then can use comma-free form: // e.g. 012345 for 0,1,2,3,4 -> 5 vector< vector > inputs; state output; if(line.length() < n_inputs+1) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line << " - too few entries"; return oss.str(); } for(unsigned int i=0;i'9') { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line; return oss.str(); } inputs.push_back(vector(1,c-'0')); } unsigned char c = line[n_inputs]; if(c<'0' || c>'9') { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line; return oss.str(); } output = c-'0'; transition_table.push_back(make_pair(inputs,output)); } else // transition line with commas { vector tokens = tokenize(line,", #\t"); if(tokens.size() < n_inputs+1) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line << " - too few entries"; return oss.str(); } // first pass: which variables appear more than once? these are "bound" (must take the same value each time they appear in this transition) vector bound_variables; for(map< string, vector >::const_iterator var_it=variables.begin();var_it!=variables.end();var_it++) if(count(tokens.begin(),tokens.begin()+n_inputs+1,var_it->first)>1) bound_variables.push_back(var_it->first); unsigned int n_bound_variables = (unsigned int)bound_variables.size(); // second pass: iterate through the possible states for the bound variables, adding a transition for each combination vector< vector > inputs(n_inputs); state output; map bound_variable_indices; // each is an index into vector of 'variables' map for(unsigned int i=0;i(1,variables[tokens[i]][bound_variable_indices[tokens[i]]]); // this input is a bound variable else if(variables.find(tokens[i])!=variables.end()) inputs[i] = variables[tokens[i]]; // this input is an unbound variable else { unsigned int s=0; if(sscanf(tokens[i].c_str(),"%u",&s)!=1) // this input is a state { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line; return oss.str(); } if(s>=n_states) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line << " - state out of range"; return oss.str(); } inputs[i] = vector(1,(state)s); } } // collect the output if(!bound_variables.empty() && find(bound_variables.begin(),bound_variables.end(),tokens[n_inputs])!=bound_variables.end()) output = variables[tokens[n_inputs]][bound_variable_indices[tokens[n_inputs]]]; else { unsigned int s; if(variables.find(tokens[n_inputs])!=variables.end() && variables[tokens[n_inputs]].size()==1) { // single-state variables are permitted as the output s = variables[tokens[n_inputs]][0]; } else if(sscanf(tokens[n_inputs].c_str(),"%u",&s)!=1) // if not a bound variable, output must be a state { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line << " - output must be state, single-state variable or bound variable"; return oss.str(); } if(s>=n_states) { ostringstream oss; oss << "Error reading " << full_filename << " on line " << lineno << ": " << line << " - state out of range"; return oss.str(); } output = (state)s; } transition_table.push_back(make_pair(inputs,output)); // move on to the next value of bound variables { unsigned int iChanging=0; for(;iChanging=n_bound_variables) break; } } } } } // (finished reading lines from the file) if(!n_states_parsed || !neighborhood_parsed || !symmetries_parsed) { ostringstream oss; oss << "Error reading " << full_filename << ": one or more of n_states, neighborhood or symmetries missing"; return oss.str(); } this->neighborhood = neighborhood; this->n_states = n_states; PackTransitions(symmetries,n_inputs,transition_table); return string(""); // success } // convert transition table to bitmask lookup void ruletable_algo::PackTransitions(const string& symmetries, int n_inputs, const vector< pair< vector< vector >, state > >& transition_table) { // cumbersome initialization of a remap array for the different symmetries map< string, vector< vector > > symmetry_remap[N_SUPPORTED_NEIGHBORHOODS]; { int vn_rotate4[4][6] = {{0,1,2,3,4,5},{0,2,3,4,1,5},{0,3,4,1,2,5},{0,4,1,2,3,5}}; for(int i=0;i<4;i++) symmetry_remap[vonNeumann]["rotate4"].push_back(vector(vn_rotate4[i],vn_rotate4[i]+6)); int vn_rotate4reflect[8][6] = {{0,1,2,3,4,5},{0,2,3,4,1,5},{0,3,4,1,2,5},{0,4,1,2,3,5}, {0,4,3,2,1,5},{0,3,2,1,4,5},{0,2,1,4,3,5},{0,1,4,3,2,5}}; for(int i=0;i<8;i++) symmetry_remap[vonNeumann]["rotate4reflect"].push_back(vector(vn_rotate4reflect[i],vn_rotate4reflect[i]+6)); int vn_reflect_horizontal[2][6] = {{0,1,2,3,4,5},{0,1,4,3,2,5}}; for(int i=0;i<2;i++) symmetry_remap[vonNeumann]["reflect_horizontal"].push_back(vector(vn_reflect_horizontal[i],vn_reflect_horizontal[i]+6)); int moore_rotate4[4][10] = {{0,1,2,3,4,5,6,7,8,9},{0,3,4,5,6,7,8,1,2,9},{0,5,6,7,8,1,2,3,4,9},{0,7,8,1,2,3,4,5,6,9}}; for(int i=0;i<4;i++) symmetry_remap[Moore]["rotate4"].push_back(vector(moore_rotate4[i],moore_rotate4[i]+10)); int moore_rotate8[8][10] = {{0,1,2,3,4,5,6,7,8,9},{0,2,3,4,5,6,7,8,1,9},{0,3,4,5,6,7,8,1,2,9},{0,4,5,6,7,8,1,2,3,9}, {0,5,6,7,8,1,2,3,4,9},{0,6,7,8,1,2,3,4,5,9},{0,7,8,1,2,3,4,5,6,9},{0,8,1,2,3,4,5,6,7,9}}; for(int i=0;i<8;i++) symmetry_remap[Moore]["rotate8"].push_back(vector(moore_rotate8[i],moore_rotate8[i]+10)); int moore_rotate4reflect[8][10] = {{0,1,2,3,4,5,6,7,8,9},{0,3,4,5,6,7,8,1,2,9},{0,5,6,7,8,1,2,3,4,9},{0,7,8,1,2,3,4,5,6,9}, {0,1,8,7,6,5,4,3,2,9},{0,7,6,5,4,3,2,1,8,9},{0,5,4,3,2,1,8,7,6,9},{0,3,2,1,8,7,6,5,4,9}}; for(int i=0;i<8;i++) symmetry_remap[Moore]["rotate4reflect"].push_back(vector(moore_rotate4reflect[i],moore_rotate4reflect[i]+10)); int moore_rotate8reflect[16][10] = {{0,1,2,3,4,5,6,7,8,9},{0,2,3,4,5,6,7,8,1,9},{0,3,4,5,6,7,8,1,2,9},{0,4,5,6,7,8,1,2,3,9}, {0,5,6,7,8,1,2,3,4,9},{0,6,7,8,1,2,3,4,5,9},{0,7,8,1,2,3,4,5,6,9},{0,8,1,2,3,4,5,6,7,9}, {0,8,7,6,5,4,3,2,1,9},{0,7,6,5,4,3,2,1,8,9},{0,6,5,4,3,2,1,8,7,9},{0,5,4,3,2,1,8,7,6,9}, {0,4,3,2,1,8,7,6,5,9},{0,3,2,1,8,7,6,5,4,9},{0,2,1,8,7,6,5,4,3,9},{0,1,8,7,6,5,4,3,2,9}}; for(int i=0;i<16;i++) symmetry_remap[Moore]["rotate8reflect"].push_back(vector(moore_rotate8reflect[i],moore_rotate8reflect[i]+10)); int moore_reflect_horizontal[2][10] = {{0,1,2,3,4,5,6,7,8,9},{0,1,8,7,6,5,4,3,2,9}}; for(int i=0;i<2;i++) symmetry_remap[Moore]["reflect_horizontal"].push_back(vector(moore_reflect_horizontal[i],moore_reflect_horizontal[i]+10)); int oneDimensional_reflect[2][4] = {{0,1,2,3},{0,2,1,3}}; for(int i=0;i<2;i++) symmetry_remap[oneDimensional]["reflect"].push_back(vector(oneDimensional_reflect[i],oneDimensional_reflect[i]+4)); int hex_rotate2[2][8] = {{0,1,2,3,4,5,6,7},{0,4,5,6,1,2,3,7}}; for(int i=0;i<2;i++) symmetry_remap[hexagonal]["rotate2"].push_back(vector(hex_rotate2[i],hex_rotate2[i]+8)); int hex_rotate3[3][8] = {{0,1,2,3,4,5,6,7},{0,3,4,5,6,1,2,7},{0,5,6,1,2,3,4,7}}; for(int i=0;i<3;i++) symmetry_remap[hexagonal]["rotate3"].push_back(vector(hex_rotate3[i],hex_rotate3[i]+8)); int hex_rotate6[6][8] = {{0,1,2,3,4,5,6,7},{0,2,3,4,5,6,1,7},{0,3,4,5,6,1,2,7}, {0,4,5,6,1,2,3,7},{0,5,6,1,2,3,4,7},{0,6,1,2,3,4,5,7}}; for(int i=0;i<6;i++) symmetry_remap[hexagonal]["rotate6"].push_back(vector(hex_rotate6[i],hex_rotate6[i]+8)); int hex_rotate6reflect[12][8] = {{0,1,2,3,4,5,6,7},{0,2,3,4,5,6,1,7},{0,3,4,5,6,1,2,7}, {0,4,5,6,1,2,3,7},{0,5,6,1,2,3,4,7},{0,6,1,2,3,4,5,7}, {0,6,5,4,3,2,1,7},{0,5,4,3,2,1,6,7},{0,4,3,2,1,6,5,7}, {0,3,2,1,6,5,4,7},{0,2,1,6,5,4,3,7},{0,1,6,5,4,3,2,7}}; for(int i=0;i<12;i++) symmetry_remap[hexagonal]["rotate6reflect"].push_back(vector(hex_rotate6reflect[i],hex_rotate6reflect[i]+8)); } // initialize the packed transition table this->lut.assign(n_inputs,vector< vector >(this->n_states)); this->output.clear(); this->n_compressed_rules = 0; // each transition rule looks like: e.g. 1,[2,3,5],4,[0,1],3 -> 0 vector< vector > permuted_inputs(n_inputs); for(vector< pair< vector< vector >, state> >::const_iterator rule_it = transition_table.begin(); rule_it!=transition_table.end(); rule_it++) { const vector< vector > & inputs = rule_it->first; state output = rule_it->second; if(symmetries=="none") { PackTransition(inputs,output); } else if(symmetries=="permute") { // work through the permutations of all but the centre cell permuted_inputs = inputs; sort(permuted_inputs.begin()+1,permuted_inputs.end()); // (must sort before permuting) do { PackTransition(permuted_inputs,output); } while(next_permutation(permuted_inputs.begin()+1,permuted_inputs.end())); // (skips duplicates) } else { const vector< vector > & remap = symmetry_remap[this->neighborhood][symmetries]; for(int iSymm=0;iSymm<(int)remap.size();iSymm++) { for(int i=0;i > & inputs, state output) { int n_inputs = (int)inputs.size(); const unsigned int n_bits = (unsigned int)(sizeof(TBits)*8); this->output.push_back(output); int iRule = (int)(this->output.size()-1); int iBit = iRule % n_bits; unsigned int iRuleC = (iRule-iBit)/n_bits; // the compressed index of the rule // add a new compressed rule if required if(iRuleC >= this->n_compressed_rules) { for(int iInput=0;iInputlut[iInput][iState].push_back(0); this->n_compressed_rules++; } TBits mask = (TBits)1 << iBit; // (cast needed to ensure this is a 64-bit shift, not a 32-bit shift) for(int iNbor=0;iNbor & possibles = inputs[iNbor]; for(vector::const_iterator poss_it=possibles.begin();poss_it!=possibles.end();poss_it++) { // add the bits this->lut[iNbor][*poss_it][iRuleC] |= mask; } } } const char* ruletable_algo::getrule() { return this->current_rule.c_str(); } const char* ruletable_algo::DefaultRule() { return "Langtons-Loops"; } ruletable_algo::ruletable_algo() : n_states(8), neighborhood(vonNeumann), n_compressed_rules(0) { maxCellStates = n_states; } ruletable_algo::~ruletable_algo() { } // --- the update function --- state ruletable_algo::slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) { TBits is_match = 0; // AKT: explicitly initialized to avoid gcc warning for(unsigned int iRuleC=0;iRuleCn_compressed_rules;iRuleC++) { // is there a match for any of the (e.g.) 64 rules within iRuleC? // (we don't have to worry about symmetries here since they were expanded out in PackTransitions) switch(this->neighborhood) { case vonNeumann: // c,n,e,s,w is_match = this->lut[0][c][iRuleC] & this->lut[1][n][iRuleC] & this->lut[2][e][iRuleC] & this->lut[3][s][iRuleC] & this->lut[4][w][iRuleC]; break; case Moore: // c,n,ne,e,se,s,sw,w,nw is_match = this->lut[0][c][iRuleC] & this->lut[1][n][iRuleC] & this->lut[2][ne][iRuleC] & this->lut[3][e][iRuleC] & this->lut[4][se][iRuleC] & this->lut[5][s][iRuleC] & this->lut[6][sw][iRuleC] & this->lut[7][w][iRuleC] & this->lut[8][nw][iRuleC]; break; case hexagonal: // c,n,e,se,s,w,nw is_match = this->lut[0][c][iRuleC] & this->lut[1][n][iRuleC] & this->lut[2][e][iRuleC] & this->lut[3][se][iRuleC] & this->lut[4][s][iRuleC] & this->lut[5][w][iRuleC] & this->lut[6][nw][iRuleC]; break; case oneDimensional: // c,w,e is_match = this->lut[0][c][iRuleC] & this->lut[1][w][iRuleC] & this->lut[2][e][iRuleC]; break; } // if any of them matched, return the output of the first if(is_match) { // find the least significant bit of is_match unsigned int iBit=0; TBits mask=1; while(!(is_match&mask)) { ++iBit; mask <<= 1; } return this->output[ iRuleC*sizeof(TBits)*8 + iBit ]; // find the uncompressed rule index } } return c; // default: no change } static lifealgo *creator() { return new ruletable_algo(); } void ruletable_algo::doInitializeAlgoInfo(staticAlgoInfo &ai) { ghashbase::doInitializeAlgoInfo(ai); ai.setAlgorithmName("RuleTable"); ai.setAlgorithmCreator(&creator); ai.minstates = 2; ai.maxstates = 256; // init default color scheme ai.defgradient = true; // use gradient ai.defr1 = 255; // start color = red ai.defg1 = 0; ai.defb1 = 0; ai.defr2 = 255; // end color = yellow ai.defg2 = 255; ai.defb2 = 0; // if not using gradient then set all states to white for (int i=0; i<256; i++) { ai.defr[i] = ai.defg[i] = ai.defb[i] = 255; } } golly-2.7-src/gollybase/ruleloaderalgo.h0000644000175000017500000000363712536111364015364 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef RULELOADERALGO_H #define RULELOADERALGO_H #include "ghashbase.h" #include "ruletable_algo.h" #include "ruletreealgo.h" /** * This algorithm loads rule data from external files. */ class ruleloaderalgo : public ghashbase { public: ruleloaderalgo(); virtual ~ruleloaderalgo(); virtual state slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se); virtual const char* setrule(const char* s); virtual const char* getrule(); virtual const char* DefaultRule(); virtual int NumCellStates(); static void doInitializeAlgoInfo(staticAlgoInfo &); protected: ruletable_algo* LocalRuleTable; // local instance of RuleTable algo ruletreealgo* LocalRuleTree; // local instance of RuleTree algo enum RuleTypes {TABLE, TREE} rule_type; void SetAlgoVariables(RuleTypes ruletype); const char* LoadTableOrTree(FILE* rulefile, const char* rule); }; #endif golly-2.7-src/gollybase/lifealgo.h0000644000175000017500000002026712536111364014143 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /** * This is the pure abstract class any life calculation algorithm * must support. As long as a life algorithm implements this * interface, it can be invoked by our driver code. */ #ifndef LIFEALGO_H #define LIFEALGO_H #include "bigint.h" #include "viewport.h" #include "liferender.h" #include "lifepoll.h" #include "readpattern.h" #include "platform.h" #include // moving the include vector *before* platform.h breaks compilation #ifdef _MSC_VER #pragma warning(disable:4702) // disable "unreachable code" warnings from MSVC #endif #include #ifdef _MSC_VER #pragma warning(default:4702) // enable "unreachable code" warnings #endif using std::vector; #include // this must not be increased beyond 32767, because we use a bigint // multiply that only supports multiplicands up to that size. const int MAX_FRAME_COUNT = 32000 ; /** * Timeline support is pretty generic. */ class timeline_t { public: timeline_t() : recording(0), framecount(0), savetimeline(1), start(0), inc(0), next(0), end(0), frames() {} int recording, framecount, base, expo, savetimeline ; bigint start, inc, next, end ; vector frames ; } ; class lifealgo { public: lifealgo() : generation(0), increment(0), timeline(), grid_type(SQUARE_GRID) { poller = &default_poller ; gridwd = gridht = 0 ; // default is an unbounded universe } virtual ~lifealgo() ; virtual void clearall() = 0 ; // returns <0 if error virtual int setcell(int x, int y, int newstate) = 0 ; virtual int getcell(int x, int y) = 0 ; virtual int nextcell(int x, int y, int &v) = 0 ; // call after setcell/clearcell calls virtual void endofpattern() = 0 ; virtual void setIncrement(bigint inc) = 0 ; virtual void setIncrement(int inc) = 0 ; virtual void setGeneration(bigint gen) = 0 ; const bigint &getIncrement() { return increment ; } const bigint &getGeneration() { return generation ; } virtual const bigint &getPopulation() = 0 ; virtual int isEmpty() = 0 ; // can we do the gen count doubling? only hashlife virtual int hyperCapable() = 0 ; virtual void setMaxMemory(int m) = 0 ; // never alloc more than this virtual int getMaxMemory() = 0 ; virtual const char *setrule(const char *) = 0 ; // new rules; returns err msg virtual const char *getrule() = 0 ; // get current rule set virtual void step() = 0 ; // do inc gens virtual void draw(viewport &view, liferender &renderer) = 0 ; virtual void fit(viewport &view, int force) = 0 ; virtual void findedges(bigint *t, bigint *l, bigint *b, bigint *r) = 0 ; virtual void lowerRightPixel(bigint &x, bigint &y, int mag) = 0 ; virtual const char *writeNativeFormat(std::ostream &os, char *comments) = 0 ; void setpoll(lifepoll *pollerarg) { poller = pollerarg ; } virtual const char *readmacrocell(char *) { return "Cannot read macrocell format." ; } // Verbosity crosses algorithms. We need to embed this sort of option // into some global shared thing or something rather than use static. static void setVerbose(int v) { verbose = v ; } static int getVerbose() { return verbose ; } virtual const char* DefaultRule() { return "B3/S23"; } // return number of cell states in this universe (2..256) virtual int NumCellStates() { return 2; } // timeline support virtual void* getcurrentstate() = 0 ; virtual void setcurrentstate(void *) = 0 ; int startrecording(int base, int expo) ; pair stoprecording() ; pair getbaseexpo() { return make_pair(timeline.base, timeline.expo) ; } void extendtimeline() ; void pruneframes() ; const bigint &gettimelinestart() { return timeline.start ; } const bigint &gettimelineend() { return timeline.end ; } const bigint &gettimelineinc() { return timeline.inc ; } int getframecount() { return timeline.framecount ; } int isrecording() { return timeline.recording ; } int gotoframe(int i) ; void destroytimeline() ; void savetimelinewithframe(int yesno) { timeline.savetimeline = yesno ; } // support for a bounded universe with various topologies: // plane, cylinder, torus, Klein bottle, cross-surface, sphere unsigned int gridwd, gridht ; // bounded universe if either is > 0 bigint gridleft, gridright ; // undefined if gridwd is 0 bigint gridtop, gridbottom ; // undefined if gridht is 0 bool boundedplane ; // topology is a bounded plane? bool sphere ; // topology is a sphere? bool htwist, vtwist ; // Klein bottle if either is true, // or cross-surface if both are true int hshift, vshift ; // torus with horizontal or vertical shift const char* setgridsize(const char* suffix) ; // use in setrule() to parse a suffix like ":T100,200" and set // the above parameters const char* canonicalsuffix() ; // use in setrule() to return the canonical version of suffix; // eg. ":t0020" would be converted to ":T20,0" enum TGridType { SQUARE_GRID, TRI_GRID, HEX_GRID, VN_GRID } ; TGridType getgridtype() const { return grid_type ; } protected: lifepoll *poller ; static int verbose ; int maxCellStates ; // keep up to date; setcell depends on it bigint generation ; bigint increment ; timeline_t timeline ; TGridType grid_type ; } ; /** * If you need any static information from a lifealgo, this class can be * called (or overridden) to set up all that data. Right now the * functions do nothing; override if you need that info. These are * called one by one by a static method in the algorithm itself, * if that information is available. The ones marked optional need * not be called. */ class staticAlgoInfo { public: staticAlgoInfo() ; virtual ~staticAlgoInfo() { } ; // mandatory void setAlgorithmName(const char *s) { algoName = s ; } void setAlgorithmCreator(lifealgo *(*f)()) { creator = f ; } // optional; override if you want to retain this data virtual void setDefaultBaseStep(int) {} virtual void setDefaultMaxMem(int) {} // minimum and maximum number of cell states supported by this algorithm; // both must be within 2..256 int minstates; int maxstates; // default color scheme bool defgradient; // use color gradient? unsigned char defr1, defg1, defb1; // color at start of gradient unsigned char defr2, defg2, defb2; // color at end of gradient // if defgradient is false then use these colors for each cell state unsigned char defr[256], defg[256], defb[256]; // default icon data (in XPM format) const char **defxpm7x7; // 7x7 icons const char **defxpm15x15; // 15x15 icons const char **defxpm31x31; // 31x31 icons // basic data const char *algoName ; lifealgo *(*creator)() ; int id ; // my index staticAlgoInfo *next ; // support: give me sequential algorithm IDs static int getNumAlgos() { return nextAlgoId ; } static int nextAlgoId ; static staticAlgoInfo &tick() ; static staticAlgoInfo *head ; static staticAlgoInfo *byName(const char *s) ; static int nameToIndex(const char *s) ; } ; #endif golly-2.7-src/gollybase/ruletreealgo.h0000644000175000017500000000347012536111364015050 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef RULETREEALGO_H #define RULETREEALGO_H #include "ghashbase.h" /** * An algorithm that uses an n-dary decision diagram. */ class ruletreealgo : public ghashbase { public: ruletreealgo() ; virtual ~ruletreealgo() ; virtual state slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) ; virtual const char* setrule(const char* s) ; virtual const char* getrule() ; virtual const char* DefaultRule() ; virtual int NumCellStates() ; static void doInitializeAlgoInfo(staticAlgoInfo &) ; // these two methods are needed for RuleLoader algo bool IsDefaultRule(const char* rulename); const char* LoadTree(FILE* rulefile, int lineno, char endchar, const char* s); private: int *a, base ; state *b ; int num_neighbors, num_states, num_nodes ; char rule[MAXRULESIZE] ; }; #endif golly-2.7-src/gollybase/readpattern.h0000644000175000017500000000341112536111364014662 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef READPATTERN_H #define READPATTERN_H #include "bigint.h" class lifealgo ; /* * Read pattern file into given life algorithm implementation. */ const char *readpattern(const char *filename, lifealgo &imp) ; /* * Get next line from current pattern file. */ char *getline(char *line, int maxlinelen) ; /* * Similar to readpattern but we return the pattern edges * (not necessarily the minimal bounding box; eg. if an * RLE pattern is empty or has empty borders). */ const char *readclipboard(const char *filename, lifealgo &imp, bigint *t, bigint *l, bigint *b, bigint *r) ; /* * Extract comments from pattern file and store in given buffer. * It is the caller's job to free commptr when done (if not NULL). */ const char *readcomments(const char *filename, char **commptr) ; #endif golly-2.7-src/gollybase/writepattern.h0000644000175000017500000000317312536111364015106 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef WRITEPATTERN_H #define WRITEPATTERN_H class lifealgo; typedef enum { RLE_format, // run length encoded XRLE_format, // extended RLE MC_format // macrocell (native hashlife format) } pattern_format; typedef enum { no_compression, // write uncompressed data gzip_compression // write gzip compressed data } output_compression; /* * Save current pattern to a file. */ const char *writepattern(const char *filename, lifealgo &imp, pattern_format format, output_compression compression, int top, int left, int bottom, int right); #endif golly-2.7-src/gollybase/ruletreealgo.cpp0000644000175000017500000002213612536111364015403 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "ruletreealgo.h" #include "util.h" // for lifegetuserrules, lifegetrulesdir, lifewarning #include // for case-insensitive string comparison #include #ifndef WIN32 #define stricmp strcasecmp #endif #include #include #include using namespace std ; bool ruletreealgo::IsDefaultRule(const char* rulename) { // nicer to check for different versions of default rule return (stricmp(rulename, "B3/S23") == 0 || stricmp(rulename, "B3S23") == 0 || strcmp(rulename, "23/3") == 0); } static FILE* static_rulefile = NULL; static int static_lineno = 0; static char static_endchar = 0; const char* ruletreealgo::LoadTree(FILE* rulefile, int lineno, char endchar, const char* s) { // set static vars so setrule() will load tree data from .rule file static_rulefile = rulefile; static_lineno = lineno; static_endchar = endchar; const char* err = setrule(s); // reset static vars static_rulefile = NULL; static_lineno = 0; static_endchar = 0; return err; } int ruletreealgo::NumCellStates() { return num_states ; } const int MAXFILELEN = 4096 ; /* provide the ability to load the default rule without requiring a file */ static const char *defaultRuleData[] = { "num_states=2", "num_neighbors=8", "num_nodes=32", "1 0 0", "2 0 0", "1 0 1", "2 0 2", "3 1 3", "1 1 1", "2 2 5", "3 3 6", "4 4 7", "2 5 0", "3 6 9", "4 7 10", "5 8 11", "3 9 1", "4 10 13", "5 11 14", "6 12 15", "3 1 1", "4 13 17", "5 14 18", "6 15 19", "7 16 20", "4 17 17", "5 18 22", "6 19 23", "7 20 24", "8 21 25", "5 22 22", "6 23 27", "7 24 28", "8 25 29", "9 26 30", 0 } ; static FILE *OpenTreeFile(const char *rule, const char *dir, char *path) { // look for rule.tree in given dir and set path if (strlen(dir) + strlen(rule) + 15 > (unsigned int)MAXFILELEN) { lifewarning("Path too long") ; return NULL ; } sprintf(path, "%s%s.tree", dir, rule) ; // change "dangerous" characters to underscores for (char *p=path + strlen(dir); *p; p++) if (*p == '/' || *p == '\\') *p = '_' ; return fopen(path, "r") ; } const char* ruletreealgo::setrule(const char* s) { const char *colonptr = strchr(s, ':'); string rule_name(s); if (colonptr) rule_name.assign(s,colonptr); char strbuf[MAXFILELEN+1] ; FILE *f = 0 ; linereader lr(0) ; int lineno = 0 ; bool isDefaultRule = IsDefaultRule(rule_name.c_str()) ; if (isDefaultRule) { // no need to read tree data from a file } else if (static_rulefile) { // read tree data from currently open .rule file lr.setfile(static_rulefile); lr.setcloseonfree(); lineno = static_lineno; } else { if (strlen(rule_name.c_str()) >= (unsigned int)MAXRULESIZE) { return "Rule length too long" ; } // look for rule.tree in user's rules dir then in Golly's rules dir f = OpenTreeFile(rule_name.c_str(), lifegetuserrules(), strbuf); if (f == 0) f = OpenTreeFile(rule_name.c_str(), lifegetrulesdir(), strbuf); if (f == 0) { return "File not found" ; } lr.setfile(f) ; lr.setcloseonfree() ; } // check for rule suffix like ":T200,100" to specify a bounded universe if (colonptr) { const char* err = setgridsize(colonptr); if (err) return err; } else { // universe is unbounded gridwd = 0; gridht = 0; } int mnum_states=-1, mnum_neighbors=-1, mnum_nodes=-1 ; vector dat ; vector datb ; vector noff ; int lev = 1000 ; for (;;) { if (isDefaultRule) { if (defaultRuleData[lineno] == 0) break ; strcpy(strbuf, defaultRuleData[lineno]) ; } else { if (lr.fgets(strbuf, MAXFILELEN) == 0) break ; if (static_rulefile && strbuf[0] == static_endchar) break; } lineno++ ; if (strbuf[0] != '#' && strbuf[0] != 0 && sscanf(strbuf, " num_states = %d", &mnum_states) != 1 && sscanf(strbuf, " num_neighbors = %d", &mnum_neighbors) != 1 && sscanf(strbuf, " num_nodes = %d", &mnum_nodes) != 1) { if (mnum_states < 2 || mnum_states > 256 || (mnum_neighbors != 4 && mnum_neighbors != 8) || mnum_nodes < mnum_neighbors || mnum_nodes > 100000000) { return "Bad basic values" ; } if (strbuf[0] < '1' || strbuf[0] > '0' + 1 + mnum_neighbors) { return "Bad line in tree data 1" ; } lev = strbuf[0] - '0' ; int vcnt = 0 ; char *p = strbuf + 1 ; if (lev == 1) noff.push_back((int)(datb.size())) ; else noff.push_back((int)(dat.size())) ; while (*p) { while (*p && *p <= ' ') p++ ; int v = 0 ; while (*p > ' ') { if (*p < '0' || *p > '9') { return "Bad line in tree data 2" ; } v = v * 10 + *p++ - '0' ; } if (lev == 1) { if (v < 0 || v >= mnum_states) { return "Bad state value in tree data" ; } datb.push_back((state)v) ; } else { if (v < 0 || ((unsigned int)v) >= noff.size()) { return "Bad node value in tree data" ; } dat.push_back(noff[v]) ; } vcnt++ ; } if (vcnt != mnum_states) { return "Bad number of values on tree data line" ; } } } if (dat.size() + datb.size() != (unsigned int)(mnum_nodes * mnum_states)) return "Bad count of values in tree data" ; if (lev != mnum_neighbors + 1) return "Bad last node (wrong level)" ; int *na = (int*)calloc(sizeof(int), dat.size()) ; state *nb = (state*)calloc(sizeof(state), datb.size()) ; if (na == 0 || nb == 0) return "Out of memory in tree allocation" ; if (a) free(a) ; if (b) free(b) ; num_nodes = mnum_nodes ; num_states = mnum_states ; num_neighbors = mnum_neighbors ; for (unsigned int i=0; i 0 || gridht > 0) { // setgridsize() was successfully called above, so append suffix int len = (int)strlen(rule) ; const char* bounds = canonicalsuffix() ; int i = 0 ; while (bounds[i]) rule[len++] = bounds[i++] ; rule[len] = 0 ; } return 0 ; } const char* ruletreealgo::getrule() { return rule ; } const char* ruletreealgo::DefaultRule() { return "B3/S23" ; } ruletreealgo::ruletreealgo() : ghashbase(), a(0), base(0), b(0), num_neighbors(0), num_states(0), num_nodes(0) { rule[0] = 0 ; } ruletreealgo::~ruletreealgo() { if (a != 0) { free(a) ; a = 0 ; } if (b != 0) { free(b) ; b = 0 ; } } state ruletreealgo::slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) { if (num_neighbors == 4) return b[a[a[a[a[base+n]+w]+e]+s]+c] ; else return b[a[a[a[a[a[a[a[a[base+nw]+ne]+sw]+se]+n]+w]+e]+s]+c] ; } static lifealgo *creator() { return new ruletreealgo() ; } void ruletreealgo::doInitializeAlgoInfo(staticAlgoInfo &ai) { ghashbase::doInitializeAlgoInfo(ai) ; ai.setAlgorithmName("RuleTree") ; ai.setAlgorithmCreator(&creator) ; ai.minstates = 2 ; ai.maxstates = 256 ; // init default color scheme ai.defgradient = true; // use gradient ai.defr1 = 255; // start color = red ai.defg1 = 0; ai.defb1 = 0; ai.defr2 = 255; // end color = yellow ai.defg2 = 255; ai.defb2 = 0; // if not using gradient then set all states to white for (int i=0; i<256; i++) ai.defr[i] = ai.defg[i] = ai.defb[i] = 255; } golly-2.7-src/gollybase/hlifealgo.cpp0000644000175000017500000016516512536111364014655 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /* * hlife 0.99 by Radical Eye Software. * * All good ideas here were originated by Gosper or Bell or others, I'm * sure, and all bad ones by yours truly. * * The main reason I wrote this program was to attempt to push out the * evaluation of metacatacryst as far as I could. So this program * really does very little other than compute life as far into the * future as possible, using as little memory as possible (and reusing * it if necessary). No UI, few options. */ #include "hlifealgo.h" #include "util.h" #include #include #include using namespace std ; /* * Prime hash sizes tend to work best. */ static g_uintptr_t nextprime(g_uintptr_t i) { g_uintptr_t j ; i |= 1 ; for (;; i+=2) { for (j=3; j*j<=i; j+=2) if (i % j == 0) break ; if (j*j > i) return i ; } } /* * Note that all the places we represent 4-squares by short, we use * unsigned shorts; this is so we can directly index into these arrays. */ static unsigned char shortpop[65536] ; /* * The cached result of an 8-square is a new 4-square representing * two generations into the future. This subroutine calculates that * future, assuming ruletable is calculated (see below). The code * that it uses is similar to code you'll see again, so we explain * what's going on in some detail. * * Each time we build a leaf node, we compute the result, because it * is reasonably quick. * * The first generation result of an 8-square is a 6-square, which * we represent as nine 2-squares. The nine 2-squares are called * t00 through t22, and are arranged in a matrix: * * t00 t01 t02 * t10 t11 t12 * t20 t21 t22 * * To compute each of these, we need to extract the relevant bits * from the four 4-square values n->nw, n->ne, n->sw, and n->ne. * We can use these values to directly index into the ruletable * array. * * Then, given the nine values, we can compute a resulting 4-square * by computing four 2-square results, and combining these into a * single 4-square. * * It's a bit intricate, but it's not really overwhelming. */ #define combine9(t00,t01,t02,t10,t11,t12,t20,t21,t22) \ ((t00) << 15) | ((t01) << 13) | (((t02) << 11) & 0x1000) | \ (((t10) << 7) & 0x880) | ((t11) << 5) | (((t12) << 3) & 0x110) | \ (((t20) >> 1) & 0x8) | ((t21) >> 3) | ((t22) >> 5) void hlifealgo::leafres(leaf *n) { unsigned short t00 = ruletable[n->nw], t01 = ruletable[((n->nw << 2) & 0xcccc) | ((n->ne >> 2) & 0x3333)], t02 = ruletable[n->ne], t10 = ruletable[((n->nw << 8) & 0xff00) | ((n->sw >> 8) & 0x00ff)], t11 = ruletable[((n->nw << 10) & 0xcc00) | ((n->ne << 6) & 0x3300) | ((n->sw >> 6) & 0x00cc) | ((n->se >> 10) & 0x0033)], t12 = ruletable[((n->ne << 8) & 0xff00) | ((n->se >> 8) & 0x00ff)], t20 = ruletable[n->sw], t21 = ruletable[((n->sw << 2) & 0xcccc) | ((n->se >> 2) & 0x3333)], t22 = ruletable[n->se] ; n->res1 = combine9(t00,t01,t02,t10,t11,t12,t20,t21,t22) ; n->res2 = (ruletable[(t00 << 10) | (t01 << 8) | (t10 << 2) | t11] << 10) | (ruletable[(t01 << 10) | (t02 << 8) | (t11 << 2) | t12] << 8) | (ruletable[(t10 << 10) | (t11 << 8) | (t20 << 2) | t21] << 2) | ruletable[(t11 << 10) | (t12 << 8) | (t21 << 2) | t22] ; n->leafpop = shortpop[n->nw] + shortpop[n->ne] + shortpop[n->sw] + shortpop[n->se] ; } /* * We do now support garbage collection, but there are some routines we * call frequently to help us. */ #define node_hash(a,b,c,d) (65537*(g_uintptr_t)(d)+257*(g_uintptr_t)(c)+17*(g_uintptr_t)(b)+5*(g_uintptr_t)(a)) #define leaf_hash(a,b,c,d) (65537*(d)+257*(c)+17*(b)+5*(a)) /* * Resize the hash. */ void hlifealgo::resize() { g_uintptr_t i, nhashprime = nextprime(2 * hashprime) ; node *p, **nhashtab ; if (alloced > maxmem || nhashprime * sizeof(node *) > (maxmem - alloced)) { hashlimit = G_MAX ; return ; } /* * Don't let the hash table buckets take more than 4% of the * memory. If we're starting to strain memory, let the buckets * fill up a bit more. */ if (nhashprime > (maxmem/(25*sizeof(int *)))) { nhashprime = nextprime(maxmem/(25*sizeof(int *))) ; if (nhashprime == hashprime) { hashlimit = G_MAX ; return ; } } if (verbose) { strcpy(statusline, "Resizing hash...") ; lifestatus(statusline) ; } nhashtab = (node **)calloc(nhashprime, sizeof(node *)) ; if (nhashtab == 0) { lifewarning("Out of memory; running in a somewhat slower mode; " "try reducing the hash memory limit after restarting.") ; hashlimit = G_MAX ; return ; } alloced += sizeof(node *) * (nhashprime - hashprime) ; for (i=0; inext ; g_uintptr_t h ; if (is_node(p)) { h = node_hash(p->nw, p->ne, p->sw, p->se) ; } else { leaf *l = (leaf *)p ; h = leaf_hash(l->nw, l->ne, l->sw, l->se) ; } h %= nhashprime ; p->next = nhashtab[h] ; nhashtab[h] = p ; p = np ; } } free(hashtab) ; hashtab = nhashtab ; hashprime = nhashprime ; hashlimit = hashprime ; if (verbose) { strcpy(statusline+strlen(statusline), " done.") ; lifestatus(statusline) ; } } /* * These next two routines are (nearly) our only hash table access * routines; we simply look up the passed in information. If we * find it in the hash table, we return it; otherwise, we build a * new node and store it in the hash table, and return that. */ node *hlifealgo::find_node(node *nw, node *ne, node *sw, node *se) { node *p ; g_uintptr_t h = node_hash(nw,ne,sw,se) ; node *pred = 0 ; h = h % hashprime ; for (p=hashtab[h]; p; p = p->next) { /* make sure to compare nw *first* */ if (nw == p->nw && ne == p->ne && sw == p->sw && se == p->se) { if (pred) { /* move this one to the front */ pred->next = p->next ; p->next = hashtab[h] ; hashtab[h] = p ; } return save(p) ; } pred = p ; } p = newnode() ; p->nw = nw ; p->ne = ne ; p->sw = sw ; p->se = se ; p->res = 0 ; p->next = hashtab[h] ; hashtab[h] = p ; hashpop++ ; if (hashpop > hashlimit) resize() ; return save(p) ; } void hlifealgo::unhash_node(node *n) { node *p ; g_uintptr_t h = node_hash(n->nw,n->ne,n->sw,n->se) ; node *pred = 0 ; h = h % hashprime ; for (p=hashtab[h]; p; p = p->next) { if (p == n) { if (pred) pred->next = p->next ; else hashtab[h] = p->next ; return ; } pred = p ; } lifefatal("Didn't find node to unhash") ; } void hlifealgo::rehash_node(node *n) { g_uintptr_t h = node_hash(n->nw,n->ne,n->sw,n->se) ; h = h % hashprime ; n->next = hashtab[h] ; hashtab[h] = n ; } leaf *hlifealgo::find_leaf(unsigned short nw, unsigned short ne, unsigned short sw, unsigned short se) { leaf *p ; leaf *pred = 0 ; g_uintptr_t h = leaf_hash(nw, ne, sw, se) ; h = h % hashprime ; for (p=(leaf *)hashtab[h]; p; p = (leaf *)p->next) { if (nw == p->nw && ne == p->ne && sw == p->sw && se == p->se && !is_node(p)) { if (pred) { pred->next = p->next ; p->next = hashtab[h] ; hashtab[h] = (node *)p ; } return (leaf *)save((node *)p) ; } pred = p ; } p = newleaf() ; p->nw = nw ; p->ne = ne ; p->sw = sw ; p->se = se ; leafres(p) ; p->isnode = 0 ; p->next = hashtab[h] ; hashtab[h] = (node *)p ; hashpop++ ; if (hashpop > hashlimit) resize() ; return (leaf *)save((node *)p) ; } /* * The following routine does the same, but first it checks to see if * the cached result is any good. If it is, it directly returns that. * Otherwise, it figures out whether to call the leaf routine or the * non-leaf routine by whether two nodes down is a leaf node or not. * (We'll understand why this is a bit later.) All the sp stuff is * stack pointer and garbage collection stuff. */ node *hlifealgo::getres(node *n, int depth) { if (n->res) return n->res ; node *res = 0 ; /** * This routine be the only place we assign to res. We use * the fact that the poll routine is *sticky* to allow us to * manage unwinding the stack without munging our data * structures. Note that there may be many find_nodes * and getres called before we finally actually exit from * here, because the stack is deep and we don't want to * put checks throughout the code. Instead we need two * calls here, one to prevent us going deeper, and another * to prevent us from destroying the cache field. */ if (poller->poll()) return zeronode(depth-1) ; int sp = gsp ; depth-- ; if (ngens >= depth) { if (is_node(n->nw)) { res = dorecurs(n->nw, n->ne, n->sw, n->se, depth) ; } else { res = (node *)dorecurs_leaf((leaf *)n->nw, (leaf *)n->ne, (leaf *)n->sw, (leaf *)n->se) ; } } else { if (halvesdone < 1000) halvesdone++ ; if (is_node(n->nw)) { res = dorecurs_half(n->nw, n->ne, n->sw, n->se, depth) ; } else if (ngens == 0) { res = (node *)dorecurs_leaf_quarter((leaf *)n->nw, (leaf *)n->ne, (leaf *)n->sw, (leaf *)n->se) ; } else { res = (node *)dorecurs_leaf_half((leaf *)n->nw, (leaf *)n->ne, (leaf *)n->sw, (leaf *)n->se) ; } } pop(sp) ; if (poller->isInterrupted()) // don't assign this to the cache field! res = zeronode(depth) ; else n->res = res ; return res ; } /* * So let's say the cached way failed. How do we do it the slow way? * Recursively, of course. For an n-square (composed of the four * n/2-squares passed in, compute the n/2-square that is n/4 * generations ahead. * * This routine works exactly the same as the leafres() routine, only * instead of working on an 8-square, we're working on an n-square, * returning an n/2-square, and we build that n/2-square by first building * 9 n/4-squares, use those to calculate 4 more n/4-squares, and * then put these together into a new n/2-square. Simple, eh? */ node *hlifealgo::dorecurs(node *n, node *ne, node *t, node *e, int depth) { int sp = gsp ; node *t00 = getres(n, depth), *t01 = getres(find_node(n->ne, ne->nw, n->se, ne->sw), depth), *t02 = getres(ne, depth), *t12 = getres(find_node(ne->sw, ne->se, e->nw, e->ne), depth), *t11 = getres(find_node(n->se, ne->sw, t->ne, e->nw), depth), *t10 = getres(find_node(n->sw, n->se, t->nw, t->ne), depth), *t20 = getres(t, depth), *t21 = getres(find_node(t->ne, e->nw, t->se, e->sw), depth), *t22 = getres(e, depth), *t44 = getres(find_node(t11, t12, t21, t22), depth), *t43 = getres(find_node(t10, t11, t20, t21), depth), *t33 = getres(find_node(t00, t01, t10, t11), depth), *t34 = getres(find_node(t01, t02, t11, t12), depth) ; n = find_node(t33, t34, t43, t44) ; pop(sp) ; return save(n) ; } /* * Same as above, but we only do one step instead of 2. */ node *hlifealgo::dorecurs_half(node *n, node *ne, node *t, node *e, int depth) { int sp = gsp ; node *t00 = getres(n, depth), *t01 = getres(find_node(n->ne, ne->nw, n->se, ne->sw), depth), *t10 = getres(find_node(n->sw, n->se, t->nw, t->ne), depth), *t11 = getres(find_node(n->se, ne->sw, t->ne, e->nw), depth), *t02 = getres(ne, depth), *t12 = getres(find_node(ne->sw, ne->se, e->nw, e->ne), depth), *t20 = getres(t, depth), *t21 = getres(find_node(t->ne, e->nw, t->se, e->sw), depth), *t22 = getres(e, depth) ; if (depth > 3) { n = find_node(find_node(t00->se, t01->sw, t10->ne, t11->nw), find_node(t01->se, t02->sw, t11->ne, t12->nw), find_node(t10->se, t11->sw, t20->ne, t21->nw), find_node(t11->se, t12->sw, t21->ne, t22->nw)) ; } else { n = find_node((node *)find_leaf(((leaf *)t00)->se, ((leaf *)t01)->sw, ((leaf *)t10)->ne, ((leaf *)t11)->nw), (node *)find_leaf(((leaf *)t01)->se, ((leaf *)t02)->sw, ((leaf *)t11)->ne, ((leaf *)t12)->nw), (node *)find_leaf(((leaf *)t10)->se, ((leaf *)t11)->sw, ((leaf *)t20)->ne, ((leaf *)t21)->nw), (node *)find_leaf(((leaf *)t11)->se, ((leaf *)t12)->sw, ((leaf *)t21)->ne, ((leaf *)t22)->nw)) ; } pop(sp) ; return save(n) ; } /* * If the node is a 16-node, then the constituents are leaves, so we * need a very similar but still somewhat different subroutine. Since * we do not (yet) garbage collect leaves, we don't need all that * save/pop mumbo-jumbo. */ leaf *hlifealgo::dorecurs_leaf(leaf *n, leaf *ne, leaf *t, leaf *e) { unsigned short t00 = n->res2, t01 = find_leaf(n->ne, ne->nw, n->se, ne->sw)->res2, t02 = ne->res2, t10 = find_leaf(n->sw, n->se, t->nw, t->ne)->res2, t11 = find_leaf(n->se, ne->sw, t->ne, e->nw)->res2, t12 = find_leaf(ne->sw, ne->se, e->nw, e->ne)->res2, t20 = t->res2, t21 = find_leaf(t->ne, e->nw, t->se, e->sw)->res2, t22 = e->res2 ; return find_leaf(find_leaf(t00, t01, t10, t11)->res2, find_leaf(t01, t02, t11, t12)->res2, find_leaf(t10, t11, t20, t21)->res2, find_leaf(t11, t12, t21, t22)->res2) ; } /* * Same as above but we only do two generations. */ #define combine4(t00,t01,t10,t11) (unsigned short)\ ((((t00)<<10)&0xcc00)|(((t01)<<6)&0x3300)|(((t10)>>6)&0xcc)|(((t11)>>10)&0x33)) leaf *hlifealgo::dorecurs_leaf_half(leaf *n, leaf *ne, leaf *t, leaf *e) { unsigned short t00 = n->res2, t01 = find_leaf(n->ne, ne->nw, n->se, ne->sw)->res2, t02 = ne->res2, t10 = find_leaf(n->sw, n->se, t->nw, t->ne)->res2, t11 = find_leaf(n->se, ne->sw, t->ne, e->nw)->res2, t12 = find_leaf(ne->sw, ne->se, e->nw, e->ne)->res2, t20 = t->res2, t21 = find_leaf(t->ne, e->nw, t->se, e->sw)->res2, t22 = e->res2 ; return find_leaf(combine4(t00, t01, t10, t11), combine4(t01, t02, t11, t12), combine4(t10, t11, t20, t21), combine4(t11, t12, t21, t22)) ; } /* * Same as above but we only do one generation. */ leaf *hlifealgo::dorecurs_leaf_quarter(leaf *n, leaf *ne, leaf *t, leaf *e) { unsigned short t00 = n->res1, t01 = find_leaf(n->ne, ne->nw, n->se, ne->sw)->res1, t02 = ne->res1, t10 = find_leaf(n->sw, n->se, t->nw, t->ne)->res1, t11 = find_leaf(n->se, ne->sw, t->ne, e->nw)->res1, t12 = find_leaf(ne->sw, ne->se, e->nw, e->ne)->res1, t20 = t->res1, t21 = find_leaf(t->ne, e->nw, t->se, e->sw)->res1, t22 = e->res1 ; return find_leaf(combine4(t00, t01, t10, t11), combine4(t01, t02, t11, t12), combine4(t10, t11, t20, t21), combine4(t11, t12, t21, t22)) ; } /* * We keep free nodes in a linked list for allocation, and we allocate * them 1000 at a time. */ node *hlifealgo::newnode() { node *r ; if (freenodes == 0) { int i ; freenodes = (node *)calloc(1001, sizeof(node)) ; if (freenodes == 0) lifefatal("Out of memory; try reducing the hash memory limit.") ; alloced += 1001 * sizeof(node) ; freenodes->next = nodeblocks ; nodeblocks = freenodes++ ; for (i=0; i<999; i++) { freenodes[1].next = freenodes ; freenodes++ ; } totalthings += 1000 ; } if (freenodes->next == 0 && alloced + 1000 * sizeof(node) > maxmem && okaytogc) { do_gc(0) ; } r = freenodes ; freenodes = freenodes->next ; return r ; } /* * Leaves are the same. */ leaf *hlifealgo::newleaf() { return (leaf *)newnode() ; } /* * Sometimes we want the new node or leaf to be automatically cleared * for us. */ node *hlifealgo::newclearednode() { return (node *)memset(newnode(), 0, sizeof(node)) ; } leaf *hlifealgo::newclearedleaf() { return (leaf *)memset(newleaf(), 0, sizeof(leaf)) ; } hlifealgo::hlifealgo() { int i ; /* * The population of one-bits in an integer is one more than the * population of one-bits in the integer with one fewer bit set, * and we can turn off a bit by anding an integer with the next * lower integer. */ if (shortpop[1] == 0) for (i=1; i<65536; i++) shortpop[i] = shortpop[i & (i - 1)] + 1 ; hashprime = nextprime(1000) ; hashlimit = hashprime ; hashpop = 0 ; hashtab = (node **)calloc(hashprime, sizeof(node *)) ; if (hashtab == 0) lifefatal("Out of memory (1).") ; alloced += hashprime * sizeof(node *) ; ngens = 0 ; stacksize = 0 ; halvesdone = 0 ; nzeros = 0 ; stack = 0 ; gsp = 0 ; alloced = 0 ; maxmem = 256 * 1024 * 1024 ; freenodes = 0 ; okaytogc = 0 ; totalthings = 0 ; nodeblocks = 0 ; zeronodea = 0 ; ruletable = hliferules.rule0 ; /* * We initialize our universe to be a 16-square. We are in drawing * mode at this point. */ root = (node *)newclearednode() ; population = 0 ; generation = 0 ; increment = 1 ; setincrement = 1 ; nonpow2 = 1 ; pow2step = 1 ; llsize = 0 ; depth = 3 ; hashed = 0 ; popValid = 0 ; needPop = 0 ; inGC = 0 ; cacheinvalid = 0 ; gccount = 0 ; gcstep = 0 ; } /** * Destructor frees memory. */ hlifealgo::~hlifealgo() { free(hashtab) ; while (nodeblocks) { node *r = nodeblocks ; nodeblocks = nodeblocks->next ; free(r) ; } if (zeronodea) free(zeronodea) ; if (stack) free(stack) ; if (llsize) { delete [] llxb ; delete [] llyb ; } } /** * Set increment. */ void hlifealgo::setIncrement(bigint inc) { increment = inc ; } /** * Do a step. */ void hlifealgo::step() { poller->bailIfCalculating() ; // we use while here because the increment may be changed while we are // doing the hashtable sweep; if that happens, we may need to sweep // again. int cleareddownto = 1000000000 ; while (increment != setincrement) { bigint pendingincrement = increment ; int newpow2 = 0 ; bigint t = pendingincrement ; while (t > 0 && t.even()) { newpow2++ ; t.div2() ; } nonpow2 = t.low31() ; if (t != nonpow2) lifefatal("bad increment") ; int downto = newpow2 ; if (ngens < newpow2) downto = ngens ; if (newpow2 != ngens && cleareddownto > downto) { new_ngens(newpow2) ; cleareddownto = downto ; } else { ngens = newpow2 ; } setincrement = pendingincrement ; pow2step = 1 ; while (newpow2--) pow2step += pow2step ; } gcstep = 0 ; for (int i=0; iisInterrupted()) // we *were* interrupted break ; popValid = 0 ; root = newroot ; } depth = node_depth(root) ; extendtimeline() ; } void hlifealgo::setcurrentstate(void *n) { if (root != (node *)n) { root = (node *)n ; depth = node_depth(root) ; popValid = 0 ; } } /* * Set the max memory */ void hlifealgo::setMaxMemory(int newmemlimit) { if (newmemlimit < 10) newmemlimit = 10 ; #ifndef GOLLY64BIT else if (newmemlimit > 4000) newmemlimit = 4000 ; #endif g_uintptr_t newlimit = ((g_uintptr_t)newmemlimit) << 20 ; if (alloced > newlimit) { lifewarning("Sorry, more memory currently used than allowed.") ; return ; } maxmem = newlimit ; hashlimit = hashprime ; } /** * Clear everything. */ void hlifealgo::clearall() { lifefatal("clearall not implemented yet") ; } /* * This routine expands our universe by a factor of two, maintaining * centering. We use four new nodes, and *reuse* the root so this cannot * be called after we've started hashing. */ void hlifealgo::pushroot_1() { node *t ; t = newclearednode() ; t->se = root->nw ; root->nw = t ; t = newclearednode() ; t->sw = root->ne ; root->ne = t ; t = newclearednode() ; t->ne = root->sw ; root->sw = t ; t = newclearednode() ; t->nw = root->se ; root->se = t ; depth++ ; } /* * Return the depth of this node (2 is 8x8). */ int hlifealgo::node_depth(node *n) { int depth = 2 ; while (is_node(n)) { depth++ ; n = n->nw ; } return depth ; } /* * This routine returns the canonical clear space node at a particular * depth. */ node *hlifealgo::zeronode(int depth) { while (depth >= nzeros) { int nnzeros = 2 * nzeros + 10 ; zeronodea = (node **)realloc(zeronodea, nnzeros * sizeof(node *)) ; if (zeronodea == 0) lifefatal("Out of memory (2).") ; alloced += (nnzeros - nzeros) * sizeof(node *) ; while (nzeros < nnzeros) zeronodea[nzeros++] = 0 ; } if (zeronodea[depth] == 0) { if (depth == 2) { zeronodea[depth] = (node *)find_leaf(0, 0, 0, 0) ; } else { node *z = zeronode(depth-1) ; zeronodea[depth] = find_node(z, z, z, z) ; } } return zeronodea[depth] ; } /* * Same, but with hashed nodes. */ node *hlifealgo::pushroot(node *n) { int depth = node_depth(n) ; node *z = zeronode(depth-1) ; return find_node(find_node(z, z, z, n->nw), find_node(z, z, n->ne, z), find_node(z, n->sw, z, z), find_node(n->se, z, z, z)) ; } /* * Here is our recursive routine to set a bit in our universe. We * pass in a depth, and walk the space. Again, a lot of bit twiddling, * but really not all that complicated. We allocate new nodes and * leaves on our way down. * * Note that at this point our universe lives outside the hash table * and has not been canonicalized, and that many of the pointers in * the nodes can be null. We'll patch this up in due course. */ node *hlifealgo::setbit(node *n, int x, int y, int newstate, int depth) { if (depth == 2) { leaf *l = (leaf *)n ; if (hashed) { unsigned short nw = l->nw ; unsigned short sw = l->sw ; unsigned short ne = l->ne ; unsigned short se = l->se ; if (newstate) { if (x < 0) if (y < 0) sw |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else nw |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else if (y < 0) se |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else ne |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; } else { if (x < 0) if (y < 0) sw &= ~(1 << (3 - (x & 3) + 4 * (y & 3))) ; else nw &= ~(1 << (3 - (x & 3) + 4 * (y & 3))) ; else if (y < 0) se &= ~(1 << (3 - (x & 3) + 4 * (y & 3))) ; else ne &= ~(1 << (3 - (x & 3) + 4 * (y & 3))) ; } return save((node *)find_leaf(nw, ne, sw, se)) ; } if (newstate) { if (x < 0) if (y < 0) l->sw |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else l->nw |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else if (y < 0) l->se |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else l->ne |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; } else { if (x < 0) if (y < 0) l->sw &= ~(1 << (3 - (x & 3) + 4 * (y & 3))) ; else l->nw &= ~(1 << (3 - (x & 3) + 4 * (y & 3))) ; else if (y < 0) l->se &= ~(1 << (3 - (x & 3) + 4 * (y & 3))) ; else l->ne &= ~(1 << (3 - (x & 3) + 4 * (y & 3))) ; } return (node *)l ; } else { unsigned int w = 0, wh = 0 ; if (depth >= 31) { if (depth == this->depth) wh = 0x80000000 ; } else { w = 1 << depth ; wh = 1 << (depth - 1) ; } depth-- ; node **nptr ; if (x < 0) { if (y < 0) nptr = &(n->sw) ; else nptr = &(n->nw) ; } else { if (y < 0) nptr = &(n->se) ; else nptr = &(n->ne) ; } if (*nptr == 0) { if (depth == 2) *nptr = (node *)newclearedleaf() ; else *nptr = newclearednode() ; } node *s = setbit(*nptr, (x & (w - 1)) - wh, (y & (w - 1)) - wh, newstate, depth) ; if (hashed) { node *nw = n->nw ; node *sw = n->sw ; node *ne = n->ne ; node *se = n->se ; if (x < 0) { if (y < 0) sw = s ; else nw = s ; } else { if (y < 0) se = s ; else ne = s ; } n = save(find_node(nw, ne, sw, se)) ; } else { *nptr = s ; } return n ; } } /* * Here is our recursive routine to get a bit in our universe. We * pass in a depth, and walk the space. Again, a lot of bit twiddling, * but really not all that complicated. */ int hlifealgo::getbit(node *n, int x, int y, int depth) { if (depth == 2) { leaf *l = (leaf *)n ; int test = 0 ; if (x < 0) if (y < 0) test = (l->sw & (1 << (3 - (x & 3) + 4 * (y & 3)))) ; else test = (l->nw & (1 << (3 - (x & 3) + 4 * (y & 3)))) ; else if (y < 0) test = (l->se & (1 << (3 - (x & 3) + 4 * (y & 3)))) ; else test = (l->ne & (1 << (3 - (x & 3) + 4 * (y & 3)))) ; if (test) return 1 ; return 0 ; } else { unsigned int w = 0, wh = 0 ; if (depth >= 31) { if (depth == this->depth) wh = 0x80000000 ; } else { w = 1 << depth ; wh = 1 << (depth - 1) ; } depth-- ; node *nptr ; if (x < 0) { if (y < 0) nptr = n->sw ; else nptr = n->nw ; } else { if (y < 0) nptr = n->se ; else nptr = n->ne ; } if (nptr == 0 || nptr == zeronode(depth)) return 0 ; return getbit(nptr, (x & (w - 1)) - wh, (y & (w - 1)) - wh, depth) ; } } /* * Here is our recursive routine to get the next bit in our universe. We * pass in a depth, and walk the space. Again, a lot of bit twiddling, * but really not all that complicated. */ int hlifealgo::nextbit(node *n, int x, int y, int depth) { if (n == 0 || n == zeronode(depth)) return -1 ; if (depth == 2) { leaf *l = (leaf *)n ; int test = 0 ; if (y < 0) test = (((l->sw >> (4 * (y & 3))) & 15) << 4) | ((l->se >> (4 * (y & 3))) & 15) ; else test = (((l->nw >> (4 * (y & 3))) & 15) << 4) | ((l->ne >> (4 * (y & 3))) & 15) ; test &= (1 << (4 - x)) - 1 ; if (test) { int r = 0 ; int b = 1 << (3 - x) ; while ((test & b) == 0) { r++ ; b >>= 1 ; } return r ; } return -1 ; // none found } else { unsigned int w = 0, wh = 0 ; w = 1 << depth ; wh = 1 << (depth - 1) ; node *lft, *rght ; depth-- ; if (y < 0) { lft = n->sw ; rght = n->se ; } else { lft = n->nw ; rght = n->ne ; } int r = 0 ; if (x < 0) { int t = nextbit(lft, (x & (w-1)) - wh, (y & (w - 1)) - wh, depth) ; if (t >= 0) return t ; r = -x ; x = 0 ; } int t = nextbit(rght, (x & (w-1)) - wh, (y & (w - 1)) - wh, depth) ; if (t >= 0) return r + t ; return -1 ; } } /* * Our nonrecurse top-level bit setting routine simply expands the * universe as necessary to encompass the passed-in coordinates, and * then invokes the recursive setbit. Right now it works hashed or * unhashed (but it's faster when unhashed). We also turn on the inGC * flag to inhibit popcount. */ int hlifealgo::setcell(int x, int y, int newstate) { if (newstate & ~1) return -1 ; if (hashed) { clearstack() ; save(root) ; okaytogc = 1 ; } inGC = 1 ; y = - y ; int sx = x ; int sy = y ; if (depth <= 31) { sx >>= depth ; sy >>= depth ; } else { sx >>= 31 ; sy >>= 31 ; } while (sx > 0 || sx < -1 || sy > 0 || sy < -1) { if (hashed) { root = save(pushroot(root)) ; depth++ ; } else { pushroot_1() ; } sx >>= 1 ; sy >>= 1 ; } root = setbit(root, x, y, newstate, depth) ; if (hashed) { okaytogc = 0 ; } return 0 ; } /* * Our nonrecurse top-level bit getting routine. */ int hlifealgo::getcell(int x, int y) { y = - y ; int sx = x ; int sy = y ; if (depth <= 31) { sx >>= depth ; sy >>= depth ; } else { sx >>= 31 ; sy >>= 31 ; } if (sx > 0 || sx < -1 || sy > 0 || sy < -1) return 0 ; return getbit(root, x, y, depth) ; } /* * A recursive bit getting routine, but this one returns the * number of pixels to the right to the next set cell in the * current universe, or -1 if none set to the right, or if * the next set pixel is out of range. */ int hlifealgo::nextcell(int x, int y, int &v) { v = 1 ; y = - y ; int sx = x ; int sy = y ; if (depth <= 31) { sx >>= depth ; sy >>= depth ; } else { sx >>= 31 ; sy >>= 31 ; } while (sx > 0 || sx < -1 || sy > 0 || sy < -1) { if (hashed) { root = save(pushroot(root)) ; depth++ ; } else { pushroot_1() ; } sx >>= 1 ; sy >>= 1 ; } if (depth > 30) { struct node tnode = *root ; int mdepth = depth ; while (mdepth > 30) { tnode.nw = tnode.nw->se ; tnode.ne = tnode.ne->sw ; tnode.sw = tnode.sw->ne ; tnode.se = tnode.se->nw ; mdepth-- ; } return nextbit(&tnode, x, y, mdepth) ; } return nextbit(root, x, y, depth) ; } /* * Canonicalize a universe by filling in the null pointers and then * invoking find_node on each node. Drops the original universe on * the floor [big deal, it's probably small anyway]. */ node *hlifealgo::hashpattern(node *root, int depth) { node *r ; if (root == 0) { r = zeronode(depth) ; } else if (depth == 2) { leaf *n = (leaf *)root ; r = (node *)find_leaf(n->nw, n->ne, n->sw, n->se) ; n->next = freenodes ; freenodes = root ; } else { depth-- ; r = find_node(hashpattern(root->nw, depth), hashpattern(root->ne, depth), hashpattern(root->sw, depth), hashpattern(root->se, depth)) ; root->next = freenodes ; freenodes = root ; } return r ; } void hlifealgo::endofpattern() { poller->bailIfCalculating() ; if (!hashed) { root = hashpattern(root, depth) ; hashed = 1 ; } popValid = 0 ; needPop = 0 ; inGC = 0 ; } void hlifealgo::ensure_hashed() { if (!hashed) endofpattern() ; } /* * Pop off any levels we don't need. */ node *hlifealgo::popzeros(node *n) { int depth = node_depth(n) ; while (depth > 3) { node *z = zeronode(depth-2) ; if (n->nw->nw == z && n->nw->ne == z && n->nw->sw == z && n->ne->nw == z && n->ne->ne == z && n->ne->se == z && n->sw->nw == z && n->sw->sw == z && n->sw->se == z && n->se->ne == z && n->se->sw == z && n->se->se == z) { depth-- ; n = find_node(n->nw->se, n->ne->sw, n->sw->ne, n->se->nw) ; } else { break ; } } return n ; } /* * A lot of the routines from here on down traverse the universe, hanging * information off the nodes. The way they generally do so is by using * (or abusing) the cache (res) field, and the least significant bit of * the hash next field (as a visited bit). */ #define marked(n) (1 & (g_uintptr_t)(n)->next) #define mark(n) ((n)->next = (node *)(1 | (g_uintptr_t)(n)->next)) #define clearmark(n) ((n)->next = (node *)(~1 & (g_uintptr_t)(n)->next)) #define clearmarkbit(p) ((node *)(~1 & (g_uintptr_t)(p))) /* * Sometimes we want to use *res* instead of next to mark. You cannot * do this to leaves, though. */ #define marked2(n) (1 & (g_uintptr_t)(n)->res) #define mark2(n) ((n)->res = (node *)(1 | (g_uintptr_t)(n)->res)) #define clearmark2(n) ((n)->res = (node *)(~1 & (g_uintptr_t)(n)->res)) static void sum4(bigint &dest, const bigint &a, const bigint &b, const bigint &c, const bigint &d) { dest = a ; dest += b ; dest += c ; dest += d ; } /* * This recursive routine calculates the population by hanging the * population on marked nodes. */ const bigint &hlifealgo::calcpop(node *root, int depth) { if (root == zeronode(depth)) return bigint::zero ; if (depth == 2) { root->nw = 0 ; bigint &r = *(bigint *)&(root->nw) ; leaf *n = (leaf *)root ; r = n->leafpop ; return r ; } else if (marked2(root)) { return *(bigint*)&(root->next) ; } else { depth-- ; unhash_node(root) ; /** * We use the memory in root->next as a value bigint. But we want to * make sure the copy constructor doesn't "clean up" something that * doesn't exist. So we clear it to zero here. */ root->next = (node *)0 ; // I wish I could come up with a cleaner way sum4(*(bigint *)&(root->next), calcpop(root->nw, depth), calcpop(root->ne, depth), calcpop(root->sw, depth), calcpop(root->se, depth)) ; mark2(root) ; return *(bigint *)&(root->next) ; } } /* * Call this after doing something that unhashes nodes in order to * use the next field as a temp pointer. */ void hlifealgo::aftercalcpop2(node *root, int depth, int cleanbigints) { if (root == zeronode(depth)) return ; if (depth == 2) { root->nw = 0 ; // all these bigints are guaranteed to be small return ; } if (marked2(root)) { clearmark2(root) ; depth-- ; aftercalcpop2(root->nw, depth, cleanbigints) ; aftercalcpop2(root->ne, depth, cleanbigints) ; aftercalcpop2(root->sw, depth, cleanbigints) ; aftercalcpop2(root->se, depth, cleanbigints) ; if (cleanbigints) *(bigint *)&(root->next) = bigint::zero ; // clean up; yuck! rehash_node(root) ; } } /* * This top level routine calculates the population of a universe. */ void hlifealgo::calcPopulation(node *root) { int depth ; ensure_hashed() ; depth = node_depth(root) ; population = calcpop(root, depth) ; aftercalcpop2(root, depth, 1) ; } /* * Is the universe empty? */ int hlifealgo::isEmpty() { ensure_hashed() ; return root == zeronode(depth) ; } /* * This routine marks a node as needed to be saved. */ node *hlifealgo::save(node *n) { if (gsp >= stacksize) { int nstacksize = stacksize * 2 + 100 ; alloced += sizeof(node *)*(nstacksize-stacksize) ; stack = (node **)realloc(stack, nstacksize * sizeof(node *)) ; if (stack == 0) lifefatal("Out of memory (3).") ; stacksize = nstacksize ; } stack[gsp++] = n ; return n ; } /* * This routine pops the stack back to a previous depth. */ void hlifealgo::pop(int n) { gsp = n ; } /* * This routine clears the stack altogether. */ void hlifealgo::clearstack() { gsp = 0 ; } /* * Do a gc. Walk down from all nodes reachable on the stack, saveing * them by setting the odd bit on the next link. Then, walk the hash, * eliminating the res from everything that's not saveed, and moving * the nodes from the hash to the freelist as appropriate. Finally, * walk the hash again, clearing the low order bits in the next pointers. */ void hlifealgo::gc_mark(node *root, int invalidate) { if (!marked(root)) { mark(root) ; if (is_node(root)) { gc_mark(root->nw, invalidate) ; gc_mark(root->ne, invalidate) ; gc_mark(root->sw, invalidate) ; gc_mark(root->se, invalidate) ; if (root->res) { if (invalidate) root->res = 0 ; else gc_mark(root->res, invalidate) ; } } } } /** * If the invalidate flag is set, we want to kill *all* cache entries * and recalculate all leaves. */ void hlifealgo::do_gc(int invalidate) { int i ; g_uintptr_t freed_nodes=0 ; node *p, *pp ; inGC = 1 ; gccount++ ; gcstep++ ; if (verbose) { if (gcstep > 1) sprintf(statusline, "GC #%d(%d) ", gccount, gcstep) ; else sprintf(statusline, "GC #%d ", gccount) ; lifestatus(statusline) ; } for (i=nzeros-1; i>=0; i--) if (zeronodea[i] != 0) break ; if (i >= 0) gc_mark(zeronodea[i], 0) ; // never invalidate zeronode for (i=0; ipoll() ; gc_mark(stack[i], invalidate) ; } for (i=0; inext) { poller->poll() ; for (pp=p+1, i=1; i<1001; i++, pp++) { if (marked(pp)) { g_uintptr_t h = 0 ; if (pp->nw) { /* yes, it's a node */ h = node_hash(pp->nw, pp->ne, pp->sw, pp->se) % hashprime ; } else { leaf *lp = (leaf *)pp ; if (invalidate) leafres(lp) ; h = leaf_hash(lp->nw, lp->ne, lp->sw, lp->se) % hashprime ; } pp->next = hashtab[h] ; hashtab[h] = pp ; hashpop++ ; } else { pp->next = freenodes ; freenodes = pp ; freed_nodes++ ; } } } inGC = 0 ; if (verbose) { int perc = (int)(freed_nodes / (totalthings / 100)) ; sprintf(statusline+strlen(statusline), " freed %d percent (%d).", perc, (int)freed_nodes) ; lifestatus(statusline) ; } if (needPop) { calcPopulation(root) ; popValid = 1 ; needPop = 0 ; poller->updatePop() ; } } /* * Clear the cache bits down to the appropriate level, marking the * nodes we've handled. */ void hlifealgo::clearcache(node *n, int depth, int clearto) { if (!marked(n)) { mark(n) ; if (depth > 3) { depth-- ; poller->poll() ; clearcache(n->nw, depth, clearto) ; clearcache(n->ne, depth, clearto) ; clearcache(n->sw, depth, clearto) ; clearcache(n->se, depth, clearto) ; if (n->res) clearcache(n->res, depth, clearto) ; } if (depth >= clearto) n->res = 0 ; } } /* * Clear the entire cache of everything, and recalculate all leaves. * This can be very expensive. */ void hlifealgo::clearcache() { cacheinvalid = 1 ; } /* * Change the ngens value. Requires us to walk the hash, clearing * the cache fields of any nodes that do not have the appropriate * values. */ void hlifealgo::new_ngens(int newval) { g_uintptr_t i ; node *p, *pp ; int clearto = ngens ; if (newval > ngens && halvesdone == 0) { ngens = newval ; return ; } if (verbose) { strcpy(statusline, "Changing increment...") ; lifestatus(statusline) ; } if (newval < clearto) clearto = newval ; clearto++ ; /* clear this depth and above */ if (clearto < 3) clearto = 3 ; ngens = newval ; inGC = 1 ; for (i=0; inext)) if (is_node(p) && !marked(p)) clearcache(p, node_depth(p), clearto) ; for (p=nodeblocks; p; p=p->next) { poller->poll() ; for (pp=p+1, i=1; i<1001; i++, pp++) clearmark(pp) ; } halvesdone = 0 ; inGC = 0 ; if (needPop) { calcPopulation(root) ; popValid = 1 ; needPop = 0 ; poller->updatePop() ; } if (verbose) { strcpy(statusline+strlen(statusline), " done.") ; lifestatus(statusline) ; } } /* * Return log2. */ int hlifealgo::log2(unsigned int n) { int r = 0 ; while ((n & 1) == 0) { n >>= 1 ; r++ ; } if (n != 1) { lifefatal("Expected power of two!") ; } return r ; } static bigint negone = -1 ; const bigint &hlifealgo::getPopulation() { // note: if called during gc, then we cannot call calcPopulation // since that will mess up the gc. if (!popValid) { if (inGC) { needPop = 1 ; return negone ; } else { calcPopulation(root) ; popValid = 1 ; needPop = 0 ; } } return population ; } /* * Finally, we get to run the pattern. We first ensure that all * clearspace nodes and the input pattern is never garbage * collected; we turn on garbage collection, and then we invoke our * magic top-level routine passing in clearspace borders that are * guaranteed large enough. */ node *hlifealgo::runpattern() { node *n = root ; save(root) ; // do this in case we interrupt generation ensure_hashed() ; okaytogc = 1 ; if (cacheinvalid) { do_gc(1) ; // invalidate the entire cache and recalc leaves cacheinvalid = 0 ; } int depth = node_depth(n) ; node *n2 ; n = pushroot(n) ; depth++ ; n = pushroot(n) ; depth++ ; while (ngens + 2 > depth) { n = pushroot(n) ; depth++ ; } save(zeronode(nzeros-1)) ; save(n) ; n2 = getres(n, depth) ; okaytogc = 0 ; clearstack() ; if (halvesdone == 1) { n->res = 0 ; halvesdone = 0 ; } if (poller->isInterrupted()) return 0 ; // indicate it was interrupted n = popzeros(n2) ; generation += pow2step ; return n ; } const char *hlifealgo::readmacrocell(char *line) { int n=0 ; g_uintptr_t i=1, nw=0, ne=0, sw=0, se=0, indlen=0 ; int r, d ; node **ind = 0 ; root = 0 ; while (getline(line, 10000)) { if (i >= indlen) { g_uintptr_t nlen = i + indlen + 10 ; ind = (node **)realloc(ind, sizeof(node*) * nlen) ; if (ind == 0) lifefatal("Out of memory (4).") ; while (indlen < nlen) ind[indlen++] = 0 ; } if (line[0] == '.' || line[0] == '*' || line[0] == '$') { int x=0, y=7 ; unsigned short lnw=0, lne=0, lsw=0, lse=0 ; char *p = 0 ; for (p=line; *p > ' '; p++) { switch(*p) { case '*': if (x > 7 || y < 0) return "Illegal coordinates in readmacrocell." ; if (x < 4) if (y < 4) lsw |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else lnw |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else if (y < 4) lse |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; else lne |= 1 << (3 - (x & 3) + 4 * (y & 3)) ; /* note: fall through here */ case '.': x++ ; break ; case '$': x = 0 ; y-- ; break ; default: return "Illegal character in readmacrocell." ; } } clearstack() ; ind[i++] = (node *)find_leaf(lnw, lne, lsw, lse) ; } else if (line[0] == '#') { switch (line[1]) { char *p, *pp ; const char *err ; case 'R': p = line + 2 ; while (*p && *p <= ' ') p++ ; pp = p ; while (*pp > ' ') pp++ ; *pp = 0 ; // AKT: need to check for B0-not-Smax rule err = hliferules.setrule(p, this); if (err) return err; if (hliferules.alternate_rules) return "B0-not-Smax rules are not allowed in HashLife."; break ; case 'G': p = line + 2 ; while (*p && *p <= ' ') p++ ; pp = p ; while (*pp >= '0' && *pp <= '9') pp++ ; *pp = 0 ; generation = bigint(p) ; break ; // either: // #FRAMES count base inc // or // #FRAME index node case 'F': if (strncmp(line, "#FRAMES ", 8) == 0) { p = line + 8 ; while (*p && *p <= ' ') p++ ; int cnt = atol(p) ; if (cnt < 0 || cnt > MAX_FRAME_COUNT) return "Bad FRAMES line" ; destroytimeline() ; while ('0' <= *p && *p <= '9') p++ ; while (*p && *p <= ' ') p++ ; pp = p ; while ((*pp >= '0' && *pp <= '9') || *pp == ',') pp++ ; if (*pp == 0) return "Bad FRAMES line" ; *pp = 0 ; timeline.start = bigint(p) ; timeline.end = timeline.start ; timeline.next = timeline.start ; p = pp + 1 ; while (*p && *p <= ' ') p++ ; pp = p ; while (*pp > ' ') pp++ ; *pp = 0 ; if (strchr(p, '^')) { int tbase=0, texpo=0 ; if (sscanf(p, "%d^%d", &tbase, &texpo) != 2 || tbase < 2 || texpo < 0) return "Bad FRAMES line" ; timeline.base = tbase ; timeline.expo = texpo ; timeline.inc = 1 ; while (texpo--) timeline.inc.mul_smallint(tbase) ; } else { timeline.inc = bigint(p) ; // if it's a power of two, we're good int texpo = timeline.inc.lowbitset() ; int tbase = 2 ; bigint test = 1 ; for (int i=0; i MAX_FRAME_COUNT || frameind < 0 || nodeind > i || timeline.framecount != frameind) return "Bad FRAME line" ; timeline.frames.push_back(ind[nodeind]) ; timeline.framecount++ ; timeline.end = timeline.next ; timeline.next += timeline.inc ; } break ; } } else { n = sscanf(line, "%d %" PRIuPTR " %" PRIuPTR " %" PRIuPTR " %" PRIuPTR " %d", &d, &nw, &ne, &sw, &se, &r) ; if (n < 0) // blank line; permit continue ; if (n == 0) { // conversion error in first argument; we allow only if the only // content on the line is whitespace. char *ws = line ; while (*ws && *ws <= ' ') ws++ ; if (*ws > 0) return "Parse error in macrocell format." ; continue ; } if (n < 5) // AKT: best not to use lifefatal here because user won't see any // error message when reading clipboard data starting with "[..." return "Parse error in readmacrocell." ; if (d < 4) return "Oops; bad depth in readmacrocell." ; ind[0] = zeronode(d-2) ; /* allow zeros to work right */ if (nw >= i || ind[nw] == 0 || ne >= i || ind[ne] == 0 || sw >= i || ind[sw] == 0 || se >= i || ind[se] == 0) { return "Node out of range in readmacrocell." ; } clearstack() ; root = ind[i++] = find_node(ind[nw], ind[ne], ind[sw], ind[se]) ; depth = d - 1 ; } } if (ind) free(ind) ; if (root == 0) { // AKT: allow empty macrocell pattern; note that endofpattern() // will be called soon so don't set hashed here // return "Invalid macrocell file: no nodes." ; return 0 ; } hashed = 1 ; return 0 ; } const char *hlifealgo::setrule(const char *s) { poller->bailIfCalculating() ; const char* err = hliferules.setrule(s, this); if (err) return err; clearcache() ; if (hliferules.alternate_rules) return "B0-not-Smax rules are not allowed in HashLife."; if (hliferules.isHexagonal()) grid_type = HEX_GRID; else if (hliferules.isVonNeumann()) grid_type = VN_GRID; else grid_type = SQUARE_GRID; return 0 ; } void hlifealgo::unpack8x8(unsigned short nw, unsigned short ne, unsigned short sw, unsigned short se, unsigned int *top, unsigned int *bot) { *top = ((nw & 0xf000) << 16) | (((ne & 0xf000) | (nw & 0xf00)) << 12) | (((ne & 0xf00) | (nw & 0xf0)) << 8) | (((ne & 0xf0) | (nw & 0xf)) << 4) | (ne & 0xf) ; *bot = ((sw & 0xf000) << 16) | (((se & 0xf000) | (sw & 0xf00)) << 12) | (((se & 0xf00) | (sw & 0xf0)) << 8) | (((se & 0xf0) | (sw & 0xf)) << 4) | (se & 0xf) ; } /** * Write out the native macrocell format. This is the one we use when * we're not interactive and displaying a progress dialog. */ g_uintptr_t hlifealgo::writecell(std::ostream &os, node *root, int depth) { g_uintptr_t thiscell = 0 ; if (root == zeronode(depth)) return 0 ; if (depth == 2) { if (root->nw != 0) return (g_uintptr_t)(root->nw) ; } else { if (marked2(root)) return (g_uintptr_t)(root->next) ; unhash_node(root) ; mark2(root) ; } if (depth == 2) { int i, j ; unsigned int top, bot ; leaf *n = (leaf *)root ; thiscell = ++cellcounter ; root->nw = (node *)thiscell ; unpack8x8(n->nw, n->ne, n->sw, n->se, &top, &bot) ; for (j=7; (top | bot) && j>=0; j--) { int bits = (top >> 24) ; top = (top << 8) | (bot >> 24) ; bot = (bot << 8) ; for (i=0; bits && i<8; i++, bits = (bits << 1) & 255) if (bits & 128) os << '*' ; else os << '.' ; os << '$' ; } os << '\n' ; } else { g_uintptr_t nw = writecell(os, root->nw, depth-1) ; g_uintptr_t ne = writecell(os, root->ne, depth-1) ; g_uintptr_t sw = writecell(os, root->sw, depth-1) ; g_uintptr_t se = writecell(os, root->se, depth-1) ; thiscell = ++cellcounter ; root->next = (node *)thiscell ; os << depth+1 << ' ' << nw << ' ' << ne << ' ' << sw << ' ' << se << '\n'; } return thiscell ; } /** * This new two-pass method works by doing a prepass that numbers the * nodes and counts the number of nodes that should be sent, so we can * display an accurate progress dialog. */ g_uintptr_t hlifealgo::writecell_2p1(node *root, int depth) { g_uintptr_t thiscell = 0 ; if (root == zeronode(depth)) return 0 ; if (depth == 2) { if (root->nw != 0) return (g_uintptr_t)(root->nw) ; } else { if (marked2(root)) return (g_uintptr_t)(root->next) ; unhash_node(root) ; mark2(root) ; } if (depth == 2) { thiscell = ++cellcounter ; // note: we *must* not abort this prescan if ((cellcounter & 4095) == 0) lifeabortprogress(0, "Scanning tree") ; root->nw = (node *)thiscell ; } else { writecell_2p1(root->nw, depth-1) ; writecell_2p1(root->ne, depth-1) ; writecell_2p1(root->sw, depth-1) ; writecell_2p1(root->se, depth-1) ; thiscell = ++cellcounter ; // note: we *must* not abort this prescan if ((cellcounter & 4095) == 0) lifeabortprogress(0, "Scanning tree") ; root->next = (node *)thiscell ; } return thiscell ; } /** * This one writes the cells, but assuming they've already been * numbered, and displaying a progress dialog. */ static char progressmsg[80] ; g_uintptr_t hlifealgo::writecell_2p2(std::ostream &os, node *root, int depth) { g_uintptr_t thiscell = 0 ; if (root == zeronode(depth)) return 0 ; if (depth == 2) { if (cellcounter + 1 != (g_uintptr_t)(root->nw)) return (g_uintptr_t)(root->nw) ; thiscell = ++cellcounter ; if ((cellcounter & 4095) == 0) { std::streampos siz = os.tellp(); sprintf(progressmsg, "File size: %.2f MB", double(siz) / 1048576.0) ; lifeabortprogress(thiscell/(double)writecells, progressmsg) ; } int i, j ; unsigned int top, bot ; leaf *n = (leaf *)root ; root->nw = (node *)thiscell ; unpack8x8(n->nw, n->ne, n->sw, n->se, &top, &bot) ; for (j=7; (top | bot) && j>=0; j--) { int bits = (top >> 24) ; top = (top << 8) | (bot >> 24) ; bot = (bot << 8) ; for (i=0; bits && i<8; i++, bits = (bits << 1) & 255) if (bits & 128) os << '*' ; else os << '.' ; os << '$' ; } os << '\n' ; } else { if (cellcounter + 1 > (g_uintptr_t)(root->next) || isaborted()) return (g_uintptr_t)(root->next) ; g_uintptr_t nw = writecell_2p2(os, root->nw, depth-1) ; g_uintptr_t ne = writecell_2p2(os, root->ne, depth-1) ; g_uintptr_t sw = writecell_2p2(os, root->sw, depth-1) ; g_uintptr_t se = writecell_2p2(os, root->se, depth-1) ; if (!isaborted() && cellcounter + 1 != (g_uintptr_t)(root->next)) { // this should never happen lifefatal("Internal in writecell_2p2") ; return (g_uintptr_t)(root->next) ; } thiscell = ++cellcounter ; if ((cellcounter & 4095) == 0) { std::streampos siz = os.tellp(); sprintf(progressmsg, "File size: %.2f MB", double(siz) / 1048576.0) ; lifeabortprogress(thiscell/(double)writecells, progressmsg) ; } root->next = (node *)thiscell ; os << depth+1 << ' ' << nw << ' ' << ne << ' ' << sw << ' ' << se << '\n'; } return thiscell ; } #define STRINGIFY(arg) STR2(arg) #define STR2(arg) #arg const char *hlifealgo::writeNativeFormat(std::ostream &os, char *comments) { int depth = node_depth(root) ; os << "[M2] (golly " STRINGIFY(VERSION) ")\n" ; // AKT: always write out explicit rule os << "#R " << hliferules.getrule() << '\n' ; if (generation > bigint::zero) { // write non-zero gen count os << "#G " << generation.tostring('\0') << '\n' ; } if (comments) { // write given comment line(s), but we can't just do "os << comments" because the // lines might not start with #C (eg. if they came from the end of a .rle file), // so we must ensure that each comment line in the .mc file starts with #C char *p = comments; while (*p != '\0') { char *line = p; // note that readcomments() in readpattern.cpp ensures each line ends with \n while (*p != '\n') p++; if (line[0] != '#' || line[1] != 'C') { os << "#C "; } if (line != p) { *p = '\0'; os << line; *p = '\n'; } os << '\n'; p++; } } inGC = 1 ; /* this is the old way: cellcounter = 0 ; writecell(f, root, depth) ; */ /* this is the new two-pass way */ cellcounter = 0 ; vector depths(timeline.framecount) ; int framestosave = timeline.framecount ; if (timeline.savetimeline == 0) framestosave = 0 ; if (framestosave) { for (int i=0; inext << '\n' ; } } writecell_2p2(os, root, depth) ; /* end new two-pass way */ if (framestosave) { for (int i=0; i 0) ? interrupted : inner_poll() ; } int inner_poll() ; /** * Sometimes we do a lengthy operation that we *don't* poll * during. After such operations, this function resets the * poll countdown back to zero so we get very quick response. */ void reset_countdown() { countdown = 0 ; } /** * Some routines should not be called during a poll() such as ones * that would modify the state of the algorithm process. Some * can be safely called but should be deferred. This routine lets * us know if we are called from the callback or not. */ int isCalculating() { return calculating ; } void bailIfCalculating() ; /** * Sometimes getPopulation is called when hashlife is in a state * where we just can't calculate it at that point in time. So * hashlife remembers that the population was requested, and * when the GC is finished, calcs the pop and executes this * callback to update the status window. */ virtual void updatePop() ; private: int interrupted ; int calculating ; int countdown ; } ; extern lifepoll default_poller ; #endif golly-2.7-src/gollybase/liferender.cpp0000644000175000017500000000176412536111364015034 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "liferender.h" liferender::~liferender() {} golly-2.7-src/gollybase/generationsalgo.h0000644000175000017500000000320112536111364015527 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef GENERALGO_H #define GENERALGO_H #include "ghashbase.h" /** * Our Generations algo class. */ class generationsalgo : public ghashbase { public: generationsalgo() ; virtual ~generationsalgo() ; virtual state slowcalc(state nw, state n, state ne, state w, state c, state e, state sw, state s, state se) ; virtual const char* setrule(const char* s) ; virtual const char* getrule() ; virtual const char* DefaultRule() ; virtual int NumCellStates() ; static void doInitializeAlgoInfo(staticAlgoInfo &) ; private: int bornbits ; int staybits ; // canonical version of valid rule passed into setrule char canonrule[MAXRULESIZE] ; }; #endif golly-2.7-src/gollybase/ghashdraw.cpp0000644000175000017500000006050212536111364014660 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /** * This file is where we figure out how to draw ghashbase structures, * no matter what the magnification or renderer. */ #include "ghashbase.h" #include "util.h" #include #include #include #include using namespace std ; // 64x64 is slightly faster on Mac (< 1%) and Win (1 to 2%) // and much faster on Linux/GTK (5 to 40%) const int logpmsize = 6 ; // 6=64x64 7=128x128 8=256x256 const int pmsize = (1< 1) { // store state info int i = (pmsize-1+lly) * pmsize - llx; if (sw) pixbuf[i] = sw; if (se) pixbuf[i+1] = se; i -= pmsize; if (nw) pixbuf[i] = nw; if (ne) pixbuf[i+1] = ne; } else { // store rgb info int i = (pmsize-1+lly) * rowoff - (llx*bpp); if (sw) { pixbuf[i] = cellred[sw] ; pixbuf[i+1] = cellgreen[sw] ; pixbuf[i+2] = cellblue[sw] ; } i += bpp ; if (se) { pixbuf[i] = cellred[se] ; pixbuf[i+1] = cellgreen[se] ; pixbuf[i+2] = cellblue[se] ; } i -= rowoff ; if (ne) { pixbuf[i] = cellred[ne] ; pixbuf[i+1] = cellgreen[ne] ; pixbuf[i+2] = cellblue[ne] ; } i -= bpp ; if (nw) { pixbuf[i] = cellred[nw] ; pixbuf[i+1] = cellgreen[nw] ; pixbuf[i+2] = cellblue[nw] ; } } } void ghashbase::draw4x4_1(ghnode *n, ghnode *z, int llx, int lly) { // AKT: draw all live cells using state 1 color -- nicer to use an average color??? // pmag == 1, so store rgb info int i = (pmsize-1+lly) * rowoff - (llx*bpp); if (n->sw != z) { pixbuf[i] = cellred[1]; pixbuf[i+1] = cellgreen[1]; pixbuf[i+2] = cellblue[1]; } i += bpp; if (n->se != z) { pixbuf[i] = cellred[1]; pixbuf[i+1] = cellgreen[1]; pixbuf[i+2] = cellblue[1]; } i -= rowoff; if (n->ne != z) { pixbuf[i] = cellred[1] ; pixbuf[i+1] = cellgreen[1] ; pixbuf[i+2] = cellblue[1] ; } i -= bpp; if (n->nw != z) { pixbuf[i] = cellred[1] ; pixbuf[i+1] = cellgreen[1] ; pixbuf[i+2] = cellblue[1] ; } } // AKT: kill all cells in pixbuf void ghashbase::killpixels() { if (pmag > 1) { // pixblit assumes pixbuf contains pmsize*pmsize bytes where each byte // is a cell state, so it's easy to kill all cells memset(pixbuf, 0, pmsize*pmsize); } else { // pixblit assumes pixbuf contains 3 bytes (r,g,b) for each pixel if (cellred[0] == cellgreen[0] && cellgreen[0] == cellblue[0]) { // use fast method memset(pixbuf, cellred[0], sizeof(ipixbuf)); } else { // use slow method (or kill the 1st row and memcpy into the other rows???) for (int i = 0; i < ibufsize; i += bpp) { pixbuf[i] = cellred[0]; pixbuf[i+1] = cellgreen[0]; pixbuf[i+2] = cellblue[0]; } } } } void ghashbase::clearrect(int minx, int miny, int w, int h) { // minx,miny is lower left corner if (w <= 0 || h <= 0) return ; if (pmag > 1) { minx *= pmag ; miny *= pmag ; w *= pmag ; h *= pmag ; } miny = uviewh - miny - h ; renderer->killrect(minx, miny, w, h) ; } void ghashbase::renderbm(int x, int y) { // x,y is lower left corner int rx = x ; int ry = y ; int rw = pmsize ; int rh = pmsize ; if (pmag > 1) { rx *= pmag ; ry *= pmag ; rw *= pmag ; rh *= pmag ; } ry = uviewh - ry - rh ; renderer->pixblit(rx, ry, rw, rh, (char *)pixbuf, pmag); killpixels(); } /* * Here, llx and lly are coordinates in screen pixels describing * where the lower left pixel of the screen is. Draw one ghnode. * This is our main recursive routine. */ void ghashbase::drawghnode(ghnode *n, int llx, int lly, int depth, ghnode *z) { int sw = 1 << (depth - mag + 1) ; if (sw >= pmsize && (llx + vieww <= 0 || lly + viewh <= 0 || llx >= sw || lly >= sw)) return ; if (n == z) { if (sw >= pmsize) clearrect(-llx, -lly, sw, sw) ; } else if (depth > 0 && sw > 2) { z = z->nw ; sw >>= 1 ; depth-- ; if (sw == (pmsize >> 1)) { drawghnode(n->sw, 0, 0, depth, z) ; drawghnode(n->se, -(pmsize/2), 0, depth, z) ; drawghnode(n->nw, 0, -(pmsize/2), depth, z) ; drawghnode(n->ne, -(pmsize/2), -(pmsize/2), depth, z) ; renderbm(-llx, -lly) ; } else { drawghnode(n->sw, llx, lly, depth, z) ; drawghnode(n->se, llx-sw, lly, depth, z) ; drawghnode(n->nw, llx, lly-sw, depth, z) ; drawghnode(n->ne, llx-sw, lly-sw, depth, z) ; } } else if (depth > 0 && sw == 2) { draw4x4_1(n, z->nw, llx, lly) ; } else if (sw == 1) { drawpixel(-llx, -lly) ; } else { struct ghleaf *l = (struct ghleaf *)n ; sw >>= 1 ; if (sw == 1) { draw4x4_1(l->sw, l->se, l->nw, l->ne, llx, lly) ; } else { lifefatal("Can't happen") ; } } } /* * Fill in the llxb and llyb bits from the viewport information. * Allocate if necessary. This arithmetic should be done carefully. */ void ghashbase::fill_ll(int d) { pair coor = view->at(0, view->getymax()) ; coor.second.mul_smallint(-1) ; bigint s = 1 ; s <<= d ; coor.first += s ; coor.second += s ; int bitsreq = coor.first.bitsreq() ; int bitsreq2 = coor.second.bitsreq() ; if (bitsreq2 > bitsreq) bitsreq = bitsreq2 ; if (bitsreq <= d) bitsreq = d + 1 ; // need to access llxyb[d] if (bitsreq > llsize) { if (llsize) { delete [] llxb ; delete [] llyb ; } llxb = new char[bitsreq] ; llyb = new char[bitsreq] ; llsize = bitsreq ; } llbits = bitsreq ; coor.first.tochararr(llxb, llbits) ; coor.second.tochararr(llyb, llbits) ; } /* * This is the top-level draw routine that takes the root ghnode. * It maintains four ghnodes onto which the screen fits and uses the * high bits of llx/lly to project those four ghnodes as far down * the tree as possible, so we know we can get away with just * 32-bit arithmetic in the above recursive routine. This way * we don't need any high-precision addition or subtraction to * display an image. */ void ghashbase::draw(viewport &viewarg, liferender &rendererarg) { /* AKT: call killpixels below memset(pixbuf, 0, sizeof(ipixbuf)) ; */ ensure_hashed() ; renderer = &rendererarg ; // AKT: set cellred/green/blue ptrs renderer->getcolors(&cellred, &cellgreen, &cellblue); view = &viewarg ; uvieww = view->getwidth() ; uviewh = view->getheight() ; if (view->getmag() > 0) { pmag = 1 << (view->getmag()) ; mag = 0 ; viewh = ((uviewh - 1) >> view->getmag()) + 1 ; vieww = ((uvieww - 1) >> view->getmag()) + 1 ; uviewh += (-uviewh) & (pmag - 1) ; } else { mag = (-view->getmag()) ; pmag = 1 ; viewh = uviewh ; vieww = uvieww ; } // AKT: must call killpixels after setting pmag killpixels(); int d = depth ; fill_ll(d) ; int maxd = vieww ; int i ; ghnode *z = zeroghnode(d) ; ghnode *sw = root, *nw = z, *ne = z, *se = z ; if (viewh > maxd) maxd = viewh ; int llx=-llxb[llbits-1], lly=-llyb[llbits-1] ; /* Skip down to top of tree. */ for (i=llbits-1; i>d && i>=mag; i--) { /* go down to d, but not further than mag */ llx = (llx << 1) + llxb[i] ; lly = (lly << 1) + llyb[i] ; if (llx > 2*maxd || lly > 2*maxd || llx < -2*maxd || lly < -2*maxd) { clearrect(0, 0, vieww, viewh) ; goto bail ; } } /* Find the lowest four we need to examine */ while (d > 0 && d - mag >= 0 && (d - mag > 28 || (1 << (d - mag)) > 2 * maxd)) { llx = (llx << 1) + llxb[d] ; lly = (lly << 1) + llyb[d] ; if (llx >= 1) { if (lly >= 1) { ne = ne->sw ; nw = nw->se ; se = se->nw ; sw = sw->ne ; lly-- ; } else { ne = se->nw ; nw = sw->ne ; se = se->sw ; sw = sw->se ; } llx-- ; } else { if (lly >= 1) { ne = nw->se ; nw = nw->sw ; se = sw->ne ; sw = sw->nw ; lly-- ; } else { ne = sw->ne ; nw = sw->nw ; se = sw->se ; sw = sw->sw ; } } if (llx > 2*maxd || lly > 2*maxd || llx < -2*maxd || lly < -2*maxd) { clearrect(0, 0, vieww, viewh) ; goto bail ; } d-- ; } /* At this point we know we can use 32-bit arithmetic. */ for (i=d; i>=mag; i--) { llx = (llx << 1) + llxb[i] ; lly = (lly << 1) + llyb[i] ; } /* clear the border *around* the universe if necessary */ if (d + 1 <= mag) { ghnode *z = zeroghnode(d) ; if (llx > 0 || lly > 0 || llx + vieww <= 0 || lly + viewh <= 0 || (sw == z && se == z && nw == z && ne == z)) { clearrect(0, 0, vieww, viewh) ; } else { clearrect(0, 1-lly, vieww, viewh-1+lly) ; clearrect(0, 0, vieww, -lly) ; clearrect(0, -lly, -llx, 1) ; clearrect(1-llx, -lly, vieww-1+llx, 1) ; drawpixel(0, 0) ; renderbm(-llx, -lly) ; } } else { z = zeroghnode(d) ; maxd = 1 << (d - mag + 2) ; clearrect(0, maxd-lly, vieww, viewh-maxd+lly) ; clearrect(0, 0, vieww, -lly) ; clearrect(0, -lly, -llx, maxd) ; clearrect(maxd-llx, -lly, vieww-maxd+llx, maxd) ; if (maxd <= pmsize) { maxd >>= 1 ; drawghnode(sw, 0, 0, d, z) ; drawghnode(se, -maxd, 0, d, z) ; drawghnode(nw, 0, -maxd, d, z) ; drawghnode(ne, -maxd, -maxd, d, z) ; renderbm(-llx, -lly) ; } else { maxd >>= 1 ; drawghnode(sw, llx, lly, d, z) ; drawghnode(se, llx-maxd, lly, d, z) ; drawghnode(nw, llx, lly-maxd, d, z) ; drawghnode(ne, llx-maxd, lly-maxd, d, z) ; } } bail: renderer = 0 ; view = 0 ; } static int getbitsfromleaves(const vector &v) { unsigned short nw=0, ne=0, sw=0, se=0 ; int i; for (i=0; i<(int)v.size(); i++) { ghleaf *p = (ghleaf *)v[i] ; nw |= p->nw ; ne |= p->ne ; sw |= p->sw ; se |= p->se ; } int r = 0 ; // horizontal bits are least significant ones unsigned short w = nw | sw ; unsigned short e = ne | se ; // vertical bits are next 8 unsigned short n = nw | ne ; unsigned short s = sw | se ; if (w) r |= 512 ; if (e) r |= 256 ; if (n) r |= 2 ; if (s) r |= 1 ; return r ; } /** * Copy the vector, but sort it and uniquify it so we don't have a ton * of duplicate ghnodes. */ static void sortunique(vector &dest, vector &src) { swap(src, dest) ; // note: this is superfast sort(dest.begin(), dest.end()) ; vector::iterator new_end = unique(dest.begin(), dest.end()) ; dest.erase(new_end, dest.end()) ; src.clear() ; } using namespace std ; void ghashbase::findedges(bigint *ptop, bigint *pleft, bigint *pbottom, bigint *pright) { // following code is from fit() but all goal/size stuff // has been removed so it finds the exact pattern edges ensure_hashed() ; bigint xmin = -1 ; bigint xmax = 1 ; bigint ymin = -1 ; bigint ymax = 1 ; int currdepth = depth ; int i; if (root == zeroghnode(currdepth)) { // return impossible edges to indicate empty pattern; // not really a problem because caller should check first *ptop = 1 ; *pleft = 1 ; *pbottom = 0 ; *pright = 0 ; return ; } vector top, left, bottom, right ; top.push_back(root) ; left.push_back(root) ; bottom.push_back(root) ; right.push_back(root) ; int topbm = 0, bottombm = 0, rightbm = 0, leftbm = 0 ; while (currdepth >= -2) { currdepth-- ; if (currdepth == -1) { // we have ghleaf ghnodes; turn them into bitmasks topbm = getbitsfromleaves(top) & 0xff ; bottombm = getbitsfromleaves(bottom) & 0xff ; leftbm = getbitsfromleaves(left) >> 8 ; rightbm = getbitsfromleaves(right) >> 8 ; } if (currdepth == -1) { int sz = 1 << (currdepth + 2) ; int maskhi = (1 << sz) - (1 << (sz >> 1)) ; int masklo = (1 << (sz >> 1)) - 1 ; ymax += ymax ; if ((topbm & maskhi) == 0) { ymax.add_smallint(-2) ; } else { topbm >>= (sz >> 1) ; } ymin += ymin ; if ((bottombm & masklo) == 0) { ymin.add_smallint(2) ; bottombm >>= (sz >> 1) ; } xmax += xmax ; if ((rightbm & masklo) == 0) { xmax.add_smallint(-2) ; rightbm >>= (sz >> 1) ; } xmin += xmin ; if ((leftbm & maskhi) == 0) { xmin.add_smallint(2) ; } else { leftbm >>= (sz >> 1) ; } } else if (currdepth >= 0) { ghnode *z = 0 ; if (hashed) z = zeroghnode(currdepth) ; vector newv ; int outer = 0 ; for (i=0; i<(int)top.size(); i++) { ghnode *t = top[i] ; if (!outer && (t->nw != z || t->ne != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->nw != z) newv.push_back(t->nw) ; if (t->ne != z) newv.push_back(t->ne) ; } else { if (t->sw != z) newv.push_back(t->sw) ; if (t->se != z) newv.push_back(t->se) ; } } sortunique(top, newv) ; ymax += ymax ; if (!outer) { ymax.add_smallint(-2) ; } outer = 0 ; for (i=0; i<(int)bottom.size(); i++) { ghnode *t = bottom[i] ; if (!outer && (t->sw != z || t->se != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->sw != z) newv.push_back(t->sw) ; if (t->se != z) newv.push_back(t->se) ; } else { if (t->nw != z) newv.push_back(t->nw) ; if (t->ne != z) newv.push_back(t->ne) ; } } sortunique(bottom, newv) ; ymin += ymin ; if (!outer) { ymin.add_smallint(2) ; } outer = 0 ; for (i=0; i<(int)right.size(); i++) { ghnode *t = right[i] ; if (!outer && (t->ne != z || t->se != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->ne != z) newv.push_back(t->ne) ; if (t->se != z) newv.push_back(t->se) ; } else { if (t->nw != z) newv.push_back(t->nw) ; if (t->sw != z) newv.push_back(t->sw) ; } } sortunique(right, newv) ; xmax += xmax ; if (!outer) { xmax.add_smallint(-2) ; } outer = 0 ; for (i=0; i<(int)left.size(); i++) { ghnode *t = left[i] ; if (!outer && (t->nw != z || t->sw != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->nw != z) newv.push_back(t->nw) ; if (t->sw != z) newv.push_back(t->sw) ; } else { if (t->ne != z) newv.push_back(t->ne) ; if (t->se != z) newv.push_back(t->se) ; } } sortunique(left, newv) ; xmin += xmin ; if (!outer) { xmin.add_smallint(2) ; } } } xmin >>= 1 ; xmax >>= 1 ; ymin >>= 1 ; ymax >>= 1 ; xmin <<= (currdepth + 3) ; ymin <<= (currdepth + 3) ; xmax <<= (currdepth + 3) ; ymax <<= (currdepth + 3) ; xmax -= 1 ; ymax -= 1 ; ymin.mul_smallint(-1) ; ymax.mul_smallint(-1) ; // set pattern edges *ptop = ymax ; // due to y flip *pbottom = ymin ; // due to y flip *pleft = xmin ; *pright = xmax ; } void ghashbase::fit(viewport &view, int force) { ensure_hashed() ; bigint xmin = -1 ; bigint xmax = 1 ; bigint ymin = -1 ; bigint ymax = 1 ; int xgoal = view.getwidth() ; int ygoal = view.getheight() ; if (xgoal < 8) xgoal = 8 ; if (ygoal < 8) ygoal = 8 ; int xsize = 2 ; int ysize = 2 ; int currdepth = depth ; int i; if (root == zeroghnode(currdepth)) { view.center() ; view.setmag(MAX_MAG) ; return ; } vector top, left, bottom, right ; top.push_back(root) ; left.push_back(root) ; bottom.push_back(root) ; right.push_back(root) ; int topbm = 0, bottombm = 0, rightbm = 0, leftbm = 0 ; while (currdepth >= 0) { currdepth-- ; if (currdepth == -1) { // we have ghleaf ghnodes; turn them into bitmasks topbm = getbitsfromleaves(top) & 0xff ; bottombm = getbitsfromleaves(bottom) & 0xff ; leftbm = getbitsfromleaves(left) >> 8 ; rightbm = getbitsfromleaves(right) >> 8 ; } if (currdepth == -1) { int sz = 1 << (currdepth + 2) ; int maskhi = (1 << sz) - (1 << (sz >> 1)) ; int masklo = (1 << (sz >> 1)) - 1 ; ymax += ymax ; if ((topbm & maskhi) == 0) { ymax.add_smallint(-2) ; ysize-- ; } else { topbm >>= (sz >> 1) ; } ymin += ymin ; if ((bottombm & masklo) == 0) { ymin.add_smallint(2) ; ysize-- ; bottombm >>= (sz >> 1) ; } xmax += xmax ; if ((rightbm & masklo) == 0) { xmax.add_smallint(-2) ; xsize-- ; rightbm >>= (sz >> 1) ; } xmin += xmin ; if ((leftbm & maskhi) == 0) { xmin.add_smallint(2) ; xsize-- ; } else { leftbm >>= (sz >> 1) ; } xsize <<= 1 ; ysize <<= 1 ; } else if (currdepth >= 0) { ghnode *z = 0 ; if (hashed) z = zeroghnode(currdepth) ; vector newv ; int outer = 0 ; for (i=0; i<(int)top.size(); i++) { ghnode *t = top[i] ; if (!outer && (t->nw != z || t->ne != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->nw != z) newv.push_back(t->nw) ; if (t->ne != z) newv.push_back(t->ne) ; } else { if (t->sw != z) newv.push_back(t->sw) ; if (t->se != z) newv.push_back(t->se) ; } } top = newv ; newv.clear() ; ymax += ymax ; if (!outer) { ymax.add_smallint(-2) ; ysize-- ; } outer = 0 ; for (i=0; i<(int)bottom.size(); i++) { ghnode *t = bottom[i] ; if (!outer && (t->sw != z || t->se != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->sw != z) newv.push_back(t->sw) ; if (t->se != z) newv.push_back(t->se) ; } else { if (t->nw != z) newv.push_back(t->nw) ; if (t->ne != z) newv.push_back(t->ne) ; } } bottom = newv ; newv.clear() ; ymin += ymin ; if (!outer) { ymin.add_smallint(2) ; ysize-- ; } ysize *= 2 ; outer = 0 ; for (i=0; i<(int)right.size(); i++) { ghnode *t = right[i] ; if (!outer && (t->ne != z || t->se != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->ne != z) newv.push_back(t->ne) ; if (t->se != z) newv.push_back(t->se) ; } else { if (t->nw != z) newv.push_back(t->nw) ; if (t->sw != z) newv.push_back(t->sw) ; } } right = newv ; newv.clear() ; xmax += xmax ; if (!outer) { xmax.add_smallint(-2) ; xsize-- ; } outer = 0 ; for (i=0; i<(int)left.size(); i++) { ghnode *t = left[i] ; if (!outer && (t->nw != z || t->sw != z)) { newv.clear() ; outer = 1 ; } if (outer) { if (t->nw != z) newv.push_back(t->nw) ; if (t->sw != z) newv.push_back(t->sw) ; } else { if (t->ne != z) newv.push_back(t->ne) ; if (t->se != z) newv.push_back(t->se) ; } } left = newv ; newv.clear() ; xmin += xmin ; if (!outer) { xmin.add_smallint(2) ; xsize-- ; } xsize *= 2 ; } if (xsize > xgoal || ysize > ygoal) break ; } if (currdepth < 0){ xmin >>= -currdepth ; ymin >>= -currdepth ; xmax >>= -currdepth ; ymax >>= -currdepth ; } else { xmin <<= currdepth ; ymin <<= currdepth ; xmax <<= currdepth ; ymax <<= currdepth ; } xmax -= 1 ; ymax -= 1 ; ymin.mul_smallint(-1) ; ymax.mul_smallint(-1) ; if (!force) { // if all four of the above dimensions are in the viewport, don't change if (view.contains(xmin, ymin) && view.contains(xmax, ymax)) return ; } int mag = - currdepth - 1 ; while (xsize <= xgoal && ysize <= ygoal && mag < MAX_MAG) { mag++ ; xsize *= 2 ; ysize *= 2 ; } view.setpositionmag(xmin, xmax, ymin, ymax, mag) ; } void ghashbase::lowerRightPixel(bigint &x, bigint &y, int mag) { if (mag >= 0) return ; x >>= -mag ; x <<= -mag ; y -= 1 ; y >>= -mag ; y <<= -mag ; y += 1 ; } golly-2.7-src/gollybase/lifealgo.cpp0000644000175000017500000002635312536111364014500 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "lifealgo.h" #include "string.h" using namespace std ; lifealgo::~lifealgo() { poller = 0 ; maxCellStates = 2 ; } int lifealgo::verbose ; /* * Right now, the base/expo should match the current increment. * We do not check this. */ int lifealgo::startrecording(int basearg, int expoarg) { if (timeline.framecount) { // already have a timeline; skip to its end gotoframe(timeline.framecount-1) ; } else { // use the current frame and increment to start a new timeline void *now = getcurrentstate() ; if (now == 0) return 0 ; timeline.base = basearg ; timeline.expo = expoarg ; timeline.frames.push_back(now) ; timeline.framecount = 1 ; timeline.end = timeline.start = generation ; timeline.inc = increment ; } timeline.next = timeline.end ; timeline.next += timeline.inc ; timeline.recording = 1 ; return timeline.framecount ; } pair lifealgo::stoprecording() { timeline.recording = 0 ; timeline.next = 0 ; return make_pair(timeline.base, timeline.expo) ; } void lifealgo::extendtimeline() { if (timeline.recording && generation == timeline.next) { void *now = getcurrentstate() ; if (now && timeline.framecount < MAX_FRAME_COUNT) { timeline.frames.push_back(now) ; timeline.framecount++ ; timeline.end = timeline.next ; timeline.next += timeline.inc ; } } } /* * Note that this *also* changes inc, so don't call unless this is * what you want to do. It does not update or change the base or * expo if the base != 2, so they can get out of sync. * * Currently this is only used by bgolly, and it will only work * properly if the increment argument is a power of two. */ void lifealgo::pruneframes() { if (timeline.framecount > 1) { for (int i=2; i> 1] = timeline.frames[i] ; timeline.framecount = (timeline.framecount + 1) >> 1 ; timeline.frames.resize(timeline.framecount) ; timeline.inc += timeline.inc ; timeline.end = timeline.inc ; timeline.end.mul_smallint(timeline.framecount-1) ; timeline.end += timeline.start ; timeline.next = timeline.end ; timeline.next += timeline.inc ; if (timeline.base == 2) timeline.expo++ ; } } int lifealgo::gotoframe(int i) { if (i < 0 || i >= timeline.framecount) return 0 ; setcurrentstate(timeline.frames[i]) ; // AKT: avoid mul_smallint(i) crashing with divide-by-zero if i is 0 if (i > 0) { generation = timeline.inc ; generation.mul_smallint(i) ; } else { generation = 0; } generation += timeline.start ; return timeline.framecount ; } void lifealgo::destroytimeline() { timeline.frames.clear() ; timeline.recording = 0 ; timeline.framecount = 0 ; timeline.end = 0 ; timeline.start = 0 ; timeline.inc = 0 ; timeline.next = 0 ; } // AKT: the next 2 routines provide support for a bounded universe const char* lifealgo::setgridsize(const char* suffix) { // parse a rule suffix like ":T100,200" and set the various grid parameters; // note that we allow any legal partial suffix -- this lets people type a // suffix into the Set Rule dialog without the algorithm changing to UNKNOWN const char *p = suffix; char topology = 0; gridwd = gridht = 0; hshift = vshift = 0; htwist = vtwist = false; boundedplane = false; sphere = false; p++; if (*p == 0) return 0; // treat ":" like ":T0,0" if (*p == 't' || *p == 'T') { // torus or infinite tube topology = 'T'; } else if (*p == 'p' || *p == 'P') { boundedplane = true; topology = 'P'; } else if (*p == 's' || *p == 'S') { sphere = true; topology = 'S'; } else if (*p == 'k' || *p == 'K') { // Klein bottle (either htwist or vtwist should become true) topology = 'K'; } else if (*p == 'c' || *p == 'C') { // cross-surface htwist = vtwist = true; topology = 'C'; } else { return "Unknown grid topology."; } p++; if (*p == 0) return 0; // treat ":" like ":T0,0" while ('0' <= *p && *p <= '9') { if (gridwd >= 200000000) { gridwd = 2000000000; // keep width within editable limits } else { gridwd = 10 * gridwd + *p - '0'; } p++; } if (*p == '*') { if (topology != 'K') return "Only specify a twist for a Klein bottle."; htwist = true; p++; } if (*p == '+' || *p == '-') { if (topology == 'P') return "Plane can't have a shift."; if (topology == 'S') return "Sphere can't have a shift."; if (topology == 'C') return "Cross-surface can't have a shift."; if (topology == 'K' && !htwist) return "Shift must be on twisted edges."; if (gridwd == 0) return "Can't shift infinite width."; int sign = *p == '+' ? 1 : -1; p++; while ('0' <= *p && *p <= '9') { hshift = 10 * hshift + *p - '0'; p++; } if (hshift >= (int)gridwd) hshift = hshift % (int)gridwd; hshift *= sign; } if (*p == ',' && topology != 'S') { p++; } else if (*p) { return "Unexpected stuff after grid width."; } // gridwd has been set if ((topology == 'K' || topology == 'C' || topology == 'S') && gridwd == 0) { return "Given topology can't have an infinite width."; } if (*p == 0) { // grid height is not specified so set it to grid width; // ie. treat ":T100" like ":T100,100"; // this also allows us to have ":S100" rather than ":S100,100" gridht = gridwd; } else { while ('0' <= *p && *p <= '9') { if (gridht >= 200000000) { gridht = 2000000000; // keep height within editable limits } else { gridht = 10 * gridht + *p - '0'; } p++; } if (*p == '*') { if (topology != 'K') return "Only specify a twist for a Klein bottle."; if (htwist) return "Klein bottle can't have both horizontal and vertical twists."; vtwist = true; p++; } if (*p == '+' || *p == '-') { if (topology == 'P') return "Plane can't have a shift."; if (topology == 'C') return "Cross-surface can't have a shift."; if (topology == 'K' && !vtwist) return "Shift must be on twisted edges."; if (hshift != 0) return "Can't have both horizontal and vertical shifts."; if (gridht == 0) return "Can't shift infinite height."; int sign = *p == '+' ? 1 : -1; p++; while ('0' <= *p && *p <= '9') { vshift = 10 * vshift + *p - '0'; p++; } if (vshift >= (int)gridht) vshift = vshift % (int)gridht; vshift *= sign; } if (*p) return "Unexpected stuff after grid height."; } // gridht has been set if ((topology == 'K' || topology == 'C') && gridht == 0) { return "Klein bottle or cross-surface can't have an infinite height."; } if (topology == 'K' && !(htwist || vtwist)) { // treat ":K10,20" like ":K10,20*" vtwist = true; } if ((hshift != 0 || vshift != 0) && (gridwd == 0 || gridht == 0)) { return "Shifting is not allowed if either grid dimension is unbounded."; } // now ok to set grid edges if (gridwd > 0) { gridleft = -int(gridwd) / 2; gridright = int(gridwd) - 1; gridright += gridleft; } else { // play safe and set these to something gridleft = bigint::zero; gridright = bigint::zero; } if (gridht > 0) { gridtop = -int(gridht) / 2; gridbottom = int(gridht) - 1; gridbottom += gridtop; } else { // play safe and set these to something gridtop = bigint::zero; gridbottom = bigint::zero; } return 0; } const char* lifealgo::canonicalsuffix() { if (gridwd > 0 || gridht > 0) { static char bounds[64]; if (boundedplane) { sprintf(bounds, ":P%u,%u", gridwd, gridht); } else if (sphere) { // sphere requires a square grid (gridwd == gridht) sprintf(bounds, ":S%u", gridwd); } else if (htwist && vtwist) { // cross-surface if both horizontal and vertical edges are twisted sprintf(bounds, ":C%u,%u", gridwd, gridht); } else if (htwist) { // Klein bottle if only horizontal edges are twisted if (hshift != 0 && (gridwd & 1) == 0) { // twist and shift is only possible if gridwd is even and hshift is 1 sprintf(bounds, ":K%u*+1,%u", gridwd, gridht); } else { sprintf(bounds, ":K%u*,%u", gridwd, gridht); } } else if (vtwist) { // Klein bottle if only vertical edges are twisted if (vshift != 0 && (gridht & 1) == 0) { // twist and shift is only possible if gridht is even and vshift is 1 sprintf(bounds, ":K%u,%u*+1", gridwd, gridht); } else { sprintf(bounds, ":K%u,%u*", gridwd, gridht); } } else if (hshift < 0) { // torus with -ve horizontal shift sprintf(bounds, ":T%u%d,%u", gridwd, hshift, gridht); } else if (hshift > 0) { // torus with +ve horizontal shift sprintf(bounds, ":T%u+%d,%u", gridwd, hshift, gridht); } else if (vshift < 0) { // torus with -ve vertical shift sprintf(bounds, ":T%u,%u%d", gridwd, gridht, vshift); } else if (vshift > 0) { // torus with +ve vertical shift sprintf(bounds, ":T%u,%u+%d", gridwd, gridht, vshift); } else { // unshifted torus, or an infinite tube sprintf(bounds, ":T%u,%u", gridwd, gridht); } return bounds; } else { // unbounded universe return 0; } } int staticAlgoInfo::nextAlgoId = 0 ; staticAlgoInfo *staticAlgoInfo::head = 0 ; staticAlgoInfo::staticAlgoInfo() { id = nextAlgoId++ ; next = head ; head = this ; // init default icon data defxpm7x7 = NULL; defxpm15x15 = NULL; defxpm31x31 = NULL; } staticAlgoInfo *staticAlgoInfo::byName(const char *s) { for (staticAlgoInfo *i=head; i; i=i->next) if (strcmp(i->algoName, s) == 0) return i ; return 0 ; } int staticAlgoInfo::nameToIndex(const char *s) { staticAlgoInfo *r = byName(s) ; if (r == 0) return -1 ; return r->id ; } staticAlgoInfo &staticAlgoInfo::tick() { return *(new staticAlgoInfo()) ; } golly-2.7-src/gollybase/bigint.cpp0000644000175000017500000004365612536111364014177 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include #include #include #include #include #include "util.h" #undef SLOWCHECK using namespace std ; /** * Static data. */ static const int MAX_SIMPLE = 0x3fffffff ; static const int MIN_SIMPLE = -0x40000000 ; char *bigint::printbuf ; int *bigint::work ; int bigint::printbuflen ; int bigint::workarrlen ; char bigint::sepchar = ',' ; int bigint::sepcount = 3 ; /** * Routines. */ bigint::bigint() { v.i = 1 ; } bigint::bigint(int i) { fromint(i) ; } bigint::bigint(G_INT64 i) { if (i <= INT_MAX && i >= INT_MIN) fromint((int)i) ; else { v.i = 0 ; vectorize(0) ; v.p[0] = 3 ; v.p[1] = (int)(i & 0x7fffffff) ; v.p[2] = (int)((i >> 31) & 0x7fffffff) ; v.p[3] = 0 ; ripple((int)(i >> 62), 3) ; } } // we can parse ####, 2^###, -##### // AKT: we ignore all non-digits (except for leading '-') // so we can parse strings like "1,234" or "+1.234"; // it is up to caller to impose smarter restrictions bigint::bigint(const char *s) { if (*s == '2' && s[1] == '^') { long x = atol(s+2) ; if (x < 31) fromint(1 << x) ; else { int sz = 2 + (x + 1) / 31 ; int asz = sz ; while (asz & (asz - 1)) asz &= asz - 1 ; asz *= 2 ; v.p = new int[asz] ; v.p[0] = sz ; for (int i=1; i<=sz; i++) v.p[i] = 0 ; v.p[sz-1] = 1 << (x % 31) ; } } else { int neg = 0 ; if (*s == '-') { neg = 1 ; s++ ; } fromint(0) ; while (*s) { // AKT: was *s != sepchar if (*s >= '0' && *s <= '9') { mul_smallint(10) ; if (neg) add_smallint('0'-*s) ; else add_smallint(*s-'0') ; } s++ ; } } } static int *copyarr(int *p) { int sz = *p ; while (sz & (sz - 1)) sz &= sz - 1 ; sz *= 2 ; int *r = new int[sz] ; memcpy(r, p, sizeof(int) * (p[0] + 1)) ; #ifdef SLOWCHECK for (int i=p[0]+1; i printbuflen) { if (printbuf) delete [] printbuf ; printbuf = new char[2 * lenreq] ; printbuflen = 2 * lenreq ; } int sz = 1 ; if (0 == (v.i & 1)) sz = size() ; ensurework(sz) ; int neg = sign() < 0 ; if (v.i & 1) { if (neg) work[0] = -(v.i >> 1) ; else work[0] = v.i >> 1 ; } else { if (neg) { int carry = 1 ; for (int i=0; i+1> 31) & 1 ; } work[sz-1] = carry + ~v.p[sz] ; } else { for (int i=0; i=0; i--) { G_INT64 c = carry * G_MAKEINT64(0x80000000) + work[i] ; carry = (int)(c % bigradix) ; work[i] = (int)(c / bigradix) ; allbits |= work[i] ; } for (i=0; i<9; i++) { // put the nine digits in *p++ = (char)(carry % 10 + '0') ; carry /= 10 ; } if (allbits == 0) break ; } while (p > printbuf + 1 && *(p-1) == '0') p-- ; char *r = p ; if (neg) *r++ = '-' ; for (int i=(int)(p-printbuf-1); i>=0; i--) { *r++ = printbuf[i] ; if (i && sep && (i % sepcount == 0)) *r++ = sep ; } *r++ = 0 ; return p ; } void bigint::grow(int osz, int nsz) { int bdiffs = osz ^ nsz ; if (bdiffs > osz) { while (bdiffs & (bdiffs - 1)) bdiffs &= bdiffs - 1 ; int *nv = new int[2*bdiffs] ; for (int i=0; i<=osz; i++) nv[i] = v.p[i] ; #ifdef SLOWCHECK for (int i=osz+1; i<2*bdiffs; i++) nv[i] = 0xdeadbeef ; #endif delete [] v.p ; v.p = nv ; } int av = v.p[osz] ; while (osz < nsz) { v.p[osz] = av & 0x7fffffff ; osz++ ; } v.p[nsz] = av ; v.p[0] = nsz ; } bigint& bigint::operator+=(const bigint &a) { if (a.v.i & 1) add_smallint(a.v.i >> 1) ; else { if (v.i & 1) vectorize(v.i >> 1) ; ripple(a, 0) ; } return *this ; } bigint& bigint::operator-=(const bigint &a) { if (a.v.i & 1) add_smallint(-(a.v.i >> 1)) ; else { if (v.i & 1) vectorize(v.i >> 1) ; ripplesub(a, 1) ; } return *this ; } int bigint::sign() const { int si = v.i ; if (0 == (si & 1)) si = v.p[size()] ; if (si > 0) return 1 ; if (si < 0) return -1 ; return 0 ; } int bigint::size() const { return v.p[0] ; } void bigint::add_smallint(int a) { if (v.i & 1) fromint((v.i >> 1) + a) ; else ripple(a, 1) ; } // do we need to shrink it to keep it canonical? void bigint::shrink(int pos) { while (pos > 1 && ((v.p[pos] - v.p[pos-1]) & 0x7fffffff) == 0) { pos-- ; v.p[pos] = v.p[pos+1] ; v.p[0] = pos ; } if (pos == 1) { int c = v.p[1] ; delete [] v.p ; v.i = 1 | (c << 1) ; } else if (pos == 2 && ((v.p[2] ^ v.p[1]) & 0x40000000) == 0) { int c = v.p[1] + (v.p[2] << 31) ; delete [] v.p ; v.i = 1 | (c << 1) ; } } void grow(int osz, int nsz) ; // note: carry may be any legal 31-bit int, *or* positive 2^30 // note: may only be called on arrayed bigints void bigint::ripple(int carry, int pos) { int c ; int sz = size() ; while (pos < sz) { c = v.p[pos] + (carry & 0x7fffffff) ; carry = ((c >> 31) & 1) + (carry >> 31) ; v.p[pos++] = c & 0x7fffffff; } c = v.p[pos] + carry ; if (c == 0 || c == -1) { // see if we can make it smaller v.p[pos] = c ; shrink(pos) ; } else { // need to extend if (0 == (sz & (sz + 1))) { // grow array (oops) grow(sz, sz+1) ; } else v.p[0] = sz + 1 ; v.p[pos] = c & 0x7fffffff ; v.p[pos+1] = -((c >> 31) & 1) ; } } void bigint::ripple(const bigint &a, int carry) { int asz = a.size() ; int tsz = size() ; int pos = 1 ; if (tsz < asz) { // gotta resize grow(tsz, asz) ; tsz = asz ; } while (pos < asz) { int c = v.p[pos] + a.v.p[pos] + carry ; carry = (c >> 31) & 1 ; v.p[pos++] = c & 0x7fffffff; } ripple(carry + a.v.p[pos], pos) ; } void bigint::ripplesub(const bigint &a, int carry) { int asz = a.size() ; int tsz = size() ; int pos = 1 ; if (tsz < asz) { // gotta resize grow(tsz, asz) ; tsz = asz ; } while (pos < asz) { int c = v.p[pos] + (0x7fffffff ^ a.v.p[pos]) + carry ; carry = (c >> 31) & 1 ; v.p[pos++] = c & 0x7fffffff; } ripple(carry + ~a.v.p[pos], pos) ; } // make sure it's in vector form; may leave it not canonical! void bigint::vectorize(int i) { v.p = new int[4] ; v.p[0] = 2 ; v.p[1] = i & 0x7fffffff ; if (i < 0) v.p[2] = -1 ; else v.p[2] = 0 ; #ifdef SLOWCHECK v.p[3] = 0xdeadbeef ; #endif } void bigint::fromint(int i) { if (i <= MAX_SIMPLE && i >= MIN_SIMPLE) v.i = (i << 1) | 1 ; else vectorize(i) ; } void bigint::ensurework(int sz) const { sz += 3 ; if (sz > workarrlen) { if (work) delete [] work ; work = new int[sz * 2] ; workarrlen = sz * 2 ; } } void bigint::mul_smallint(int a) { int c ; if (a == 0) { *this = 0 ; return ; } if (v.i & 1) { if ((v.i >> 1) <= MAX_SIMPLE / a) { c = (v.i >> 1) * a ; fromint((v.i >> 1) * a) ; return ; } vectorize(v.i >> 1) ; } int sz = size() ; int carry = 0 ; int pos = 1 ; while (pos < sz) { int clo = (v.p[pos] & 0xffff) * a + carry ; int chi = (v.p[pos] >> 16) * a + (clo >> 16) ; carry = chi >> 15 ; v.p[pos++] = (clo & 0xffff) + ((chi & 0x7fff) << 16) ; } c = v.p[pos] * a + carry ; if (c == 0 || c == -1) { // see if we can make it smaller v.p[pos] = c ; shrink(pos) ; } else { // need to extend if (0 == (sz & (sz + 1))) { // grow array (oops) grow(sz, sz+1) ; } else v.p[0] = sz + 1 ; v.p[pos] = c & 0x7fffffff ; v.p[pos+1] = -((c >> 31) & 1) ; } } void bigint::div_smallint(int a) { if (v.i & 1) { int r = (v.i >> 1) / a ; fromint(r) ; return ; } if (v.p[v.p[0]] < 0) lifefatal("we don't support divsmallint when negative yet") ; int carry = 0 ; int pos = v.p[0] ; while (pos > 0) { G_INT64 t = ((G_INT64)carry << G_MAKEINT64(31)) + v.p[pos] ; carry = (int)(t % a) ; v.p[pos] = (int)(t / a) ; pos-- ; } shrink(v.p[0]) ; } int bigint::mod_smallint(int a) { if (v.i & 1) return (((v.i >> 1) % a) + a) % a ; int pos = v.p[0] ; int mm = (1 << 31) % a ; int r = 0 ; while (pos > 0) { r = (mm * r + v.p[pos]) % a ; pos-- ; } return (r + a) % a ; } void bigint::div2() { if (v.i & 1) { v.i = ((v.i >> 1) | 1) ; return ; } int sz = v.p[0] ; int carry = -v.p[sz] ; for (int i=sz-1; i>0; i--) { int c = (v.p[i] >> 1) + (carry << 30) ; carry = v.p[i] & 1 ; v.p[i] = c ; } shrink(v.p[0]) ; } bigint& bigint::operator>>=(int i) { if (v.i & 1) { if (i > 31) v.i = ((v.i >> 31) | 1) ; else v.i = ((v.i >> i) | 1) ; return *this ; } int bigsh = i / 31 ; if (bigsh) { if (bigsh >= v.p[0]) { v.p[1] = v.p[v.p[0]] ; v.p[0] = 1 ; } else { for (int j=1; j+bigsh<=v.p[0]; j++) v.p[j] = v.p[j+bigsh] ; v.p[0] -= bigsh ; } i -= bigsh * 31 ; } int carry = v.p[v.p[0]] ; if (i) { for (int j=v.p[0]-1; j>0; j--) { int c = ((v.p[j] >> i) | (carry << (31-i))) & 0x7fffffff ; carry = v.p[j] ; v.p[j] = c ; } } shrink(v.p[0]) ; return *this ; } bigint& bigint::operator<<=(int i) { if (v.i & 1) { if (v.i == 1) return *this ; if (i < 30 && (v.i >> 31) == (v.i >> (31 - i))) { v.i = ((v.i & ~1) << i) | 1 ; return *this ; } vectorize(v.i >> 1) ; } int bigsh = i / 31 ; int nsize = v.p[0] + bigsh + 1 ; // how big we need it to be, worst case grow(v.p[0], nsize) ; if (bigsh) { int j ; for (j=v.p[0]-1; j>bigsh; j--) v.p[j] = v.p[j-bigsh] ; for (j=bigsh; j>0; j--) v.p[j] = 0 ; i -= bigsh * 31 ; } int carry = 0 ; if (i) { for (int j=1; j> (31-i))) & 0x7fffffff ; carry = v.p[j] ; v.p[j] = c ; } } shrink(v.p[0]) ; return *this ; } void bigint::mulpow2(int p) { if (p > 0) *this <<= p ; else if (p < 0) *this >>= -p ; } int bigint::even() const { if (v.i & 1) return 1-((v.i >> 1) & 1) ; else return 1-(v.p[1] & 1) ; } int bigint::odd() const { if (v.i & 1) return ((v.i >> 1) & 1) ; else return (v.p[1] & 1) ; } int bigint::low31() const { if (v.i & 1) return ((v.i >> 1) & 0x7fffffff) ; else return v.p[1] ; } int bigint::operator==(const bigint &b) const { if ((b.v.i - v.i) & 1) return 0 ; if (v.i & 1) return v.i == b.v.i ; if (b.v.p[0] != v.p[0]) return 0 ; return memcmp(v.p, b.v.p, sizeof(int) * (v.p[0] + 1)) == 0 ; } int bigint::operator!=(const bigint &b) const { return !(*this == b) ; } int bigint::operator<(const bigint &b) const { if (b.v.i & 1) if (v.i & 1) return v.i < b.v.i ; else return v.p[v.p[0]] < 0 ; else if (v.i & 1) return b.v.p[b.v.p[0]] >= 0 ; int d = v.p[v.p[0]] - b.v.p[b.v.p[0]] ; if (d < 0) return 1 ; if (d > 0) return 0 ; if (v.p[0] > b.v.p[0]) return v.p[v.p[0]] < 0 ; else if (v.p[0] < b.v.p[0]) return v.p[v.p[0]] >= 0 ; for (int i=v.p[0]; i>0; i--) if (v.p[i] < b.v.p[i]) return 1 ; else if (v.p[i] > b.v.p[i]) return 0 ; return 0 ; } int bigint::operator<=(const bigint &b) const { if (b.v.i & 1) if (v.i & 1) return v.i <= b.v.i ; else return v.p[v.p[0]] < 0 ; else if (v.i & 1) return b.v.p[b.v.p[0]] >= 0 ; int d = v.p[v.p[0]] - b.v.p[b.v.p[0]] ; if (d < 0) return 1 ; if (d > 0) return 0 ; if (v.p[0] > b.v.p[0]) return v.p[v.p[0]] < 0 ; else if (v.p[0] < b.v.p[0]) return v.p[v.p[0]] >= 0 ; for (int i=v.p[0]; i>0; i--) if (v.p[i] < b.v.p[i]) return 1 ; else if (v.p[i] > b.v.p[i]) return 0 ; return 1 ; } int bigint::operator>(const bigint &b) const { return !(*this <= b) ; } int bigint::operator>=(const bigint &b) const { return !(*this < b) ; } static double mybpow(int n) { double r = 1 ; double s = 65536.0 * 32768.0 ; while (n) { if (n & 1) r *= s ; s *= s ; n >>= 1 ; } return r ; } /** * Turn this bigint into a double. */ double bigint::todouble() const { if (v.i & 1) return (double)(v.i >> 1) ; double r = 0 ; double m = 1 ; int lim = 1 ; if (v.p[0] > 4) { lim = v.p[0] - 3 ; m = mybpow(lim-1) ; } for (int i=lim; i<=v.p[0]; i++) { r = r + m * v.p[i] ; m *= 65536 * 32768.0 ; } return r ; } /** * Turn this bigint into a double in a way that preserves huge exponents. * Here are some examples: * * To represent * the quantity We return the value * 27 1.27 * -6.02e23 -23.602 * 6.02e23 23.602 * 9.99e299 299.999 * 1.0e300 300.1 * 1.0e1000 1000.1 This would normally overflow * 6.7e12345 12345.67 */ double bigint::toscinot() const { double mant, exponent; double k_1_10 = 0.1; double k_1_10000 = 0.0001; double k_base = 65536.0 * 32768.0; exponent = 0; if (v.i & 1) { /* small integer */ mant = (double)(v.i >> 1) ; } else { /* big integer: a string of 31-bit chunks */ mant = 0 ; double m = 1 ; for (int i=1; i<=v.p[0]; i++) { mant = mant + m * v.p[i] ; m *= k_base ; while (m >= 100000.0) { m *= k_1_10000; mant *= k_1_10000; exponent += 4.0; } } } /* Add the last few powers of 10 back into the mantissa */ while(((mant < 0.5) && (mant > -0.5)) && (exponent > 0.0)) { mant *= 10.0; exponent -= 1.0; } /* Mantissa might be greater than 1 at this point */ while((mant >= 1.0) || (mant <= -1.0)) { mant *= k_1_10; exponent += 1.0; } if (mant >= 0) { // Normal case: 6.02e23 -> 23.602 return(exponent + mant); } // Negative case: -6.02e23 -> -23.602 // In this example mant will be -0.602 and exponent will be 23.0 return(mant - exponent); } /** * Return an int. */ int bigint::toint() const { if (v.i & 1) return (v.i >> 1) ; return (v.p[v.p[0]] << 31) | v.p[1] ; } /** * How many bits required to represent this, approximately? * Should overestimate but not by too much. */ int bigint::bitsreq() const { if (v.i & 1) return 31 ; return v.p[0] * 31 ; } /** * Find the lowest bit set. */ int bigint::lowbitset() const { int r = 0 ; if (v.i & 1) { if (v.i == 1) return -1 ; for (int i=1; i<32; i++) if ((v.i >> i) & 1) return i-1 ; } int o = 1 ; while (v.p[o] == 0) { o++ ; r += 31 ; } for (int i=0; i<32; i++) if ((v.p[o] >> i) & 1) return i + r ; return -1 ; } /** * Fill a character array with the bits. Top one is always * the sign bit. */ void bigint::tochararr(char *fillme, int n) const { int at = 0 ; while (n > 0) { int w = 0 ; if (v.i & 1) { if (at == 0) w = v.i >> 1 ; else w = v.i >> 31 ; } else { if (at < v.p[0]) w = v.p[at+1] ; else w = v.p[v.p[0]] ; } int lim = 31 ; if (n < 31) lim = n ; for (int i=0; i>= 1 ; } n -= 31 ; at++ ; } } /** * Manifests. */ const bigint bigint::zero(0) ; const bigint bigint::one(1) ; const bigint bigint::two(2) ; const bigint bigint::three(3) ; const bigint bigint::maxint(INT_MAX) ; const bigint bigint::minint(INT_MIN) ; golly-2.7-src/gollybase/writepattern.cpp0000644000175000017500000002666312536111364015452 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "writepattern.h" #include "lifealgo.h" #include "util.h" // for *progress calls #include #include #include #include #ifdef ZLIB #include #include #endif #ifdef __APPLE__ #define BUFFSIZE 4096 // 4K is best for Mac OS X #else #define BUFFSIZE 8192 // 8K is best for Windows and other platforms??? #endif // globals for writing RLE files static char outbuff[BUFFSIZE]; static size_t outpos; // current write position in outbuff static bool badwrite; // fwrite failed? // using buffered putchar instead of fputc is about 20% faster on Mac OS X static void putchar(char ch, std::ostream &os) { if (badwrite) return; if (outpos == BUFFSIZE) { if (!os.write(outbuff, outpos)) badwrite = true; outpos = 0; } outbuff[outpos] = ch; outpos++; } const int WRLE_NONE = -3 ; const int WRLE_EOP = -2 ; const int WRLE_NEWLINE = -1 ; // output of RLE pattern data is channelled thru here to make it easier to // ensure all lines have <= 70 characters void AddRun(std::ostream &f, int state, // in: state of cell to write int multistate, // true if #cell states > 2 unsigned int &run, // in and out unsigned int &linelen) // ditto { unsigned int i, numlen; char numstr[32]; if ( run > 1 ) { sprintf(numstr, "%u", run); numlen = (int)strlen(numstr); } else { numlen = 0; // no run count shown if 1 } if ( linelen + numlen + 1 + multistate > 70 ) { putchar('\n', f); linelen = 0; } i = 0; while (i < numlen) { putchar(numstr[i], f); i++; } if (multistate) { if (state <= 0) putchar(".$!"[-state], f) ; else { if (state > 24) { int hi = (state - 25) / 24 ; putchar((char)(hi + 'p'), f) ; linelen++ ; state -= (hi + 1) * 24 ; } putchar((char)('A' + state - 1), f) ; } } else putchar("!$bo"[state+2], f) ; linelen += numlen + 1; run = 0; // reset run count } // write current pattern to file using extended RLE format const char *writerle(std::ostream &os, char *comments, lifealgo &imp, int top, int left, int bottom, int right, bool xrle) { badwrite = false; if (xrle) { // write out #CXRLE line; note that the XRLE indicator is prefixed // with #C so apps like Life32 and MCell will ignore the line os << "#CXRLE Pos=" << left << ',' << top; if (imp.getGeneration() > bigint::zero) os << " Gen=" << imp.getGeneration().tostring('\0'); os << '\n'; } char *endcomms = NULL; if (comments && comments[0]) { // write given comment line(s) -- can't just do fputs(comments,f) // because comments might include arbitrary text after the "!" char *p = comments; while (*p == '#') { while (*p != '\n') p++; p++; } if (p != comments) { char savech = *p; *p = '\0'; os << comments; *p = savech; } // any comment lines not starting with # will be written after "!" if (*p != '\0') endcomms = p; } if ( imp.isEmpty() || top > bottom || left > right ) { // empty pattern os << "x = 0, y = 0, rule = " << imp.getrule() << "\n!\n"; } else { // do header line unsigned int wd = right - left + 1; unsigned int ht = bottom - top + 1; sprintf(outbuff, "x = %u, y = %u, rule = %s\n", wd, ht, imp.getrule()); outpos = strlen(outbuff); // do RLE data unsigned int linelen = 0; unsigned int brun = 0; unsigned int orun = 0; unsigned int dollrun = 0; int laststate = WRLE_NONE ; int multistate = imp.NumCellStates() > 2 ; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = imp.getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; int v = 0 ; for ( cy=top; cy<=bottom; cy++ ) { // set lastchar to anything except 'o' or 'b' laststate = WRLE_NONE ; currcount++; for ( cx=left; cx<=right; cx++ ) { int skip = imp.nextcell(cx, cy, v); if (skip + cx > right) skip = -1; // pretend we found no more live cells if (skip > 0) { // have exactly "skip" dead cells here if (laststate == 0) { brun += skip; } else { if (orun > 0) { // output current run of live cells AddRun(os, laststate, multistate, orun, linelen); } laststate = 0 ; brun = skip; } } if (skip >= 0) { // found next live cell in this row cx += skip; if (laststate == v) { orun++; } else { if (dollrun > 0) // output current run of $ chars AddRun(os, WRLE_NEWLINE, multistate, dollrun, linelen); if (brun > 0) // output current run of dead cells AddRun(os, 0, multistate, brun, linelen); if (orun > 0) AddRun(os, laststate, multistate, orun, linelen) ; laststate = v ; orun = 1; } currcount++; } else { cx = right + 1; // done this row } if (currcount > 1024) { char msg[128]; accumcount += currcount; currcount = 0; sprintf(msg, "File size: %.2f MB", os.tellp() / 1048576.0); if (lifeabortprogress(accumcount / maxcount, msg)) break; } } // end of current row if (isaborted()) break; if (laststate == 0) // forget dead cells at end of row brun = 0; else if (laststate >= 0) // output current run of live cells AddRun(os, laststate, multistate, orun, linelen); dollrun++; } // terminate RLE data dollrun = 1; AddRun(os, WRLE_EOP, multistate, dollrun, linelen); putchar('\n', os); // flush outbuff if (outpos > 0 && !badwrite && !os.write(outbuff, outpos)) badwrite = true; } if (endcomms) os << endcomms; if (badwrite) return "Failed to write output buffer!"; else return 0; } const char *writemacrocell(std::ostream &os, char *comments, lifealgo &imp) { if (imp.hyperCapable()) return imp.writeNativeFormat(os, comments); else return "Not yet implemented."; } #ifdef ZLIB class gzbuf : public std::streambuf { public: gzbuf() : file(NULL) { } gzbuf(const char *path) : file(NULL) { open(path); } ~gzbuf() { close(); } gzbuf *open(const char *path) { if (file) return NULL; file = gzopen(path, "wb"); return file ? this : NULL; } gzbuf *close() { if (!file) return NULL; int res = gzclose(file); file = NULL; return res == Z_OK ? this : NULL; } bool is_open() const { return file!=NULL; } int overflow(int c=EOF) { if (c == EOF) return c ; return gzputc(file, c) ; } std::streamsize xsputn(const char_type *s, std::streamsize n) { return gzwrite(file, s, (unsigned int)n); } int sync() { return gzflush(file, Z_SYNC_FLUSH) == Z_OK ? 0 : -1; } pos_type seekoff(off_type off, std::ios_base::seekdir way, std::ios_base::openmode which) { if (file && off == 0 && way == std::ios_base::cur && which == std::ios_base::out) { #if ZLIB_VERNUM >= 0x1240 // gzoffset is only available in zlib 1.2.4 or later return pos_type(gzoffset(file)); #else // return an approximation of file size (only used in progress dialog) z_off_t offset = gztell(file); if (offset > 0) offset /= 4; return pos_type(offset); #endif } return pos_type(off_type(-1)); } private: gzFile file; }; #endif const char *writepattern(const char *filename, lifealgo &imp, pattern_format format, output_compression compression, int top, int left, int bottom, int right) { // extract any comments if file exists so we can copy them to new file char *commptr = NULL; FILE *f = fopen(filename, "r"); if (f) { fclose(f); const char *err = readcomments(filename, &commptr); if (err) { if (commptr) free(commptr); return err; } } // skip past any old #CXRLE lines at start of existing XRLE file char *comments = commptr; if (comments) { while (strncmp(comments, "#CXRLE", 6) == 0) { while (*comments != '\n') comments++; comments++; } } // open output stream std::streambuf *streambuf = NULL; std::filebuf filebuf; #ifdef ZLIB gzbuf gzbuf; #endif switch (compression) { default: /* no output compression */ streambuf = filebuf.open(filename, std::ios_base::out); break; case gzip_compression: #ifdef ZLIB streambuf = gzbuf.open(filename); break; #else if (commptr) free(commptr); return "GZIP compression not supported"; #endif } if (!streambuf) { if (commptr) free(commptr); return "Can't create pattern file!"; } std::ostream os(streambuf); lifebeginprogress("Writing pattern file"); const char *errmsg = NULL; switch (format) { case RLE_format: errmsg = writerle(os, comments, imp, top, left, bottom, right, false); break; case XRLE_format: errmsg = writerle(os, comments, imp, top, left, bottom, right, true); break; case MC_format: // macrocell format ignores given edges errmsg = writemacrocell(os, comments, imp); break; default: errmsg = "Unsupported pattern format!"; } if (errmsg == NULL && !os.flush()) errmsg = "Error occurred writing file; maybe disk is full?"; lifeendprogress(); if (commptr) free(commptr); if (isaborted()) return "File contains truncated pattern."; else return errmsg; } golly-2.7-src/Scripts/0000755000175000017500000000000012536111545011730 500000000000000golly-2.7-src/Scripts/Perl/0000755000175000017500000000000012536111546012633 500000000000000golly-2.7-src/Scripts/Perl/tile.pl0000644000175000017500000001311312536111364014042 00000000000000# Tile current selection with pattern inside selection. # Author: Andrew Trevorrow (andrew@trevorrow.com), June 2007. # Updated to handle multi-state patterns, Aug 2008. use strict; my @selrect = g_getselrect(); g_exit("There is no selection.") if @selrect == 0; my $selpatt = g_getcells(@selrect); g_exit("No pattern in selection.") if @{$selpatt} == 0; # determine if selpatt is one-state or multi-state my $inc = 2; if (@{$selpatt} & 1 == 1) { $inc = 3 } # ------------------------------------------------------------------------------ # return a rect which is the minimal bounding box of given pattern sub getminbox { my $cells = shift; my $len = @{$cells}; return () if $len < 2; my $minx = $cells->[0]; my $miny = $cells->[1]; my $maxx = $minx; my $maxy = $miny; # ignore padding int if present $len -= 1 if ($inc == 3) and ($len % 3 == 1); for (my $x = 0; $x < $len; $x += $inc) { if ($cells->[$x] < $minx) { $minx = $cells->[$x] } if ($cells->[$x] > $maxx) { $maxx = $cells->[$x] } } for (my $y = 1; $y < $len; $y += $inc) { if ($cells->[$y] < $miny) { $miny = $cells->[$y] } if ($cells->[$y] > $maxy) { $maxy = $cells->[$y] } } return ($minx, $miny, $maxx - $minx + 1, $maxy - $miny + 1); } # ------------------------------------------------------------------------------ sub clip_left { my ($cells, $left) = @_; my $len = @{$cells}; my $x = 0; if ($inc == 3) { # ignore padding int if present $len -= 1 if $len % 3 == 1; while ($x < $len) { if ($cells->[$x] >= $left) { g_setcell($cells->[$x], $cells->[$x+1], $cells->[$x+2]); } $x += 3; } } else { while ($x < $len) { if ($cells->[$x] >= $left) { g_setcell($cells->[$x], $cells->[$x+1], 1); } $x += 2; } } } # ------------------------------------------------------------------------------ sub clip_right { my ($cells, $right) = @_; my $len = @{$cells}; my $x = 0; if ($inc == 3) { # ignore padding int if present $len -= 1 if $len % 3 == 1; while ($x < $len) { if ($cells->[$x] <= $right) { g_setcell($cells->[$x], $cells->[$x+1], $cells->[$x+2]); } $x += 3; } } else { while ($x < $len) { if ($cells->[$x] <= $right) { g_setcell($cells->[$x], $cells->[$x+1], 1); } $x += 2; } } } # ------------------------------------------------------------------------------ sub clip_top { my ($cells, $top) = @_; my $len = @{$cells}; my $y = 1; if ($inc == 3) { # ignore padding int if present $len -= 1 if $len % 3 == 1; while ($y < $len) { if ($cells->[$y] >= $top) { g_setcell($cells->[$y-1], $cells->[$y], $cells->[$y+1]); } $y += 3; } } else { while ($y < $len) { if ($cells->[$y] >= $top) { g_setcell($cells->[$y-1], $cells->[$y], 1); } $y += 2; } } } # ------------------------------------------------------------------------------ sub clip_bottom { my ($cells, $bottom) = @_; my $len = @{$cells}; my $y = 1; if ($inc == 3) { # ignore padding int if present $len -= 1 if $len % 3 == 1; while ($y < $len) { if ($cells->[$y] <= $bottom) { g_setcell($cells->[$y-1], $cells->[$y], $cells->[$y+1]); } $y += 3; } } else { while ($y < $len) { if ($cells->[$y] <= $bottom) { g_setcell($cells->[$y-1], $cells->[$y], 1); } $y += 2; } } } # ------------------------------------------------------------------------------ # set selection edges my $selleft = $selrect[0]; my $seltop = $selrect[1]; my $selright = $selleft + $selrect[2] - 1; my $selbottom = $seltop + $selrect[3] - 1; # find selpatt's minimal bounding box my @bbox = getminbox($selpatt); my $i; # first tile selpatt horizontally, clipping where necessary my $left = $bbox[0]; my $right = $left + $bbox[2] - 1; $i = 0; while ($left > $selleft) { $left -= $bbox[2]; $i += 1; if ($left >= $selleft) { g_putcells($selpatt, -$bbox[2] * $i, 0); } else { my $tempcells = g_transform($selpatt, -$bbox[2] * $i, 0); clip_left($tempcells, $selleft); } } $i = 0; while ($right < $selright) { $right += $bbox[2]; $i += 1; if ($right <= $selright) { g_putcells($selpatt, $bbox[2] * $i, 0); } else { my $tempcells = g_transform($selpatt, $bbox[2] * $i, 0); clip_right($tempcells, $selright); } } # get new selection pattern and tile vertically, clipping where necessary $selpatt = g_getcells(@selrect); @bbox = getminbox($selpatt); my $top = $bbox[1]; my $bottom = $top + $bbox[3] - 1; $i = 0; while ($top > $seltop) { $top -= $bbox[3]; $i += 1; if ($top >= $seltop) { g_putcells($selpatt, 0, -$bbox[3] * $i); } else { my $tempcells = g_transform($selpatt, 0, -$bbox[3] * $i); clip_top($tempcells, $seltop); } } $i = 0; while ($bottom < $selbottom) { $bottom += $bbox[3]; $i += 1; if ($bottom <= $selbottom) { g_putcells($selpatt, 0, $bbox[3] * $i); } else { my $tempcells = g_transform($selpatt, 0, $bbox[3] * $i); clip_bottom($tempcells, $selbottom); } } g_fitsel() if !g_visrect(@selrect); golly-2.7-src/Scripts/Perl/giffer.pl0000644000175000017500000001047212536111364014354 00000000000000# Runs the current selection for a given number of steps and # creates a black and white animated GIF file. # Based on code by Tony Smith. use strict; g_exit("There is no pattern.") if g_empty(); my @rect = g_getselrect(); g_exit("There is no selection.") if @rect == 0; my $x = $rect[0]; my $y = $rect[1]; my $width = $rect[2]; my $height = $rect[3]; my $s = g_getstring("Enter the number of frames, the pause time between\n". "each frame (in centisecs) and the output file:", "100 1 out.gif", "Create animated GIF"); my ($frames, $pause, $filename) = split(' ', $s, 3); $frames = 100 if $frames eq ""; $pause = 1 if $pause eq ""; $filename = "out.gif" if $filename eq ""; g_exit("Number of frames is not an integer: $frames") if $frames !~ /^\d+$/; g_exit("Pause time is not an integer: $pause") if $pause !~ /^\d+$/; # ------------------------------------------------------------------------------ { my $header = "GIF89a"; my $global = pack('v2B8c2', $width, $height, '10000000', 0, 0); my $colortable = pack('H*', 'FFFFFF000000'); my $applic = chr(11) . 'NETSCAPE2.0' . pack('c2vc', 3, 1, 0, 0); my $descriptor = pack('v4B8', 0, 0, $width, $height, '00000000'); open GIF, '>', $filename; print GIF $header, $global, $colortable; print GIF '!', chr(0xFF), $applic; for (my $f = 0; $f < $frames; $f++) { print GIF '!', chr(0xF9), pack('cB8vc2', 4, '00000000', $pause, 0, 0); # get data for this frame print GIF ',', $descriptor, chr(2), &compress( &getdata() ); my $finc = $f + 1; g_show "frame: $finc/$frames"; if ($finc < $frames) { g_step(); g_update(); } } print GIF ';'; close(GIF); g_show "GIF animation saved in $filename"; } # ------------------------------------------------------------------------------ sub getdata { my @lines = (); # each array element is a line of 0 and 1 characters for (my $row = $y; $row < $y + $height; $row++) { my $line = ""; for (my $col = $x; $col < $x + $width; $col++) { if (g_getcell($col, $row)) { $line .= "1"; } else { $line .= "0"; } } push(@lines, $line); } return \@lines; } # ------------------------------------------------------------------------------ sub compress { # black and white special my @lines = @{$_[0]}; # array reference is parameter my %table = ('0' => 0, '1' => 1); my $curr = my $cc = 4; my $used = my $eoi = 5; my $bits = my $size = 3; my $mask = 7; my $output = my $code = ''; foreach my $input (@lines) { while (length($input)) { my $next = substr($input, 0, 1, ''); if (exists $table{"$code$next"}) {$code .= $next} else { $used++; $table{"$code$next"} = $used; $curr += $table{$code} << $bits; $bits += $size; while ($bits >= 8) { $output .= chr($curr & 255); $curr = $curr >> 8; $bits -= 8; } if ($used > $mask) { if ($size < 12) { $size ++; $mask = $mask * 2 + 1; } else { $curr += $cc << $bits; # output cc in current width $bits += $size; while ($bits >= 8) { $output .= chr($curr & 255); $curr = $curr >> 8; $bits -= 8; } %table = ('0' => 0, '1' => 1); # reset table $used = 5; $size = 3; $mask = 7; } } $code = $next; } } } $curr += $table{$code} << $bits; $bits += $size; while ($bits >= 8) { $output .= chr($curr & 255); $curr = $curr >> 8; $bits -= 8; } $output .= chr($curr); my $subbed = ''; while (length($output) > 255) {$subbed .= chr(255) . substr($output, 0, 255, '')} return $subbed . chr(length($output)) . $output . chr(0); } golly-2.7-src/Scripts/Perl/density.pl0000644000175000017500000000056312536111364014571 00000000000000# Calculates the density of live cells in the current pattern. # Author: Andrew Trevorrow (andrew@trevorrow.com), June 2007. use strict; my @rect = g_getrect(); g_exit("The pattern is empty.") if @rect == 0; my $d = g_getpop() / ($rect[2] * $rect[3]); if ($d < 0.000001) { g_show(sprintf("Density = %.1e",$d)); } else { g_show(sprintf("Density = %.6f",$d)); } golly-2.7-src/Scripts/Perl/goto.pl0000644000175000017500000000711212536111364014057 00000000000000# Go to a requested generation. The given generation can be an # absolute number like 1,000,000 (commas are optional) or a number # relative to the current generation like +9 or -6. If the target # generation is less than the current generation then we go back # to the starting generation (normally 0) and advance to the target. # Authors: Andrew Trevorrow and Dave Greene, June 2007. use strict; use Time::HiRes qw ( time ); # -------------------------------------------------------------------- sub go_to { my $gen = shift; my $currgen = g_getgen(); my $newgen = $gen; if (substr($gen,0,1) eq '+') { $newgen = $currgen + $gen; } elsif (substr($gen,0,1) eq '-') { my $n = -$gen; if ($currgen > $n) { $newgen = $currgen - $n; } else { $newgen = 0; } } if ($newgen < $currgen) { # try to go back to starting gen (not necessarily 0) and # then forwards to newgen; note that reset() also restores # algorithm and/or rule, so too bad if user changed those # after the starting info was saved; # first save current location and scale my ($midx, $midy) = g_getpos(); my $mag = g_getmag(); g_reset(); # restore location and scale g_setpos($midx, $midy); g_setmag($mag); # current gen might be > 0 if user loaded a pattern file # that set the gen count $currgen = g_getgen(); if ($newgen < $currgen) { g_error("Can't go back any further; pattern was saved ". "at generation $currgen."); return; } } return if $newgen == $currgen; g_show("Hit escape to abort..."); my $oldsecs = time; # do 1 step first, to ensure a reasonable value is saved for the step size: g_run(1); ++$currgen; my $base = g_getbase(); my $todo = $newgen - $currgen; my $exp = 0; while ($todo > 0) { my $num_steps = $todo % $base; g_setstep($exp++); $todo = ($todo - $num_steps)/$base; while ($num_steps-- > 0) { if (g_empty()) { g_show("Pattern is empty."); return; } g_step(); my $newsecs = time; if ($newsecs - $oldsecs >= 1.0) { # do an update every sec $oldsecs = $newsecs; g_update(); } } } g_show(""); } # -------------------------------------------------------------------- sub savegen { my ($filename, $gen) = @_; if (not open(OUTFILE, ">".$filename)) { g_warn("Can't save gen in $filename:\n$!"); } else { print OUTFILE $gen; close OUTFILE; } } # -------------------------------------------------------------------- # use same file name as in goto.py my $GotoINIFileName = g_getdir("data")."goto.ini"; my $previousgen = ""; if (open(INFILE, $GotoINIFileName)) { $previousgen = ; close INFILE; } my $gen = g_getstring("Enter the desired generation number,\n". "or -n/+n to go back/forwards by n:", $previousgen, "Go to generation"); if ($gen eq "") { g_exit(); } elsif ($gen eq '+' or $gen eq '-') { # clear the default savegen($GotoINIFileName, ""); } elsif ($gen !~ /^[+-]?\d[\d,]*$/) { g_exit("Sorry, but \"$gen\" is not a valid integer."); } else { # best to save given gen now in case user aborts script savegen($GotoINIFileName, $gen); $gen =~ s/,//g; my $oldstep = g_getstep(); go_to($gen); g_setstep($oldstep); } golly-2.7-src/Scripts/Perl/tile-with-clip.pl0000644000175000017500000000427312536111364015747 00000000000000# Tile current selection with clipboard pattern. # Author: Andrew Trevorrow (andrew@trevorrow.com), June 2007. # Updated to handle multi-state patterns, Aug 2008. use strict; # assume one-state cell array (may change below) my $multistate = 0; # ------------------------------------------------------------------------------ sub clip_rb { # set given cells except those outside given right and bottom edges my ($cells, $right, $bottom) = @_; my $len = @{$cells}; my $x = 0; my $y = 1; if ($multistate) { # ignore padding int if present $len -= 1 if $len % 3 == 1; while ($x < $len) { if (($cells->[$x] <= $right) and ($cells->[$y] <= $bottom)) { g_setcell($cells->[$x], $cells->[$y], $cells->[$x+2]); } $x += 3; $y += 3; } } else { while ($x < $len) { if (($cells->[$x] <= $right) and ($cells->[$y] <= $bottom)) { g_setcell($cells->[$x], $cells->[$y], 1); } $x += 2; $y += 2; } } } # ------------------------------------------------------------------------------ my @selrect = g_getselrect(); g_exit("There is no selection.") if @selrect == 0; # set selection edges my $selleft = $selrect[0]; my $seltop = $selrect[1]; my $selright = $selleft + $selrect[2] - 1; my $selbottom = $seltop + $selrect[3] - 1; my $p = g_getclip(); # 1st 2 items are wd,ht my $pwidth = shift(@{$p}); my $pheight = shift(@{$p}); if (@{$p} & 1 == 1) { $multistate = 1 } g_clear(0); if (@{$p} > 0) { # tile selrect with p, clipping right & bottom edges if necessary my $y = $seltop; while ($y <= $selbottom) { my $bottom = $y + $pheight - 1; my $x = $selleft; while ($x <= $selright) { my $right = $x + $pwidth - 1; if (($right <= $selright) and ($bottom <= $selbottom)) { g_putcells($p, $x, $y); } else { my $tempcells = g_transform($p, $x, $y); clip_rb($tempcells, $selright, $selbottom); } $x += $pwidth; } $y += $pheight; } } g_fitsel() if !g_visrect(@selrect); golly-2.7-src/Scripts/Perl/oscar.pl0000644000175000017500000001557512536111364014232 00000000000000# Oscar is an OSCillation AnalyzeR for use with Golly. # Author: Andrew Trevorrow (andrew@trevorrow.com), June 2007. # Modified to use Math::BigInt, December 2008. # Modified to handle B0-and-not-S8 rules, August 2009. # This script uses Gabriel Nivasch's "keep minima" algorithm. # For each generation, calculate a hash value for the pattern. Keep all of # the record-breaking minimal hashes in a list, with the oldest first. # For example, after 5 generations the saved hash values might be: # # 8 12 16 24 25, # # If the next hash goes down to 13 then the list can be shortened: # # 8 12 13. # # If the current hash matches one of the saved hashes, it is highly likely # the pattern is oscillating. By keeping a corresponding list of generation # counts we can calculate the period. We also keep lists of population # counts and bounding boxes to reduce the chance of spurious oscillator # detection due to hash collisions. The bounding box info also allows us # to detect moving oscillators (spaceships/knightships). use strict; use Time::HiRes qw ( time ); use Math::BigInt; # use arbitrarily big integers # -------------------------------------------------------------------- # initialize lists my @hashlist = (); # for pattern hash values my @genlist = (); # corresponding generation counts my @poplist = (); # corresponding population counts my @boxlist = (); # corresponding bounding boxes # -------------------------------------------------------------------- sub show_spaceship_speed { # we found a moving oscillator my ($period, $deltax, $deltay) = @_; if ($period == 1) { g_show("Spaceship detected (speed = c)"); } elsif ($deltax == $deltay or $deltax == 0 or $deltay == 0) { my $speed = ""; if ($deltax == 0 or $deltay == 0) { # orthogonal spaceship if ($deltax > 1 or $deltay > 1) { $speed .= ($deltax + $deltay); } } else { # diagonal spaceship (deltax == deltay) if ($deltax > 1) { $speed .= $deltax; } } g_show("Spaceship detected (speed = $speed"."c/$period)"); } else { # deltax != deltay and both > 0 my $speed = "$deltay,$deltax"; g_show("Knightship detected (speed = $speed"."c/$period)"); } } # -------------------------------------------------------------------- sub oscillating { # return 1 if the pattern is empty, stable or oscillating # first get current pattern's bounding box my @pbox = g_getrect(); if (@pbox == 0) { g_show("The pattern is empty."); return 1; } # get current pattern and create "normalized" version -- ie. shift its # top left corner to 0,0 -- so we can detect spaceships and knightships ## my $shifted = g_transform(g_getcells(@pbox), -$pbox[0], -$pbox[1]); # create hash value of shifted pattern ## my $h = 0; ## foreach (@{$shifted}) { ## $h = ($h % 10000000) * 33 + $_; ## } # use g_hash command (5 times faster than above code) my $h = g_hash(@pbox); # check if outer-totalistic rule has B0 but not S8 my $rule = g_getrule(); my ($prefix, $suffix) = split(':', $rule, 2); my $hasB0notS8 = ($prefix =~ m/^B0/ and $prefix =~ m|/| and $prefix !~ m/8$/); # determine where to insert h into hashlist my $pos = 0; while ($pos < @hashlist) { if ($h > $hashlist[$pos]) { $pos += 1; } elsif ($h < $hashlist[$pos]) { # shorten lists and append info below splice(@hashlist, $pos); splice(@genlist, $pos); splice(@poplist, $pos); splice(@boxlist, $pos); last; } else { # h == hashlist[pos] so pattern is probably oscillating, but just in # case this is a hash collision we also compare pop count and box size my @rect = @{$boxlist[$pos]}; my $currpop = Math::BigInt->new(g_getpop()); if ( $currpop->bcmp($poplist[$pos]) == 0 and $pbox[2] == $rect[2] and $pbox[3] == $rect[3] ) { my $currgen = Math::BigInt->new(g_getgen()); my $bigp = $currgen->bsub($genlist[$pos]); my $period = $bigp->numify(); if ($hasB0notS8 and ($period % 2) and $pbox[0] == $rect[0] and $pbox[1] == $rect[1] and $pbox[2] == $rect[2] and $pbox[3] == $rect[3]) { # ignore this hash value because B0-and-not-S8 rules are # emulated by using different rules for odd and even gens, # so it's possible to have identical patterns at gen G and # gen G+p if p is odd return 0; } if ($period == 1) { if ($pbox[0] == $rect[0] and $pbox[1] == $rect[1] and $pbox[2] == $rect[2] and $pbox[3] == $rect[3]) { g_show("The pattern is stable."); } else { show_spaceship_speed(1, 0, 0); } } elsif ($pbox[0] == $rect[0] and $pbox[1] == $rect[1] and $pbox[2] == $rect[2] and $pbox[3] == $rect[3]) { g_show("Oscillator detected (period = $period)"); } else { my $deltax = abs($rect[0] - $pbox[0]); my $deltay = abs($rect[1] - $pbox[1]); show_spaceship_speed($period, $deltax, $deltay); } return 1; } else { # look at next matching hash value or insert if no more $pos += 1; } } } # store hash/gen/pop/box info at same position in various lists splice(@hashlist, $pos, 0, $h); splice(@genlist, $pos, 0, Math::BigInt->new(g_getgen())); splice(@poplist, $pos, 0, Math::BigInt->new(g_getpop())); splice(@boxlist, $pos, 0, \@pbox); return 0; } # -------------------------------------------------------------------- sub fit_if_not_visible { # fit pattern in viewport if not empty and not completely visible my @r = g_getrect(); if (@r > 0 and !g_visrect(@r)) { g_fit() } } # -------------------------------------------------------------------- g_show("Checking for oscillation... (hit escape to abort)"); my $oldsecs = time; while ( not oscillating() ) { g_run(1); my $newsecs = time; if ($newsecs - $oldsecs >= 1.0) { # show pattern every second $oldsecs = $newsecs; fit_if_not_visible(); g_update(); } } fit_if_not_visible(); golly-2.7-src/Scripts/Perl/make-torus.pl0000644000175000017500000000133612536111364015200 00000000000000# Use the current selection to create a toroidal universe. # Author: Andrew Trevorrow (andrew@trevorrow.com), Oct 2010. use strict; my @selrect = g_getselrect(); g_exit("There is no selection.") if @selrect == 0; my $x = $selrect[0]; my $y = $selrect[1]; my $wd = $selrect[2]; my $ht = $selrect[3]; my $selcells = g_getcells(@selrect); if (!g_empty()) { g_clear(0); g_clear(1); } # get current rule, remove any existing suffix, then add new suffix my ($rule, $suffix) = split(":",g_getrule(),2); g_setrule("$rule:T$wd,$ht"); my $newx = -int($wd/2); my $newy = -int($ht/2); $selrect[0] = $newx; $selrect[1] = $newy; g_select(@selrect); g_putcells($selcells, $newx - $x, $newy - $y) if length($selcells) > 0; g_fitsel(); golly-2.7-src/Scripts/Perl/invert.pl0000644000175000017500000000142612536111364014420 00000000000000# Invert all cell states in the current selection. # Author: Andrew Trevorrow (andrew@trevorrow.com), May 2007. # Updated to use g_numstates command, Jun 2008. use strict; use Time::HiRes qw (time); my @rect = g_getselrect(); g_exit("There is no selection.") if @rect == 0; my $x = $rect[0]; my $y = $rect[1]; my $wd = $rect[2]; my $ht = $rect[3]; my $oldsecs = time; my $maxstate = g_numstates() - 1; for (my $row = $y; $row < $y + $ht; $row++) { # if large selection then give some indication of progress my $newsecs = time; if ($newsecs - $oldsecs >= 1.0) { $oldsecs = $newsecs; g_update(); } for (my $col = $x; $col < $x + $wd; $col++) { g_setcell($col, $row, $maxstate - g_getcell($col, $row)); } } g_fitsel() if !g_visrect(@rect); golly-2.7-src/Scripts/Perl/pop-plot.pl0000644000175000017500000002721212536111364014664 00000000000000# Run the current pattern for a given number of steps (using current # step size) and create a plot of population vs time in separate layer. # Author: Andrew Trevorrow (andrew@trevorrow.com), June 2007. use strict; use Time::HiRes qw (time); use List::Util qw (min max); # ------------------------------------------------------------------------------ # size of plot my $xlen = 500; # length of x axis my $ylen = 500; # length of y axis # ------------------------------------------------------------------------------ # create a mono-spaced ASCII font my %mfont; $mfont{' '} = g_parse(''); $mfont{'!'} = g_parse('2bo$2bo$2bo$2bo$2bo2$2bo!'); $mfont{'"'} = g_parse('bobo$bobo$bobo!'); $mfont{'#'} = g_parse('bobo$bobo$5o$bobo$5o$bobo$bobo!'); $mfont{'$'} = g_parse('b3o$obobo$obo$b3o$2bobo$obobo$b3o!'); $mfont{'%'} = g_parse('2o2bo$2o2bo$3bo$2bo$bo$o2b2o$o2b2o!'); $mfont{'&'} = g_parse('b2o$o2bo$o2bo$b2o$o2bo$o2bo$b2obo!'); $mfont{'\''} = g_parse('2bo$2bo$2bo!'); $mfont{'('} = g_parse('3bo$2bo$2bo$2bo$2bo$2bo$3bo!'); $mfont{')'} = g_parse('bo$2bo$2bo$2bo$2bo$2bo$bo!'); $mfont{'*'} = g_parse('$obobo$b3o$5o$b3o$obobo!'); $mfont{'+'} = g_parse('$2bo$2bo$5o$2bo$2bo!'); $mfont{','} = g_parse('6$2bo$2bo$bo!'); $mfont{'-'} = g_parse('3$5o!'); $mfont{'.'} = g_parse('6$2bo!'); $mfont{'/'} = g_parse('3bo$3bo$2bo$2bo$2bo$bo$bo!'); $mfont{'0'} = g_parse('b3o$o3bo$o2b2o$obobo$2o2bo$o3bo$b3o!'); $mfont{'1'} = g_parse('2bo$b2o$2bo$2bo$2bo$2bo$b3o!'); $mfont{'2'} = g_parse('b3o$o3bo$4bo$3bo$2bo$bo$5o!'); $mfont{'3'} = g_parse('b3o$o3bo$4bo$2b2o$4bo$o3bo$b3o!'); $mfont{'4'} = g_parse('3bo$2b2o$bobo$o2bo$5o$3bo$3bo!'); $mfont{'5'} = g_parse('5o$o$o$b3o$4bo$o3bo$b3o!'); $mfont{'6'} = g_parse('b3o$o$o$4o$o3bo$o3bo$b3o!'); $mfont{'7'} = g_parse('5o$4bo$3bo$2bo$bo$o$o!'); $mfont{'8'} = g_parse('b3o$o3bo$o3bo$b3o$o3bo$o3bo$b3o!'); $mfont{'9'} = g_parse('b3o$o3bo$o3bo$b4o$4bo$4bo$b3o!'); $mfont{':'} = g_parse('2$2bo4$2bo!'); $mfont{';'} = g_parse('2$2bo4$2bo$2bo$bo!'); $mfont{'<'} = g_parse('$3bo$2bo$bo$2bo$3bo!'); $mfont{'='} = g_parse('2$5o2$5o!'); $mfont{'>'} = g_parse('$bo$2bo$3bo$2bo$bo!'); $mfont{'?'} = g_parse('b3o$o3bo$4bo$2b2o$2bo2$2bo!'); $mfont{'@'} = g_parse('b3o$o3bo$ob3o$obobo$ob2o$o$b3o!'); $mfont{'A'} = g_parse('b3o$o3bo$o3bo$5o$o3bo$o3bo$o3bo!'); $mfont{'B'} = g_parse('4o$o3bo$o3bo$4o$o3bo$o3bo$4o!'); $mfont{'C'} = g_parse('b3o$o3bo$o$o$o$o3bo$b3o!'); $mfont{'D'} = g_parse('4o$o3bo$o3bo$o3bo$o3bo$o3bo$4o!'); $mfont{'E'} = g_parse('5o$o$o$3o$o$o$5o!'); $mfont{'F'} = g_parse('5o$o$o$3o$o$o$o!'); $mfont{'G'} = g_parse('b3o$o3bo$o$o2b2o$o3bo$o3bo$b3o!'); $mfont{'H'} = g_parse('o3bo$o3bo$o3bo$5o$o3bo$o3bo$o3bo!'); $mfont{'I'} = g_parse('b3o$2bo$2bo$2bo$2bo$2bo$b3o!'); $mfont{'J'} = g_parse('2b3o$3bo$3bo$3bo$3bo$o2bo$b2o!'); $mfont{'K'} = g_parse('o3bo$o2bo$obo$2o$obo$o2bo$o3bo!'); $mfont{'L'} = g_parse('o$o$o$o$o$o$5o!'); $mfont{'M'} = g_parse('o3bo$2ob2o$obobo$obobo$o3bo$o3bo$o3bo!'); $mfont{'N'} = g_parse('o3bo$2o2bo$obobo$o2b2o$o3bo$o3bo$o3bo!'); $mfont{'O'} = g_parse('b3o$o3bo$o3bo$o3bo$o3bo$o3bo$b3o!'); $mfont{'P'} = g_parse('4o$o3bo$o3bo$4o$o$o$o!'); $mfont{'Q'} = g_parse('b3o$o3bo$o3bo$o3bo$obobo$o2bo$b2obo!'); $mfont{'R'} = g_parse('4o$o3bo$o3bo$4o$o2bo$o3bo$o3bo!'); $mfont{'S'} = g_parse('b3o$o3bo$o$b3o$4bo$o3bo$b3o!'); $mfont{'T'} = g_parse('5o$2bo$2bo$2bo$2bo$2bo$2bo!'); $mfont{'U'} = g_parse('o3bo$o3bo$o3bo$o3bo$o3bo$o3bo$b3o!'); $mfont{'V'} = g_parse('o3bo$o3bo$o3bo$o3bo$o3bo$bobo$2bo!'); $mfont{'W'} = g_parse('o3bo$o3bo$o3bo$obobo$obobo$2ob2o$o3bo!'); $mfont{'X'} = g_parse('o3bo$o3bo$bobo$2bo$bobo$o3bo$o3bo!'); $mfont{'Y'} = g_parse('o3bo$o3bo$bobo$2bo$2bo$2bo$2bo!'); $mfont{'Z'} = g_parse('5o$4bo$3bo$2bo$bo$o$5o!'); $mfont{'['} = g_parse('2b2o$2bo$2bo$2bo$2bo$2bo$2b2o!'); $mfont{'\\'} = g_parse('bo$bo$2bo$2bo$2bo$3bo$3bo!'); $mfont{']'} = g_parse('b2o$2bo$2bo$2bo$2bo$2bo$b2o!'); $mfont{'^'} = g_parse('2bo$bobo$o3bo!'); $mfont{'_'} = g_parse('6$5o!'); $mfont{'`'} = g_parse('o$bo!'); $mfont{'a'} = g_parse('2$b4o$o3bo$o3bo$o3bo$b4o!'); $mfont{'b'} = g_parse('o$o$4o$o3bo$o3bo$o3bo$4o!'); $mfont{'c'} = g_parse('2$b4o$o$o$o$b4o!'); $mfont{'d'} = g_parse('4bo$4bo$b4o$o3bo$o3bo$o3bo$b4o!'); $mfont{'e'} = g_parse('2$b3o$o3bo$5o$o$b4o!'); $mfont{'f'} = g_parse('2b2o$bo2bo$bo$3o$bo$bo$bo!'); $mfont{'g'} = g_parse('2$b3o$o3bo$o3bo$o3bo$b4o$4bo$b3o!'); $mfont{'h'} = g_parse('o$o$ob2o$2o2bo$o3bo$o3bo$o3bo!'); $mfont{'i'} = g_parse('$2bo2$2bo$2bo$2bo$2b2o!'); $mfont{'j'} = g_parse('$3bo2$3bo$3bo$3bo$3bo$o2bo$b2o!'); $mfont{'k'} = g_parse('o$o$o2bo$obo$3o$o2bo$o3bo!'); $mfont{'l'} = g_parse('b2o$2bo$2bo$2bo$2bo$2bo$2b2o!'); $mfont{'m'} = g_parse('2$bobo$obobo$obobo$o3bo$o3bo!'); $mfont{'n'} = g_parse('2$4o$o3bo$o3bo$o3bo$o3bo!'); $mfont{'o'} = g_parse('2$b3o$o3bo$o3bo$o3bo$b3o!'); $mfont{'p'} = g_parse('2$4o$o3bo$o3bo$o3bo$4o$o$o!'); $mfont{'q'} = g_parse('2$b4o$o3bo$o3bo$o3bo$b4o$4bo$4bo!'); $mfont{'r'} = g_parse('2$ob2o$2o2bo$o$o$o!'); $mfont{'s'} = g_parse('2$b4o$o$b3o$4bo$4o!'); $mfont{'t'} = g_parse('$2bo$5o$2bo$2bo$2bo$3b2o!'); $mfont{'u'} = g_parse('2$o3bo$o3bo$o3bo$o3bo$b4o!'); $mfont{'v'} = g_parse('2$o3bo$o3bo$o3bo$bobo$2bo!'); $mfont{'w'} = g_parse('2$o3bo$o3bo$obobo$2ob2o$o3bo!'); $mfont{'x'} = g_parse('2$o3bo$bobo$2bo$bobo$o3bo!'); $mfont{'y'} = g_parse('2$o3bo$o3bo$o3bo$o3bo$b4o$4bo$b3o!'); $mfont{'z'} = g_parse('2$5o$3bo$2bo$bo$5o!'); $mfont{'{'} = g_parse('3bo$2bo$2bo$bo$2bo$2bo$3bo!'); $mfont{'|'} = g_parse('2bo$2bo$2bo$2bo$2bo$2bo$2bo!'); $mfont{'}'} = g_parse('bo$2bo$2bo$3bo$2bo$2bo$bo!'); $mfont{'~'} = g_parse('2$bo$obobo$3bo!'); # ------------------------------------------------------------------------------ # convert given string to a cell array using above mono-spaced font sub make_text { my $string = shift; my @p = (); my $x = 0; for my $ch (split(//,$string)) { $ch = '?' if not exists $mfont{$ch}; my $symbol = g_transform($mfont{$ch}, $x, 0); push(@p, @{$symbol}); $x += 6; } return \@p; } # ------------------------------------------------------------------------------ # draw a line of cells from x1,y1 to x2,y2 using Bresenham's algorithm sub draw_line { my ($x1, $y1, $x2, $y2) = @_; g_setcell($x1, $y1, 1); return if $x1 == $x2 and $y1 == $y2; my $dx = $x2 - $x1; my $ax = abs($dx) * 2; my $sx = 1; $sx = -1 if $dx < 0; my $dy = $y2 - $y1; my $ay = abs($dy) * 2; my $sy = 1; $sy = -1 if $dy < 0; if ($ax > $ay) { my $d = $ay - ($ax / 2); while ($x1 != $x2) { g_setcell($x1, $y1, 1); if ($d >= 0) { $y1 += $sy; $d -= $ax; } $x1 += $sx; $d += $ay; } } else { my $d = $ax - ($ay / 2); while ($y1 != $y2) { g_setcell($x1, $y1, 1); if ($d >= 0) { $x1 += $sx; $d -= $ay; } $y1 += $sy; $d += $ax; } } g_setcell($x2, $y2, 1); } # ------------------------------------------------------------------------------ # fit pattern in viewport if not empty and not completely visible sub fit_if_not_visible { my @r = g_getrect(); if (@r > 0 and !g_visrect(@r)) { g_fit() } } # ------------------------------------------------------------------------------ # return a rect which is the minimal bounding box of the given pattern; # note that the pattern is two-state so we don't have to worry about # getting a multi-state cell array here sub getminbox { my $cells = shift; my $len = @{$cells}; return () if $len < 2; my $minx = $cells->[0]; my $miny = $cells->[1]; my $maxx = $minx; my $maxy = $miny; for (my $x = 0; $x < $len; $x += 2) { if ($cells->[$x] < $minx) { $minx = $cells->[$x] } if ($cells->[$x] > $maxx) { $maxx = $cells->[$x] } } for (my $y = 1; $y < $len; $y += 2) { if ($cells->[$y] < $miny) { $miny = $cells->[$y] } if ($cells->[$y] > $maxy) { $maxy = $cells->[$y] } } return ($minx, $miny, $maxx - $minx + 1, $maxy - $miny + 1); } # ------------------------------------------------------------------------------ g_exit("There is no pattern.") if g_empty(); # check that a layer is available for population plot my $layername = "population plot"; my $poplayer = -1; for my $i (0..g_numlayers()-1) { if (g_getname($i) eq $layername) { $poplayer = $i; last; } } if ($poplayer == -1 and g_numlayers() == g_maxlayers()) { g_exit("You need to delete a layer."); } # prompt user for number of steps my $s = g_getstring("Enter the number of steps:", $xlen, "Population plotter"); g_exit() if length($s) == 0; g_exit("Number of steps is not a +ve integer: $s") if $s !~ /^\d+$/ or $s == 0; my $numsteps = $s; # generate pattern for given number of steps my @poplist = ( int(g_getpop()) ); my @genlist = ( int(g_getgen()) ); my $oldsecs = time; for my $i (0..$numsteps-1) { g_step(); push(@poplist, int(g_getpop())); push(@genlist, int(g_getgen())); my $newsecs = time; if ($newsecs - $oldsecs >= 1.0) { # show pattern every second $oldsecs = $newsecs; fit_if_not_visible(); g_update(); g_show(sprintf("Step %d of %d", $i+1, $numsteps)); } } fit_if_not_visible(); # save some info before we switch layers my $stepsize = sprintf("%d^%d", g_getbase(), g_getstep()); my $pattname = g_getname(); # create population plot in separate layer g_setoption("stacklayers", 0); g_setoption("tilelayers", 0); g_setoption("showlayerbar", 1); if ($poplayer == -1) { $poplayer = g_addlayer(); } else { g_setlayer($poplayer); } g_new($layername); # use same rule but without any suffix (we don't want a bounded grid) my ($rule, $suffix) = split(":",g_getrule(),2); g_setrule($rule); my ($deadr, $deadg, $deadb) = g_getcolor("deadcells"); if (($deadr + $deadg + $deadb) / 3 > 128) { # use black if light background g_setcolors([1,0,0,0]); } else { # use white if dark background g_setcolors([1,255,255,255]); } my $minpop = min(@poplist); my $maxpop = max(@poplist); if ($minpop == $maxpop) { # avoid division by zero $minpop -= 1; } my $popscale = ($maxpop - $minpop) / $ylen; my $mingen = min(@genlist); my $maxgen = max(@genlist); my $genscale = ($maxgen - $mingen) / $xlen; # draw axes with origin at 0,0 draw_line(0, 0, $xlen, 0); draw_line(0, 0, 0, -$ylen); # add annotation using mono-spaced ASCII font my $t = make_text(uc($pattname)); my @tbox = getminbox($t); g_putcells($t, ($xlen - $tbox[2]) / 2, -$ylen - 10 - $tbox[3]); $t = make_text("POPULATION"); @tbox = getminbox($t); g_putcells($t, -10 - $tbox[3], -($ylen - $tbox[2]) / 2, 0, 1, -1, 0); $t = make_text("$minpop"); @tbox = getminbox($t); g_putcells($t, -$tbox[2] - 10, -$tbox[3] / 2); $t = make_text("$maxpop"); @tbox = getminbox($t); g_putcells($t, -$tbox[2] - 10, -$ylen - $tbox[3] / 2); $t = make_text("GENERATION (step=$stepsize)"); @tbox = getminbox($t); g_putcells($t, ($xlen - $tbox[2]) / 2, 10); $t = make_text("$mingen"); @tbox = getminbox($t); g_putcells($t, -$tbox[2] / 2, 10); $t = make_text("$maxgen"); @tbox = getminbox($t); g_putcells($t, $xlen - $tbox[2] / 2, 10); # display result at scale 1:1 g_fit(); g_setmag(0); g_show(""); # plot the data (do last because it could take a while if numsteps is huge) my $x = int(($genlist[0] - $mingen) / $genscale); my $y = int(($poplist[0] - $minpop) / $popscale); $oldsecs = time; for my $i (0..$numsteps-1) { my $newx = int(($genlist[$i+1] - $mingen) / $genscale); my $newy = int(($poplist[$i+1] - $minpop) / $popscale); draw_line($x, -$y, $newx, -$newy); $x = $newx; $y = $newy; my $newsecs = time; if ($newsecs - $oldsecs >= 1.0) { # show pattern every second $oldsecs = $newsecs; g_update(); } } golly-2.7-src/Scripts/Perl/shift.pl0000644000175000017500000000463712536111364014235 00000000000000# Shift current selection by given x y amounts using optional mode. # Author: Andrew Trevorrow (andrew@trevorrow.com), June 2007. # Updated to check for bounded grid, Oct 2010. use strict; my @selrect = g_getselrect(); g_exit("There is no selection.") if @selrect == 0; # use same file name as in shift.py my $INIFileName = g_getdir("data")."shift.ini"; my $oldparams = "0 0 or"; if (open(INFILE, $INIFileName)) { $oldparams = ; close INFILE; } my $s = g_getstring("Enter x y shift amounts and an optional mode\n". "(valid modes are copy/or/xor, default is or):", $oldparams, "Shift selection"); my ($x, $y, $mode) = split(' ', $s, 3); # check x and y g_exit() if $x eq ""; g_exit("Enter x and y amounts separated by a space.") if $y eq ""; g_exit("Bad x value: $x") unless $x =~ /^[+-]?\d+$/; g_exit("Bad y value: $y") unless $y =~ /^[+-]?\d+$/; # check optional mode if ($mode eq "") { $mode = "or"; } else { $mode = lc($mode); $mode = "copy" if $mode eq "c"; $mode = "or" if $mode eq "o"; $mode = "xor" if $mode eq "x"; if (not ($mode eq "copy" or $mode eq "or" or $mode eq "xor")) { g_exit("Unknown mode: $mode (must be copy/or/xor)"); } } # given parameters are valid so save them for next run if (not open(OUTFILE, ">".$INIFileName)) { g_warn("Can't save given parameters in $INIFileName:\n$!"); } else { print OUTFILE $s; close OUTFILE; } # abort shift if the new selection would be outside a bounded grid if (g_getwidth() > 0) { my $gridl = -int(g_getwidth()/2); my $gridr = $gridl + g_getwidth() - 1; my $newl = $selrect[0] + $x; my $newr = $newl + $selrect[2] - 1; if ($newl < $gridl or $newr > $gridr) { g_exit("New selection would be outside grid."); } } if (g_getheight() > 0) { my $gridt = -int(g_getheight()/2); my $gridb = $gridt + g_getheight() - 1; my $newt = $selrect[1] + $y; my $newb = $newt + $selrect[3] - 1; if ($newt < $gridt or $newb > $gridb) { g_exit("New selection would be outside grid."); } } # do the shift by cutting the current selection and pasting it into # the new position without changing the current clipboard pattern my $selcells = g_getcells(@selrect); g_clear(0); $selrect[0] += $x; $selrect[1] += $y; g_select(@selrect); g_clear(0) if $mode eq "copy"; g_putcells($selcells, $x, $y, 1, 0, 0, 1, $mode); g_fitsel() if !g_visrect(@selrect); golly-2.7-src/Scripts/Perl/envelope.pl0000644000175000017500000001002012536111364014714 00000000000000# Use multiple layers to create a history of the current pattern. # The "envelope" layer remembers all live cells. # Author: Andrew Trevorrow (andrew@trevorrow.com), June 2007. # Updated to use new setcolors command, September 2008. use strict; g_exit("There is no pattern.") if g_empty(); my $currindex = g_getlayer(); my $startindex; my $envindex; my $startname = "starting pattern"; my $envname = "envelope"; if ($currindex > 1 and g_getname($currindex - 1) eq $startname and g_getname($currindex - 2) eq $envname) { # continue from where we left off $startindex = $currindex - 1; $envindex = $currindex - 2; } elsif ($currindex + 2 < g_numlayers() and g_getname($currindex + 1) eq $startname and g_getname($currindex) eq $envname) { # switch from envelope layer to current layer and continue $currindex += 2; g_setlayer($currindex); $startindex = $currindex - 1; $envindex = $currindex - 2; } elsif ($currindex + 1 < g_numlayers() and g_getname($currindex) eq $startname and g_getname($currindex - 1) eq $envname) { # switch from starting layer to current layer and continue $currindex += 1; g_setlayer($currindex); $startindex = $currindex - 1; $envindex = $currindex - 2; } else { # start a new envelope using pattern in current layer if (g_numlayers() + 1 > g_maxlayers()) { g_exit("You need to delete a couple of layers."); } if (g_numlayers() + 2 > g_maxlayers()) { g_exit("You need to delete a layer."); } # get current layer's starting pattern my $startpatt = g_getcells(g_getrect()); $envindex = g_addlayer(); # create layer for remembering all live cells g_setcolors([-1,100,100,100]); # set all states to darkish gray g_putcells($startpatt); # copy starting pattern into this layer $startindex = g_addlayer(); # create layer for starting pattern g_setcolors([-1,0,255,0]); # set all states to green g_putcells($startpatt); # copy starting pattern into this layer # move currindex to above the envelope and starting pattern g_movelayer($currindex, $envindex); g_movelayer($envindex, $startindex); $currindex = $startindex; $startindex = $currindex - 1; $envindex = $currindex - 2; # name the starting and envelope layers so user can run script # again and continue from where it was stopped g_setname($startname, $startindex); g_setname($envname, $envindex); } # ------------------------------------------------------------------------------ sub envelope { # draw stacked layers using same location and scale g_setoption("stacklayers", 1); g_show("Hit escape key to stop script..."); while (1) { g_run(1); if (g_empty()) { g_show("Pattern died out."); last; } # copy current pattern to envelope layer; # we temporarily disable event checking so thumb scrolling # and other mouse events won't cause confusing changes my $currpatt = g_getcells(g_getrect()); g_check(0); g_setlayer($envindex); g_putcells($currpatt); g_setlayer($currindex); g_check(1); my $step = 1; my $expo = g_getstep(); if ($expo > 0) { $step = g_getbase()**$expo; } if (g_getgen() % $step == 0) { # display all 3 layers (envelope, start, current) g_update(); } } } # ------------------------------------------------------------------------------ # show status bar but hide layer & edit bars (faster, and avoids flashing) my $oldstatus = g_setoption("showstatusbar", 1); my $oldlayerbar = g_setoption("showlayerbar", 0); my $oldeditbar = g_setoption("showeditbar", 0); envelope(); END { # this code is always executed, even after escape/error; # restore original state of status/layer/edit bars g_setoption("showstatusbar", $oldstatus); g_setoption("showlayerbar", $oldlayerbar); g_setoption("showeditbar", $oldeditbar); } golly-2.7-src/Scripts/Perl/p1100-MWSS-gun.pl0000644000175000017500000001632412536111364015233 00000000000000# Bill Gosper's pure-period p1100 double MWSS gun, circa 1984 use strict; g_new("P1100 gun"); g_setalgo("HashLife"); g_setrule("B3/S23"); # update status bar now so we don't see different colors when # g_show is called g_update(); my $glider = g_parse('bo$bbo$3o!'); my $block = g_parse('oo$oo!'); my $eater = g_parse('oo$bo$bobo$bboo!'); my $bhept = g_parse('bbo$boo$oo$boo!'); my $centinal = $eater; push @$centinal,@{g_transform($bhept,8,3)}; push @$centinal,@{g_evolve(g_transform($centinal,51,0,-1,0,0,1),1)}; push @$centinal,@{g_transform($centinal,0,16,1,0,0,-1)}; my @temp = (@{g_transform(g_evolve($centinal,1),16,3,0,-1,1,0)}, @{g_transform(g_evolve($centinal,19),52,0,0,-1,1,0)}, @{g_transform(g_evolve($centinal,81),55,51,0,1,-1,0)}, @{g_transform(g_evolve($centinal,99),91,54,0,1,-1,0)}); my $overpass = \@temp; # build the source signal -- the most compact set of gliders # from which all other gliders and spaceships can be generated. # Also add the first four centinals to guide the recipe gliders my @MWSSrecipes = ( @{g_transform($glider,5759,738,0,1,-1,0)}, @{g_transform($glider,6325,667,-1,0,0,1)}, @{g_transform(g_evolve($glider,3),5824,896,-1,0,0,1)}, @{g_transform(g_evolve($glider,2),5912,1264)}, @{g_transform(g_evolve($glider,2),6135,1261,-1,0,0,1)}, @{g_transform(g_evolve($glider,1),5912,1490,1,0,0,-1)}, @{g_transform($glider,6229,4717,-1,0,0,1)}, @{g_transform(g_evolve($glider,1),6229,5029,-1,0,0,-1)}, @{g_transform(g_evolve($glider,1),5920,5032,1,0,0,-1)}, @{g_transform($glider,6230,5188,-1,0,0,-1)}, @{g_transform(g_evolve($glider,3),6230,5306,-1,0,0,-1)}, @{g_transform(g_evolve($glider,3),5959,5309,1,0,0,-1)}, @{g_transform(g_evolve($centinal,44),6185,5096,-1,0,0,1)}, @{g_transform(g_evolve($centinal,73),5897,1066)}, @{g_transform(g_evolve($centinal,42),5782,690)}, @{g_transform(g_evolve($centinal,25),5793,897,0,-1,1,0)}, 6095,-65,6075,228); # suppress outbound MWSSes with two extra cells # to change behavior at center, comment out one of the options below: # true p1100 gun #my @all = (@{g_transform($eater,6018,5924,0,1,-1,0)}, # @{g_transform($eater,6037,5943,0,1,-1,0)}); # synch center to recreate original p1100x5 gun pattern: my @all = @{g_transform($block,6018,6787)}; # generate the MWSSes for the glider-fanout ladder for (my $i = 0; $i < 7; $i += 1) { g_show("Building rung $i of ladder..."); push @all, @MWSSrecipes; @all = @{g_evolve(\@all,1100)}; } # add the actual glider-fanout ladder -- six rungs for (my $i = 0; $i < 6; $i += 1) { push @all, @{g_transform($glider,6030,1706+550*$i,0,-1,-1,0)}, @{g_transform(g_evolve($centinal,15),6102,1585+550*$i)}, @{g_transform($block,6029,1721+550*$i)}, @{g_transform(g_evolve($centinal,34),5996,1725+550*$i,0,1,-1,0)}, @{g_transform($block,6087,1747+550*$i)}, @{g_transform(g_evolve($centinal,87),6122,1745+550*$i,0,-1,1,0)}; } # add the rest of the centinals to guide the ladder's output gliders g_show("Adding centinal reflectors..."); push @all, @{g_transform(g_evolve($centinal,88),5704,0)}, @{g_transform(g_evolve($centinal,29),6423,295,-1,0,0,1)}, @{g_transform(g_evolve($centinal,74),5616,298)}, @{g_transform(g_evolve($centinal,40),6361,613,0,-1,1,0)}, @{g_transform(g_evolve($centinal,23),6502,620,-1,0,0,1)}, @{g_transform(g_evolve($centinal,36),5636,986)}, @{g_transform(g_evolve($centinal,38),6370,1008,0,-1,1,0)}, @{g_transform(g_evolve($centinal,19),5747,1347,0,-1,1,0)}, @{g_transform(g_evolve($centinal,67),5851,1516)}, @{g_transform($centinal,4061,2605,0,1,-1,0)}, @{g_transform(g_evolve($centinal,10),5376,3908,0,1,-1,0)}, @{g_transform(g_evolve($centinal,77),8191,4407,-1,0,0,1)}, @{g_transform(g_evolve($centinal,6),4988,4606)}, @{g_transform(g_evolve($centinal,34),6357,4608,-1,0,0,1)}, @{g_transform(g_evolve($centinal,27),8129,4621,-1,0,0,1)}, @{g_transform(g_evolve($centinal,92),5159,5051)}, @{g_transform(g_evolve($centinal,53),7991,5201,-1,0,0,1)}, @{g_transform(g_evolve($centinal,94),7038,5370,0,1,-1,0)}, @{g_transform(g_evolve($centinal,13),5591,5379,0,1,-1,0)}, @{g_transform(g_evolve($centinal,3),5858,5428,0,1,-1,0)}, @{g_transform(g_evolve($centinal,87),7805,5511,-1,0,0,1)}, @{g_transform(g_evolve($centinal,98),401,5557,0,1,-1,0)}, @{g_transform(g_evolve($centinal,14),955,5561,0,1,-1,0)}, @{g_transform(g_evolve($centinal,8),6592,5584,0,1,-1,0)}, @{g_transform(g_evolve($centinal,39),6933,5698,-1,0,0,1)}, @{g_transform(g_evolve($centinal,32),6230,5881)}, @{g_transform(g_evolve($centinal,47),11676,5854,0,1,-1,0)}, @{g_transform(g_evolve($centinal,68),0,5748,0,1,-1,0)}, @{g_transform(g_evolve($centinal,89),6871,5912,-1,0,0,1)}, @{g_transform(g_evolve($centinal,45),12095,6027,0,1,-1,0)}, @{g_transform(g_evolve($centinal,86),6209,6134)}, @{g_transform(g_evolve($centinal,55),6868,6357,-1,0,0,1)}, @{g_transform(g_evolve($centinal,95),9939,6491,0,1,-1,0)}, @{g_transform(g_evolve($centinal,23),8782,6548,0,1,-1,0)}, @{g_transform(g_evolve($centinal,58),3066,6572,0,1,-1,0)}, @{g_transform(g_evolve($centinal,21),9326,6596,0,1,-1,0)}, @{g_transform(g_evolve($centinal,80),3628,6626,0,1,-1,0)}, @{g_transform(g_evolve($centinal,45),6821,6528,-1,0,0,1)}, @{g_transform(g_evolve($centinal,33),10373,6649,0,1,-1,0)}, @{g_transform(g_evolve($centinal,16),2587,6685,0,1,-1,0)}; # reflect the symmetrical part and add the center asymmetric stuff -- push @all, @{g_transform(\@all,0,13583,1,0,0,-1)}, @{g_transform($block,1081,6791)}, @{g_transform($block,2731,6791)}, @{g_transform($block,3831,6791)}, @{g_transform($block,9108,6791)}, @{g_transform($block,10208,6791)}, @{g_transform($block,11308,6791)}, @{g_transform($overpass,8475,6737)}, @{g_transform(g_evolve($overpass,39),3365,6737,-1,0,0,1)}, @{g_transform($overpass,9575,6737)}, @{g_transform(g_evolve($overpass,39),2265,6737,-1,0,0,1)}, @{g_transform($overpass,10675,6737)}, @{g_transform(g_evolve($overpass,39),1715,6737,-1,0,0,1)}; push @MWSSrecipes,@{g_transform(\@MWSSrecipes,0,13583,1,0,0,-1)}; g_putcells(\@all); g_fit(); # Different glider paths are different lengths, so incomplete # glider recipes must be overwritten for a while to prevent disaster. for (my $i = 0; $i < 46; $i += 1) { my $t = 49500 - $i*1100; g_show("Filling glider tracks -- $t ticks left."); g_update(); g_putcells(\@MWSSrecipes); g_run(1100); } g_show(""); # reset gen count to 0 g_setgen("0"); golly-2.7-src/Scripts/Python/0000755000175000017500000000000012536111546013212 500000000000000golly-2.7-src/Scripts/Python/tile.py0000644000175000017500000000757712536111364014457 00000000000000# Tile current selection with pattern inside selection. # Author: Andrew Trevorrow (andrew@trevorrow.com), March 2006. # Updated to use exit command, Nov 2006. # Updated to handle multi-state patterns, Aug 2008. from glife import * import golly as g selrect = rect( g.getselrect() ) if selrect.empty: g.exit("There is no selection.") selpatt = pattern( g.getcells(g.getselrect()) ) if len(selpatt) == 0: g.exit("No pattern in selection.") # determine if selpatt is one-state or multi-state inc = 2 if len(selpatt) & 1 == 1: inc = 3 # ------------------------------------------------------------------------------ def clip_left (patt, left): clist = list(patt) # remove padding int if present if (inc == 3) and (len(clist) % 3 == 1): clist.pop() x = 0 while x < len(clist): if clist[x] < left: clist[x : x+inc] = [] # remove cell from list else: x += inc # append padding int if necessary if (inc == 3) and (len(clist) & 1 == 0): clist.append(0) return pattern(clist) # ------------------------------------------------------------------------------ def clip_right (patt, right): clist = list(patt) # remove padding int if present if (inc == 3) and (len(clist) % 3 == 1): clist.pop() x = 0 while x < len(clist): if clist[x] > right: clist[x : x+inc] = [] # remove cell from list else: x += inc # append padding int if necessary if (inc == 3) and (len(clist) & 1 == 0): clist.append(0) return pattern(clist) # ------------------------------------------------------------------------------ def clip_top (patt, top): clist = list(patt) # remove padding int if present if (inc == 3) and (len(clist) % 3 == 1): clist.pop() y = 1 while y < len(clist): if clist[y] < top: clist[y-1 : y-1+inc] = [] # remove cell from list else: y += inc # append padding int if necessary if (inc == 3) and (len(clist) & 1 == 0): clist.append(0) return pattern(clist) # ------------------------------------------------------------------------------ def clip_bottom (patt, bottom): clist = list(patt) # remove padding int if present if (inc == 3) and (len(clist) % 3 == 1): clist.pop() y = 1 while y < len(clist): if clist[y] > bottom: clist[y-1 : y-1+inc] = [] # remove cell from list else: y += inc # append padding int if necessary if (inc == 3) and (len(clist) & 1 == 0): clist.append(0) return pattern(clist) # ------------------------------------------------------------------------------ # find selpatt's minimal bounding box bbox = getminbox(selpatt) # first tile selpatt horizontally, clipping where necessary left = bbox.left i = 0 while left > selrect.left: left -= bbox.width i += 1 if left >= selrect.left: selpatt.put(-bbox.width * i, 0) else: clip_left( selpatt(-bbox.width * i, 0), selrect.left ).put() right = bbox.right i = 0 while right < selrect.right: right += bbox.width i += 1 if right <= selrect.right: selpatt.put(bbox.width * i, 0) else: clip_right( selpatt(bbox.width * i, 0), selrect.right ).put() # get new selection pattern and tile vertically, clipping where necessary selpatt = pattern( g.getcells(g.getselrect()) ) bbox = getminbox(selpatt) top = bbox.top i = 0 while top > selrect.top: top -= bbox.height i += 1 if top >= selrect.top: selpatt.put(0, -bbox.height * i) else: clip_top( selpatt(0, -bbox.height * i), selrect.top ).put() bottom = bbox.bottom i = 0 while bottom < selrect.bottom: bottom += bbox.height i += 1 if bottom <= selrect.bottom: selpatt.put(0, bbox.height * i) else: clip_bottom( selpatt(0, bbox.height * i), selrect.bottom ).put() if not selrect.visible(): g.fitsel() golly-2.7-src/Scripts/Python/make-torus.py0000644000175000017500000000132612536111364015573 00000000000000# Use the current selection to create a toroidal universe. # Author: Andrew Trevorrow (andrew@trevorrow.com), Sept 2010. from glife import inside, outside import golly as g selrect = g.getselrect() if len(selrect) == 0: g.exit("There is no selection.") x = selrect[0] y = selrect[1] wd = selrect[2] ht = selrect[3] selcells = g.getcells(selrect) if not g.empty(): g.clear(inside) g.clear(outside) # get current rule, remove any existing suffix, then add new suffix rule = g.getrule().split(":")[0] g.setrule(rule + ":T" + str(wd) + "," + str(ht)) newx = -int(wd/2) newy = -int(ht/2) selrect[0] = newx selrect[1] = newy g.select(selrect) if len(selcells) > 0: g.putcells(selcells, newx - x, newy - y) g.fitsel() golly-2.7-src/Scripts/Python/oscar.py0000644000175000017500000001332012536111364014610 00000000000000# Oscar is an OSCillation AnalyzeR for use with Golly. # Author: Andrew Trevorrow (andrew@trevorrow.com), March 2006. # Modified to handle B0-and-not-S8 rules, August 2009. # This script uses Gabriel Nivasch's "keep minima" algorithm. # For each generation, calculate a hash value for the pattern. Keep all of # the record-breaking minimal hashes in a list, with the oldest first. # For example, after 5 generations the saved hash values might be: # # 8 12 16 24 25, # # If the next hash goes down to 13 then the list can be shortened: # # 8 12 13. # # When the current hash matches one of the saved hashes, it is highly likely # the pattern is oscillating. By keeping a corresponding list of generation # counts we can calculate the period. We also keep lists of population # counts and bounding boxes; they are used to reduce the chance of spurious # oscillator detection due to hash collisions. The bounding box info also # allows us to detect moving oscillators (spaceships/knightships). import golly as g from glife import rect, pattern from time import time # -------------------------------------------------------------------- # initialize lists hashlist = [] # for pattern hash values genlist = [] # corresponding generation counts poplist = [] # corresponding population counts boxlist = [] # corresponding bounding boxes # -------------------------------------------------------------------- def show_spaceship_speed(period, deltax, deltay): # we found a moving oscillator if period == 1: g.show("Spaceship detected (speed = c)") elif (deltax == deltay) or (deltax == 0) or (deltay == 0): speed = "" if (deltax == 0) or (deltay == 0): # orthogonal spaceship if (deltax > 1) or (deltay > 1): speed += str(deltax + deltay) else: # diagonal spaceship (deltax == deltay) if deltax > 1: speed += str(deltax) g.show("Spaceship detected (speed = " + speed + "c/" +str(period) + ")") else: # deltax != deltay and both > 0 speed = str(deltay) + "," + str(deltax) g.show("Knightship detected (speed = " + speed + "c/" + str(period) + ")") # -------------------------------------------------------------------- def oscillating(): # return True if the pattern is empty, stable or oscillating # first get current pattern's bounding box prect = g.getrect() pbox = rect(prect) if pbox.empty: g.show("The pattern is empty.") return True # get current pattern and create hash of "normalized" version -- ie. shift # its top left corner to 0,0 -- so we can detect spaceships and knightships ## currpatt = pattern( g.getcells(prect) ) ## h = hash( tuple( currpatt(-pbox.left, -pbox.top) ) ) # use Golly's hash command (3 times faster than above code) h = g.hash(prect) # check if outer-totalistic rule has B0 but not S8 rule = g.getrule().split(":")[0] hasB0notS8 = rule.startswith("B0") and (rule.find("/") > 1) and not rule.endswith("8") # determine where to insert h into hashlist pos = 0 listlen = len(hashlist) while pos < listlen: if h > hashlist[pos]: pos += 1 elif h < hashlist[pos]: # shorten lists and append info below del hashlist[pos : listlen] del genlist[pos : listlen] del poplist[pos : listlen] del boxlist[pos : listlen] break else: # h == hashlist[pos] so pattern is probably oscillating, but just in # case this is a hash collision we also compare pop count and box size if (int(g.getpop()) == poplist[pos]) and \ (pbox.wd == boxlist[pos].wd) and \ (pbox.ht == boxlist[pos].ht): period = int(g.getgen()) - genlist[pos] if hasB0notS8 and (period % 2 > 0) and (pbox == boxlist[pos]): # ignore this hash value because B0-and-not-S8 rules are # emulated by using different rules for odd and even gens, # so it's possible to have identical patterns at gen G and # gen G+p if p is odd return False if period == 1: if pbox == boxlist[pos]: g.show("The pattern is stable.") else: show_spaceship_speed(1, 0, 0) elif pbox == boxlist[pos]: g.show("Oscillator detected (period = " + str(period) + ")") else: deltax = abs(boxlist[pos].x - pbox.x) deltay = abs(boxlist[pos].y - pbox.y) show_spaceship_speed(period, deltax, deltay) return True else: # look at next matching hash value or insert if no more pos += 1 # store hash/gen/pop/box info at same position in various lists hashlist.insert(pos, h) genlist.insert(pos, int(g.getgen())) poplist.insert(pos, int(g.getpop())) boxlist.insert(pos, pbox) return False # -------------------------------------------------------------------- def fit_if_not_visible(): # fit pattern in viewport if not empty and not completely visible r = rect(g.getrect()) if (not r.empty) and (not r.visible()): g.fit() # -------------------------------------------------------------------- g.show("Checking for oscillation... (hit escape to abort)") oldsecs = time() while not oscillating(): g.run(1) newsecs = time() if newsecs - oldsecs >= 1.0: # show pattern every second oldsecs = newsecs fit_if_not_visible() g.update() fit_if_not_visible() golly-2.7-src/Scripts/Python/flood-fill.py0000644000175000017500000001106512536111364015534 00000000000000# Fill clicked region with current drawing state. # Author: Andrew Trevorrow (andrew@trevorrow.com), Jan 2011. import golly as g from time import time # avoid an unbounded fill if g.empty(): if g.getwidth() == 0 or g.getheight() == 0: g.exit("You cannot fill an empty universe that is unbounded!") else: # set fill limits to the pattern's bounding box # (these will be extended below if the grid is bounded) r = g.getrect() minx = r[0] miny = r[1] maxx = minx + r[2] - 1 maxy = miny + r[3] - 1 # allow filling to extend to the edges of bounded grid if g.getwidth() > 0: minx = -int(g.getwidth()/2) maxx = minx + g.getwidth() - 1 if g.getheight() > 0: miny = -int(g.getheight()/2) maxy = miny + g.getheight() - 1 # ------------------------------------------------------------------------------ def checkneighbor(x, y, oldstate): # first check if x,y is outside fill limits if x < minx or x > maxx: return False if y < miny or y > maxy: return False return g.getcell(x, y) == oldstate # ------------------------------------------------------------------------------ def floodfill(): newstate = g.getoption("drawingstate") oldstate = newstate # wait for user to click a cell g.show("Click the region you wish to fill... (hit escape to abort)") while oldstate == newstate: event = g.getevent() if event.startswith("click"): # event is a string like "click 10 20 left none" evt, xstr, ystr, butt, mods = event.split() x = int(xstr) y = int(ystr) if x < minx or x > maxx or y < miny or y > maxy: # click is outside pattern's bounding box in unbounded universe g.warn("Click within the pattern's bounding box\n"+ "otherwise the fill will be unbounded.") else: # note that user might have changed drawing state newstate = g.getoption("drawingstate") oldstate = g.getcell(x, y) if oldstate == newstate: g.warn("The clicked cell must have a different state\n"+ "to the current drawing state.") else: g.doevent(event) # tell Golly to handle all further keyboard/mouse events g.getevent(False) # do flood fill starting with clicked cell g.show("Filling clicked region... (hit escape to stop)") clist = [ (x,y) ] g.setcell(x, y, newstate) oldsecs = time() while len(clist) > 0: # remove cell from start of clist x, y = clist.pop(0) newsecs = time() if newsecs - oldsecs >= 0.5: # show changed pattern every half second oldsecs = newsecs g.update() # check if any orthogonal neighboring cells are in oldstate if checkneighbor( x, y-1, oldstate): clist.append( (x, y-1) ) g.setcell( x, y-1, newstate) if checkneighbor( x, y+1, oldstate): clist.append( (x, y+1) ) g.setcell( x, y+1, newstate) if checkneighbor( x+1, y, oldstate): clist.append( (x+1, y) ) g.setcell( x+1, y, newstate) if checkneighbor( x-1, y, oldstate): clist.append( (x-1, y) ) g.setcell( x-1, y, newstate) # diagonal neighbors are more complicated because we don't # want to cross a diagonal line of live cells if checkneighbor( x+1, y+1, oldstate) and (g.getcell(x, y+1) == 0 or g.getcell(x+1, y) == 0): clist.append( (x+1, y+1) ) g.setcell( x+1, y+1, newstate) if checkneighbor( x+1, y-1, oldstate) and (g.getcell(x, y-1) == 0 or g.getcell(x+1, y) == 0): clist.append( (x+1, y-1) ) g.setcell( x+1, y-1, newstate) if checkneighbor( x-1, y+1, oldstate) and (g.getcell(x, y+1) == 0 or g.getcell(x-1, y) == 0): clist.append( (x-1, y+1) ) g.setcell( x-1, y+1, newstate) if checkneighbor( x-1, y-1, oldstate) and (g.getcell(x, y-1) == 0 or g.getcell(x-1, y) == 0): clist.append( (x-1, y-1) ) g.setcell( x-1, y-1, newstate) # ------------------------------------------------------------------------------ oldcursor = g.getcursor() g.setcursor("Draw") try: floodfill() finally: g.setcursor(oldcursor) g.show(" ") golly-2.7-src/Scripts/Python/draw-lines.py0000644000175000017500000000764712536111364015565 00000000000000# Allow user to draw one or more straight lines by clicking end points. # Author: Andrew Trevorrow (andrew@trevorrow.com), Jan 2011. import golly as g # ------------------------------------------------------------------------------ def drawline(x1, y1, x2, y2): # draw a line of cells from x1,y1 to x2,y2 using Bresenham's algorithm; # we also return the old cells in the line so we can erase line later oldcells = [] # note that x1,y1 has already been drawn # oldcells.append( (x1, y1, g.getcell(x1, y1)) ) # g.setcell(x1, y1, drawstate) if x1 == x2 and y1 == y2: g.update() return oldcells dx = x2 - x1 ax = abs(dx) * 2 sx = 1 if dx < 0: sx = -1 dy = y2 - y1 ay = abs(dy) * 2 sy = 1 if dy < 0: sy = -1 if ax > ay: d = ay - (ax / 2) while x1 != x2: oldcells.append( (x1, y1, g.getcell(x1, y1)) ) g.setcell(x1, y1, drawstate) if d >= 0: y1 += sy d -= ax x1 += sx d += ay else: d = ax - (ay / 2) while y1 != y2: oldcells.append( (x1, y1, g.getcell(x1, y1)) ) g.setcell(x1, y1, drawstate) if d >= 0: x1 += sx d -= ay y1 += sy d += ax oldcells.append( (x2, y2, g.getcell(x2, y2)) ) g.setcell(x2, y2, drawstate) g.update() return oldcells # ------------------------------------------------------------------------------ def eraseline(oldcells): for t in oldcells: x, y, s = t g.setcell(x, y, s) # ------------------------------------------------------------------------------ def drawlines(): global oldline, firstcell started = False oldmouse = "" while True: event = g.getevent() if event.startswith("click"): # event is a string like "click 10 20 left altctrlshift" evt, x, y, butt, mods = event.split() oldmouse = x + ' ' + y if started: # draw permanent line from start pos to end pos endx = int(x) endy = int(y) drawline(startx, starty, endx, endy) # this is also the start of another line startx = endx starty = endy oldline = [] firstcell = [] else: # start first line startx = int(x) starty = int(y) firstcell = [ startx, starty, g.getcell(startx, starty) ] g.setcell(startx, starty, drawstate) g.update() started = True g.show("Click where to end this line (and start another line)...") else: # event might be "" or "key m none" if len(event) > 0: g.doevent(event) mousepos = g.getxy() if started and len(mousepos) == 0: # erase old line if mouse is not over grid if len(oldline) > 0: eraseline(oldline) oldline = [] g.update() elif started and len(mousepos) > 0 and mousepos != oldmouse: # mouse has moved, so erase old line (if any) and draw new line if len(oldline) > 0: eraseline(oldline) x, y = mousepos.split() oldline = drawline(startx, starty, int(x), int(y)) oldmouse = mousepos # ------------------------------------------------------------------------------ g.show("Click where to start line...") oldcursor = g.getcursor() g.setcursor("Draw") drawstate = g.getoption("drawingstate") oldline = [] firstcell = [] # pos and state of the 1st cell clicked try: drawlines() finally: g.setcursor(oldcursor) if len(oldline) > 0: eraseline(oldline) if len(firstcell) > 0: x, y, s = firstcell g.setcell(x, y, s) golly-2.7-src/Scripts/Python/make-Codd-constructor.py0000644000175000017500000000437012536111364017655 00000000000000# Make a pattern from states 1 and 0, select it and then # run this script to make a Codd CA pattern that will then # construct the pattern. The constructor will then attempt # to inject sheathing and triggering signals to a point one # up from the pattern's bottom-left corner. # # See example: Patterns/Codd/golly-constructor.rle # # Tim Hutton from glife import rect from time import time import golly as g r = rect( g.getselrect() ) if r.empty: g.exit("There is no selection.") oldsecs = time() maxstate = g.numstates() - 1 # these are the commands: extend = '70116011' extend_left = '4011401150116011' extend_right = '5011501140116011' retract = '4011501160116011' retract_left = '5011601160116011' retract_right = '4011601160116011' mark = '701160114011501170116011' erase = '601170114011501160116011' sense = '70117011' cap = '40116011' inject_sheath = '701150116011' inject_trigger = '60117011701160116011' # (sometimes you don't need two blanks after each command but I haven't analysed this fully) # we first write the commands to a string, and then to the grid # (we start off facing right, at the bottom-left of the construction area) # write the cells that are in state 1 (can ignore the zeros) # (still plenty of room for optimisation here) tape = '11' for row in xrange(r.top, r.top + r.height): # if large selection then give some indication of progress newsecs = time() if newsecs - oldsecs >= 1.0: oldsecs = newsecs g.update() for col in xrange(r.left, r.left + r.width): if g.getcell(col, row)==1: tape += extend*(4+col-r.left) + extend_left + extend*(r.top+r.height-row) tape += mark tape += retract*(r.top+r.height-row) + retract_left + retract*(4+col-r.left) elif g.getcell(col,row)!=0: g.exit('Cells in the selected area must be in states 0 or 1 only.') # finally we sheath and trigger and retract tape += extend_left + extend*4 + extend_right + extend tape += inject_sheath + '1'*50 + inject_trigger tape += retract*2 + retract_right + retract*4 + retract_left # now write the tape out x = r.left+r.width+10 y = r.top+r.height+10 g.setcell(x+1,y,2) for i in tape: g.setcell(x,y-1,2) g.setcell(x,y,int(i)) g.setcell(x,y+1,2) x-=1 golly-2.7-src/Scripts/Python/pop-plot.py0000644000175000017500000001167712536111364015270 00000000000000# Run the current pattern for a given number of steps (using current # step size) and create a plot of population vs time in separate layer. # Author: Andrew Trevorrow (andrew@trevorrow.com), May 2007. import golly as g from glife import getminbox, rect, rccw from glife.text import make_text from time import time # -------------------------------------------------------------------- # size of plot xlen = 500 # length of x axis ylen = 500 # length of y axis # -------------------------------------------------------------------- # draw a line of cells from x1,y1 to x2,y2 using Bresenham's algorithm def draw_line(x1, y1, x2, y2): g.setcell(x1, y1, 1) if x1 == x2 and y1 == y2: return dx = x2 - x1 ax = abs(dx) * 2 sx = 1 if dx < 0: sx = -1 dy = y2 - y1 ay = abs(dy) * 2 sy = 1 if dy < 0: sy = -1 if ax > ay: d = ay - (ax / 2) while x1 != x2: g.setcell(x1, y1, 1) if d >= 0: y1 += sy d -= ax x1 += sx d += ay else: d = ax - (ay / 2) while y1 != y2: g.setcell(x1, y1, 1) if d >= 0: x1 += sx d -= ay y1 += sy d += ax g.setcell(x2, y2, 1) # -------------------------------------------------------------------- # fit pattern in viewport if not empty and not completely visible def fit_if_not_visible(): try: r = rect(g.getrect()) if (not r.empty) and (not r.visible()): g.fit() except: # getrect failed because pattern is too big g.fit() # -------------------------------------------------------------------- if g.empty(): g.exit("There is no pattern.") # check that a layer is available for population plot layername = "population plot" poplayer = -1 for i in xrange(g.numlayers()): if g.getname(i) == layername: poplayer = i break if poplayer == -1 and g.numlayers() == g.maxlayers(): g.exit("You need to delete a layer.") # prompt user for number of steps numsteps = xlen s = g.getstring("Enter the number of steps:", str(numsteps), "Population plotter") if len(s) > 0: numsteps = int(s) if numsteps <= 0: g.exit() # generate pattern for given number of steps poplist = [ int(g.getpop()) ] genlist = [ int(g.getgen()) ] oldsecs = time() for i in xrange(numsteps): g.step() poplist.append( int(g.getpop()) ) genlist.append( int(g.getgen()) ) newsecs = time() if newsecs - oldsecs >= 1.0: # show pattern every second oldsecs = newsecs fit_if_not_visible() g.update() g.show("Step %i of %i" % (i+1, numsteps)) fit_if_not_visible() # save some info before we switch layers stepsize = "%i^%i" % (g.getbase(), g.getstep()) pattname = g.getname() # create population plot in separate layer g.setoption("stacklayers", 0) g.setoption("tilelayers", 0) g.setoption("showlayerbar", 1) if poplayer == -1: poplayer = g.addlayer() else: g.setlayer(poplayer) g.new(layername) # use same rule but without any suffix (we don't want a bounded grid) g.setrule(g.getrule().split(":")[0]) deadr, deadg, deadb = g.getcolor("deadcells") if (deadr + deadg + deadb) / 3 > 128: # use black if light background g.setcolors([1,0,0,0]) else: # use white if dark background g.setcolors([1,255,255,255]) minpop = min(poplist) maxpop = max(poplist) if minpop == maxpop: # avoid division by zero minpop -= 1 popscale = float(maxpop - minpop) / float(ylen) mingen = min(genlist) maxgen = max(genlist) genscale = float(maxgen - mingen) / float(xlen) # draw axes with origin at 0,0 draw_line(0, 0, xlen, 0) draw_line(0, 0, 0, -ylen) # add annotation using mono-spaced ASCII font t = make_text(pattname.upper(), "mono") bbox = getminbox(t) t.put((xlen - bbox.wd) / 2, -ylen - 10 - bbox.ht) t = make_text("POPULATION", "mono") bbox = getminbox(t) t.put(-10 - bbox.ht, -(ylen - bbox.wd) / 2, rccw) t = make_text(str(minpop), "mono") bbox = getminbox(t) t.put(-bbox.wd - 10, -bbox.ht / 2) t = make_text(str(maxpop), "mono") bbox = getminbox(t) t.put(-bbox.wd - 10, -ylen - bbox.ht / 2) t = make_text("GENERATION (step=%s)" % stepsize, "mono") bbox = getminbox(t) t.put((xlen - bbox.wd) / 2, 10) t = make_text(str(mingen), "mono") bbox = getminbox(t) t.put(-bbox.wd / 2, 10) t = make_text(str(maxgen), "mono") bbox = getminbox(t) t.put(xlen - bbox.wd / 2, 10) # display result at scale 1:1 g.fit() g.setmag(0) g.show("") # plot the data (do last because it could take a while if numsteps is huge) x = int(float(genlist[0] - mingen) / genscale) y = int(float(poplist[0] - minpop) / popscale) oldsecs = time() for i in xrange(numsteps): newx = int(float(genlist[i+1] - mingen) / genscale) newy = int(float(poplist[i+1] - minpop) / popscale) draw_line(x, -y, newx, -newy) x = newx y = newy newsecs = time() if newsecs - oldsecs >= 1.0: # update plot every second oldsecs = newsecs g.update() golly-2.7-src/Scripts/Python/Rule-Generators/0000755000175000017500000000000012536111546016230 500000000000000golly-2.7-src/Scripts/Python/Rule-Generators/TriTurmite-gen.py0000644000175000017500000006105512536111364021406 00000000000000# Generator for Triangular Turmite rules import golly import random import string from glife.EmulateTriangular import * from glife.WriteRuleTable import * prefix = 'TriTurmite' # http://bytes.com/topic/python/answers/25176-list-subsets get_subsets = lambda items: [[x for (pos,x) in zip(range(len(items)), items) if (2**pos) & switches] for switches in range(2**len(items))] # Generate a random rule, while filtering out the dull ones. # More to try: # - if turmite can get stuck in period-2 cycles then rule is bad (or might it avoid them?) # - (extending) if turmite has (c,2 (or 8),s) for state s and color c then will loop on the spot (unlikely to avoid?) example_spec = '{{{1, 2, 0}, {0, 1, 0}}}' import random ns = 2 nc = 3 while True: # (we break out if ok) example_spec = '{' for state in range(ns): if state > 0: example_spec += ',' example_spec += '{' for color in range(nc): if color > 0: example_spec += ',' new_color = random.randint(0,nc-1) dir_to_turn = [1,2,4][random.randint(0,2)] # (we don't consider splitting and dying here) new_state = random.randint(0,ns-1) example_spec += '{' + str(new_color) + "," + str(dir_to_turn) + "," + str(new_state) + '}' example_spec += '}' example_spec += '}' is_rule_acceptable = True action_table = eval(string.replace(string.replace(example_spec,'}',']'),'{','[')) # does Turmite change at least one color? changes_one = False for state in range(ns): for color in range(nc): if not action_table[state][color][0] == color: changes_one = True if not changes_one: is_rule_acceptable = False # does Turmite write every non-zero color? colors_written = set([]) for state in range(ns): for color in range(nc): colors_written.add(action_table[state][color][0]) if not colors_written==set(range(1,nc)): is_rule_acceptable = False # does Turmite ever turn? turmite_turns = False for state in range(ns): for color in range(nc): if not action_table[state][color][0] in [4]: # u-turn turmite_turns = True if not turmite_turns: is_rule_acceptable = False # does turmite get stuck in any subset of states? for subset in get_subsets(range(ns)): if len(subset)==0 or len(subset)==ns: # (just an optimisation) continue leaves_subset = False for state in subset: for color in range(nc): if not action_table[state][color][2] in subset: leaves_subset = True if not leaves_subset: is_rule_acceptable = False break # (just an optimisation) # does turmite wobble on the spot? (u-turn that doesn't change color or state) for state in range(ns): for color in range(nc): if action_table[state][color][0]==color and action_table[state][color][1]==4 and action_table[state][color][2]==state: is_rule_acceptable = False # so was the rule acceptable, in the end? if is_rule_acceptable: break spec = golly.getstring( '''This script will create a TriTurmite CA for a given specification. Enter a specification string: a curly-bracketed table of n_states rows and n_colors columns, where each entry is a triple of integers. The elements of each triple are: a: the new color of the square b: the direction(s) for the Turmite to turn (1=Left, 2=Right, 4=U-turn) c: the new internal state of the Turmite Example: {{{1, 2, 0}, {0, 1, 0}}} Has 1 state and 2 colors. The triple {1,2,0} says: 1. set the color of the square to 1 2. turn right (2) 3. adopt state 0 (no change) and move forward one square This is the equivalent of Langton's Ant. Enter string: ''', example_spec, 'Enter TriTurmite specification:') '''Some interesting rule found with this script: {{{2,4,0},{2,4,0},{1,2,1}},{{1,2,1},{2,1,0},{1,4,1}}} - lightning cloud {{{1,1,1},{1,2,0},{2,1,1}},{{2,2,1},{2,2,1},{1,4,0}}} - makes a highway (seems to be rarer in tri grids compared to square grids?) {{{2,2,1},{1,2,0},{1,1,1}},{{1,2,0},{2,1,0},{1,4,1}}} - data pyramid {{{2,1,0},{1,4,1},{1,1,0}},{{2,4,0},{2,2,1},{1,1,1}}} - a filled version of the tri-grid Langton's ant {{{1,1,0},{2,2,1},{1,1,0}},{{1,4,0},{2,2,0},{2,2,0}}} - hypnodisc ''' # convert the specification string into action_table[state][color] # (convert Mathematica code to Python and run eval) action_table = eval(string.replace(string.replace(spec,'}',']'),'{','[')) n_states = len(action_table) n_colors = len(action_table[0]) # (N.B. The terminology 'state' here refers to the internal state of the finite # state machine that each Turmite is using, not the contents of each Golly # cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The # actual 'Golly state' in this emulation of Turmites is given by the # "encoding" section below.) n_dirs = 3 # TODO: check table is full and valid total_states = n_colors+n_colors*n_states*3 # problem if we try to export more than 255 states if total_states > 128: # max allowed using checkerboard emulation (see EmulateTriangular) golly.warn("Number of states required exceeds Golly's limit of 255.") golly.exit() # encoding: # (0-n_colors: empty square) def encode(c,s,d): # turmite on color c in state s facing away from direction d return n_colors + 3*(n_states*c+s) + d # http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html def flatten(l, ltypes=(list, tuple)): ltype = type(l) l = list(l) i = 0 while i < len(l): while isinstance(l[i], ltypes): if not l[i]: l.pop(i) i -= 1 break else: l[i:i + 1] = l[i] i += 1 return ltype(l) # convert the string to a form we can embed in a filename spec_string = ''.join(map(str,map(lambda x:hex(x)[2:],flatten(action_table)))) # (ambiguous but we have to try something) # what direction would a turmite have been facing to end up here from direction # d if it turned t: would_have_been_facing[t][d] would_have_been_facing={ 1:[2,0,1], # left 2:[1,2,0], # right 4:[0,1,2], # u-turn } not_arriving_from_here = [range(n_colors) for i in range(n_dirs)] # (we're going to modify them) for color in range(n_colors): for state in range(n_states): turnset = action_table[state][color][1] for turn in [1,2,4]: if not turn&turnset: # didn't turn this way for dir in range(n_dirs): facing = would_have_been_facing[turn][dir] not_arriving_from_here[dir] += [encode(color,state,facing)] # What states leave output_color behind? leaving_color_behind = {} for output_color in range(n_colors): leaving_color_behind[output_color] = [output_color] # (no turmite present) for state in range(n_states): for color in range(n_colors): if action_table[state][color][0]==output_color: leaving_color_behind[output_color] += [encode(color,state,d) for d in range(n_dirs)] # any direction # we can't build the rule tree directly so we collect the transitions ready for emulation transitions = [] # A single turmite is entering this square: for s in range(n_states): for dir in range(n_dirs): # collect all the possibilities for a turmite to arrive in state s from direction dir inputs = [] for state in range(n_states): for color in range(n_colors): if action_table[state][color][2]==s: turnset = action_table[state][color][1] # sum of all turns inputs += [encode(color,state,would_have_been_facing[turn][dir]) \ for turn in [1,2,4] if turn&turnset] if len(inputs)>0: for central_color in range(n_colors): # output the required transition ### AKT: this code causes syntax error in Python 2.3: ### transition = [leaving_color_behind[central_color]] + \ ### [ inputs if i==dir else not_arriving_from_here[i] for i in range(n_dirs) ] + \ ### [ [encode(central_color,s,dir)] ] transition = [leaving_color_behind[central_color]] for i in range(n_dirs): if i==dir: transition.append(inputs) else: transition.append(not_arriving_from_here[i]) transition += [ [encode(central_color,s,dir)] ] transitions += [transition] # default: square is left with no turmite present for output_color,inputs in leaving_color_behind.items(): transition = [inputs]+[range(total_states)]*n_dirs+[[output_color]] transitions += [transition] rule_name = prefix+'_'+spec_string # To see the intermediate output as a rule table (can use RuleTableToTree.py to load it): #WriteRuleTable("triangularVonNeumann",total_states,transitions,golly.getdir('rules')+rule_name+'_asTable.table') # -- make some icons -- palette=[[0,0,0],[0,155,67],[127,0,255],[128,128,128],[185,184,96],[0,100,255],[196,255,254], [254,96,255],[126,125,21],[21,126,125],[255,116,116],[116,255,116],[116,116,255], [228,227,0],[28,255,27],[255,27,28],[0,228,227],[227,0,228],[27,28,255],[59,59,59], [234,195,176],[175,196,255],[171,194,68],[194,68,171],[68,171,194],[72,184,71],[184,71,72], [71,72,184],[169,255,188],[252,179,63],[63,252,179],[179,63,252],[80,9,0],[0,80,9],[9,0,80], [255,175,250],[199,134,213],[115,100,95],[188,163,0],[0,188,163],[163,0,188],[203,73,0], [0,203,73],[73,0,203],[94,189,0],[189,0,94]] if total_states<=16: TriangularTransitionsToRuleTree_SplittingMethod("triangularVonNeumann",total_states,transitions,rule_name) width = 15*(total_states*total_states-1) + 15 # we set the background color height = 22 pixels = [[(0,0,0) for x in range(width)] for y in range(height)] # turmite icons: 0=black, 1=background color, 2=turmite color turmite_big = [[[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,0,1,1,1,1,1,1,2,2,2,2,1,1], [1,1,1,0,1,1,1,1,1,1,1,2,2,1,1], [1,1,1,1,0,1,1,1,1,1,2,1,2,1,1], [1,1,1,1,1,0,1,1,1,2,1,1,2,1,1], [1,1,1,1,1,1,0,1,2,1,1,1,1,1,1], [1,1,1,1,1,1,1,0,1,1,1,1,1,1,1], [1,1,1,1,1,1,2,1,0,1,1,1,1,1,1], [1,1,2,1,1,2,1,1,1,0,1,1,1,1,1], [1,1,2,1,2,1,1,1,1,1,0,1,1,1,1], [1,1,2,2,1,1,1,1,1,1,1,0,1,1,1], [1,1,2,2,2,2,1,1,1,1,1,1,0,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,0,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,0]], [[0,1,1,1,1,1,1,1,2,1,1,1,1,1,1], [1,0,1,1,1,1,1,1,2,1,1,1,1,1,1], [1,1,0,1,1,1,1,1,1,2,1,1,1,1,1], [1,1,1,0,1,1,1,1,1,2,1,1,1,1,1], [1,1,1,1,0,1,1,1,1,1,2,1,1,1,1], [1,1,2,1,1,0,1,1,1,1,2,1,2,1,1], [1,1,2,2,1,1,0,1,1,1,1,2,2,1,1], [1,1,2,2,2,1,1,0,1,1,2,2,2,1,1], [1,1,2,2,1,1,1,1,0,1,1,2,2,1,1], [1,1,2,1,2,1,1,1,1,0,1,1,2,1,1], [1,1,1,1,2,1,1,1,1,1,0,1,1,1,1], [1,1,1,1,1,2,1,1,1,1,1,0,1,1,1], [1,1,1,1,1,2,1,1,1,1,1,1,0,1,1], [1,1,1,1,1,1,2,1,1,1,1,1,1,0,1], [1,1,1,1,1,1,2,1,1,1,1,1,1,1,0]], [[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,0,1,1,2,2,2,2,2,1,1,1,1,1], [1,1,1,0,1,1,2,2,2,1,1,1,1,1,1], [1,1,1,1,0,1,1,2,1,2,2,1,1,1,1], [1,1,1,1,1,0,1,1,1,1,1,2,2,1,1], [1,1,1,1,1,1,0,1,1,1,1,1,1,2,2], [1,1,1,1,1,1,1,0,1,1,1,1,1,1,1], [2,2,1,1,1,1,1,1,0,1,1,1,1,1,1], [1,1,2,2,1,1,1,1,1,0,1,1,1,1,1], [1,1,1,1,2,2,1,2,1,1,0,1,1,1,1], [1,1,1,1,1,1,2,2,2,1,1,0,1,1,1], [1,1,1,1,1,2,2,2,2,2,1,1,0,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,0,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,0]]] turmite_small = [[[0,1,1,1,1,1,1], [1,0,1,2,2,2,1], [1,1,0,1,1,2,1], [1,2,1,0,1,2,1], [1,2,1,1,0,1,1], [1,2,2,2,1,0,1], [1,1,1,1,1,1,0]], [[0,1,1,1,1,1,1], [1,0,1,1,1,2,1], [1,1,0,1,2,2,1], [1,2,1,0,1,2,1], [1,2,2,1,0,1,1], [1,2,1,1,1,0,1], [1,1,1,1,1,1,0]], [[0,1,1,1,1,1,1], [1,0,1,2,2,2,1], [1,1,0,1,2,1,1], [1,1,1,0,1,1,1], [1,1,2,1,0,1,1], [1,2,2,2,1,0,1], [1,1,1,1,1,1,0]]] # TODO: do something about this horrible code for lc in range(n_colors): for uc in range(n_colors): '''draw the cells with no turmites''' golly_state = uc * total_states + lc for row in range(15): for column in range(15): if column>row: # upper pixels[row][(golly_state-1)*15+column] = palette[uc] elif columnrow: # upper pixels[15+row][(golly_state-1)*15+column] = palette[uc] elif columnrow: # upper bg_col = palette[uc] fg_col = palette[n_colors+us] pixels[row][(golly_state-1)*15+column] = [palette[0],bg_col,fg_col][turmite_big[ud][row][column]] elif columnrow: # upper bg_col = palette[uc] fg_col = palette[n_colors+us] pixels[15+row][(golly_state-1)*15+column] = [palette[0],bg_col,fg_col][turmite_small[ud][row][column]] elif columncolumn: # lower bg_col = palette[lc] fg_col = palette[n_colors+ls] pixels[row][(golly_state-1)*15+column] = [palette[0],bg_col,fg_col][turmite_big[ld][row][column]] elif column>row: # upper pixels[row][(golly_state-1)*15+column] = palette[uc] for row in range(7): for column in range(7): if row>column: # lower bg_col = palette[lc] fg_col = palette[n_colors+ls] pixels[15+row][(golly_state-1)*15+column] = [palette[0],bg_col,fg_col][turmite_small[ld][row][column]] elif column>row: # upper pixels[15+row][(golly_state-1)*15+column] = palette[uc] '''draw the cells with a turmite in both halves''' for us in range(n_states): for ud in range(n_dirs): upper = encode(uc,us,ud) golly_state = upper * total_states + lower for row in range(15): for column in range(15): if row>column: # lower bg_col = palette[lc] fg_col = palette[n_colors+ls] pixels[row][(golly_state-1)*15+column] = [palette[0],bg_col,fg_col][turmite_big[ld][row][column]] elif column>row: # upper bg_col = palette[uc] fg_col = palette[n_colors+us] pixels[row][(golly_state-1)*15+column] = [palette[0],bg_col,fg_col][turmite_big[ud][row][column]] for row in range(7): for column in range(7): if row>column: # lower bg_col = palette[lc] fg_col = palette[n_colors+ls] pixels[15+row][(golly_state-1)*15+column] = [palette[0],bg_col,fg_col][turmite_small[ld][row][column]] elif column>row: # upper bg_col = palette[uc] fg_col = palette[n_colors+us] pixels[15+row][(golly_state-1)*15+column] = [palette[0],bg_col,fg_col][turmite_small[ud][row][column]] ConvertTreeToRule(rule_name, total_states, pixels) elif total_states<=128: TriangularTransitionsToRuleTree_CheckerboardMethod("triangularVonNeumann",total_states,transitions,rule_name) width = 15*(total_states*2-2) + 15 # we set the background color height = 22 pixels = [[(0,0,0) for x in range(width)] for y in range(height)] # turmite icons: 0=black, 1=background color, 2=turmite color lower = [[[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,2,0,0,0,0], [0,0,0,1,1,1,1,1,2,2,1,1,0,0,0], [0,0,1,1,2,1,2,2,1,1,1,1,1,0,0], [0,1,1,2,2,2,1,1,1,1,1,1,1,1,0], [1,1,2,2,2,2,2,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]], [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,1,1,1,2,1,1,1,0,0,0,0], [0,0,0,1,1,1,2,2,2,1,1,1,0,0,0], [0,0,1,1,1,2,2,2,2,2,1,1,1,0,0], [0,1,1,1,1,1,1,2,1,1,1,1,1,1,0], [1,1,1,1,1,1,1,2,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,2,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]], [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,2,1,1,1,1,1,1,0,0,0,0], [0,0,0,1,1,2,2,1,1,1,1,1,0,0,0], [0,0,1,1,1,1,1,2,2,1,2,1,1,0,0], [0,1,1,1,1,1,1,1,1,2,2,2,1,1,0], [1,1,1,1,1,1,1,1,2,2,2,2,2,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]]] lower7x7 = [[[0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,1,0,0,0], [0,0,1,1,1,0,0], [0,1,2,2,1,1,0], [1,1,1,1,1,1,1], [0,0,0,0,0,0,0]], [[0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,1,0,0,0], [0,0,1,2,1,0,0], [0,1,2,1,2,1,0], [1,1,1,1,1,1,1], [0,0,0,0,0,0,0]], [[0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,1,0,0,0], [0,0,1,1,1,0,0], [0,1,1,2,2,1,0], [1,1,1,1,1,1,1], [0,0,0,0,0,0,0]]] # (we invert the lower triangle to get the upper triangle) for color in range(n_colors): bg_color = palette[color] # draw the 15x15 icon for row in range(15): for column in range(15): # lower triangle pixels[row][(color-1)*15+column] = \ [palette[0],bg_color,bg_color][lower[0][row][column]] # upper triangle pixels[row][(color+total_states-2)*15+column] = \ [palette[0],bg_color,bg_color][lower[0][13-row][column]] # draw the 7x7 icon for row in range(7): for column in range(7): # lower triangle pixels[15+row][(color-1)*15+column] = \ [palette[0],bg_color,bg_color][lower7x7[0][row][column]] # upper triangle pixels[15+row][(color+total_states-2)*15+column] = \ [palette[0],bg_color,bg_color][lower7x7[0][6-row][column]] for state in range(n_states): fg_color = palette[n_colors+state] for dir in range(n_dirs): # draw the 15x15 icon for row in range(15): for column in range(15): # lower triangle pixels[row][(encode(color,state,dir)-1)*15+column] = \ [palette[0],bg_color,fg_color][lower[dir][row][column]] # upper triangle pixels[row][(encode(color,state,dir)+total_states-2)*15+column] = \ [palette[0],bg_color,fg_color][lower[2-dir][13-row][column]] # draw the 7x7 icon for row in range(7): for column in range(7): # lower triangle pixels[15+row][(encode(color,state,dir)-1)*15+column] = \ [palette[0],bg_color,fg_color][lower7x7[dir][row][column]] # upper triangle pixels[15+row][(encode(color,state,dir)+total_states-2)*15+column] = \ [palette[0],bg_color,fg_color][lower7x7[2-dir][6-row][column]] ConvertTreeToRule(rule_name, total_states, pixels) else: golly.warn('Too many states!') golly.exit() # -- select the rule -- golly.new(rule_name+'-demo.rle') golly.setalgo('RuleLoader') golly.setrule(rule_name) golly.setcell(0,0,encode(0,0,0)) # start with a single turmite golly.show('Created '+rule_name+'.rule and selected that rule.') golly-2.7-src/Scripts/Python/Rule-Generators/RuleTableToTree.py0000644000175000017500000000316012536111364021522 00000000000000import golly import os from glife.ReadRuleTable import * from glife.RuleTree import * from glife.EmulateTriangular import * from glife.EmulateMargolus import * from glife.EmulateOneDimensional import * from glife.EmulateHexagonal import * # ask user to select .table file filename = golly.opendialog('Open a rule table to convert:', 'Rule tables (*.table)|*.table', golly.getdir('rules')) if len(filename) == 0: golly.exit() # user hit Cancel # add new converters here as they become available: Converters = { "vonNeumann":ConvertRuleTableTransitionsToRuleTree, "Moore":ConvertRuleTableTransitionsToRuleTree, "triangularVonNeumann":EmulateTriangular, "triangularMoore":EmulateTriangular, "Margolus":EmulateMargolus, "square4_figure8v":EmulateMargolus, "square4_figure8h":EmulateMargolus, "square4_cyclic":EmulateMargolus, "oneDimensional":EmulateOneDimensional, "hexagonal":EmulateHexagonal, } golly.show("Reading from rule table file...") n_states, neighborhood, transitions = ReadRuleTable(filename) if not neighborhood in Converters: golly.warn("Unsupported neighborhood: "+neighborhood) golly.show('') golly.exit() # all converters now create a .rule file golly.show("Building rule...") rule_name = Converters[neighborhood]( neighborhood, n_states, transitions, filename ) golly.new(rule_name+'-demo.rle') golly.setalgo('RuleLoader') golly.setrule(rule_name) golly.show('Created '+rule_name+'.rule and selected that rule.') golly-2.7-src/Scripts/Python/Rule-Generators/make-ruletree.py0000644000175000017500000000414412536111364021265 00000000000000# Generates a rule tree using a given Python transition function # passed in via the clipboard. # Here's an example function for Conway's Life # (copy all the lines between the triple quotes): ''' # B3/S23: name = "LifeTest" n_states = 2 n_neighbors = 8 # order for 8 neighbors is NW, NE, SW, SE, N, W, E, S, C def transition_function(a): n = a[0]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7] if n==2 and a[8]==1: return 1 if n==3: return 1 return 0 ''' # Another example, but using the vonNeumann neighborhood: ''' name = "ParityNWE" n_states = 5 n_neighbors = 4 # order for 4 neighbors is N, W, E, S, C def transition_function ( s ) : return ( s[0] + s[1] + s[2] ) % 5 ''' import golly from glife.RuleTree import * # exec() only works if all lines end with LF, so we need to convert # any Win line endings (CR+LF) or Mac line endings (CR) to LF CR = chr(13) LF = chr(10) try: exec(golly.getclipstr().replace(CR+LF,LF).replace(CR,LF)) MakeRuleTreeFromTransitionFunction( n_states, n_neighbors, transition_function, golly.getdir("rules")+name+".tree" ) # use name.tree to create name.rule (with no icons); # note that if name.rule already exists then we only replace the info in # the @TREE section to avoid clobbering any other info added by the user ConvertTreeToRule(name, n_states, []) golly.setalgo("RuleLoader") golly.setrule(name) golly.show("Created "+golly.getdir("rules")+name+".rule and switched to that rule.") except: import sys import traceback exception, msg, tb = sys.exc_info() golly.warn(\ '''To use this script, copy a Python format rule definition into the clipboard, e.g.: name = "ParityNWE" n_states = 5 n_neighbors = 4 # order for 4 neighbors is N, W, E, S, C def transition_function ( s ) : return ( s[0] + s[1] + s[2] ) % 5 For more examples, see the script file (right-click on it). ____________________________________________________ A problem was encountered with the supplied rule: '''+ '\n'.join(traceback.format_exception(exception, msg, tb))) golly.exit() golly-2.7-src/Scripts/Python/Rule-Generators/AbsoluteHexTurmite-gen.py0000644000175000017500000003077212536111364023075 00000000000000# Generator for Absolute-movement Hexagonal Turmite rules import golly import random from glife.EmulateHexagonal import * from glife.WriteRuleTable import * # AKT: Python 2.3 doesn't have "set" built-in try: set except NameError: from sets import Set as set prefix = 'AbsoluteHexTurmite' dirs = ['A','B','C','D','E','F'] opposite_dirs = [3,4,5,0,1,2] # http://bytes.com/topic/python/answers/25176-list-subsets get_subsets = lambda items: [[x for (pos,x) in zip(range(len(items)), items) if (2**pos) & switches] for switches in range(2**len(items))] # Generate a random rule, while filtering out the dull ones. # More to try: # - if turmite can get stuck in period-2 cycles then rule is bad (or might it avoid them?) example_spec = "{{{1, 'A', 0}, {0, 'B', 0}}}" ns = 2 nc = 3 while True: # (we break out if ok) example_spec = '{' for state in range(ns): if state > 0: example_spec += ',' example_spec += '{' for color in range(nc): if color > 0: example_spec += ',' new_color = random.randint(0,nc-1) dir_to_turn = dirs[random.randint(0,len(dirs)-1)] # (we don't consider splitting and dying here) new_state = random.randint(0,ns-1) example_spec += '{' + str(new_color) + ",'" + dir_to_turn + "'," + str(new_state) + '}' example_spec += '}' example_spec += '}' is_rule_acceptable = True action_table = eval(example_spec.replace('}',']').replace('{','[')) # does Turmite change at least one color? changes_one = False for state in range(ns): for color in range(nc): if not action_table[state][color][0] == color: changes_one = True if not changes_one: is_rule_acceptable = False # does Turmite write every non-zero color? colors_written = set([]) for state in range(ns): for color in range(nc): colors_written.add(action_table[state][color][0]) if not colors_written==set(range(1,nc)): is_rule_acceptable = False # does turmite get stuck in any subset of states? for subset in get_subsets(range(ns)): if len(subset)==0 or len(subset)==ns: # (just an optimisation) continue leaves_subset = False for state in subset: for color in range(nc): if not action_table[state][color][2] in subset: leaves_subset = True if not leaves_subset: is_rule_acceptable = False break # (just an optimisation) # so was the rule acceptable, in the end? if is_rule_acceptable: break spec = golly.getstring( '''This script will create an Absolute-movement HexTurmite CA for a given specification. Enter a specification string: a curly-bracketed table of n_states rows and n_colors columns, where each entry is a triple of integers. The elements of each triple are: a: the new color of the square b: the direction(s) for the Turmite to move ('A', 'B', .. , 'F') c: the new internal state of the Turmite Example: {{{1, 'A', 0}, {0, 'B', 0}}} Has 1 state and 2 colors. The triple {1,'A',0} says: 1. set the color of the square to 1 2. move in direction 'A' 3. adopt state 0 Enter string: ''', example_spec, 'Enter AbsoluteHexTurmite specification:') # convert the specification string into action_table[state][color] # (convert Mathematica code to Python and run eval) action_table = eval(spec.replace('}',']').replace('{','[')) n_states = len(action_table) n_colors = len(action_table[0]) # (N.B. The terminology 'state' here refers to the internal state of the finite # state machine that each Turmite is using, not the contents of each Golly # cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The # actual 'Golly state' in this emulation of Turmites is given by the # "encoding" section below.) n_dirs = 6 # TODO: check table is full and valid total_states = n_colors + n_colors*n_states if total_states > 256: golly.warn("Number of states required exceeds Golly's limit of 256.") golly.exit() # encoding: # (0-n_colors: empty square) def encode(c,s): # turmite on color c in state s return n_colors + n_states*c + s # http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html def flatten(l, ltypes=(list, tuple)): ltype = type(l) l = list(l) i = 0 while i < len(l): while isinstance(l[i], ltypes): if not l[i]: l.pop(i) i -= 1 break else: l[i:i + 1] = l[i] i += 1 return ltype(l) # convert the string to a form we can embed in a filename spec_string = '_'.join(map(str,flatten(action_table))) # (ambiguous but we have to try something) not_arriving_from_here = [range(n_colors) for i in range(n_dirs)] # (we're going to modify them) for color in range(n_colors): for state in range(n_states): moveset = action_table[state][color][1] for iMove,move in enumerate(dirs): if not move in moveset: # didn't turn this way not_arriving_from_here[opposite_dirs[iMove]] += [encode(color,state)] # What states leave output_color behind? leaving_color_behind = {} for output_color in range(n_colors): leaving_color_behind[output_color] = [output_color] # (no turmite present) for state in range(n_states): for color in range(n_colors): if action_table[state][color][0]==output_color: leaving_color_behind[output_color] += [encode(color,state)] # we can't build the rule tree directly so we collect the transitions ready for emulation transitions = [] # A single turmite is entering this square: for s in range(n_states): for dir in range(n_dirs): # collect all the possibilities for a turmite to arrive in state s from direction dir inputs = [] for state in range(n_states): for color in range(n_colors): if action_table[state][color][2]==s: if dirs[opposite_dirs[dir]] in action_table[state][color][1]: inputs += [encode(color,state)] if len(inputs)>0: for central_color in range(n_colors): # output the required transition ### AKT: this code causes syntax error in Python 2.3: ### transition = [leaving_color_behind[central_color]] + \ ### [ inputs if i==dir else not_arriving_from_here[i] for i in range(n_dirs) ] + \ ### [ [encode(central_color,s)] ] transition = [leaving_color_behind[central_color]] for i in range(n_dirs): if i==dir: transition.append(inputs) else: transition.append(not_arriving_from_here[i]) transition += [ [encode(central_color,s)] ] transitions += [transition] # default: square is left with no turmite present for output_color,inputs in leaving_color_behind.items(): transition = [inputs]+[range(total_states)]*n_dirs+[[output_color]] transitions += [transition] rule_name = prefix+'_'+spec_string # To see the intermediate output as a rule table: #WriteRuleTable('hexagonal',total_states,transitions,golly.getdir('rules')+rule_name+'_asTable.table') HexagonalTransitionsToRuleTree('hexagonal',total_states,transitions,rule_name) # -- make some icons -- palette=[[0,0,0],[0,155,67],[127,0,255],[128,128,128],[185,184,96],[0,100,255],[196,255,254], [254,96,255],[126,125,21],[21,126,125],[255,116,116],[116,255,116],[116,116,255], [228,227,0],[28,255,27],[255,27,28],[0,228,227],[227,0,228],[27,28,255],[59,59,59], [234,195,176],[175,196,255],[171,194,68],[194,68,171],[68,171,194],[72,184,71],[184,71,72], [71,72,184],[169,255,188],[252,179,63],[63,252,179],[179,63,252],[80,9,0],[0,80,9],[9,0,80], [255,175,250],[199,134,213],[115,100,95],[188,163,0],[0,188,163],[163,0,188],[203,73,0], [0,203,73],[73,0,203],[94,189,0],[189,0,94]] width = 31*(total_states-1) height = 53 pixels = [[(0,0,0) for x in range(width)] for y in range(height)] huge = [[0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]] big = [[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [1,1,1,1,1,1,2,2,2,1,1,1,0,0,0], [0,1,1,1,1,2,2,2,2,2,1,1,0,0,0], [0,1,1,1,2,2,2,2,2,2,2,1,1,0,0], [0,0,1,1,2,2,2,2,2,2,2,1,1,0,0], [0,0,1,1,2,2,2,2,2,2,2,1,1,1,0], [0,0,0,1,1,2,2,2,2,2,1,1,1,1,0], [0,0,0,1,1,1,2,2,2,1,1,1,1,1,1], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0]] small = [[0,1,1,0,0,0,0], [1,1,1,1,1,0,0], [1,1,2,2,2,1,0], [0,1,2,2,2,1,0], [0,1,2,2,2,1,1], [0,0,1,1,1,1,1], [0,0,0,0,1,1,0]] for color in range(n_colors): bg = palette[color] for row in range(31): for column in range(31): pixels[row][(color-1)*31+column] = [palette[0],bg,bg][huge[row][column]] for row in range(15): for column in range(15): pixels[31+row][(color-1)*31+column] = [palette[0],bg,bg][big[row][column]] for row in range(7): for column in range(7): pixels[46+row][(color-1)*31+column] = [palette[0],bg,bg][small[row][column]] for state in range(n_states): fg = palette[n_colors+state] # draw the 31x31 icon for row in range(31): for column in range(31): pixels[row][(encode(color,state)-1)*31+column] = [palette[0],bg,fg][huge[row][column]] # draw the 15x15 icon for row in range(15): for column in range(15): pixels[31+row][(encode(color,state)-1)*31+column] = [palette[0],bg,fg][big[row][column]] # draw the 7x7 icon for row in range(7): for column in range(7): pixels[46+row][(encode(color,state)-1)*31+column] = [palette[0],bg,fg][small[row][column]] # use rule_name.tree and icon info to create rule_name.rule ConvertTreeToRule(rule_name, total_states, pixels) # -- select the new rule -- golly.new(rule_name+'-demo.rle') golly.setalgo('RuleLoader') golly.setrule(rule_name) golly.setcell(0,0,encode(0,0)) # start with a single turmite golly.show('Created '+rule_name+'.rule and selected that rule.') golly-2.7-src/Scripts/Python/Rule-Generators/icon-importer.py0000644000175000017500000004635412536111364021323 00000000000000# Import any icons for the current rule so the user can edit them # and when finished run icon-exporter.py. # Author: Andrew Trevorrow (andrew@trevorrow.com), Feb 2013. import golly as g from glife import getminbox, pattern from glife.text import make_text from glife.BuiltinIcons import circles, diamonds, hexagons, triangles from colorsys import hsv_to_rgb import os iconinfo31 = [] # info for 31x31 icons iconinfo15 = [] # info for 15x15 icons iconinfo7 = [] # info for 7x7 icons iconcolors = [] # list of (r,g,b) colors used in ALL icon sizes colorstate = {} # dictionary for mapping (r,g,b) colors to cell states # -------------------------------------------------------------------- def parse_hex(hexstr): # parse a string like "FF00EE" or "FFFF0000EEEE" R, G, B = (0, 0, 0) if len(hexstr) == 6: R = int(hexstr[0:2],16) G = int(hexstr[2:4],16) B = int(hexstr[4:6],16) elif len(hexstr) == 12: # only use upper 2 hex digits R = int(hexstr[0:2],16) G = int(hexstr[4:6],16) B = int(hexstr[8:10],16) else: g.warn("Unexpected hex string: " + hexstr) return (R,G,B) # -------------------------------------------------------------------- def use_builtin_icons(shape): global iconinfo31, iconinfo15, iconinfo7, iconcolors if shape == "circles": lines = circles.split('\n') if shape == "diamonds": lines = diamonds.split('\n') if shape == "hexagons": lines = hexagons.split('\n') if shape == "triangles": lines = triangles.split('\n') xpmcount = 0 width = 0 height = 0 num_colors = 0 chars_per_pixel = 0 iconinfo = [] colordict = {} iconcolors = [] for line in lines: if line == "XPM": xpmcount = 1 iconinfo = [] colordict = {} elif xpmcount > 0 and line[0] == "\"": # extract the stuff inside double quotes, ignoring anything after 2nd one line = line.lstrip("\"").split("\"")[0] if xpmcount == 1: # parse "width height num_colors chars_per_pixel" header = line.split() width = int(header[0]) height = int(header[1]) num_colors = int(header[2]) chars_per_pixel = int(header[3]) iconinfo.append(width) iconinfo.append(height) iconinfo.append(num_colors) iconinfo.append(chars_per_pixel) elif xpmcount > 1 and xpmcount <= 1 + num_colors: # parse color index line like "A c #FFFFFF" or "AB c #FF009900BB00" key, c, hexrgb = line.split() rgb = parse_hex(hexrgb.lstrip("#")) if not rgb in iconcolors: iconcolors.append(rgb) colordict[key] = rgb if xpmcount == 1 + num_colors: iconinfo.append(colordict) elif xpmcount <= 1 + num_colors + height: # simply append pixel data in line like "......AAA......" iconinfo.append(line) if xpmcount == 1 + num_colors + height: if width == 31: iconinfo31 = iconinfo if width == 15: iconinfo15 = iconinfo if width == 7: iconinfo7 = iconinfo xpmcount = 0 # skip any extra lines else: xpmcount += 1 # -------------------------------------------------------------------- def import_icons(rulename): global iconinfo31, iconinfo15, iconinfo7, iconcolors # replace any illegal filename chars with underscores rulename = rulename.replace("/","_").replace("\\","_") rulepath = g.getdir("rules") + rulename + ".rule" if not os.path.isfile(rulepath): rulepath = g.getdir("app") + "Rules/" + rulename + ".rule" if not os.path.isfile(rulepath): # there is no .rule file return try: # open in universal newline mode to handle LF, CR, or CR+LF rulefile = open(rulepath,"rU") except: g.exit("Failed to open .rule file: " + rulepath) foundicons = False xpmcount = 0 width = 0 height = 0 num_colors = 0 chars_per_pixel = 0 iconinfo = [] colordict = {} iconcolors = [] # WARNING: The code below must agree with how Golly looks for icon info # (see LoadRuleInfo and ParseIcons in wxlayer.cpp). In particular, if # there are multiple @ICONS sections then only the 1st one is used. for line in rulefile: if foundicons and line.startswith("@"): # start of another section (possibly another @ICONS section) break line = line.rstrip("\n") if line == "@ICONS": foundicons = True elif foundicons and line == "XPM": xpmcount = 1 iconinfo = [] colordict = {} elif foundicons and line in ("circles","diamonds","hexagons","triangles"): use_builtin_icons(line) # don't break (agrees with Golly) elif xpmcount > 0 and line[0] == "\"": # extract the stuff inside double quotes, ignoring anything after 2nd one line = line.lstrip("\"").split("\"")[0] if xpmcount == 1: # parse "width height num_colors chars_per_pixel" header = line.split() width = int(header[0]) height = int(header[1]) num_colors = int(header[2]) chars_per_pixel = int(header[3]) iconinfo.append(width) iconinfo.append(height) iconinfo.append(num_colors) iconinfo.append(chars_per_pixel) elif xpmcount > 1 and xpmcount <= 1 + num_colors: # parse color index line like "A c #FFFFFF" or "AB c #FF009900BB00" key, c, hexrgb = line.split() rgb = parse_hex(hexrgb.lstrip("#")) if not rgb in iconcolors: iconcolors.append(rgb) colordict[key] = rgb if xpmcount == 1 + num_colors: iconinfo.append(colordict) elif xpmcount <= 1 + num_colors + height: # simply append pixel data in line like "......AAA......" iconinfo.append(line) if xpmcount == 1 + num_colors + height: if width == 31: iconinfo31 = iconinfo if width == 15: iconinfo15 = iconinfo if width == 7: iconinfo7 = iconinfo xpmcount = 0 # skip any extra lines else: xpmcount += 1 rulefile.close() # -------------------------------------------------------------------- def check_for_shared_rule(rulename): # rulename has at least one hyphen so get all chars before the last hyphen prefix = rulename.rsplit('-',1)[0] # replace any illegal filename chars with underscores filename = prefix.replace("/","_").replace("\\","_") + "-shared.rule" rulepath = g.getdir("rules") + filename if not os.path.isfile(rulepath): rulepath = g.getdir("app") + "Rules/" + filename if not os.path.isfile(rulepath): # there is no prefix-shared.rule file return "" # ask user if they would prefer to edit icons in shared file sharedname = prefix + "-shared" try: answer = g.getstring("There are no icons in " + rulename + ".rule.\n" + "Would you prefer to edit the icons in " + sharedname + ".rule?", "Yes", "Edit icons in shared rule?") except: # user hit Cancel (which would normally abort script) return "" if len(answer) == 0 or (answer[0] != "Y" and answer[0] != "y"): return "" return sharedname # user said Yes # -------------------------------------------------------------------- def draw_line(x1, y1, x2, y2, state = 1): # draw a line of cells in given state from x1,y1 to x2,y2 g.setcell(x1, y1, state) if x1 == x2 and y1 == y2: return dx = x2 - x1 ax = abs(dx) * 2 sx = 1 if dx < 0: sx = -1 dy = y2 - y1 ay = abs(dy) * 2 sy = 1 if dy < 0: sy = -1 if ax > ay: d = ay - (ax / 2) while x1 != x2: g.setcell(x1, y1, state) if d >= 0: y1 += sy d -= ax x1 += sx d += ay else: d = ax - (ay / 2) while y1 != y2: g.setcell(x1, y1, state) if d >= 0: x1 += sx d -= ay y1 += sy d += ax g.setcell(x2, y2, state) # -------------------------------------------------------------------- def color_text(string, extrastate): t = make_text(string, "mono") bbox = getminbox(t) # convert two-state pattern to multi-state and set state to extrastate mlist = [] tlist = list(t) for i in xrange(0, len(tlist), 2): mlist.append(tlist[i]) mlist.append(tlist[i+1]) mlist.append(extrastate) if len(mlist) % 2 == 0: mlist.append(0) p = pattern(mlist) return p, bbox.wd, bbox.ht # -------------------------------------------------------------------- def init_colors(): global iconcolors, colorstate if len(iconcolors) > 240: g.exit("The imported icons use too many colors!") # start with gradient from white to black (this makes it easier to # copy grayscale icons from one rule to another rule) s = 1 g.setcolors([s,255,255,255]) colorstate[(255,255,255)] = s s += 1 graylevel = 256 while graylevel > 0: graylevel -= 32 g.setcolors([s, graylevel, graylevel, graylevel]) colorstate[(graylevel, graylevel, graylevel)] = s s += 1 # now add all the colors used in the imported icons (unless added above) for rgb in iconcolors: if not rgb in colorstate: R,G,B = rgb g.setcolors([s,R,G,B]) colorstate[rgb] = s s += 1 # finally add rainbow colors in various shades (bright, pale, dark) for hue in xrange(12): if s > 255: break R,G,B = hsv_to_rgb(hue/12.0, 1.0, 1.0) g.setcolors([s, int(255*R), int(255*G), int(255*B)]) s += 1 for hue in xrange(12): if s > 255: break R,G,B = hsv_to_rgb(hue/12.0, 0.5, 1.0) g.setcolors([s, int(255*R), int(255*G), int(255*B)]) s += 1 for hue in xrange(12): if s > 255: break R,G,B = hsv_to_rgb(hue/12.0, 1.0, 0.5) g.setcolors([s, int(255*R), int(255*G), int(255*B)]) s += 1 # return the 50% gray state (used for drawing boxes and text) return colorstate[(128,128,128)] # -------------------------------------------------------------------- def draw_icon_boxes(numicons, linestate): for i in xrange(numicons): x = -1 + i*32 y = -1 # draw boxes for 31x31 icons draw_line(x, y, x, y+32, linestate) draw_line(x, y, x+32, y, linestate) draw_line(x+32, y, x+32, y+32, linestate) draw_line(x, y+32, x+32, y+32, linestate) # draw boxes for 15x15 icons draw_line(x, y+32, x, y+32+16, linestate) draw_line(x, y+32+16, x+16, y+32+16, linestate) draw_line(x+16, y+32, x+16, y+32+16, linestate) # draw boxes for 7x7 icons draw_line(x, y+32+16, x, y+32+16+8, linestate) draw_line(x, y+32+16+8, x+8, y+32+16+8, linestate) draw_line(x+8, y+32+16, x+8, y+32+16+8, linestate) # show state number above top row of icons t, twd, tht = color_text(str(i+1), linestate) t.put(x + 32/2 - twd/2, y - 2 - tht) # -------------------------------------------------------------------- def draw_icons(iconinfo, transparent): global colorstate if len(iconinfo) == 0: return width = iconinfo[0] height = iconinfo[1] num_colors = iconinfo[2] chars_per_pixel = iconinfo[3] colordict = iconinfo[4] pos = 5 numicons = height/width for i in xrange(numicons): x = i*32 y = 0 if width == 15: y = 32 if width == 7: y = 48 for row in xrange(width): pxls = iconinfo[pos] pos += 1 for col in xrange(width): offset = col*chars_per_pixel key = pxls[offset : offset + chars_per_pixel] if not key in colordict: g.exit("Unexpected key in icon data: " + key) rgb = colordict[key] if rgb != transparent: g.setcell(x+col, y+row, colorstate[rgb]) # -------------------------------------------------------------------- def create31x31icons(): # scale up the 15x15 bitmaps into 31x31 bitmaps using a simple # algorithm that conserves any vertical or horizontal symmetry global iconinfo15 width = 15 middle = 7 # middle row or column in 15x15 icon height = iconinfo15[1] numicons = height/width for i in xrange(numicons): x = i*32 y = 32 for row in xrange(width): for col in xrange(width): state = g.getcell(x+col, y+row) if state > 0: if row == middle and col == middle: # expand middle cell into 9 cells xx = i*32+15 yy = 15 g.setcell(xx, yy, state) g.setcell(xx, yy+1, state) g.setcell(xx, yy-1, state) g.setcell(xx+1, yy, state) g.setcell(xx-1, yy, state) g.setcell(xx+1, yy+1, state) g.setcell(xx+1, yy-1, state) g.setcell(xx-1, yy+1, state) g.setcell(xx-1, yy-1, state) elif row == middle: # expand cell in middle row into 6 cells xx = i*32+col*2 yy = row*2 if col > middle: xx += 1 g.setcell(xx, yy, state) g.setcell(xx, yy+1, state) g.setcell(xx+1, yy, state) g.setcell(xx+1, yy+1, state) g.setcell(xx, yy+2, state) g.setcell(xx+1, yy+2, state) elif col == middle: # expand cell in middle column into 6 cells xx = i*32+col*2 yy = row*2 if row > middle: yy += 1 g.setcell(xx, yy, state) g.setcell(xx, yy+1, state) g.setcell(xx+1, yy, state) g.setcell(xx+1, yy+1, state) g.setcell(xx+2, yy, state) g.setcell(xx+2, yy+1, state) else: # expand all other cells into 4 cells xx = i*32+col*2 yy = row*2 if col > middle: xx += 1 if row > middle: yy += 1 g.setcell(xx, yy, state) g.setcell(xx, yy+1, state) g.setcell(xx+1, yy, state) g.setcell(xx+1, yy+1, state) # -------------------------------------------------------------------- def create_smaller_icons(big, small): # scale down the big x big bitmaps into small x small bitmaps # using a simple sampling algorithm global iconinfo15, iconinfo31 if big == 15: numicons = iconinfo15[1] / 15 ybig = 32 else: # big = 31 numicons = iconinfo31[1] / 31 ybig = 0 if small == 7: y = 48 else: # small = 15 y = 32 sample = big / small offset = sample / 2 for i in xrange(numicons): x = i*32 for row in xrange(small): for col in xrange(small): state = g.getcell(x + offset + col*sample, ybig + offset + row*sample) if state > 0: g.setcell(x+col, y+row, state) # -------------------------------------------------------------------- def multi_color_icons(iconcolors): # return True if at least one icon color isn't a shade of gray for R,G,B in iconcolors: if R != G or G != B: return True # grayscale return False # -------------------------------------------------------------------- # check that a layer is available if g.numlayers() == g.maxlayers(): g.exit("You need to delete a layer.") # WARNING: changing this prefix will require same change in icon-exporter.py layerprefix = "imported icons for " if g.getname().startswith(layerprefix): g.exit("You probably meant to run icon-exporter.py.") g.addlayer() rulename = g.getrule().split(":")[0] # search for rulename.rule and import any icon data (also builds iconcolors) import_icons(rulename) if len(iconcolors) == 0 and ("-" in rulename) and not (rulename.endswith("-shared")): # rulename.rule has no icons and rulename contains a hyphen, so # check if prefix-shared.rule exists and ask user if they want to edit # the icons in that file sharedname = check_for_shared_rule(rulename) if len(sharedname) > 0: rulename = sharedname import_icons(rulename) iconnote = "" if len(iconcolors) == 0: iconnote = "There are currently no icons for this rule.\n\n" # check if icons are grayscale grayscale_icons = not multi_color_icons(iconcolors) g.new(layerprefix + rulename) livestates = g.numstates() - 1 deadcolor = g.getcolors(0) deadrgb = (deadcolor[1], deadcolor[2], deadcolor[3]) # switch to a Generations rule so we can have lots of colors g.setrule("//256") if grayscale_icons and deadrgb == (255,255,255): # if icons are grayscale and state 0 color was white then switch # to black background to avoid confusion (ie. we want black pixels # to be transparent) g.setcolors([0,0,0,0]) else: g.setcolors(deadcolor) graystate = init_colors() # if icons are grayscale then change deadrgb to black so that draw_icons # will treat black pixels as transparent if grayscale_icons: deadrgb = (0,0,0) draw_icon_boxes(livestates, graystate) draw_icons(iconinfo31, deadrgb) draw_icons(iconinfo15, deadrgb) draw_icons(iconinfo7, deadrgb) # create missing icons by scaling up/down the existing icons if len(iconinfo31) == 0 and len(iconinfo15) > 0: create31x31icons() iconnote += "The 31x31 icons were created by scaling up the 15x15 icons.\n\n" if len(iconinfo15) == 0 and len(iconinfo31) > 0: create_smaller_icons(31, 15) iconnote += "The 15x15 icons were created by scaling down the 31x31 icons.\n\n" if len(iconinfo7) == 0: if len(iconinfo15) > 0: create_smaller_icons(15, 7) iconnote += "The 7x7 icons were created by scaling down the 15x15 icons.\n\n" elif len(iconinfo31) > 0: create_smaller_icons(31, 7) iconnote += "The 7x7 icons were created by scaling down the 31x31 icons.\n\n" g.setoption("showlayerbar",True) g.setoption("showallstates",True) g.setoption("showicons",False) g.fit() g.update() g.note(iconnote + "Edit the icons and then run icon-exporter.py.") golly-2.7-src/Scripts/Python/Rule-Generators/Turmite-gen.py0000644000175000017500000006706012536111364020731 00000000000000# Generator for Turmite rules # # Following work of Ed Pegg Jr. # specifically the Mathematica notebook linked-to from here: # http://www.mathpuzzle.com/26Mar03.html # # contact: tim.hutton@gmail.com import golly import random from glife.RuleTree import * dirs=['N','E','S','W'] opposite_dirs=[2,3,0,1] # index of opposite direction turn={ # index of new direction 1:[0,1,2,3], # no turn 2:[1,2,3,0], # right 4:[2,3,0,1], # u-turn 8:[3,0,1,2], # left } prefix = 'Turmite' # N.B. Translating from Langtons-Ant-nColor to Turmite is easy: # e.g. LLRR is (1 state, 4 color) {{{1,8,0},{2,8,0},{3,2,0},{0,2,0}}} # but translating the other way is only possible if the Turmite has # exactly 1 state and only moves left or right EdPeggJrTurmiteLibrary = [ # source: http://demonstrations.wolfram.com/Turmites/ # Translated into his later notation: 1=noturn, 2=right, 4=u-turn, 8=left # (old notation was: 0=noturn,1=right,-1=left) # (all these are 2-color patterns) "{{{1, 2, 0}, {0, 8, 0}}}", # 1: Langton's ant "{{{1, 2, 0}, {0, 1, 0}}}", # 2: binary counter "{{{0, 8, 1}, {1, 2, 1}}, {{1, 1, 0}, {1, 1, 1}}}", # 3: (filled triangle) "{{{0, 1, 1}, {0, 8, 1}}, {{1, 2, 0}, {0, 1, 1}}}", # 4: spiral in a box "{{{0, 2, 1}, {0, 8, 0}}, {{1, 8, 1}, {0, 2, 0}}}", # 5: stripe-filled spiral "{{{0, 2, 1}, {0, 8, 0}}, {{1, 8, 1}, {1, 1, 0}}}", # 6: stepped pyramid "{{{0, 2, 1}, {0, 1, 1}}, {{1, 2, 1}, {1, 8, 0}}}", # 7: contoured island "{{{0, 2, 1}, {0, 2, 1}}, {{1, 1, 0}, {0, 2, 1}}}", # 8: woven placemat "{{{0, 2, 1}, {1, 2, 1}}, {{1, 8, 1}, {1, 8, 0}}}", # 9: snowflake-ish (mimics Jordan's ice-skater) "{{{1, 8, 0}, {0, 1, 1}}, {{0, 8, 0}, {0, 8, 1}}}", # 10: slow city builder "{{{1, 8, 0}, {1, 2, 1}}, {{0, 2, 0}, {0, 8, 1}}}", # 11: framed computer art "{{{1, 8, 0}, {1, 2, 1}}, {{0, 2, 1}, {1, 8, 0}}}", # 12: balloon bursting (makes a spreading highway) "{{{1, 8, 1}, {0, 8, 0}}, {{1, 1, 0}, {0, 1, 0}}}", # 13: makes a horizontal highway "{{{1, 8, 1}, {0, 8, 0}}, {{1, 2, 1}, {1, 2, 0}}}", # 14: makes a 45 degree highway "{{{1, 8, 1}, {0, 8, 1}}, {{1, 2, 1}, {0, 8, 0}}}", # 15: makes a 45 degree highway "{{{1, 8, 1}, {0, 1, 0}}, {{1, 1, 0}, {1, 2, 0}}}", # 16: spiral in a filled box "{{{1, 8, 1}, {0, 2, 0}}, {{0, 8, 0}, {0, 8, 0}}}", # 17: glaciers "{{{1, 8, 1}, {1, 8, 1}}, {{1, 2, 1}, {0, 1, 0}}}", # 18: golden rectangle! "{{{1, 8, 1}, {1, 2, 0}}, {{0, 8, 0}, {0, 8, 0}}}", # 19: fizzy spill "{{{1, 8, 1}, {1, 2, 1}}, {{1, 1, 0}, {0, 1, 1}}}", # 20: nested cabinets "{{{1, 1, 1}, {0, 8, 1}}, {{1, 2, 0}, {1, 1, 1}}}", # 21: (cross) "{{{1, 1, 1}, {0, 1, 0}}, {{0, 2, 0}, {1, 8, 0}}}", # 22: saw-tipped growth "{{{1, 1, 1}, {0, 1, 1}}, {{1, 2, 1}, {0, 1, 0}}}", # 23: curves in blocks growth "{{{1, 1, 1}, {0, 2, 0}}, {{0, 8, 0}, {0, 8, 0}}}", # 24: textured growth "{{{1, 1, 1}, {0, 2, 1}}, {{1, 8, 0}, {1, 2, 0}}}", # 25: (diamond growth) "{{{1, 1, 1}, {1, 8, 0}}, {{1, 2, 1}, {0, 1, 0}}}", # 26: coiled rope "{{{1, 2, 0}, {0, 8, 1}}, {{1, 8, 0}, {0, 1, 1}}}", # 27: (growth) "{{{1, 2, 0}, {0, 8, 1}}, {{1, 8, 0}, {0, 2, 1}}}", # 28: (square spiral) "{{{1, 2, 0}, {1, 2, 1}}, {{0, 1, 0}, {0, 1, 1}}}", # 29: loopy growth with holes "{{{1, 2, 1}, {0, 8, 1}}, {{1, 1, 0}, {0, 1, 0}}}", # 30: Langton's Ant drawn with squares "{{{1, 2, 1}, {0, 2, 0}}, {{0, 8, 1}, {1, 8, 0}}}", # 31: growth with curves and blocks "{{{1, 2, 1}, {0, 2, 0}}, {{0, 1, 0}, {1, 2, 1}}}", # 32: distracted spiral builder "{{{1, 2, 1}, {0, 2, 1}}, {{1, 1, 0}, {1, 1, 1}}}", # 33: cauliflower stalk (45 deg highway) "{{{1, 2, 1}, {1, 8, 1}}, {{1, 2, 1}, {0, 2, 0}}}", # 34: worm trails (eventually turns cyclic!) "{{{1, 2, 1}, {1, 1, 0}}, {{1, 1, 0}, {0, 1, 1}}}", # 35: eventually makes a two-way highway! "{{{1, 2, 1}, {1, 2, 0}}, {{0, 1, 0}, {0, 1, 0}}}", # 36: almost symmetric mould bloom "{{{1, 2, 1}, {1, 2, 0}}, {{0, 2, 0}, {1, 1, 1}}}", # 37: makes a 1 in 2 gradient highway "{{{1, 2, 1}, {1, 2, 1}}, {{1, 8, 1}, {0, 2, 0}}}", # 38: immediately makes a 1 in 3 highway "{{{0, 2, 1}, {1, 2, 1}}, {{0, 8, 2}, {0, 8, 0}}, {{1, 2, 2}, {1, 8, 0}}}", # 39: squares and diagonals growth "{{{1, 8, 1}, {0, 1, 0}}, {{0, 2, 2}, {1, 8, 0}}, {{1, 2, 1}, {1, 1, 0}}}", # 40: streak at approx. an 8.1 in 1 gradient "{{{1, 8, 1}, {0, 1, 2}}, {{0, 2, 2}, {1, 1, 1}}, {{1, 2, 1}, {1, 1, 0}}}", # 41: streak at approx. a 1.14 in 1 gradient "{{{1, 8, 1}, {1, 8, 1}}, {{1, 1, 0}, {0, 1, 2}}, {{0, 8, 1}, {1, 1, 1}}}", # 42: maze-like growth "{{{1, 8, 2}, {0, 2, 0}}, {{1, 8, 0}, {0, 2, 0}}, {{0, 8, 0}, {0, 8, 1}}}", # 43: growth by cornices "{{{1, 2, 0}, {0, 2, 2}}, {{0, 8, 0}, {0, 2, 0}}, {{0, 1, 1}, {1, 8, 0}}}", # 44: makes a 1 in 7 highway "{{{1, 2, 1}, {0, 8, 0}}, {{1, 2, 2}, {0, 1, 0}}, {{1, 8, 0}, {0, 8, 0}}}", # 45: makes a 4 in 1 highway # source: http://www.mathpuzzle.com/Turmite5.nb # via: http://www.mathpuzzle.com/26Mar03.html # "I wondered what would happen if a turmite could split as an action... say Left and Right. # In addition, I added the rule that when two turmites met, they annihilated each other. # Some interesting patterns came out from my initial study. My main interest is finding # turmites that will grow for a long time, then self-annihilate." "{{{1, 8, 0}, {1, 2, 1}}, {{0, 10, 0}, {0, 8, 1}}}", # 46: stops at 11 gens "{{{1, 8, 0}, {1, 2, 1}}, {{1, 10, 0}, {1, 8, 1}}}", # 47: stops at 12 gens "{{{1, 15, 0}, {0, 2, 1}}, {{0, 10, 0}, {0, 8, 1}}}", # 48: snowflake-like growth "{{{1, 2, 0}, {0, 15, 0}}}", # 49: blob growth "{{{1, 3, 0}, {0, 3, 0}}}", # 50: (spiral) - like SDSR-Loop on a macro level "{{{1, 3, 0}, {0, 1, 0}}}", # 51: (spiral) "{{{1, 10, 0}, {0, 1, 0}}}", # 52: snowflake-like growth "{{{1, 10, 1}, {0, 1, 1}}, {{0, 2, 0}, {0, 0, 0}}}", # 53: interesting square growth "{{{1, 10, 1}, {0, 5, 1}}, {{1, 2, 0}, {0, 8, 0}}}", # 54: interesting square growth "{{{1, 2, 0}, {0, 1, 1}}, {{1, 2, 0}, {0, 6, 0}}}", # 55: growth "{{{1, 2, 0}, {1, 1, 1}}, {{0, 2, 0}, {0, 11, 0}}}", # 56: wedge growth with internal snakes "{{{1, 2, 1}, {0, 2, 1}}, {{1, 15, 0}, {1, 8, 0}}}", # 57: divided square growth "{{{1, 2, 0}, {2, 8, 2}, {1, 1, 1}}, {{1, 1, 2}, {0, 2, 1}, {2, 8, 1}}, {{0, 11, 0}, {1, 1, 1}, {0, 2, 2}}}", # 58: semi-chaotic growth with spikes "{{{1, 2, 0}, {2, 8, 2}, {2, 1, 1}}, {{1, 1, 2}, {1, 1, 1}, {1, 8, 1}}, {{2, 10, 0}, {2, 8, 1}, {2, 8, 2}}}" # 59: halts after 204 gens (256 non-zero cells written) ] # N.B. the images in the demonstration project http://demonstrations.wolfram.com/Turmites/ # are mirrored - e.g. Langton's ant turns left instead of right. # (Also example #45 isn't easily accessed in the demonstration, you need to open both 'advanced' controls, # then type 45 in the top text edit box, then click in the bottom one.) # just some discoveries of my own, discovered through random search TimHuttonTurmiteLibrary = [ # One-turmite effects: "{{{1,2,1},{0,4,1}},{{1,1,0},{0,8,0}}}", # makes a period-12578 gradient 23 in 29 speed c/340 highway (what is the highest period highway?) "{{{0,2,1},{0,8,0}},{{1,8,1},{1,4,0}}}", # makes a period-68 (speed c/34) glider (what is the highest period glider?) # (or alternatively, what are the *slowest* highways and gliders?) "{{{1,4,1},{1,2,1}},{{1,8,0},{1,1,1}}}", # another ice-skater rule, makes H-fractal-like shapes "{{{1,1,1},{0,2,1}},{{0,2,1},{1,8,0}}}", # period-9 glider "{{{1,2,1},{0,8,1}},{{1,4,0},{1,8,0}}}", # another ice-skater "{{{1,4,1},{1,8,1}},{{1,4,0},{0,1,0}}}", # Langton's ant (rot 45) on a 1 background but maze-like on a 0 background "{{{0,2,1},{0,8,1}},{{1,1,0},{1,8,1}}}", # slow ice-skater makes furry shape "{{{1,8,0},{1,1,1}},{{1,8,0},{0,2,1}}}", # busy beaver (goes cyclic) <50k "{{{0,8,1},{1,8,1}},{{1,2,1},{0,2,0}}}", # interesting texture "{{{1,1,1},{0,1,0}},{{1,2,0},{1,2,1}}}", # period-17 1 in 3 gradient highway (but needs debris to get started...) "{{{0,2,1},{1,8,1}},{{1,4,0},{0,2,1}}}", # period-56 speed-28 horizontal highway "{{{1,8,0},{0,1,1}},{{1,2,0},{1,8,0}}}", # somewhat loose growth # Some two-turmite rules below: (ones that are dull with 1 turmite but fun with 2) # Guessing this behaviour may be quite common, because turmites alternate between black-and-white squares # on a checkerboard. To discover these I use a turmite testbed which includes a set of turmite pairs as # starting conditions. "{{{1,4,0},{0,1,1}},{{1,4,1},{0,2,0}}}", # loose loopy growth (but only works with two ants together, e.g. 2,2) "{{{0,1,1},{0,4,0}},{{1,2,0},{1,8,1}}}", # spiral growth on its own but changing density + structure with 2 turmites, e.g. 2,2 "{{{1,2,1},{1,1,0}},{{1,1,0},{0,2,1}}}", # extender on its own but mould v. aerials with 2, e.g. 2,3 "{{{1,1,1},{0,8,1}},{{1,8,0},{0,8,0}}}", # together they build a highway ] ''' We can scale any tumite by a factor of N: (need n_states+N new states) e.g. for the turmite: "{{{1,2,0},{0,1,0}}}", # normal binary counter "{{{1,2,1},{0,1,1}},{{0,1,0},{0,0,0}}}", # scale 2 binary counter (sparse version) (Takes twice as long.) "{{{1,2,1},{0,1,1}},{{0,1,2},{0,0,0}},{{0,1,0},{0,0,0}}}", # scale 3 binary counter, etc. (Takes three times as long.) Note that the state 1+ color 1+ transitions are never used if started on a zero background - we set them to {0,0,0} (die) simply to make this clear. Or you can step these cells. Or redraw them. e.g. for Langton's ant: "{{{1, 2, 0}, {0, 8, 0}}}", # normal Langton's ant "{{{1,2,1},{0,8,1}},{{0,1,0},{0,0,0}}}", # Langton's Ant at scale 2 (sparse version) (See also Ed Pegg Jr.'s rule #30.) This is a bit like Langton's original formulation of his ants, only using 2 colors instead of 3, and with states to keep track of when to turn instead of using color for this. We can rotate any turmites too: (need e.g. 2*n_states states for 45 degree rotation) e.g. for the binary counter: "{{{1,2,0},{0,1,0}}}", # normal binary counter "{{{1,1,1},{0,8,1}},{{0,2,0},{0,0,0}}}", # diagonal counter (turning right on off-steps) "{{{1,4,1},{0,2,1}},{{0,8,0},{0,0,0}}}", # diagonal counter (turning left on off-steps) e.g. for Langton's ant: "{{{1,2,0},{0,8,0}}}", # normal Langton's ant "{{{1,1,1},{0,4,1}},{{0,2,0},{0,0,0}}}", # Langton's ant at 45 degrees (turning right on off-steps) "{{{1,4,1},{0,1,1}},{{0,8,0},{0,0,0}}}", # Langton's ant at 45 degrees (turning left on off-steps) (These take twice as long as the normal versions.) "{{{1,1,1},{0,4,1}},{{0,2,2},{0,0,0}},{{0,1,0},{0,0,0}}}", # knight's move rotated "{{{1,1,1},{0,4,1}},{{0,1,2},{0,0,0}},{{0,2,0},{0,0,0}}}", # knight's move rotated v2 (These take three times as long.) We can increase the number of straight-ahead steps to achieve any angle of highway we want, e.g. "{{{1,1,1},{0,4,1}},{{0,2,2},{0,0,0}},{{0,1,3},{0,0,0}},{{0,1,0},{0,0,0}}}", # long knight's move rotated We can rotate twice, for fun: "{{{1,8,1},{0,2,1}},{{0,2,2},{0,0,0}},{{0,1,3},{0,0,0}},{{0,2,0},{0,0,0}}}", # rotated twice (expanded version) (same as scale 2 version) (These take four times as long.) "{{{1,8,1},{0,2,1}},{{0,2,2},{1,2,2}},{{0,2,0},{1,2,0}}}", # rotated twice (compact version) Note that with the compact version we have to walk over 'live' cells without changing them - we can't set those transitions to 'die'. This makes exactly the same pattern as Langtons Ant but takes 3 times as long. For turmites with more states, e.g.: "{{{1,8,0},{1,2,1}},{{0,2,0},{0,8,1}}}", # 11: framed computer art "{{{1,4,2},{1,1,3}},{{0,1,2},{0,4,3}},{{0,2,0},{0,0,0}},{{0,2,1},{0,0,0}}}", # framed computer art rotated # 2 states become 4 states for 45 degree rotation # (sparse version, turning right on off-steps: hence turns N becomes L,L->U,R->N,U->R) # here the new states are used as off-step storage of the old states: state 2 says I will become state 0, # state 3 says I will become state 1 Can we detect when a smaller version of a turmite is possible - can we apply it in reverse? 1=noturn, 2=right, 4=u-turn, 8=left ''' # http://bytes.com/topic/python/answers/25176-list-subsets get_subsets = lambda items: [[x for (pos,x) in zip(range(len(items)), items) if (2**pos) & switches] for switches in range(2**len(items))] example_spec = "{{{1, 8, 1}, {1, 8, 1}}, {{1, 2, 1}, {0, 1, 0}}}" # Generate a random rule, filtering out the most boring ones. # TODO: # - if turmite can get stuck in period-2 cycles then rule is bad (or might it avoid them?) # - (extending) if turmite has (c,2 (or 8),s) for state s and color c then will loop on the spot (unlikely to avoid?) ns = 2 nc = 2 while True: # (we break out if ok) example_spec = '{' for state in range(ns): if state > 0: example_spec += ',' example_spec += '{' for color in range(nc): if color > 0: example_spec += ',' new_state = random.randint(0,ns-1) new_color = random.randint(0,nc-1) dir_to_turn = [1,2,4,8][random.randint(0,3)] # (we don't consider splitting and dying here) example_spec += '{' + str(new_color) + "," + str(dir_to_turn) + "," + str(new_state) + '}' example_spec += '}' example_spec += '}' is_rule_acceptable = True action_table = eval(example_spec.replace('}',']').replace('{','[')) # will turmite zip off? if on color 0 with state s the turmite does (?,1,s) then rule is bad for state in range(ns): if action_table[state][0][1]==1 and action_table[state][0][2]==state: is_rule_acceptable = False # does Turmite change at least one color? changes_one = False for state in range(ns): for color in range(nc): if not action_table[state][color][0] == color: changes_one = True if not changes_one: is_rule_acceptable = False # does Turmite ever turn? turmite_turns = False for state in range(ns): for color in range(nc): if not action_table[state][color][0] in [1,4]: # forward or u-turn turmite_turns = True if not turmite_turns: is_rule_acceptable = False # does turmite get stuck in any subset of states? for subset in get_subsets(range(ns)): if len(subset)==0 or len(subset)==ns: # (just an optimisation) continue leaves_subset = False for state in subset: for color in range(nc): if not action_table[state][color][2] in subset: leaves_subset = True if not leaves_subset: is_rule_acceptable = False break # (just an optimisation) # does turmite wobble on the spot? (u-turn that doesn't change color or state) for state in range(ns): for color in range(nc): if action_table[state][color][0]==color and action_table[state][color][1]==4 and action_table[state][color][2]==state: is_rule_acceptable = False # so was the rule acceptable, in the end? if is_rule_acceptable: break spec = golly.getstring( '''This script will create a Turmite CA for a given specification. Enter a number (1-59) for an example Turmite from Ed Pegg Jr.'s (extended) library. (see http://demonstrations.wolfram.com/Turmites/ or the code of this script) Otherwise enter a specification string: a curly-bracketed table of n_states rows and n_colors columns, where each entry is a triple of integers. The elements of each triple are: a: the new color of the square b: the direction(s) for the Turmite to turn (1=noturn, 2=right, 4=u-turn, 8=left) c: the new internal state of the Turmite Example: {{{1, 2, 0}, {0, 8, 0}}} (example pattern #1) Has 1 state and 2 colors. The triple {1,2,0} says: 1. set the color of the square to 1 2. turn right (2) 3. adopt state 0 (no change) and move forward one square This is Langton's Ant. Enter integer or string: (default is a random example)''', example_spec, 'Enter Turmite specification:') if spec.isdigit(): spec = EdPeggJrTurmiteLibrary[int(spec)-1] # (his demonstration project UI is 1-based) # convert the specification string into action_table[state][color] # (convert Mathematica code to Python and run eval) action_table = eval(spec.replace('}',']').replace('{','[')) n_states = len(action_table) n_colors = len(action_table[0]) # (N.B. The terminology 'state' here refers to the internal state of the finite # state machine that each Turmite is using, not the contents of each Golly # cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The # actual 'Golly state' in this emulation of Turmites is given by the # "encoding" section below.) n_dirs=4 # TODO: check table is full and valid total_states = n_colors+n_colors*n_states*n_dirs # problem if we try to export more than 255 states if total_states > 255: golly.warn("Number of states required exceeds Golly's limit of 255.") golly.exit() # encoding: # (0-n_colors: empty square) def encode(c,s,d): # turmite on color c in state s facing direction d return n_colors + n_dirs*(n_states*c+s) + d # http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html def flatten(l, ltypes=(list, tuple)): ltype = type(l) l = list(l) i = 0 while i < len(l): while isinstance(l[i], ltypes): if not l[i]: l.pop(i) i -= 1 break else: l[i:i + 1] = l[i] i += 1 return ltype(l) # convert the string to a form we can embed in a filename spec_string = ''.join(map(str,map(lambda x:hex(x)[2:],flatten(action_table)))) # (ambiguous but we have to try something) # what direction would a turmite have been facing to end up here from direction # d if it turned t: would_have_been_facing[t][d] would_have_been_facing={ 1:[2,3,0,1], # no turn 2:[1,2,3,0], # right 4:[0,1,2,3], # u-turn 8:[3,0,1,2], # left } remap = [2,1,3,0] # N,E,S,W -> S,E,W,N not_arriving_from_here = [range(n_colors) for i in range(n_dirs)] # (we're going to modify them) for color in range(n_colors): for state in range(n_states): turnset = action_table[state][color][1] for turn in [1,2,4,8]: if not turn&turnset: # didn't turn this way for dir in range(n_dirs): facing = would_have_been_facing[turn][dir] not_arriving_from_here[dir] += [encode(color,state,facing)] #golly.warn(str(not_arriving_from_here)) # What states leave output_color behind? leaving_color_behind = {} for output_color in range(n_colors): leaving_color_behind[output_color] = [output_color] # (no turmite present) for state in range(n_states): for color in range(n_colors): if action_table[state][color][0]==output_color: leaving_color_behind[output_color] += [encode(color,state,d) for d in range(n_dirs)] # any direction tree = RuleTree(total_states,4) # A single turmite is entering this square: for s in range(n_states): # collect all the possibilities for a turmite to arrive in state s... inputs_sc = [] for state in range(n_states): for color in range(n_colors): if action_table[state][color][2]==s: inputs_sc += [(state,color)] # ...from direction dir for dir in range(n_dirs): inputs = [] for state,color in inputs_sc: turnset = action_table[state][color][1] # sum of all turns inputs += [encode(color,state,would_have_been_facing[turn][dir]) for turn in [1,2,4,8] if turn&turnset] if len(inputs)==0: continue for central_color in range(n_colors): # output the required transition ### AKT: this code causes syntax error in Python 2.3: ### transition_inputs = [leaving_color_behind[central_color]] + \ ### [ inputs if i==dir else not_arriving_from_here[i] for i in remap ] transition_inputs = [leaving_color_behind[central_color]] for i in remap: if i==dir: transition_inputs.append(inputs) else: transition_inputs.append(not_arriving_from_here[i]) transition_output = encode(central_color,s,opposite_dirs[dir]) tree.add_rule( transition_inputs, transition_output ) # default: square is left with no turmite present for output_color,inputs in leaving_color_behind.items(): tree.add_rule([inputs]+[range(total_states)]*4,output_color) rule_name = prefix+'_'+spec_string tree.write(golly.getdir('rules')+rule_name+'.tree') # Create some multi-colour icons so we can see what the turmite is doing # Andrew's ant drawing: (with added eyes (2) and anti-aliasing (3)) ant31x31 = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,1,2,2,1,1,1,2,2,1,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,0,0,0,3,1,1,1,3,0,0,0,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,3,1,1,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] ant15x15 = [[0,0,0,0,1,0,0,0,0,0,1,0,0,0,0], [0,0,0,0,0,1,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,2,1,2,0,0,0,0,0,0], [0,0,0,1,0,0,1,1,1,0,0,1,0,0,0], [0,0,0,0,1,0,0,1,0,0,1,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,1,0,0,1,0,0,1,0,0,0,0], [0,0,0,1,0,0,3,1,3,0,0,1,0,0,0], [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,0,3,1,3,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] ant7x7 = [ [0,1,0,0,0,1,0], [0,0,2,1,2,0,0], [0,0,0,1,0,0,0], [0,1,1,1,1,1,0], [0,0,0,1,0,0,0], [0,1,1,1,1,1,0], [0,0,0,1,0,0,0] ] palette=[[0,0,0],[0,155,67],[127,0,255],[128,128,128],[185,184,96],[0,100,255],[196,255,254], [254,96,255],[126,125,21],[21,126,125],[255,116,116],[116,255,116],[116,116,255], [228,227,0],[28,255,27],[255,27,28],[0,228,227],[227,0,228],[27,28,255],[59,59,59], [234,195,176],[175,196,255],[171,194,68],[194,68,171],[68,171,194],[72,184,71],[184,71,72], [71,72,184],[169,255,188],[252,179,63],[63,252,179],[179,63,252],[80,9,0],[0,80,9],[9,0,80], [255,175,250],[199,134,213],[115,100,95],[188,163,0],[0,188,163],[163,0,188],[203,73,0], [0,203,73],[73,0,203],[94,189,0],[189,0,94]] eyes = (255,255,255) rotate4 = [ [[1,0],[0,1]], [[0,-1],[1,0]], [[-1,0],[0,-1]], [[0,1],[-1,0]] ] offset4 = [ [0,0], [1,0], [1,1], [0,1] ] pixels = [[palette[0] for column in range(total_states)*31] for row in range(53)] for state in range(n_states): for color in range(n_colors): for dir in range(n_dirs): bg_col = palette[color] fg_col = palette[state+n_colors] mid = [(f+b)/2 for f,b in zip(fg_col,bg_col)] for x in range(31): for y in range(31): column = (encode(color,state,dir)-1)*31 + rotate4[dir][0][0]*x + \ rotate4[dir][0][1]*y + offset4[dir][0]*30 row = rotate4[dir][1][0]*x + rotate4[dir][1][1]*y + offset4[dir][1]*30 pixels[row][column] = [bg_col,fg_col,eyes,mid][ant31x31[y][x]] for x in range(15): for y in range(15): column = (encode(color,state,dir)-1)*31 + rotate4[dir][0][0]*x + \ rotate4[dir][0][1]*y + offset4[dir][0]*14 row = 31 + rotate4[dir][1][0]*x + rotate4[dir][1][1]*y + offset4[dir][1]*14 pixels[row][column] = [bg_col,fg_col,eyes,mid][ant15x15[y][x]] for x in range(7): for y in range(7): column = (encode(color,state,dir)-1)*31 + rotate4[dir][0][0]*x + \ rotate4[dir][0][1]*y + offset4[dir][0]*6 row = 46 + rotate4[dir][1][0]*x + rotate4[dir][1][1]*y + offset4[dir][1]*6 pixels[row][column] = [bg_col,fg_col,eyes,mid][ant7x7[y][x]] for color in range(n_colors): bg_col = palette[color] for row in range(31): for column in range(31): pixels[row][(color-1)*31+column] = bg_col for row in range(15): for column in range(15): pixels[31+row][(color-1)*31+column] = bg_col for row in range(7): for column in range(7): pixels[46+row][(color-1)*31+column] = bg_col # use rule_name.tree and icon info to create rule_name.rule ConvertTreeToRule(rule_name, total_states, pixels) # switch to the new rule golly.new(rule_name+'-demo.rle') golly.setalgo('RuleLoader') golly.setrule(rule_name) golly.setcell(0,0,encode(0,0,0)) # start with a single turmite golly.show('Created '+rule_name+'.rule and selected that rule.') ''' # we make a turmite testbed so we don't miss interesting behaviour # create an area of random initial configuration with a few turmites for x in range(-300,-100): for y in range(-100,100): if x%50==0 and y%50==0: golly.setcell(x,y,n_colors) # start with a turmite facing N else: golly.setcell(x,y,random.randint(0,n_colors-1)) # create a totally random area (many turmites) for x in range(-200,-100): for y in range(200,300): golly.setcell(x,y,random.randint(0,total_states-1)) # also start with some pairs of turmites # (because of checkerboard rule, sometimes turmites work in pairs) pair_separation = 30 x=0 y=100 for t1 in range(n_colors,total_states): for t2 in range(n_colors,total_states): golly.setcell(x,y,t1) golly.setcell(x+1,y,t2) x += pair_separation x = 0 y += pair_separation # also start with a filled-in area of a color for color in range(n_colors): for x in range(color*200,color*200+100): for y in range(-50,50): if x==color*200+50 and y==0: golly.setcell(x,y,encode(color,0,0)) # start with a turmite facing N else: golly.setcell(x,y,color) golly.fit() ''' golly-2.7-src/Scripts/Python/Rule-Generators/icon-exporter.py0000644000175000017500000002752712536111364021333 00000000000000# Extract icon images in current layer (created by icon-importer.py) # and either create or update the appropriate .rule file. # Author: Andrew Trevorrow (andrew@trevorrow.com), Feb 2013. import golly as g from glife import getminbox, pattern from glife.BuiltinIcons import circles, diamonds, hexagons, triangles import os from tempfile import mkstemp from shutil import move iconcolors = [] # list of (r,g,b) colors used in all icons allcolors = g.getcolors() deadrgb = (allcolors[1], allcolors[2], allcolors[3]) # this flag becomes True only if an icon uses a non-gray color (ignoring deadrgb) multi_color_icons = False # grayscale # ------------------------------------------------------------------------------ def hex2(i): # convert number from 0..255 into 2 hex digits hexdigit = "0123456789ABCDEF" result = hexdigit[i / 16] result += hexdigit[i % 16] return result # -------------------------------------------------------------------- def extract_icons(iconsize): global iconcolors, allcolors, deadrgb, multi_color_icons # do 1st pass to determine the colors used and the number of icons numicons = 0 while True: blank = True x = numicons*32 y = 0 if iconsize == 15: y = 32 if iconsize == 7: y = 48 for row in xrange(iconsize): for col in xrange(iconsize): state = g.getcell(x+col, y+row) rgb = (allcolors[state*4+1], allcolors[state*4+2], allcolors[state*4+3]) if not rgb in iconcolors: iconcolors.append(rgb) if rgb != deadrgb: R,G,B = rgb if R != G or G != B: multi_color_icons = True if state > 0: blank = False if blank: break numicons += 1 if numicons == 0: return "" # build string of lines suitable for @ICONS section charsperpixel = 1 numcolors = len(iconcolors) if numcolors > 26: charsperpixel = 2 icondata = "\nXPM\n" icondata += "/* width height num_colors chars_per_pixel */\n" icondata += "\"" + str(iconsize) + " " + str(iconsize*numicons) + " " + \ str(numcolors) + " " + str(charsperpixel) + "\"\n" icondata += "/* colors */\n" cindex = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" n = 0 for RGB in iconcolors: R,G,B = RGB hexcolor = "#" + hex2(R) + hex2(G) + hex2(B) if RGB == deadrgb: # use . or .. for background color icondata += "\"." if charsperpixel == 2: icondata += "." if not multi_color_icons: # grayscale icons so specify black as the background color hexcolor = "#000000" else: icondata += "\"" if charsperpixel == 1: icondata += cindex[n] else: icondata += cindex[n % 16] + cindex[n / 16] icondata += " c " + hexcolor + "\"\n" n += 1 for i in xrange(numicons): icondata += "/* icon for state " + str(i+1) + " */\n" x = i*32 y = 0 if iconsize == 15: y = 32 if iconsize == 7: y = 48 for row in xrange(iconsize): icondata += "\"" for col in xrange(iconsize): state = g.getcell(x+col, y+row) if state == 0: # show . or .. for background color icondata += "." if charsperpixel == 2: icondata += "." else: rgb = (allcolors[state*4+1], allcolors[state*4+2], allcolors[state*4+3]) n = 0 for RGB in iconcolors: if rgb == RGB: break n += 1 if charsperpixel == 1: icondata += cindex[n] else: icondata += cindex[n % 16] + cindex[n / 16] icondata += "\"\n" return icondata # -------------------------------------------------------------------- def parse_hex(hexstr): # parse a string like "FF00EE" or "FFFF0000EEEE" R, G, B = (0, 0, 0) if len(hexstr) == 6: R = int(hexstr[0:2],16) G = int(hexstr[2:4],16) B = int(hexstr[4:6],16) elif len(hexstr) == 12: # only use upper 2 hex digits R = int(hexstr[0:2],16) G = int(hexstr[4:6],16) B = int(hexstr[8:10],16) else: g.warn("Unexpected hex string: " + hexstr) return (R,G,B) # -------------------------------------------------------------------- def create_average_colors(iconsection): global deadrgb colordata = "@COLORS\n\n" R, G, B = deadrgb colordata += "0 " + str(R) + " " + str(G) + " " + str(B) + "\n" width = 0 height = 0 num_colors = 0 chars_per_pixel = 0 xpmcount = 0 colordict = {} row = 0 state = 0 nbcount = 0 totalR = 0 totalG = 0 totalB = 0 for line in iconsection.splitlines(): if len(line) > 0 and line[0] == "\"": # extract the stuff inside double quotes line = line.lstrip("\"").rstrip("\"") xpmcount += 1 if xpmcount == 1: # parse "width height num_colors chars_per_pixel" header = line.split() width = int(header[0]) height = int(header[1]) num_colors = int(header[2]) chars_per_pixel = int(header[3]) elif xpmcount > 1 and xpmcount <= 1 + num_colors: # parse color index line like "A c #FFFFFF" or "AB c #FF009900BB00" key, c, hexrgb = line.split() rgb = parse_hex(hexrgb.lstrip("#")) colordict[key] = rgb elif xpmcount <= 1 + num_colors + height: # parse pixel data in line like "......AAA......" for col in xrange(width): offset = col*chars_per_pixel key = line[offset : offset + chars_per_pixel] if not key in colordict: g.warn("Unexpected key in icon data: " + key) return colordata if key[0] != ".": R, G, B = colordict[key] nbcount += 1 totalR += R totalG += G totalB += B row += 1 if row == width: # we've done this icon state += 1 if nbcount > 0: colordata += str(state) + " " + str(totalR / nbcount) + " " \ + str(totalG / nbcount) + " " \ + str(totalB / nbcount) + "\n" else: # avoid div by zero colordata += str(state) + " 0 0 0\n" # reset counts for next icon row = 0 nbcount = 0 totalR = 0 totalG = 0 totalB = 0 if xpmcount == 1 + num_colors + height: break colordata += "\n" return colordata # -------------------------------------------------------------------- def get_color_section(rulepath): colordata = "" rulefile = open(rulepath,"rU") copylines = False for line in rulefile: if line.startswith("@COLORS"): copylines = True elif copylines and line.startswith("@"): break if copylines: colordata += line rulefile.close() return colordata # -------------------------------------------------------------------- def export_icons(iconsection, rulename): global multi_color_icons if multi_color_icons: # prepend a new @COLORS section with the average colors in each icon iconsection = create_average_colors(iconsection) + iconsection # replace any illegal filename chars with underscores filename = rulename.replace("/","_").replace("\\","_") # we will only create/update a .rule file in the user's rules folder # (ie. we don't modify the supplied Rules folder) rulepath = g.getdir("rules") + filename + ".rule" fileexists = os.path.isfile(rulepath) if fileexists: # .rule file already exists so replace or add @ICONS section rulefile = open(rulepath,"rU") # create a temporary file for writing new rule info temphdl, temppath = mkstemp() tempfile = open(temppath,"w") wroteicons = False skiplines = False for line in rulefile: if line.startswith("@ICONS"): # replace the existing @ICONS section tempfile.write(iconsection) wroteicons = True skiplines = True elif line.startswith("@COLORS") and multi_color_icons: # skip the existing @COLORS section # (iconsection contains a new @COLORS section) skiplines = True elif skiplines and line.startswith("@"): if wroteicons: tempfile.write("\n") skiplines = False if not skiplines: tempfile.write(line) if not wroteicons: # .rule file had no @ICONS section tempfile.write("\n") tempfile.write(iconsection) # close files rulefile.close() tempfile.flush() tempfile.close() os.close(temphdl) # remove original .rule file and rename temporary file os.remove(rulepath) move(temppath, rulepath) else: # .rule file doesn't exist so create it rulefile = open(rulepath,"w") rulefile.write("@RULE " + filename + "\n\n") if not multi_color_icons: # grayscale icons, so check if Rules/filename.rule exists # and if so copy any existing @COLORS section suppliedrule = g.getdir("app") + "Rules/" + filename + ".rule" if os.path.isfile(suppliedrule): colordata = get_color_section(suppliedrule) if len(colordata) > 0: rulefile.write(colordata) rulefile.write(iconsection) rulefile.flush() rulefile.close() # create another layer for displaying the new icons if g.numlayers() < g.maxlayers(): g.addlayer() g.new("icon test") g.setrule(rulename) for i in xrange(g.numstates()-1): g.setcell(i, 0, i+1) g.fit() g.setoption("showicons",True) g.update() if fileexists: g.note("Updated the icon data in " + rulepath) else: g.note("Created " + rulepath) # -------------------------------------------------------------------- # WARNING: changing this prefix will require same change in icon-importer.py layerprefix = "imported icons for " # check that the current layer was created by icon-importer.py layername = g.getname() if not layername.startswith(layerprefix): g.exit("The current layer wasn't created by icon-importer.py.") # get the original rule rulename = layername.split(" for ")[1] icondata = extract_icons(31) icondata += extract_icons(15) icondata += extract_icons(7) if len(icondata) == 0: g.exit("There are no icon images to export.") if not multi_color_icons: # check if the icon data matches Golly's built-in grayscale icons if icondata == circles: icondata = "\ncircles\n" elif icondata == diamonds: icondata = "\ndiamonds\n" elif icondata == hexagons: icondata = "\nhexagons\n" elif icondata == triangles: icondata = "\ntriangles\n" export_icons("@ICONS\n" + icondata, rulename) golly-2.7-src/Scripts/Python/Rule-Generators/HexTurmite-gen.py0000644000175000017500000007504712536111364021402 00000000000000# Generator for Hexagonal Turmite rules import golly import random import string from glife.EmulateHexagonal import * from glife.WriteRuleTable import * # AKT: Python 2.3 doesn't have "set" built-in try: set except NameError: from sets import Set as set prefix = 'HexTurmite' turns = [1,2,4,8,16,32] # http://bytes.com/topic/python/answers/25176-list-subsets get_subsets = lambda items: [[x for (pos,x) in zip(range(len(items)), items) if (2**pos) & switches] for switches in range(2**len(items))] # Generate a random rule, while filtering out the dull ones. # More to try: # - if turmite can get stuck in period-2 cycles then rule is bad (or might it avoid them?) # - (extending) if turmite has (c,2 (or 8),s) for state s and color c then will loop on the spot (unlikely to avoid?) example_spec = '{{{1, 2, 0}, {0, 1, 0}}}' import random ns = 2 nc = 3 while True: # (we break out if ok) example_spec = '{' for state in range(ns): if state > 0: example_spec += ',' example_spec += '{' for color in range(nc): if color > 0: example_spec += ',' new_color = random.randint(0,nc-1) dir_to_turn = turns[random.randint(0,len(turns)-1)] # (we don't consider splitting and dying here) new_state = random.randint(0,ns-1) example_spec += '{' + str(new_color) + "," + str(dir_to_turn) + "," + str(new_state) + '}' example_spec += '}' example_spec += '}' is_rule_acceptable = True action_table = eval(string.replace(string.replace(example_spec,'}',']'),'{','[')) # does Turmite change at least one color? changes_one = False for state in range(ns): for color in range(nc): if not action_table[state][color][0] == color: changes_one = True if not changes_one: is_rule_acceptable = False # does Turmite write every non-zero color? colors_written = set([]) for state in range(ns): for color in range(nc): colors_written.add(action_table[state][color][0]) if not colors_written==set(range(1,nc)): is_rule_acceptable = False # does Turmite ever turn? turmite_turns = False for state in range(ns): for color in range(nc): if not action_table[state][color][1] in [1,32]: # forward, u-turn turmite_turns = True if not turmite_turns: is_rule_acceptable = False # does turmite get stuck in any subset of states? for subset in get_subsets(range(ns)): if len(subset)==0 or len(subset)==ns: # (just an optimisation) continue leaves_subset = False for state in subset: for color in range(nc): if not action_table[state][color][2] in subset: leaves_subset = True if not leaves_subset: is_rule_acceptable = False break # (just an optimisation) # does turmite wobble on the spot? (u-turn that doesn't change color or state) for state in range(ns): for color in range(nc): if action_table[state][color][0]==color and action_table[state][color][1]==32 and action_table[state][color][2]==state: is_rule_acceptable = False # so was the rule acceptable, in the end? if is_rule_acceptable: break ''' Some interesting rules, mostly discovered through random search: 1-state 2-color: In search of Langton's ant: {{{1,4,0},{0,2,0}}} : with gentle turns we get the same as on the triangular grid (symmetric) # (by only allowing gentle turns of course a hex grid is the same as a tri grid) {{{1,16,0},{0,8,0}}} : with sharp turns we get a period-8 glider {{{1,16,0},{0,2,0}}} : with one sharp and one gentle turn we get a pleasing chaos, with a highway after ~5million steps {{{1,4,0},{0,8,0}}} : the other way round. You'd think it would be the same but no highway so far (30million steps) 2-state 2-color rules: {{{1,8,1},{1,1,0}},{{1,8,0},{1,2,0}}} - iceskater makes a thick highway after 40k its {{{1,2,1},{1,1,0}},{{1,4,1},{1,16,0}}} - loose loopy growth {{{1,2,0},{1,16,1}},{{1,1,0},{1,1,1}}} - frustrated space filler {{{1,4,1},{1,1,0}},{{1,1,0},{1,1,1}}} - katana: a 2-speed twin-highway {{{1,4,0},{1,8,1}},{{1,2,0},{1,16,0}}} - highway after 300k its 3-state 2-color rules: {{{1,1,2},{1,4,2}},{{1,2,0},{1,1,2}},{{1,32,0},{1,1,1}}} - shuriken iceskater makes a twin-highway after a few false starts {{{1,16,2},{1,2,2}},{{1,8,0},{1,1,1}},{{1,2,1},{1,4,0}}} - similar 2-state 3-color rules: {{{2,16,1},{2,16,0},{1,8,1}},{{1,32,1},{2,4,0},{1,2,0}}} - loose growth {{{1,1,1},{2,32,1},{1,8,1}},{{2,8,0},{2,16,1},{1,1,0}}} - loose geode growth ''' spec = golly.getstring( '''This script will create a HexTurmite CA for a given specification. Enter a specification string: a curly-bracketed table of n_states rows and n_colors columns, where each entry is a triple of integers. The elements of each triple are: a: the new color of the square b: the direction(s) for the Turmite to turn (1=Forward, 2=Left, 4=Right, 8=Back-left, 16=Back-right, 32=U-turn) c: the new internal state of the Turmite Example: {{{1, 4, 0}, {0, 2, 0}}} Has 1 state and 2 colors. The triple {1,4,0} says: 1. set the color of the square to 1 2. turn right (4) 3. adopt state 0 and move forward one square This is the equivalent of Langton's Ant. Enter string: ''', example_spec, 'Enter HexTurmite specification:') # convert the specification string into action_table[state][color] # (convert Mathematica code to Python and run eval) action_table = eval(string.replace(string.replace(spec,'}',']'),'{','[')) n_states = len(action_table) n_colors = len(action_table[0]) # (N.B. The terminology 'state' here refers to the internal state of the finite # state machine that each Turmite is using, not the contents of each Golly # cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The # actual 'Golly state' in this emulation of Turmites is given by the # "encoding" section below.) n_dirs = 6 # TODO: check table is full and valid total_states = n_colors + n_colors*n_states*n_dirs # problem if we try to export more than 255 states if total_states > 255: golly.warn("Number of states required exceeds Golly's limit of 255.") golly.exit() # encoding: # (0-n_colors: empty square) def encode(c,s,d): # turmite on color c in state s facing away from direction d return n_colors + n_dirs*(n_states*c + s) + d # http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html def flatten(l, ltypes=(list, tuple)): ltype = type(l) l = list(l) i = 0 while i < len(l): while isinstance(l[i], ltypes): if not l[i]: l.pop(i) i -= 1 break else: l[i:i + 1] = l[i] i += 1 return ltype(l) # convert the string to a form we can embed in a filename spec_string = '_'.join(map(str,flatten(action_table))) # (ambiguous but we have to try something) # what direction would a turmite have been facing to end up here from direction # d if it turned t: would_have_been_facing[t][d] would_have_been_facing={ 1:[0,1,2,3,4,5], # forward 2:[1,2,3,4,5,0], # left 4:[5,0,1,2,3,4], # right 8:[2,3,4,5,0,1], # back-left 16:[4,5,0,1,2,3], # back-right 32:[3,4,5,0,1,2], # u-turn } not_arriving_from_here = [range(n_colors) for i in range(n_dirs)] # (we're going to modify them) for color in range(n_colors): for state in range(n_states): turnset = action_table[state][color][1] for turn in turns: if not turn&turnset: # didn't turn this way for dir in range(n_dirs): facing = would_have_been_facing[turn][dir] not_arriving_from_here[dir] += [encode(color,state,facing)] # What states leave output_color behind? leaving_color_behind = {} for output_color in range(n_colors): leaving_color_behind[output_color] = [output_color] # (no turmite present) for state in range(n_states): for color in range(n_colors): if action_table[state][color][0]==output_color: leaving_color_behind[output_color] += [encode(color,state,d) for d in range(n_dirs)] # any direction # we can't build the rule tree directly so we collect the transitions ready for emulation transitions = [] # A single turmite is entering this square: for s in range(n_states): for dir in range(n_dirs): # collect all the possibilities for a turmite to arrive in state s from direction dir inputs = [] for state in range(n_states): for color in range(n_colors): if action_table[state][color][2]==s: turnset = action_table[state][color][1] # sum of all turns inputs += [encode(color,state,would_have_been_facing[turn][dir]) \ for turn in turns if turn&turnset] if len(inputs)>0: for central_color in range(n_colors): # output the required transition ### AKT: this code causes syntax error in Python 2.3: ### transition = [leaving_color_behind[central_color]] + \ ### [ inputs if i==dir else not_arriving_from_here[i] for i in range(n_dirs) ] + \ ### [ [encode(central_color,s,dir)] ] transition = [leaving_color_behind[central_color]] for i in range(n_dirs): if i==dir: transition.append(inputs) else: transition.append(not_arriving_from_here[i]) transition += [ [encode(central_color,s,dir)] ] transitions += [transition] # default: square is left with no turmite present for output_color,inputs in leaving_color_behind.items(): transition = [inputs]+[range(total_states)]*n_dirs+[[output_color]] transitions += [transition] rule_name = prefix+'_'+spec_string # To see the intermediate output as a rule table: #WriteRuleTable('hexagonal',total_states,transitions,golly.getdir('rules')+rule_name+'_asTable.table') HexagonalTransitionsToRuleTree('hexagonal',total_states,transitions,rule_name) # -- make some icons -- palette=[[0,0,0],[0,155,67],[127,0,255],[128,128,128],[185,184,96],[0,100,255],[196,255,254], [254,96,255],[126,125,21],[21,126,125],[255,116,116],[116,255,116],[116,116,255], [228,227,0],[28,255,27],[255,27,28],[0,228,227],[227,0,228],[27,28,255],[59,59,59], [234,195,176],[175,196,255],[171,194,68],[194,68,171],[68,171,194],[72,184,71],[184,71,72], [71,72,184],[169,255,188],[252,179,63],[63,252,179],[179,63,252],[80,9,0],[0,80,9],[9,0,80], [255,175,250],[199,134,213],[115,100,95],[188,163,0],[0,188,163],[163,0,188],[203,73,0], [0,203,73],[73,0,203],[94,189,0],[189,0,94]] width = 31*(total_states-1) height = 53 pixels = [[(0,0,0) for x in range(width)] for y in range(height)] huge = [[[0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]], [[0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]], [[0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,2,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]], [[0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]], [[0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]], [[0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,2,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]]] big = [[[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,1,1,1,1,1,1,2,1,1,1,1,0,0,0], [0,1,1,1,1,1,1,2,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,2,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,2,1,1,1,1,1,1,0], [0,0,0,1,1,1,1,2,1,1,1,1,1,1,0], [0,0,0,1,1,2,1,2,1,2,1,1,1,1,1], [0,0,0,0,1,1,2,2,2,1,1,1,1,1,1], [0,0,0,0,0,0,1,2,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0]], [[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,1,1,1,2,1,1,1,1,1,1,1,0,0,0], [0,1,1,2,1,1,1,1,1,1,1,1,1,0,0], [0,0,2,2,2,2,2,2,2,1,1,1,1,0,0], [0,0,1,2,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,1,2,1,1,1,1,1,1,1,1,1,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0]], [[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,1,2,2,2,2,1,1,1,0,0,0,0,0,0], [1,1,2,2,1,1,1,1,1,1,1,0,0,0,0], [1,1,2,1,2,1,1,1,1,1,1,1,0,0,0], [0,1,2,1,1,2,1,1,1,1,1,1,0,0,0], [0,1,1,1,1,1,2,1,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,2,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,1,2,1,1,1,1,1,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0]], [[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,2,1,0,0,0,0,0,0], [1,1,1,1,1,1,2,2,2,1,1,0,0,0,0], [1,1,1,1,1,2,1,2,1,2,1,1,0,0,0], [0,1,1,1,1,1,1,2,1,1,1,1,0,0,0], [0,1,1,1,1,1,1,2,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,2,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,2,1,1,1,1,1,1,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0]], [[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,1,1,1,1,1,1,1,1,1,2,1,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,2,1,0,0], [0,0,1,1,1,1,2,2,2,2,2,2,2,0,0], [0,0,1,1,1,1,1,1,1,1,1,2,1,1,0], [0,0,0,1,1,1,1,1,1,1,2,1,1,1,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0]], [[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,1,1,1,1,1,2,1,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,2,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,1,2,1,1,1,1,1,0], [0,0,0,1,1,1,1,1,1,2,1,1,2,1,0], [0,0,0,1,1,1,1,1,1,1,2,1,2,1,1], [0,0,0,0,1,1,1,1,1,1,1,2,2,1,1], [0,0,0,0,0,0,1,1,1,2,2,2,2,1,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0]]] small = [[[0,1,1,0,0,0,0], [1,1,1,1,1,0,0], [1,1,1,2,1,1,0], [0,1,1,2,1,1,0], [0,1,2,2,2,1,1], [0,0,1,2,1,1,1], [0,0,0,0,1,1,0]], [[0,1,1,0,0,0,0], [1,1,1,1,1,0,0], [1,1,2,1,1,1,0], [0,2,2,2,2,1,0], [0,1,2,1,1,1,1], [0,0,1,1,1,1,1], [0,0,0,0,1,1,0]], [[0,1,1,0,0,0,0], [1,2,2,1,1,0,0], [1,2,2,1,1,1,0], [0,1,1,2,1,1,0], [0,1,1,1,2,1,1], [0,0,1,1,1,1,1], [0,0,0,0,1,1,0]], [[0,1,1,0,0,0,0], [1,1,1,2,1,0,0], [1,1,2,2,2,1,0], [0,1,1,2,1,1,0], [0,1,1,2,1,1,1], [0,0,1,1,1,1,1], [0,0,0,0,1,1,0]], [[0,1,1,0,0,0,0], [1,1,1,1,1,0,0], [1,1,1,1,2,1,0], [0,1,2,2,2,2,0], [0,1,1,1,2,1,1], [0,0,1,1,1,1,1], [0,0,0,0,1,1,0]], [[0,1,1,0,0,0,0], [1,1,1,1,1,0,0], [1,1,2,1,1,1,0], [0,1,1,2,1,1,0], [0,1,1,1,2,2,1], [0,0,1,1,2,2,1], [0,0,0,0,1,1,0]]] for color in range(n_colors): bg = palette[color] for row in range(31): for column in range(31): pixels[row][(color-1)*31+column] = [palette[0],bg,bg][huge[0][row][column]] for row in range(15): for column in range(15): pixels[31+row][(color-1)*31+column] = [palette[0],bg,bg][big[0][row][column]] for row in range(7): for column in range(7): pixels[46+row][(color-1)*31+column] = [palette[0],bg,bg][small[0][row][column]] for state in range(n_states): fg = palette[n_colors+state] for dir in range(n_dirs): # draw the 31x31 icon for row in range(31): for column in range(31): pixels[row][(encode(color,state,dir)-1)*31+column] = [palette[0],bg,fg][huge[dir][row][column]] # draw the 15x15 icon for row in range(15): for column in range(15): pixels[31+row][(encode(color,state,dir)-1)*31+column] = [palette[0],bg,fg][big[dir][row][column]] # draw the 7x7 icon for row in range(7): for column in range(7): pixels[46+row][(encode(color,state,dir)-1)*31+column] = [palette[0],bg,fg][small[dir][row][column]] # use rule_name.tree and icon info to create rule_name.rule ConvertTreeToRule(rule_name, total_states, pixels) # -- select the new rule -- golly.new(rule_name+'-demo.rle') golly.setalgo('RuleLoader') golly.setrule(rule_name) golly.setcell(0,0,encode(0,0,0)) # start with a single turmite golly.show('Created '+rule_name+'.rule and selected that rule.') golly-2.7-src/Scripts/Python/Rule-Generators/FredkinModN-gen.py0000644000175000017500000000466612536111364021443 00000000000000import golly import random import time from glife.EmulateHexagonal import * from glife.EmulateTriangular import * from glife.RuleTree import * # AKT: itertools.product is new in Python 2.6 try: from itertools import product except ImportError: # see http://docs.python.org/library/itertools.html#itertools.product def product(*args, **kwds): pools = map(tuple, args) * kwds.get('repeat', 1) result = [[]] for pool in pools: result = [x+[y] for x in result for y in pool] for prod in result: yield tuple(prod) spec = golly.getstring( '''This script will write and select the rule "Fredkin-mod-n", for a given N. This rule is the Winograd extension of the Fredkin Replicator rule (the parity rule): c,{s} -> sum(s)%N (where N=2 for the original parity rule) If N is prime, this will result in any pattern being replicated at N^m timesteps (if the pattern is small enough that it doesn't overlap its copies). Specify the neighborhood (N = von Neumann, M = Moore, T = triangular von Neumann, H = hexagonal, TM = triangular Moore) and the value of N (2-255). e.g. H2, N7 (Larger values of N can take a long time.) ''', 'N3', 'Enter specification:') # work out what the string meant nhood = '' nhoods = {'N':'vonNeumann','TM':'triangularMoore','M':'Moore', 'T':'triangularVonNeumann','H':'hexagonal'} for nh in nhoods.keys(): if nh in spec: nhood = nhoods[nh] n = int(spec.replace(nh,'')) break if nhood=='': golly.exit('Unsupported string: '+spec) if n<2 or n>255: golly.exit('Value of N must lie between 2 and 255.') # assemble the transitions nbors = {'vonNeumann':4,'Moore':8,'hexagonal':6,'triangularVonNeumann':3, 'triangularMoore':12} transitions = [] for sl in product(range(n),repeat=nbors[nhood]): transitions += [ [range(n)] + [[s] for s in sl] + [[sum(sl)%n]] ] rule_name = 'Fredkin_mod'+str(n)+'_'+nhood Converters = { "vonNeumann":ConvertRuleTableTransitionsToRuleTree, "Moore":ConvertRuleTableTransitionsToRuleTree, "triangularVonNeumann":EmulateTriangular, "triangularMoore":EmulateTriangular, "hexagonal":EmulateHexagonal, } golly.show("Building rule...") rule_name = Converters[nhood]( nhood, n, transitions, rule_name+'.tree' ) golly.setrule(rule_name) golly.show('Created '+rule_name+'.rule and selected that rule.') golly-2.7-src/Scripts/Python/Rule-Generators/Langtons-Ant-gen.py0000644000175000017500000002563312536111364021605 00000000000000# generator for Langton's Ant rules # inspired by Aldoaldoz: http://www.youtube.com/watch?v=1X-gtr4pEBU # contact: tim.hutton@gmail.com import golly import random from glife.RuleTree import * opposite_dirs=[2,3,0,1] # index of opposite direction # encoding: # (0-n_colors: empty square) def encode(c,s,d): # turmite on color c in state s facing direction d return n_colors + n_dirs*(n_states*c+s) + d prefix = 'LangtonsAnt' # (We choose a different name to the inbuilt Langtons-Ant rule to avoid # name collision between the rules we output and the existing icons.) spec = golly.getstring( '''This script will create a Langton's Ant CA for a given string of actions. The string specifies which way to turn when standing on a square of each state. Examples: RL (Langton's Ant), RLR (Chaos), LLRR (Cardioid), LRRL (structure) Permitted moves: 'L':Left, 'R':Right, 'U':U-turn, 'N':No turn Enter string:''', 'RL', 'Enter string:') n_colors = len(spec) d={'R':'2','L':'8','U':'4','N':'1'} # 1=noturn, 2=right, 4=u-turn, 8=left turmite_spec = "{{"+','.join(['{'+str((i+1)%n_colors)+','+d[spec[i]]+',0}' for i in range(n_colors)])+"}}" rule_name = prefix+'_'+spec action_table = eval(turmite_spec.replace('}',']').replace('{','[')) n_states = len(action_table) n_dirs=4 # (N.B. The terminology 'state' here refers to the internal state of the finite # state machine that each Turmite is using, not the contents of each Golly # cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The # actual 'Golly state' in this emulation of Turmites is given by the # "encoding" section below.) total_states = n_colors+n_colors*n_states*n_dirs # problem if we try to export more than 255 states if total_states>255: golly.warn("Number of states required exceeds Golly's limit of 255\n\nMaximum 51 turns allowed.") golly.exit() # what direction would a turmite have been facing to end up here from direction # d if it turned t: would_have_been_facing[t][d] would_have_been_facing={ 1:[2,3,0,1], # no turn 2:[1,2,3,0], # right 4:[0,1,2,3], # u-turn 8:[3,0,1,2], # left } remap = [2,1,3,0] # N,E,S,W -> S,E,W,N not_arriving_from_here = [range(n_colors) for i in range(n_dirs)] # (we're going to modify them) for color in range(n_colors): for state in range(n_states): turnset = action_table[state][color][1] for turn in [1,2,4,8]: if not turn&turnset: # didn't turn this way for dir in range(n_dirs): facing = would_have_been_facing[turn][dir] not_arriving_from_here[dir] += [encode(color,state,facing)] # What states leave output_color behind? leaving_color_behind = {} for output_color in range(n_colors): leaving_color_behind[output_color] = [output_color] # (no turmite present) for state in range(n_states): for color in range(n_colors): if action_table[state][color][0]==output_color: leaving_color_behind[output_color] += [encode(color,state,d) for d in range(n_dirs)] # any direction tree = RuleTree(total_states,4) # A single turmite is entering this square: for s in range(n_states): # collect all the possibilities for a turmite to arrive in state s... inputs_sc = [] for state in range(n_states): for color in range(n_colors): if action_table[state][color][2]==s: inputs_sc += [(state,color)] # ...from direction dir for dir in range(n_dirs): inputs = [] for state,color in inputs_sc: turnset = action_table[state][color][1] # sum of all turns inputs += [encode(color,state,would_have_been_facing[turn][dir]) for turn in [1,2,4,8] if turn&turnset] if len(inputs)==0: continue for central_color in range(n_colors): # output the required transition ### AKT: this code causes syntax error in Python 2.3: ### transition_inputs = [leaving_color_behind[central_color]] + \ ### [ inputs if i==dir else not_arriving_from_here[i] for i in remap ] transition_inputs = [leaving_color_behind[central_color]] for i in remap: if i==dir: transition_inputs.append(inputs) else: transition_inputs.append(not_arriving_from_here[i]) transition_output = encode(central_color,s,opposite_dirs[dir]) tree.add_rule( transition_inputs, transition_output ) # default: square is left with no turmite present for output_color,inputs in leaving_color_behind.items(): tree.add_rule([inputs]+[range(total_states)]*4,output_color) tree.write(golly.getdir('rules')+rule_name+'.tree') # Create some multi-colour icons so we can see what the ant is doing # Andrew's ant drawing: (with added eyes (2) and anti-aliasing (3)) ant31x31 = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,1,2,2,1,1,1,2,2,1,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,2,2,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,0,0,0,3,1,1,1,3,0,0,0,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,3,1,1,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] ant15x15 = [[0,0,0,0,1,0,0,0,0,0,1,0,0,0,0], [0,0,0,0,0,1,0,0,0,1,0,0,0,0,0], [0,0,0,0,0,0,2,1,2,0,0,0,0,0,0], [0,0,0,1,0,0,1,1,1,0,0,1,0,0,0], [0,0,0,0,1,0,0,1,0,0,1,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,1,0,0,1,0,0,1,0,0,0,0], [0,0,0,1,0,0,3,1,3,0,0,1,0,0,0], [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,0,3,1,3,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] ant7x7 = [ [0,1,0,0,0,1,0], [0,0,2,1,2,0,0], [0,0,0,1,0,0,0], [0,1,1,1,1,1,0], [0,0,0,1,0,0,0], [0,1,1,1,1,1,0], [0,0,0,1,0,0,0] ] palette=[[0,0,0],[0,155,67],[127,0,255],[128,128,128],[185,184,96],[0,100,255],[196,255,254], [254,96,255],[126,125,21],[21,126,125],[255,116,116],[116,255,116],[116,116,255], [228,227,0],[28,255,27],[255,27,28],[0,228,227],[227,0,228],[27,28,255],[59,59,59], [234,195,176],[175,196,255],[171,194,68],[194,68,171],[68,171,194],[72,184,71],[184,71,72], [71,72,184],[169,255,188],[252,179,63],[63,252,179],[179,63,252],[80,9,0],[0,80,9],[9,0,80], [255,175,250],[199,134,213],[115,100,95],[188,163,0],[0,188,163],[163,0,188],[203,73,0], [0,203,73],[73,0,203],[94,189,0],[189,0,94]] eyes = (255,255,255) rotate4 = [ [[1,0],[0,1]], [[0,-1],[1,0]], [[-1,0],[0,-1]], [[0,1],[-1,0]] ] offset4 = [ [0,0], [1,0], [1,1], [0,1] ] pixels = [[palette[0] for column in range(total_states)*31] for row in range(53)] for state in range(n_states): for color in range(n_colors): for dir in range(n_dirs): bg_col = palette[color] fg_col = palette[state+n_colors] mid = [(f+b)/2 for f,b in zip(fg_col,bg_col)] for x in range(31): for y in range(31): column = (encode(color,state,dir)-1)*31 + rotate4[dir][0][0]*x + \ rotate4[dir][0][1]*y + offset4[dir][0]*30 row = rotate4[dir][1][0]*x + rotate4[dir][1][1]*y + offset4[dir][1]*30 pixels[row][column] = [bg_col,fg_col,eyes,mid][ant31x31[y][x]] for x in range(15): for y in range(15): column = (encode(color,state,dir)-1)*31 + rotate4[dir][0][0]*x + \ rotate4[dir][0][1]*y + offset4[dir][0]*14 row = 31 + rotate4[dir][1][0]*x + rotate4[dir][1][1]*y + offset4[dir][1]*14 pixels[row][column] = [bg_col,fg_col,eyes,mid][ant15x15[y][x]] for x in range(7): for y in range(7): column = (encode(color,state,dir)-1)*31 + rotate4[dir][0][0]*x + \ rotate4[dir][0][1]*y + offset4[dir][0]*6 row = 46 + rotate4[dir][1][0]*x + rotate4[dir][1][1]*y + offset4[dir][1]*6 pixels[row][column] = [bg_col,fg_col,eyes,mid][ant7x7[y][x]] for color in range(n_colors): bg_col = palette[color] for row in range(31): for column in range(31): pixels[row][(color-1)*31+column] = bg_col for row in range(15): for column in range(15): pixels[31+row][(color-1)*31+column] = bg_col for row in range(7): for column in range(7): pixels[46+row][(color-1)*31+column] = bg_col # use rule_name.tree and icon info to create rule_name.rule ConvertTreeToRule(rule_name, total_states, pixels) # now we can switch to the new rule golly.new(rule_name+' demo') golly.setalgo('RuleLoader') golly.setrule(rule_name) golly.setcell(0,0,n_colors+3) # start with an ant facing west golly.show('Created '+rule_name+'.rule and selected that rule.') golly-2.7-src/Scripts/Python/Rule-Generators/AbsoluteTurmite-gen.py0000644000175000017500000003266112536111364022427 00000000000000# Generator for AbsoluteTurmites rules. Also known as 2D Turing machines. # # contact: tim.hutton@gmail.com import golly import random from glife.RuleTree import * dirs=['N','E','S','W'] opposite_dirs = [ 2, 3, 0, 1 ] prefix = 'AbsoluteTurmite' # N.B. All 'relative' Turmites (including Langton's ant and the n-Color family) # can be expressed as Absolute Turmites but require 4n states instead of n. # e.g. {{{1,'E',1},{0,'W',3}},{{1,'S',2},{0,'N',0}},{{1,'W',3},{0,'E',1}},{{1,'N',0},{0,'S',2}}} # is a 4-state 2-color Absolute Turmite that matches Langton's ant # Likewise all normal 1D Turing machines can be expressed as Absolute Turmites in a # straightforward fashion. # e.g. {{{1,'E',1},{1,'W',1}},{{1,'W',0},{1,'',0}}} # is a 2-state 2-color busy beaver # In both cases the opposite transform is usually not possible. Thus Absolute Turmites # are a deeper generalization. # http://bytes.com/topic/python/answers/25176-list-subsets get_subsets = lambda items: [[x for (pos,x) in zip(range(len(items)), items) if (2**pos) & switches] for switches in range(2**len(items))] example_spec = "{{{1,'E',1},{1,'W',1}},{{1,'W',0},{1,'',0}}}" # Generate a random rule, filtering out the most boring import random ns = 3 nc = 2 while True: # (we break out if ok) example_spec = '{' for state in range(ns): if state > 0: example_spec += ',' example_spec += '{' for color in range(nc): if color > 0: example_spec += ',' new_state = random.randint(0,ns-1) new_color = random.randint(0,nc-1) dir_to_move = dirs[random.randint(0,3)] example_spec += '{' + str(new_color) + ",'" + dir_to_move + "'," + str(new_state) + '}' example_spec += '}' example_spec += '}' # is rule acceptable? is_rule_acceptable = True action_table = eval(example_spec.replace('{','[').replace('}',']')) # does Turmite change at least one color? changes_one = False for state in range(ns): for color in range(nc): if not action_table[state][color][0] == color: changes_one = True if not changes_one: is_rule_acceptable = False # does turmite get stuck in any subset of states? for subset in get_subsets(range(ns)): if len(subset)==0 or len(subset)==ns: # (just an optimisation) continue leaves_subset = False for state in subset: for color in range(nc): if not action_table[state][color][2] in subset: leaves_subset = True if not leaves_subset: is_rule_acceptable = False break # (just an optimisation) # 1-move lookahead: will turmite zip off when placed on 0? for state in range(ns): if action_table[state][0][2] == state: is_rule_acceptable = False # turmite must write each colour at least once for color in range(nc): if not "{"+str(color)+"," in example_spec: is_rule_acceptable = False # does turmite move in all directions? for dir in dirs: if not "'"+dir+"'" in example_spec: is_rule_acceptable = False if is_rule_acceptable: break spec = golly.getstring( '''This script will create an AbsoluteTurmite CA for a given specification. Enter a specification string: a curly-bracketed table of n_states rows and n_colors columns, where each entry is a triple of integers. The elements of each triple are: a: the new color of the square b: the direction(s) for the turmite to move: 'NESW' c: the new internal state of the turmite Example: {{{1,'E',1},{1,'W',1}},{{1,'W',0},{1,'',0}}} (example pattern #1) Has 2 states and 2 colors. The triple {1,'W',0} says: 1. set the color of the square to 1 2. move West 3. adopt state 0 and move forward one square This is a 1D busy beaver Enter specification string: (default is a random example)''', example_spec, 'Enter Absolute Turmite specification:') # convert the specification string into action_table[state][color] # (convert Mathematica code to Python and run eval) action_table = eval(spec.replace('{','[').replace('}',']')) n_states = len(action_table) n_colors = len(action_table[0]) # (N.B. The terminology 'state' here refers to the internal state of the finite # state machine that each turmite is using, not the contents of each Golly # cell. We use the term 'color' to denote the symbol on the 2D 'tape'. The # actual 'Golly state' in this emulation of turmites is given by the # "encoding" section below.) n_dirs = 4 # TODO: check table is full and valid total_states = n_colors + n_colors*n_states # problem if we try to export more than 255 states if total_states > 255: golly.warn("Number of states required exceeds Golly's limit of 255.") golly.exit() # encoding: # (0-n_colors: empty square) def encode(c,s): # turmite on color c in state s return n_colors + n_states*c + s # http://rightfootin.blogspot.com/2006/09/more-on-python-flatten.html def flatten(l, ltypes=(list, tuple)): ltype = type(l) l = list(l) i = 0 while i < len(l): while isinstance(l[i], ltypes): if not l[i]: l.pop(i) i -= 1 break else: l[i:i + 1] = l[i] i += 1 return ltype(l) # convert the string to a form we can embed in a filename spec_string = ''.join(map(str,map(str,flatten(action_table)))) # (ambiguous but we have to try something) rule_name = prefix+'_'+spec_string remap = [2,1,3,0] # N,E,S,W -> S,E,W,N not_arriving_from_here = [range(n_colors) for i in range(n_dirs)] # (we're going to modify them) for color in range(n_colors): for state in range(n_states): moveset = action_table[state][color][1] for iMove,move in enumerate(dirs): if not move in moveset: not_arriving_from_here[opposite_dirs[iMove]] += [encode(color,state)] # What states leave output_color behind? leaving_color_behind = {} for output_color in range(n_colors): leaving_color_behind[output_color] = [output_color] # (no turmite present) for state in range(n_states): for color in range(n_colors): if action_table[state][color][0]==output_color: leaving_color_behind[output_color] += [encode(color,state)] tree = RuleTree(total_states,4) # A single turmite is entering this square: for s in range(n_states): # collect all the possibilities for a turmite to arrive in state s... inputs_sc = [] for state in range(n_states): for color in range(n_colors): if action_table[state][color][2]==s: inputs_sc += [(state,color)] # ...from direction dir for dir in range(n_dirs): inputs = [] for state,color in inputs_sc: moveset = action_table[state][color][1] if dirs[opposite_dirs[dir]] in moveset: # e.g. is there one to the S about to move N inputs += [encode(color,state)] if len(inputs)==0: continue for central_color in range(n_colors): # output the required transition ### AKT: this code causes syntax error in Python 2.3: ### transition_inputs = [leaving_color_behind[central_color]] + \ ### [ inputs if i==dir else not_arriving_from_here[i] for i in remap ] transition_inputs = [leaving_color_behind[central_color]] for i in remap: if i==dir: transition_inputs.append(inputs) else: transition_inputs.append(not_arriving_from_here[i]) transition_output = encode(central_color,s) tree.add_rule( transition_inputs, transition_output ) # default: square is left with no turmite present for output_color,inputs in leaving_color_behind.items(): tree.add_rule([inputs]+[range(total_states)]*4,output_color) tree.write(golly.getdir('rules')+rule_name+'.tree') # Write some colour icons so we can see what the turmite is doing # A simple ball drawing, with specular highlights (2) and anti-aliasing (3): icon31x31 = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0], [0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0], [0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0], [0,0,0,0,3,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0], [0,0,0,0,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,3,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0], [0,0,0,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0], [0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0], [0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0], [0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0], [0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0], [0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0], [0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0], [0,0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,3,1,1,1,1,1,1,1,1,1,3,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] icon15x15 = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,3,3,3,0,0,0,0,0,0], [0,0,0,0,3,1,1,1,1,1,3,0,0,0,0], [0,0,0,3,1,1,1,1,1,1,1,3,0,0,0], [0,0,3,1,1,2,1,1,1,1,1,1,3,0,0], [0,0,1,1,2,1,1,1,1,1,1,1,1,0,0], [0,3,1,1,2,1,1,1,1,1,1,1,1,3,0], [0,3,1,1,1,1,1,1,1,1,1,1,1,3,0], [0,3,1,1,1,1,1,1,1,1,1,1,1,3,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,3,1,1,1,1,1,1,1,1,1,3,0,0], [0,0,0,3,1,1,1,1,1,1,1,3,0,0,0], [0,0,0,0,3,1,1,1,1,1,3,0,0,0,0], [0,0,0,0,0,0,3,3,3,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] icon7x7 = [ [0,0,3,3,3,0,0], [0,3,1,1,1,3,0], [3,1,2,1,1,1,3], [3,1,1,1,1,1,3], [3,1,1,1,1,1,3], [0,3,1,1,1,3,0], [0,0,3,3,3,0,0] ] palette=[[0,0,0],[0,155,67],[127,0,255],[128,128,128],[185,184,96],[0,100,255],[196,255,254], [254,96,255],[126,125,21],[21,126,125],[255,116,116],[116,255,116],[116,116,255], [228,227,0],[28,255,27],[255,27,28],[0,228,227],[227,0,228],[27,28,255],[59,59,59], [234,195,176],[175,196,255],[171,194,68],[194,68,171],[68,171,194],[72,184,71],[184,71,72], [71,72,184],[169,255,188],[252,179,63],[63,252,179],[179,63,252],[80,9,0],[0,80,9],[9,0,80], [255,175,250],[199,134,213],[115,100,95],[188,163,0],[0,188,163],[163,0,188],[203,73,0], [0,203,73],[73,0,203],[94,189,0],[189,0,94]] highlight=(255,255,255) pixels = [[palette[0] for column in range(total_states)*31] for row in range(53)] for state in range(n_states): for color in range(n_colors): bg_col = palette[color] fg_col = palette[state+n_colors] mid = [(f+b)/2 for f,b in zip(fg_col,bg_col)] for row in range(31): for column in range(31): pixels[row][(encode(color,state)-1)*31+column] = [bg_col,fg_col,highlight,mid][icon31x31[row][column]] for row in range(15): for column in range(15): pixels[31+row][(encode(color,state)-1)*31+column] = [bg_col,fg_col,highlight,mid][icon15x15[row][column]] for row in range(7): for column in range(7): pixels[46+row][(encode(color,state)-1)*31+column] = [bg_col,fg_col,highlight,mid][icon7x7[row][column]] for color in range(n_colors): bg_col = palette[color] for row in range(31): for column in range(31): pixels[row][(color-1)*31+column] = bg_col for row in range(15): for column in range(15): pixels[31+row][(color-1)*31+column] = bg_col for row in range(7): for column in range(7): pixels[46+row][(color-1)*31+column] = bg_col # use rule_name.tree and icon info to create rule_name.rule ConvertTreeToRule(rule_name, total_states, pixels) # now we can switch to the new rule golly.new(rule_name+'-demo.rle') golly.setalgo('RuleLoader') golly.setrule(rule_name) golly.setcell(0,0,encode(0,0)) # start with a single turmite golly.show('Created '+rule_name+'.rule and selected that rule.') golly-2.7-src/Scripts/Python/make-Devore-tape.py0000644000175000017500000004301712536111364016575 00000000000000# ================================================= # A Golly script to write the program and data # tapes for the Devore UCC. Load Devore-body.rle # and run this script, then set the machine running. # # Tape length: 105k # Rep period: 1.02 x 10^11 (102 billion) timesteps # # Script license: public domain # # Contact: tim.hutton@gmail.com # Thanks to Ron Hightower and John Devore # ================================================= import golly as g program_tape_x = 322 program_tape_y = 233 data_tape_x = 330 data_tape_y = 8 # range from start to stop (either direction) # twoway_range(0,10,2)==[0,2,4,6,8] # twoway_range(0,-10,2)==[0,-2,-4,-6,-8] def twoway_range(start,stop,step=1): return range(start,stop,(-1 if (stop-start)<0 else 1)*abs(step)) # range from start to stop including both end points (either direction) # inclusive_range(0,10,2)==[0,2,4,6,8,10] # inclusive_range(10,0,2)==[10,8,6,4,2,0] # inclusive_range(0,-10,2)==[0,-2,-4,-6,-8,-10] def inclusive_range(start,stop,step=1): return twoway_range(start,stop+(-1 if (stop-start)<0 else 1)*abs(step),step) ''' Devore instruction set: (the program tape) 0000 goto (following bits give destination) 0001 move data head (D) left 0010 move data head right 0011 jump_if_one [from whichever path is open] (following bits give destination) 0100 m (mark_if_zero) [affects whichever path is open] 0101 e (erase_if_one) [affects whichever path is open] 0110 switch between construction path and data path [D open by default] 0111 x (extend) [all these below only affect C] 1000 xl 1001 xr 1010 r (retract) 1011 rl 1100 rr 1101 i (inject sheath) # legacy from Codd, don't use this! (see below) 1110 j (inject trigger) 1111 stop Destination bits: first is sign (0=backwards, 1=forwards), followed by unary count of marks and zero terminator. E.g. 111110=+4, 011110=-4 Marks lie 6 cells below the program tape, and appear on the column before the start of the command they mark. Not every command needs a mark, just those jumped-to. Destination says how many marks forward or backwards to jump. Exception is when a goto is immediately followed by a mark - in this case the goto destination is decremented because the next mark is skipped over anyway. For injection, use the pattern: 1 1 1 1 1 1 1 1 1 Approach from the left into the receiver, then retract. This injects the sheathing signal. Then call the inject_trigger command. You can then safely retract away. The inject_sheath command was used by Codd but is now redundant, it appears. ''' goto = '0000' toggle_C_or_D = '0110' data_head_left = '0001' data_head_right = '0010' extend = '0111' extend_left = '1000' extend_right = '1001' retract = '1010' retract_left = '1011' retract_right = '1100' mark = '0100' erase = '0101' jump_if_one = '0011' inject_sheath = '1101' inject_trigger = '1110' stop = '1111' def write_string(s): global program_tape_x, program_tape_y for c in s: if c=='1': g.setcell(program_tape_x,program_tape_y,1) program_tape_x += 1 def write_data_string(s): global data_tape_x, data_tape_y for c in s: if c=='1': g.setcell(data_tape_x,data_tape_y,1) data_tape_x += 1 def write_program(program): global program_tape_x, program_tape_y # find all the labels labels = [c[:-1] for c in program if c[-1]==':'] iCurrentLabel=0 for i,c in enumerate(program): if 'jump_if_one:' in c: write_string(jump_if_one) jump = labels.index(c[c.index(':')+1:])+1-iCurrentLabel if jump<1: jump-=1 if jump>1 and program[i+1][-1]==':': jump -= 1 # (if next command is a label we don't need to jump so far) if jump<0: write_string('0') else: write_string('1') write_string('1'*abs(jump)+'0') elif 'goto:' in c: write_string(goto) jump = labels.index(c[c.index(':')+1:])+1-iCurrentLabel if jump<1: jump-=1 if jump>1 and program[i+1][-1]==':': jump -= 1 # (if next command is a label we don't need to jump so far) if jump<0: write_string('0') else: write_string('1') write_string('1'*abs(jump)+'0') elif c[-1]==':': # a label, make a mark on the marker tape g.setcell(program_tape_x-1,program_tape_y-6,1) iCurrentLabel+=1 else: # a normal command write_string(c) # ------------------------------------ # create the program: # ------------------------------------ program = [ # ---------- data tape copying phase: ------------------------ 'goto:extendup', 'write1:', # == 1 == extend_right,toggle_C_or_D,mark,toggle_C_or_D,retract_right,extend, 'nextread:', data_head_left, 'jump_if_one:write1', # 0: extend, data_head_left, 'jump_if_one:write1', # == 00 == extend, data_head_left, 'jump_if_one:write1', # == 000 == # -- end of copy -- data_head_right, # we overshot (first data entry is 01) toggle_C_or_D, # open C 'retractcopy:', retract,extend_left,extend,'jump_if_one:retractdown', retract,retract_left,'goto:retractcopy', # ---------- construction phase: ------------------------ 'rowstart:', # move into writing position extend_right,extend,extend,extend, # (make a mark at the start of the row for retraction) extend_left,extend,toggle_C_or_D,mark,toggle_C_or_D,retract,retract_left, 'nextcolumn:', data_head_right, 'jump_if_one:1', # 0: data_head_right, 'jump_if_one:01', # == 00 == data_head_right, 'jump_if_one:001', # == 000 == # (assume came immediately after start of a new row) extend_left,extend,toggle_C_or_D,erase,retract,retract_left, retract,retract,retract,retract_right, 'retractcolumn:', extend_left,extend,'jump_if_one:doneretractcolumn', retract,retract_left,retract,'goto:retractcolumn', 'doneretractcolumn:',erase,retract,retract_left, 'goto:inject', '001:', # == 001 == # -- retract row -- toggle_C_or_D, # open C 'retractrow:', retract,extend_left,extend,'jump_if_one:doneretractrow', retract,retract_left,'goto:retractrow', 'doneretractrow:', erase,retract,retract_left,toggle_C_or_D,retract,retract,retract,retract_right, extend, 'goto:rowstart', '01:', # == 01 == # -- write N 0's -- extend,extend,extend, 'goto:nextcolumn', '1:', data_head_right, 'jump_if_one:11', # == 10 == # -- write a 0 -- extend, 'goto:nextcolumn', '11:', # == 11 == # -- write a 1 -- extend_right, toggle_C_or_D, # open C mark, toggle_C_or_D, # close C retract_right, extend, 'goto:nextcolumn', # ------------------------ subroutines (here for speed): ----------------- 'extendup:', # move the construction arm into the starting position extend_right,extend,extend,extend,extend,extend,extend,extend,extend, # move up to the right height extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend, # move into writing position extend_right,extend,extend,extend, # (make a mark at the start of the copy for retraction) extend_left,extend,toggle_C_or_D,mark,toggle_C_or_D,retract,retract_left, 'goto:nextread', 'retractdown:', erase,retract,retract_left,toggle_C_or_D,retract,retract,retract,retract_right, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract,retract,retract,retract,retract,retract,retract, retract,retract,retract,retract, extend_left, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend, extend_right,extend,extend,extend,extend,extend,extend,extend,extend, # (make a mark at the bottom-left for final retraction) extend_left,extend,toggle_C_or_D,mark,toggle_C_or_D,retract,retract_left, 'goto:rowstart', # -- end of construction: retract and inject sheath+trigger -- 'inject:', retract,extend_right,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend,extend,extend,extend,extend,extend, extend,extend,extend,extend,extend, retract,inject_trigger, retract,retract,retract, stop ] # -------------------------------- # now write the tapes: # -------------------------------- # Our data tape contains coded construction instructions: # 11 : write a 1 # 10 : write a 0 # 01 : write n 0's (where n is the value below) # 001 : end of row # 000 : end of construction # # Each row is scanned from the left edge to the last 1. (A temporary marker # is used at the beginning for retraction, so rows can be any length.) Because # each row ends with a 1, we know that the sequence 000 cannot appear on the # data tape until the very end. This allows us to detect (reading backwards) # the 000 sequence, in order to know when to stop copying. # # For retracting vertically after construction another temporary marker is used. # # Following Ron Hightower's work (thanks Ron!) we copy the data tape first and # then read it from the far end. The data read head is made slightly prominent # to allow the 000 to be skipped (else it would be detected during tape-copy and # would cause it to end), but read correctly from the blank space at the end of # the data tape nearest the machine. # # The instruction set above was just one that I tried. I'm quite sure it is # possible to do this more efficiently. n=3 # found through experiment to give the shortest data tape # must match the "write N 0's" section of the program above # (I would have expected 10 or so to be better but anyway.) # first we write the program and marker tapes # then we encode the whole pattern onto the data tape # (program length is mostly unrelated to machine size, so it all works) write_program(program) # write the data tape data_tape = '' rect = g.getrect() # copy everything within the bounding rectangle width = rect[2] height = rect[3] x = rect[0] y = rect[1] for row in inclusive_range(y+height-1,y): far_right = x+width-1 while g.getcell(far_right,row)==0: far_right -= 1 if far_right= 1.0: oldsecs = newsecs g.update() for col in xrange(r.left, r.left + r.width): g.setcell(col, row, maxstate - g.getcell(col, row)) if not r.visible(): g.fitsel() golly-2.7-src/Scripts/Python/move-selection.py0000644000175000017500000001642512536111364016443 00000000000000# Allow user to move the current selection. # Author: Andrew Trevorrow (andrew@trevorrow.com), Jan 2011. import golly as g # set edges of bounded grid for later use if g.getwidth() > 0: gridl = -int(g.getwidth()/2) gridr = gridl + g.getwidth() - 1 if g.getheight() > 0: gridt = -int(g.getheight()/2) gridb = gridt + g.getheight() - 1 helpmsg = " (hit 'h' for help)" # -------------------------------------------------------------------- def showhelp1(): g.note( """Hit the escape key to abort the script. Note that alt-clicking in the selection allows you to COPY it to another location (the original selection is not deleted).""") # -------------------------------------------------------------------- def showhelp2(): g.note( """While moving the selection the following keys can be used: x -- flip selection left-right y -- flip selection top-bottom > -- rotate selection clockwise < -- rotate selection anticlockwise h -- show this help escape -- abort and restore the selection""") # ------------------------------------------------------------------------------ def cellinrect(x, y, r): # return True if given cell position is inside given rectangle if x < r[0] or x >= r[0] + r[2]: return False if y < r[1] or y >= r[1] + r[3]: return False return True # ------------------------------------------------------------------------------ def rectingrid(r): # return True if all of given rectangle is inside grid if g.getwidth() > 0 and (r[0] < gridl or r[0] + r[2] - 1 > gridr): return False if g.getheight() > 0 and (r[1] < gridt or r[1] + r[3] - 1 > gridb): return False return True # ------------------------------------------------------------------------------ def lookforkeys(event, deltax, deltay): global oldcells, selrect, selpatt # look for keys used to flip/rotate selection if event == "key x none" or event == "key y none": # flip floating selection left-right or top-bottom if len(oldcells) > 0: g.clear(0) g.putcells(selpatt, deltax, deltay) if " x " in event: g.flip(0) else: g.flip(1) selpatt = g.transform(g.getcells(selrect), -deltax, -deltay) if len(oldcells) > 0: g.clear(0) g.putcells(oldcells) g.putcells(selpatt, deltax, deltay) g.update() return if event == "key > none" or event == "key < none": # rotate floating selection clockwise or anticlockwise; # because we use g.rotate below we have to use the exact same # calculation (see Selection::Rotate in wxselect.cpp) for rotrect: midx = selrect[0] + int((selrect[2]-1)/2) midy = selrect[1] + int((selrect[3]-1)/2) newleft = midx + selrect[1] - midy newtop = midy + selrect[0] - midx rotrect = [ newleft, newtop, selrect[3], selrect[2] ] if not rectingrid(rotrect): g.warn("Rotation is not allowed if selection would be outside grid.") return g.clear(0) if len(oldcells) > 0: g.putcells(oldcells) oldcells = g.join(oldcells, g.getcells(rotrect)) g.clear(0) g.select(rotrect) g.clear(0) g.select(selrect) g.putcells(selpatt, deltax, deltay) if " > " in event: g.rotate(0) else: g.rotate(1) selrect = g.getselrect() if selrect != rotrect: g.warn("Bug: selrect != rotrect") selpatt = g.transform(g.getcells(selrect), -deltax, -deltay) if len(oldcells) > 0: g.clear(0) g.putcells(oldcells) g.putcells(selpatt, deltax, deltay) g.update() return if event == "key h none": showhelp2() return g.doevent(event) # ------------------------------------------------------------------------------ def moveselection(): global oldcells, selrect, selpatt # wait for 1st click in selection while True: event = g.getevent() if event.startswith("click"): # event is a string like "click 10 20 left none" evt, xstr, ystr, butt, mods = event.split() x = int(xstr) y = int(ystr) if cellinrect(x, y, selrect): oldmouse = xstr + ' ' + ystr firstx = x firsty = y xoffset = firstx - selrect[0] yoffset = firsty - selrect[1] if mods == "alt": # don't delete pattern in selection oldcells = g.getcells(selrect) break elif event == "key h none": showhelp1() else: g.doevent(event) # wait for 2nd click while moving selection g.show("Move mouse and click again..." + helpmsg) gotclick = False while not gotclick: event = g.getevent() if event.startswith("click"): evt, x, y, butt, mods = event.split() mousepos = x+' '+y gotclick = True else: if len(event) > 0: lookforkeys(event, x - firstx, y - firsty) # update xoffset,yoffset in case selection was rotated xoffset = x - selrect[0] yoffset = y - selrect[1] mousepos = g.getxy() if len(mousepos) > 0 and mousepos != oldmouse: # mouse has moved, so move selection rect and pattern g.clear(0) if len(oldcells) > 0: g.putcells(oldcells) xstr, ystr = mousepos.split() x = int(xstr) y = int(ystr) selrect[0] = x - xoffset selrect[1] = y - yoffset if g.getwidth() > 0: # ensure selrect doesn't move beyond left/right edge of grid if selrect[0] < gridl: selrect[0] = gridl x = selrect[0] + xoffset elif selrect[0] + selrect[2] - 1 > gridr: selrect[0] = gridr + 1 - selrect[2] x = selrect[0] + xoffset if g.getheight() > 0: # ensure selrect doesn't move beyond top/bottom edge of grid if selrect[1] < gridt: selrect[1] = gridt y = selrect[1] + yoffset elif selrect[1] + selrect[3] - 1 > gridb: selrect[1] = gridb + 1 - selrect[3] y = selrect[1] + yoffset g.select(selrect) oldcells = g.getcells(selrect) g.putcells(selpatt, x - firstx, y - firsty) oldmouse = mousepos g.update() # ------------------------------------------------------------------------------ selrect = g.getselrect() if len(selrect) == 0: g.exit("There is no selection.") selpatt = g.getcells(selrect) # remember initial selection in case user aborts script firstrect = g.getselrect() firstpatt = g.getcells(selrect) g.show("Click anywhere in selection, move mouse and click again..." + helpmsg) oldcursor = g.getcursor() g.setcursor("Move") oldcells = [] try: aborted = True moveselection() aborted = False finally: g.setcursor(oldcursor) if aborted: g.clear(0) if len(oldcells) > 0: g.putcells(oldcells) g.putcells(firstpatt) g.select(firstrect) else: g.show(" ") golly-2.7-src/Scripts/Python/metafier.py0000644000175000017500000012357012536111364015306 00000000000000# metafier.py: # Uses the current selection to build a Brice Due metapixel pattern. # See http://otcametapixel.blogspot.com for more info. # Original author: Dave Greene, 12 June 2006. # # Dave Greene, 23 June 2006: added non-Conway's-Life rule support. # Also reduced the script size by a factor of six, at the expense of # adding a moderate-sized [constant] performance hit at the start # [due to composing the base tiles from smaller subpatterns.] # # The delay is almost all due to running CellCenter[3680] at the end # to produce the large filled area for the ONcell. Subpatterns are # generally (with some exceptions) defined to match the labeled slides at # http://otcametapixel.blogspot.com/2006/05/how-does-it-work.html . # # It's still possible to simplify the script by another factor of # two or more, by replacing the four main types of P46 oscillators # [which are often quoted as flat patterns] with predefined library # versions in the correct phase; see samples in the slide-24 section. # # 24 June 2006: the script now saves a reference copy of the OFFcell # and (particularly) the slow-to-construct ONcell, so these only have # to be constructed from scratch once, the first time the script runs. # # If metapixel-ON.rle and metapixel-OFF.rle become corrupted, they # should be deleted so the script can re-generate them. # # 3 July 2007: added code to avoid errors in rules like Seeds, # where the Golly canonical form of the rule doesn't include a '/' # # Modified by Andrew Trevorrow, 20 July 2006 (faster, simpler and # doesn't change the current clipboard). # # Modified by Andrew Trevorrow, 5 October 2007 (metafied pattern is # created in a separate layer so we don't clobber the selection). import os import golly as g from glife import * selrect = g.getselrect() if len(selrect) == 0: g.exit("There is no selection.") # check that a layer is available for the metafied pattern; # if metafied layer already exists then we'll use that layername = "metafied" metalayer = -1 for i in xrange(g.numlayers()): if g.getname(i) == layername: metalayer = i break if metalayer < 0 and g.numlayers() == g.maxlayers(): g.exit("You need to delete a layer.") # note that getrule returns canonical rule string rulestr = g.getrule().split(":")[0] if (not rulestr.startswith("B")) or (rulestr.find("/S") == -1): g.exit("This script only works with B*/S* rules.") # get the current selection slist = g.getcells(selrect) selwidth = selrect[2] selheight = selrect[3] # create a 2D list of 0s and 1s representing entire selection livecell = [[0 for y in xrange(selheight)] for x in xrange(selwidth)] for i in xrange(0, len(slist), 2): livecell[slist[i] - selrect[0]][slist[i+1] - selrect[1]] = 1 # build a patch pattern based on the current rule # that fixes the appropriate broken eaters in the rules table r1, r2 = rulestr.split("/") if r1[:1] == "B": Bvalues, Svalues = r1.replace("B",""), r2.replace("S","") elif r1[:1] == "S": Svalues, Bvalues = r1.replace("S",""), r2.replace("B","") else: Svalues, Bvalues = r1, r2 # create metafied pattern in separate layer if metalayer >= 0: g.setlayer(metalayer) # switch to existing layer else: metalayer = g.addlayer() # create new layer # set rule to Life rule() Brle = Srle = "b10$b10$b26$b10$b10$b26$b10$b10$b!" for ch in Bvalues: ind = 32-int(ch)*4 # because B and S values are highest at the top! Brle = Brle[:ind] + "o" + Brle[ind+1:] for ch in Svalues: ind = 32-int(ch)*4 Srle = Srle[:ind] + "o" + Srle[ind+1:] RuleBits = pattern(Brle, 148, 1404) + pattern(Srle, 162, 1406) # load or generate the OFFcell tile: OFFcellFileName = g.getdir("data") + "metapixel-OFF.rle" ONcellFileName = g.getdir("data") + "metapixel-ON.rle" if os.access(OFFcellFileName, os.R_OK) and os.access(ONcellFileName, os.R_OK): g.show("Opening metapixel-OFF and metapixel-ON from saved pattern file.") OFFcell = pattern(g.transform(g.load(OFFcellFileName),-5,-5,1,0,0,1)) ONcell = pattern(g.transform(g.load(ONcellFileName),-5,-5,1,0,0,1)) else: g.show("Building OFF metacell definition...") # slide #21: programmables -------------------- LWSS = pattern("b4o$o3bo$4bo$o2bo!", 8, 0) DiagProximityFuse = pattern(""" bo$obo$bo2$4b2o$4b2o$59b2o$59b2o3$58b2o2b2o$9b2o3bo5bo5bo5bo5bo5bo5bo 7b2o2b2o$9bo3bobo3bobo3bobo3bobo3bobo3bobo3bobo$10bo2bo2bo2bo2bo2bo2bo 2bo2bo2bo2bo2bo2bo2bo2bo$11bobo3bobo3bobo3bobo3bobo3bobo3bobo3bo5b2o$ 12bo5bo5bo5bo5bo5bo5bo5bo3bobo$55bo2bo$56bobo$57bo! """, -5, -5) OrthoProximityFuse = pattern("2o41b2o$2o41bo$41bobo$41b2o!", 1001, 0) ProximityFuses = LWSS + DiagProximityFuse + OrthoProximityFuse AllFuses = pattern() for i in range(0,4): # place four sets of fuses around cell perimeter AllFuses = AllFuses(2047, 0, rcw) + ProximityFuses temp = pattern("o$3o$3bo$2bo!") # broken eater temp += temp(0, 10) + temp(0, 20) temp += temp(0, 46) + temp(0, 92) TableEaters = temp(145, 1401) + temp(165, 1521, flip) HoneyBitsB = pattern(""" bo$obo$obo$bo7$bo$obo$obo$bo7$bo$obo$obo$bo23$bo$obo$obo$bo7$bo$obo$ob o$bo7$bo$obo$obo$bo23$bo$obo$obo$bo7$bo$obo$obo$bo7$bo$obo$obo$bo! """, 123, 1384) HoneyBitsS = HoneyBitsB(57, 34) temp = pattern("2bobo2$obobo2$obo2$obo2$2bobo4$obo2$obobo2$2bobo!") S = temp + temp(10, 16, flip) # just practicing... B = S + pattern("o6$8bobo2$o2$obo6$o!") # ditto temp = pattern("2bobo2$obobo2$obo2$obo2$obo2$obo2$obo2$obobo2$2bobo!") O = temp + temp(10, 16, flip) temp = pattern("obo2$obo2$obobo2$obobo2$obo2bo2$obo2$obo2$obo2$obo!") N = temp + temp(10, 16, flip) temp = pattern("obobobobo2$obobobobo2$obo2$obo2$obo2$obo!") F = temp + temp(0,6) # overlap, just to try it out... Eatr = pattern("4bobo2$" * 2 + "obo2$" * 2 \ + "4bobobobobobo2$" * 2 + "12bobo2$"*2) Eater = Eatr + pattern("obo2$"*2) LabelDigits = pattern(""" obobo2$o3bo2$obobo2$o3bo2$obobo5$obobo2$4bo2$4bo2$4bo2$4bo5$obobo2$o2$ obobo2$o3bo2$obobo12$obobo2$o2$obobo2$4bo2$obobo5$o3bo2$o3bo2$obobo2$ 4bo2$4bo5$obobo2$4bo2$obobo2$4bo2$obobo12$obobo2$4bo2$obobo2$o2$obobo 5$2bo2$2bo2$2bo2$2bo2$2bo5$obobo2$o3bo2$o3bo2$o3bo2$obobo!""") VLine = pattern("o2$" * 25) VLine2 = pattern("o2$" * 71) HLine = pattern("ob" * 38) TableLabels = VLine(18, 1440) + VLine(96, 1440) + Eater(77, 1446) \ + HLine(20, 1440) + HLine(20, 1488) + O(39, 1444) + N(55, 1444) \ + O(23, 1468) + F(39, 1468) + F(55, 1468) + Eatr(77, 1470) TableLabels += pattern("ob" * 29 + "8bobobo", 120, 1533) \ + HLine(118, 1391) + VLine2(118, 1393) + VLine2(192, 1393) \ + B(123, 1410) + B(123, 1456) + B(123, 1502) \ + S(177, 1398) + S(177, 1444) + S(177, 1490) \ + LabelDigits(138, 1396) + LabelDigits(168, 1401) all = AllFuses + TableEaters + TableLabels + HoneyBitsB + HoneyBitsS # slide 22: linear clock -------------------- LinearClockGun = pattern(""" 19bo$17b3o$16bo$16b2o$30bo$28b3o$27bo$27b2o$13b3o$12bo2b2o$11bo3b2o$ 12b3o$12b2o$15bo$13b2o$13b2o$2b2o5b2o2b2o$bobo9b2o8b2o$bo6b3o12b2o$2o 8b4o$12b3o$12bob2o$11b2o2bo$11b2ob2o$12bobo$13bo2$6b2o$5bobo$5bo$4b2o$ 10b2o36bo6b2o$11bo37b2o4b2o$8b3o37b2o$8bo$57bo$15b2o39bobo$14bobo15b2o 23bo$13b2obo15b2o24b3o63b2o$8bo5b2o44bo63b2o$6b3o6bo$5bo112bo5bo$6b3o 6bo15b2o84b3o3b3o$8bo5b2o15b2o20b2o62bo2bobo2bo$13b2obo35b2ob2o62b2ob 2o$14bobo18b3o15b4o$15b2o18bobo16b2o$35bobo$36bobo78bo7bo$38bo79bobobo bo$70bo47bobobobo$70b3o44bob2ob2obo$37bo35bo43b2o5b2o$37bo34b2o20b2o$ 59bo35bo$59b3o33bobo$62bo33b2o$61b2o4$28b2o7b2o11bo24bo$28bob2o3b2obo 10b3o22b3o$28bo3bobo3bo9b2obo21b2o2bo41b2ob2o$28b2o2bobo2b2o9b3o21b2o 3b2o11b2o28bobo$29b3o3b3o11b2o19bobo2bobo13bo10b3o8b2o5bobo$30bo5bo33b 2o3b2o9b2o3bobo7bo2bo4bo3b2o6bo$65b2o19bobo3b2o6bo3bo3bobo$65b2o21bo 11bo7bobo$25b2o13b2o46b2o13bo$25b2o2b2o5b2o2b2o58b2obo$29b2o5b2o$121b 2o$103bob2o14bobo$103b3o17bo$40bo63bo18b2o$40bo2b2o72b2o$39bo5bo36b2o 33bo$40bobo2b2o35bobo33b3o$27bo12bo3b2o38bo35bo$25b3o14b3o39b2o20b2o$ 24bo41b2o10b2o26bo$25b3o14b3o20bo2bo9bo28b3o$27bo12bo3b2o20b2o11b3o27b o$40bobo2b2o4b2o28bo$39bo5bo5b2o$40bo2b2o$40bo! """, 46, 1924) Gap = "3bo7bo7bo$b3o5b3o5b3o$o7bo7bo$2o6b2o6b2o21$" # string, not pattern! LinearClockEaters = pattern("3bo$b3o$o$2o5$" * 36 + Gap \ + "3bo$b3o$o$2o5$" * 10 + "24$" + "3bo$b3o$o$2o5$" * 17 \ + Gap + "3bo$b3o$o$2o5$" * 42 + Gap \ + "3bo$b3o$o$2o5$3bo7bo$b3o5b3o$o7bo$2o6b2o13$" \ + "3bo$b3o$o$2o5$" * 30 + "8$" + "3bo$b3o$o$2o5$" * 2 + Gap + "16$" \ + "3bo$b3o$o$2o5$" * 11 + "8$" + "3bo$b3o$o$2o5$" * 19, 101, 422) LinearClockCap = pattern(""" 3b2o13bo7bo$2bo2bo10b3o5b3o$bobobo9bo7bo14b2o$3obo10b2o6b2o13bobo$3o 29bo6b3o$30b2ob2ob3ob2o$30b2ob2ob5o$32bo5bo$2b2o29b2ob2o$2b2o3$32bo5bo $31b2o5b2o$30bob2o3b2obo$30bob2o3b2obo$31b3o3b3o$31b3o3b3o10$33b2ob2o$ 34bobo$34bobo$35bo! """, 83, 401) all += LinearClockGun[1840] + LinearClockEaters + LinearClockCap # slide 23: MWSS track -------------------- MWSS = pattern("b5o$o4bo$5bo$o3bo$2bo!", 521, 1973) P46Osc = pattern(""" 40bo$31b2o5b3o$10b3o14b2o3bo4bo$10bo3bo12b2o3bobo3bo$3bo6bo4bo17bobo3b o$b3o7bo3bo18bo3b2o$o$b3o7bo3bo7b3o$3bo6bo4bo5b2obob2o$10bo3bo5bo5b2o$ 10b3o8b2obob2o$23b3o!""") P46Gun = pattern(""" 31b2o$30b2o$31b5o9bo$16b3o13b4o9b3o$14bo3bo29bo$3bo9bo4bo13b4o9b3o$b3o 9bo3bo13b5o9bo$o29b2o$b3o9bo3bo13b2o$3bo9bo4bo$14bo3bo$16b3o!""") GliderToMWSS = P46Osc(449, 1963) + P46Gun(474, 1981) # exact match would be P46Gun[46](474, 1981), but that glider is absorbed StateBit = pattern("b2o$obo$bo!", 569, 1970) Snake = pattern("2o$o$bo$2o!", 570, 1965) BitKeeper = pattern(""" 15bobo2b2o19b2o$14bo3bob3o19bo$15bo6b2o15b3o$3bo12b5obo16bo$b3o15b3o$o $b3o15b3o$3bo12b5obo$15bo6b2o3b2o$14bo3bob3o4b2o$15bobo2b2o! """, 524, 1982) GliderFromTheBlue = pattern(""" 23b2o$23bo2bobo$25b2ob3o$31bo$25b2ob3o$12bo3bo8b2obo$11bo5bo$17bo$3bo 8bo3b2o$b3o9b3o$o$b3o9b3o19bo$3bo8bo3b2o7bo7b3o$17bo4bo2bob2o3bo$11bo 5bo10bo4bo$12bo3bo10bo4b2o2$23b5o$24b4o$26bo!""") GliderToLWSS = pattern(""" 3bo$2bobo$bo3bo3b2o$b5o3b2o$obobobo$bo3bo2$bo3bo$obobobo$b5o$bo3bo$2bo bo$3bo6$b3o5b3o$2ob2o3b2ob2o$2obobobobob2o$bo3bobo3bo$bo2bo3bo2bo$2b3o 3b3o4$4b2ob2o$5bobo$5bobo$6bo!""", 663, 1931) # P46Osc really ReflectLWSS = pattern(""" b2o$b2o8$b3o3b3o$o2bo3bo2bo$2obo3bob2o14$3b2ob2o$4bobo$4bobo$5bo! """, 589, 1940) ReflectLWSS2 = pattern(""" 15b2o3bo$15b3obob2o4b2o$15b3o4bo4b2o$3bo14bo3bo$b3o15b3o$o$b3o15b3o$3b o14bo3bo$15b3o4bo$15b3obob2o$15b2o3bo!""", 573, 1884) # P46Osc really LWSStoBoat = pattern(""" 2o14b2o9b2o$2o15b2o8b2o$13b5o$13b4o2$3b2o8b4o$2bobob2o5b5o$b2o3b2o9b2o 8b2o$2bobob2o8b2o9b2o$3b2o!""", 821, 1883) # P46Osc really ReflectMWSS = pattern(""" 22b2o5b2o$18b2o2b2o5b2o2b2o$18b2o2b2o5b2o2b2o$22b3o3b3o$21bo2bo3bo2bo$ 25bobo$21b2o7b2o$21b2o7b2o$24bo3bo$24b2ob2o$22b3o3b3o$22b2o5b2o$22bo7b o10$b2o27b2o$b2o25b2ob2o$26bo2bobo$6bo3b2o14bo$2o2b2obob3o14bo4bo$2o2b o4b3o15bo3bo$4bo3bo15b2o2b3o$5b3o16b2o2$5b3o$4bo3bo$2o2bo4b3o13b2o$2o 2b2obob3o13b2o$6bo3b2o2$b2o$b2o!""") HoneyBit = pattern("b2o$o2bo$b2o!") CornerSignalSystem = pattern() CornerSignalSystem += pattern(""" 4b2o4b3o$4b2o3bo3bo$9b2ob2o$10bobo2$10bobo$9b2ob2o$9bo3bo$10b3o9$3b3o 5b3o$3bo2b2ob2o2bo$4b3o3b3o$5bo5bo4$2o13b2o$2o2b2o5b2o2b2o$4b2o5b2o! """, 70, 9) # P46OscAlt1 really # include stopper for pattern corners, destroyed in the interior of # multi-cell metapatterns by the tub-LWSS-fuse combination CornerSignalSystem += pattern("5b2o$5b2o3$2o2b2o$2o2b2o!", 86, 1) CornerSignalSystem += pattern(""" 11b2o$11b2o12$4b3o3b3o$4b3o3b3o$3bob2o3b2obo$3bob2o3b2obo$4b2o5b2o$5bo 5bo6$2o13b2o$2o2b2o5b2o2b2o$4b2o5b2o!""", 159, 0) # P46OscAlt1 really SignalSystem = pattern() for i in range(0,3): # place three sets of mechanisms to signal neighbors SignalSystem = SignalSystem[32](2047, 0, rcw) \ + HoneyBit(42, 111, rcw) + ReflectMWSS(38, 46) + GliderFromTheBlue(73, 52) \ + CornerSignalSystem + HoneyBit(964, 40) + GliderFromTheBlue[12](953, 52) # need to add the fourth (west) side separately because signal stops there, # so two-thirds of the pieces are customized or in slighly different locations # (could have started in SW corner and used range(0,4) for some of it, # but I happened to start in the NW corner and now I'm feeling lazy) # west edge: SignalSystem += HoneyBit(48, 1086, rcw) + pattern(""" 11b2o$12bo$12bob2o$13bobo$3bo$2bobo$2bobo$b2ob2o$4bo$b2o2bo7bo$2bo2bo 7bobo$o8b3o$2o9b3o2bo$9b2o4b2o$13b2o6$8bo3bo$8bo3bo3$5b2obo3bob2o$6b3o 3b3o$7bo5bo6$8b2ob2o$9bobo$9bobo$10bo!""", 52, 1059) # GliderFromTheBlue really # southwest corner: SignalSystem += pattern(""" 11b2o$12bo$12bob2o$13bobo$3bo$2bobo$2bobo$b2ob2o2$b2ob2o7b3o$2bob2o6bo 2bo$o13b2o$2o9bo3bo$11bo2b2o$13bob2o9$5b2o7b2o$5bob2o3b2obo$5bo3bobo3b o$5b2o2bobo2b2o$6b3o3b3o$7bo5bo4$8b2ob2o$9bobo6b2o$9bobo7bo$10bo5b3o$ 16bo!""", 52, 1885) # GliderFromTheBlue plus a terminating eater really SignalSystem += pattern(""" 24b2o$24b2o3$2o14b3o6b2o$2o12bo3bo6b2o$13bo4bo$13bo3bo2$3b3o7bo3bo$b2o bob2o5bo4bo$b2o5bo5bo3bo6b2o$b2obob2o8b3o6b2o$3b3o2$24b2o$24b2o! """, 0, 1818) # P46OscAlt1 really -- lengthened version of CornerSignalSystem SignalSystem += pattern("2o$2o2b2o$4b2o3$4b2o$4b2o!", 1, 1955) + pattern(""" 24b2o$24b2o2$14b3o$13bo4bo6b2o$12bo5bo6b2o$13bo$14b2o2$14b2o$13bo$2o 10bo5bo6b2o$2o11bo4bo6b2o$14b3o2$24b2o$24b2o!""", 9, 1961) # P46OscAlt1 really all += SignalSystem + GliderToMWSS + MWSS + Snake + BitKeeper all += GliderFromTheBlue(607, 1953) + GliderToLWSS + ReflectLWSS \ + ReflectLWSS2 + LWSStoBoat # all += StateBit # do this later on, when defining OFFcell and ONcell # slide 24: LWSS track -------------------- # [phase adjusters and a bunch of honeybits] PhaseAdjuster = P46Gun(2, 11, flip_y) + P46Gun[12](0, 32) \ + pattern("o$3o$3bo$2b2o!", 0, 13) \ + pattern("2b2o$bobo$bo$2o!", 2, 26) # eaters really all += PhaseAdjuster[43](1772,10) + PhaseAdjuster[26](2037, 1772, rcw) all += PhaseAdjuster[43](269, 2037, flip) + PhaseAdjuster[9](58, 1203, swap_xy_flip) # the third adjuster was a different shape in the original metacell, # but one of the same shape could be substituted with no ill effects LWSSPacketGun = pattern(""" 50b2o$52bo$37b2o10b2o2bo$37b2o11bo2bo$51bobo8bo$51b2o9b3o$65bo$40b2o9b 2o9b3o$38bo3b2o7bobo8bo$38bo4bo6bo2bo$38bo3b2o5b2o2bo$40b2o10bo$50b2o 5$52bo$52b3o$55bo$54b2o$41bo$41b3o$b2o5b2o34bo$b2o5b2o33b2o3$45b2o$43b o3bo5b2o9b2o$42bo5bo3bo2bo4b3o2bo$42bo4bo5bo4bo2b5o$42bo2bo7bo2b4o$43b obo8bob2o3bo$44bo8b2obob3o7b2o$55bo3bo8bobo$52b3o15bo$53bo16b2o$bo7bo$ b2o5b2o$b3o3b3o$3b2ob2o45b2o$3bo3bo22b2o21b2o$2o7b2o20bo$2o7b2o17b3o$ 4bobo21bo35b2o$o2bo3bo2bo53bobo$b3o3b3o56bo$66b2o$60b2o$60bo$b2o25b2o 31b3o$b2o25b2o33bo2$19b2o$17b2o2bo7b2o$17b6o6b2o$17b4o4$17b4o$17b6o6b 2o$17b2o2bo7b2o$19b2o2$28b2o$12bobo13b2o$13b2o$13bo5$17b2o$17b2o19$49b o3b3o$48bobo2b5o3b2o$48bo3b2o3b2o2b2o$49bo2bo3b2o$50b3o3bo2$50b3o3bo$ 49bo2bo3b2o$34b2o12bo3b2o3b2o2b2o$34b2o12bobo2b5o3b2o$49bo3b3o5$39bo$ 17b3o19b3o$17bo2bo21bo$17bo23b2o$17bo10bo$18bobo7b3o$31bo$30b2o$43bo3b o$42b5obo$41b3o4b2o$41b2ob5o$43b3o2$45bo$41bo2b3o$40b2obo3bo7b2o$34b2o 3b2ob3obo2b2o4bobo$34b2o3b3ob2o4b2o6bo$39b3o15b2o4$41bo$41bob3o$42bo3b o$13b2o3b2o8bo17bo$12bo2bobo2bo7bo2b2o10b2obo4b2o$11bo9bo5bo5bo11bo5bo bo$10b2o9b2o5bobo2b2o18bo$11bo9bo6bo3b2o3bo15b2o$12bo2bobo2bo9b3o4b3o 7b2o$13b2o3b2o20bo6bo$30b3o4b3o8b3o$28bo3b2o3bo12bo$12b2o14bobo2b2o$ 12b2o13bo5bo$28bo2b2o$28bo!""", 108, 710) all += LWSSPacketGun + pattern(""" b2o$b2o$7b3o$6bo3bo$6b2ob2o2$6b2ob2o$8bo4$bo7bo$o2bo3bo2bo$4bobo$4bobo $4bobo$o2bo3bo2bo$b3o3b3o8$3b2ob2o$4bobo$4bobo$5bo!""", 18, 725) # P46Osc really P46OscAlt1 = pattern(""" b2o$b2o2$6bo3b2o$2o2b2obob3o13b2o$2o2bo4b3o13b2o$4bo3bo$5b3o$19b2o3b2o $5b3o10b3o3b3o$4bo3bo7b3o7b3o$2o2bo4b3o4b3o7b3o$2o2b2obob3o4b3o7b3o$6b o3b2o6b3o3b3o$19b2o3b2o$b2o$b2o!""") all += P46OscAlt1(4, 24) + P46OscAlt1[12](224, 67, swap_xy_flip) P46OscAlt2 = pattern(""" 2o8b3o14b2o$2o8bo3bo12b2o$10bo4bo$11bo3bo2$11bo3bo7b3o$10bo4bo5b2obob 2o$2o8bo3bo5bo5b2o$2o8b3o8b2obob2o$23b3o!""") all += P46OscAlt2(179, 19) + P46OscAlt1[29](2023, 4, rcw) # got impatient here, started throwing in placeholders instead of true definitions -- # NE corner along E edge: all += pattern(""" b2o$b2o2$8b2o9b2o3b2o$2o5bobo8bob2ob2obo$2o4b2obo8bo7bo$7b2o9bob2ob2ob o$8bo10b2o3b2o2$8bo$7b2o$2o4b2obo15b2o$2o5bobo15b2o$8b2o2$b2o$b2o! """, 1980, 208) + pattern(""" 2b2o5b2o$2b2o5b2o15$b3o5b3o$2ob2o3b2ob2o$2obobobobob2o$bo3bobo3bo$bo2b o3bo2bo$2b3o3b3o6$9b2o$9b2o!""", 2018, 179) # both P46OscAlt really # SE corner: all += pattern(""" 24b2o$24b2o$14bo$13bo2bo$12b5o8b2o$11b2ob3o8b2o$12bob2o$13b2o2$13b2o$ 12bob2o$2o9b2ob3o8b2o$2o10b5o8b2o$13bo2bo$14bo$24b2o$24b2o! """, 2017, 2007) # P46OscAlt really # SE corner along S edge: all += pattern(""" 4b2o5b2o$2o2b2o5b2o2b2o$2o13b2o10$4bo7bo$3bobo5bobo$6bo3bo$3bo2bo3bo2b o$4bobo3bobo$6b2ob2o$3b2ob2ob2ob2o$3b2o2bobo2b2o$4b3o3b3o$5bo5bo4$4b2o $4b2o!""", 1823, 1980) + pattern(""" 20bo$15bo3bo$14bo8b2o2b2o$14bo2b2o5bo2b2o$15b2o5bobo$16b3o3b2o2$16b3o 3b2o$15b2o5bobo$2o12bo2b2o5bo2b2o$2o12bo8b2o2b2o$15bo3bo$20bo! """, 1840, 2018) # both P46OscAlt really # SW corner: all += pattern(""" 4b2o4b3o$4b2o3bo3bo$9b2ob2o$10bobo2$10bobo$9b2ob2o$9bo3bo$10b3o9$3b3o 5b3o$3bo2b2ob2o2bo$4b3o3b3o$5bo5bo4$2o13b2o$2o2b2o5b2o2b2o$4b2o5b2o! """, 24, 2017) # P46OscAlt really # SW corner along W edge: all += pattern(""" 24b2o$24b2o3$2o14b2o7b2o$2o15b2o6b2o$13b5o$13b4o2$3b2o8b4o$2bobob2o5b 5o$b2o3b2o9b2o6b2o$2bobob2o8b2o7b2o$3b2o2$24b2o$24b2o! """, 41, 1769) + pattern(""" b2o5bo$b2o4bobo$6bo3bo$6bo3bo$5b3ob3o$6bo3bo$6b2ob2o$7bobo$8bo5$3bo3bo $3bo3bo3$2obo3bob2o$b3o3b3o$2bo5bo8$b2o5b2o$b2o5b2o! """, 6, 1786) # both P46OscAlt really # LWSS -> G -> LWSS timing adjustment, middle of W edge: all += pattern(""" b2o5b2o$b2o5b2o16$3o5b3o$o2b2ob2o2bo$b3o3b3o$2bo5bo7$b2o$b2o! """, 10, 1217) + pattern(""" 4bo$2b5o10bo$bo2bob2o9b2o8b2o$o7bo9b2o7b2o$bo2bob2o5b2o2b2o$2b5o$4bo2$ 13b2o2b2o$2o16b2o7b2o$2o15b2o8b2o$17bo! """, 35, 1269) # both P46OscAlt really # final LWSS reflector, middle of W edge: all += pattern(""" 15bo$14b2o$13b3obo9b2o$12b2o13b2o$3bo9b2o$b3o10bo$o$b3o10bo10bo$3bo9b 2o8b2obo$12b2o8b2ob3o$13b3obo5bo2bo$14b2o8b2o$15bo! """, 8, 973) # P46Osc really # slide 25: decode -------------------- # sync buffer: all += pattern(""" b2o5b2o$b2o5b2o7$2bo5bo$b3o3b3o$o2b2ob2o2bo$3o5b3o9$b3o$o3bo$2ob2o$bob o2$bobo$2ob2o$o3bo3b2o$b3o4b2o!""", 150, 958) # P46OscAlt3 really all += pattern(""" 10b2o$2o6b2ob2o14b2o$2o6bo2bo15b2o$8bo2bo$9b2o2$9b2o$8bo2bo$8bo2bo15b 2o$8b2ob2o14b2o$10b2o!""", 155, 998) # P46OscAlt3 really all += pattern(""" 15bobo2b2o$2o12bo3bob3o4b2o$2o13bo6b2o3b2o$16b5obo$19b3o2$19b3o$16b5ob o$2o13bo6b2o$2o12bo3bob3o$15bobo2b2o!""", 114, 1008) # P46OscAlt3 really all += pattern(""" b2o$b2o11$2bo5bo$bobo3bobo$o3bobo3bo$o3bobo3bo$o9bo2$b2o5b2o3$3b2ob2o$ 4bobo$3b2ob2o$4bobo$3b2ob2o$4bobo$4bobo$5bo!""", 141, 1024) # P46OscAlt3 really # P46 to P40 converter: all += pattern(""" 14bo$14b3o$17bo$16b2o50bo$10b2o54b3o$11bo53bo$11bobo51b2o$12b2o57b2o$ 48b2o21bo$48bo20bobo$33bo12bobo20b2o$33b3o10b2o$36bo$35b2o2$6b2o$7bo 22bo$7bobo19b2o$8b2o10bo4bo49b2o$19b2o3b2o30bo18bo$18b2o3b2o29b4o15bob o$19b2o4bo27b2o3b2o13b2o$20b2o34bo3bo$56bo3bo$56bo2b2o$54bo3bo2$33b2o$ 33bo$34b3o$36bo11b2o$22b2o25bo$22bo23b3o$19bo3b3o20bo$17b3o5bo33b2o$ 16bo43bo$16b2o39b3o8bo$30bo26bo8b3o$28b3o34bo$27bo37b2o$27b2o42b2o$48b 2o21bo$17b2ob2o26bo20bobo$17b2ob2o11bo12bobo20b2o$33b3o10b2o$24b2o10bo $24b2o9b2o21b2o$58b2o$16b2o$2b2o11b2obo15bo$bobo12bob4o13bo$bo15bo2b3o 10b3o39b2o$2o16bo3bo52bo$18b4o51bobo$20bo8b3o34b2o5b2o$31bo21b3o7bo2b 3o$17b2o11bo21b2ob2o2b4o2bo2bo$17b2o15b2o15bo4b2ob4ob2o2bo$34b2o16b6o 6b2obo$53b2o2bo8bo$6b2o49b2obo$5bobo50bobo$5bo52bo$4b2o42b2o$10b2o37bo $11bo34b3o$8b3o35bo$8bo50b2o$60bo$57b3o$8bo48bo$6bobo$7bobo$7bo2$19b2o $19b2o4$2b2o13b2o$3bo11bo2bo$3bobo9bo2bo$4b2o8b2ob2o$13b2ob2o$12b2o3b 2o$13b3o2bo$18bo$15bobo15b2o$16bo16bobo$35bo$35b2o$29b2o$29bo$30b3o$ 32bo$18b2o$18bo$14bo4b3o$14b3o4bo$17bo$16b2o50bo$10b2o54b3o$11bo53bo$ 11bobo51b2o$12b2o57b2o$48b2o21bo$48bo20bobo$23b2o8bo12bobo20b2o$23b2o 8b3o10b2o$36bo$35b2o21b2o$58b2o$6b2o16bo$7bo15b3o$7bobo8bo3bo$8b2o7b3o bob2o8bo41b2o$16bo3b2obo8bobo19bo20bo$18b4o2bo7bo2bo17bobo3bobo4bo6bob o$12b5o2bo4bo5bo4bo16bo3b3obobo2bobo5b2o$12bo2b3o4bo2bo3bo5bo15b2o2bo 4bobobo3b2o$12b2o9b2o5bo3bo15b2ob3o5bo3b2o$31b2o16bo4bo$50b4o6b2o4bo2b o$51b2o6bo6bobo$33b2o24b3o4b2o$33bo24b2o$34b3o21bo$36bo11b2o$14bo7b2o 25bo$14b3o5bo23b3o$17bo5b3o20bo$16b2o7bo33b2o7bo$10b2o48bo5b3o$11bo45b 3o5bo$11bobo43bo7b2o$12b2o57b2o$48b2o21bo$18b2o28bo20bobo$18b2o13bo12b obo20b2o$33b3o10b2o$20bo15bo26b2o$14b3o3b2ob2o10b2o26b2o$14b2o5bobobo 32bo$6b2o8bo4bob2o31b2obo$7bo12b3o37bo5b2o$7bobo6b2o2bobo33b2o2bo5b2o$ 8b2o6b6o37bob2o12b2o$16b3o4b2o32bobob2o3b2o7bo$23b2o34bo2bo3b2o5bobo$ 57bob2o12b2o$59bob2o$60b2o4$33b2o$33bo$34b3o$36bo11b2o$14bo7b2o25bo$ 14b3o5bo23b3o$17bo5b3o20bo$16b2o7bo33b2o7bo$10b2o48bo5b3o$11bo45b3o5bo $11bobo43bo7b2o$12b2o57b2o$48b2o21bo$48bo20bobo$33bo12bobo20b2o$33b3o 10b2o$36bo$35b2o2$6b2o$7bo10b3o8b2o$7bobo7bo2bo4bo3b2o$8b2o6bo3bo3bobo 48b2o$16bo7bobo25bo22bo$19bo32b2o19bobo$16b2obo37bo4bo10b2o$57b2o3b2o$ 58b2o3b2o$19bob2o34bo4b2o$19b3o39b2o$20bo$33b2o$33bo$34b3o$36bo11b2o$ 22b2o25bo$22bo23b3o$19bo3b3o20bo$17b3o5bo33b2o$16bo43bo$16b2o39b3o8bo$ 30bo26bo8b3o$28b3o34bo$27bo37b2o$27b2o42b2o$48b2o21bo$17b2ob2o26bo20bo bo$17b2ob2o11bo12bobo20b2o$33b3o10b2o$16b2o6b2o10bo$14bo3bo5b2o9b2o21b 2o$13bo4b2o38b2o$13bo5bo$2b2o$bobo10bo4bo$bo12b2obob2obo34b3o15b2o$2o 30bo2b3o19b4o14bo$31bo3bobo14b2o3b2ob2o3b2o6bobo$32bob3o14bo7bo5b3o5b 2o$49bo2bo5b3o3bob3o$49bo2bo5b2obo2b2obo$34b2o12bo3bo8b2ob2obo$34b2o 13b3o7bobo3bobo$60bo4bo2bo$6b2o57b3o$5bobo50b2o6bo$5bo52b2o$4b2o42b2o$ 10b2o37bo$11bo34b3o$8b3o35bo$8bo50b2o$60bo$57b3o$8bo48bo$6bobo$7bobo$ 7bo2$19b2o$19b2o4$2b2o$3bo$3bobo$4b2o4b4o$9b2o2bo5b2o$8b2o2bo4bobob2o$ 9bo2bo2b2o5bo$10b2o6bo3bo$15bo5bo11b2o$16b4o13bobo$18bo16bo$35b2o$29b 2o$29bo$30b3o$32bo$18b2o$18bo$19b3o$21bo!""", 116, 1059) # really 14 p184 guns # logic core latches: all += pattern(""" 24bo2bo$14b3o7bo$13bo4bo9bo$12bo5bo8b2o$3bo9bo8bo$b3o10b2o8b2o$o$b3o 10b2o8b2o$3bo9bo8bo3bo$12bo5bo4bo2bo$13bo4bo4bo2bo$14b3o7b2o! """, 33, 1332) # P46Osc really all += pattern(""" 4b2o5b2o$2o2b2o5b2o2b2o$2o13b2o2$4b3o3b3o$4bo2bobo2bo$3bo3bobo3bo$4bo 2bobo2bo$6bo3bo$4b2o5b2o$3b3o5b3o$3b3o5b3o5$10b3o$10b3o$9b5o$8b2o3b2o$ 8b2o3b2o4$8b2o3b2o$4b2o2b2o3b2o$4b2o3b5o$10b3o$10b3o!""", 35, 1348) # P46OscAlt1 really all += pattern(""" b2o$b2o2$13bobo2b2o$2o10bo3bob3o$2o11bo6b2o$14b5obo$17b3o2$17b3o$14b5o bo$2o11bo6b2o3b2o$2o10bo3bob3o4b2o$13bobo2b2o2$b2o$b2o! """, 24, 1661) # P46OscAlt1 really all += pattern(""" b2o$b2o12$b3o3b3o$b3o3b3o$ob2o3b2obo$ob2o3b2obo$b2o5b2o$2bo5bo3$3b2ob 2o$4bobo$4bobo$4bobo$3b2ob2o$4bobo$4bobo$5bo!""", 49, 1679) # P46Osc really all += pattern(""" b2o$o2bo$o7bo$o2bo3bobo$2ob2ob2ob2o$4bobo$3b2ob2o5$b3o3b3o$o9bo$o3bobo 3bo$b3o3b3o$2bo5bo10$3b2ob2o$4bobo$4bobo$5bo!""", 140, 1546) # P46Osc really all += pattern(""" 2b3o$2b3o4b2o$bo3bo3b2o$o5bo$b2ob2o2$b2ob2o$o5bo$bo3bo$2b3o$2b3o7$b2o 7b2o$bob2o3b2obo$bo3bobo3bo$b2o2bobo2b2o$2b3o3b3o$3bo5bo6$2b2o5b2o$2b 2o5b2o!""", 184, 1538) # P46OscAlt3 really all += pattern("2o$o$b3o$3bo!", 159, 1537) # eater really # slide 26: read B/S table -------------------- # most of the B/S logic latches -- missing some reflectors off to the left (?) # TODO: take this apart and integrate with missing pieces all += pattern(""" 34bo$33bobo$33bobo$32b2ob2o11$30bo7bo22b2o5b2o$29bobo5bobo21b2o5b2o$ 32bo3bo$29bo2bo3bo2bo$30bobo3bobo$32b2ob2o$29b2ob2ob2ob2o$29b2o2bobo2b 2o$30b3o3b3o$31bo5bo23b3o3b3o$60bo2bo3bo2bo$60b2obo3bob2o2$37b2o$37b2o 6$62bo$60b2ob2o$60b2ob2o15b2o5b2o$80b2o5b2o$59bobobobo2$60b2ob2o$61b3o 4b2o$62bo5b2o4$81bo5bo$80b3o3b3o$80bob2ob2obo$82b2ob2o$82b2ob2o$82b2ob 2o6$80b3o$80b3o2$79b2ob2o$79bo3bo$80b3o$81bo5b2o$87b2o199$51bo$50bobo$ 50bobo$49b2ob2o13$47bo7bo$46b4o3b4o$46bo3bobo3bo$47bo2bobo2bo$47b3o3b 3o7$47b2o$47b2o9$62b3ob3o9b2o$61bob2ob2obo7b2ob2o6b2o$60b2o7b2o7bo2bo 6b2o$61bob2ob2obo8bo2bo$62b3ob3o10b2o2$79b2o$78bo2bo$61b2o15bo2bo6b2o$ 61b2o14b2ob2o6b2o$78b2o5$80b2o5b2o$80b2o5b2o11$81bo5bo$80bobo3bobo$79b o3bobo3bo$79bo3bobo3bo$79bo9bo2$80b2o5b2o4$82bo3bo$80b2o$79bo3bobo3b2o $79bo3bobo$80b3o$87bo2bo$87b2o12$8b2o$8b2o13$b2o5b2o$o2bo3bo2bo$bo2bob o2bo$4bobo$2b3ob3o$3o5b3o$2o7b2o$2o7b2o$bob2ob2obo$bob2ob2obo2$3b2ob2o $4bobo$4bobo$5bo26$9bo$8bobo$8bobo$7b2ob2o11$5b2o5b2o$4bo2bo3bo2bo$7b 2ob2o$6bobobobo$6bobobobo$4bo9bo$3bo11bo2$7b2ob2o$5bo2bobo2bo$5b3o3b3o 3$5b2o$5b2o38$10bo$9bobo28bo$9bobo21b2o4bobo$8b2ob2o20bo5bobo$31bobo4b 2ob2o$18b2o11b2o$19bo18b2ob2o$19bobo$20b2o16b2ob2o3$23b2o$22bobo11bo7b o$24bo$6b2o5b2o19b3o7b3o$5bo2bo3bo2bo19b2ob2ob2ob2o$6bo2bobo2bo15b2o4b 3o3b3o$9bobo18bobo4bo5bo$7b3ob3o16bo$5b3o5b3o$5b2o7b2o$5b2o7b2o$6bob2o b2obo$6b3o3b3o$7bo5bo$9b3o3b3o$8bo2bo3bo2bo$12bobo$8b2o7b2o$8b2o7b2o$ 11bo3bo$11b2ob2o$9b3o3b3o$9b2o5b2o16bo5bo$9bo7bo15bobo3bobo$32bo3bobo 3bo$32bo3bobo3bo$32bo9bo2$33b2o5b2o3$35b2ob2o$36bobo$35b2ob2o$11b2ob2o 20bobo$12bobo20b2ob2o$12bobo21bobo$13bo22bobo$37bo3$52b2o$51b5o$35b2o 14bo4bo5b2o$35b2o14b3o2bo5b2o$52bo2b2o$53b2o$37bo3bo$35b2obobob2o9b2o$ 34bob2o3b2obo7bo2b2o$33bo2bo5bo2bo5b3o2bo5b2o$34bob2o3b2obo6bo4bo5b2o$ 35b2obobob2o7b5o$37bo3bo10b2o8$19b2o$18bo2bo$18bobo2bo$19bo$20b2obo$ 22bo3$21b2o$21b2o4b3o$27b3o$26bo3bo$26b2ob2o$26bo3bo$27bobo$27bobo$28b o5$23b2ob2o$22bo5bo2$21bo7bo$21bo2bobo2bo$21b3o3b3o9$21b2o5b2o$21b2o5b 2o23$9bo2bo$12bo7b3o$8bo9bo4bo$8b2o8bo5bo35bo$14bo8bo36b2o$11b2o8b2o 24b2o9bob3o$47b2o13b2o$11b2o8b2o38b2o$14bo8bo37bo$8b2o8bo5bo10b2o$8bo 9bo4bo11b2o24bo$12bo7b3o38b2o$9bo2bo34b2o13b2o10b2o$47b2o9bob3o11b2o$ 60b2o$60bo!""", 108, 1317) # slide 27: boat logic -------------------- all += pattern(""" 32b4o$31b2o2bo$30b2o2bo$26bo4bo2bo25b2o$24b3o5b2o25b2ob2o$23bo36bo2bo$ 24b3o5b2o26bo2bo4bo$26bo4bo2bo26b2o5b3o$30b2o2bo36bo$31b2o2bo25b2o5b3o $32b4o7bo16bo2bo4bo$41b2o17bo2bo$42b2o15b2ob2o$60b2o3$b2o$b2o2$14b4o$ 2o12bo2b2o$2o13bo2b2o$15bo2bo$16b2o2$16b2o15b2ob2o$15bo2bo12bobo3bo$2o 13bo2b2o5b2o3bobo3bo$2o12bo2b2o6b2o3bo4bo$14b4o11b2o5b3o$38bo$b2o$b2o! """, 209, 1852) # P46Osc plus P46Gun plus custom eater really # boat-logic: need to add outlying pieces to west, break up into 12 all += pattern(""" 119bo$35b2o81b2ob2o$34b5o11b2o54b2o10b2o2bo3b2o217b2o$34bo4bo11bo53bo 2bo11bob2o3bo217bo7b3o5b4o$34b3o2bo10bo49bo4bo2b2o9bo2bo3bo219bo6bo7b 2obo$21bo13bo2b2o11b3o43bo3bo3bo2bo11b2o5b3o213b3o7b2obo7bo10bo$19b3o 14b2o15bo41b7o5bo12bo8bo213bo11b2o5b2o11b3o$18bo75bo283bo$19b3o14b2o 57b7o5bo247b2o5b2o11b3o$21bo13bo2b2o57bo3bo3bo2bo246b2o7bo10bo$34b3o2b o60bo4bo2b2o251b2obo$34bo4bo65bo2bo252b4o$34b5o4b2obo59b2o11b2obo227bo $35b2o6b2ob3o70b2ob3o223b6o$49bo75bo221bo4bo$43b2ob3o70b2ob3o223b3ob2o $41bo2bobo70bo2bobo227bobo2bo$41b2o74b2o235b2o11$53bo37b2o$48bo3bo28b 2o7bobo187bo3bo$47bo7bo25b2o6b2obo186bo5bo$47bo2b2o5bo32b2o14bo107bobo 2b2o58bo$36bo11b2o5b2obo32bo14b3o90b2o12bo3bob3o4b2o43bo7b2o3bo8bo$34b 3o12b3o3b2ob3o48bo89b2o13bo6b2o3b2o41b3o9b3o9b3o$33bo27bo29bo14b3o106b 5obo46bo27bo$34b3o12b3o3b2ob3o29b2o14bo111b3o48b3o9b3o9b3o$36bo11b2o5b 2obo30b2obo17bo88bobo3bobo63bo7b2o3bo8bo$47bo2b2o5bo32bobo17b3o88bo3bo 12b3o58bo$47bo7bo35b2o20bo83bo11bo5b5obo57bo5bo$48bo3bo59b2o82bo3bo5bo 3bo3bo6b2o3b2o52bo3bo$53bo143bo11bo3bo3bob3o4b2o$201bo3bo8bobo2b2o$ 199bobo3bobo12$2b2o5b2o$2b2o5b2o$59bo229bob2o$58b2o228bo2b2o2b3o$57b2o 229bo6b2o$51bo6b2o2b2o9bo101b2o109b4o3b3o12bo$49b3o21b3o99bo108b3o3bo 3bo13b3o$48bo27bo99b3o70bo33bo27bo$49b3o21b3o102bo70b3o32b3o3bo3bo13b 3o$51bo6b2o2b2o9bo178bo33b4o3b3o12bo$57b2o192b2o35bo6b2o$58b2o228bo2b 2o2b3o$59bo229bob2o$2b3o3b3o$2b3o3b3o$bob2o3b2obo$bob2o3b2obo$2b2o5b2o $3bo5bo4$4b2ob2o$3bo5bo$b5ob2ob2o$2ob3ob2ob2o$3o6bo$bobo$2b2o263b4o5b 6o$212b6o5b4o40bob2o7b4o$212b4o7b2obo40bo7bob2o$76b2o46b2o89b2obo7bo 41b2o5b2o$75bo2bo44bo2bo90b2o5b2o$76b2o46b2o142b2o5b2o$217b2o5b2o41bo 7bob2o$215b2obo7bo26b2o12bob2o7b4o$212b4o7b2obo12b2o12b2o12b4o5b6o$ 212b6o5b4o12b2o!""", 679, 1875) # P46Osc1-4 boat logic # mystery stuff along bottom edge that needs a home in a slide: all += pattern(""" b2o5b2o$b2o5b2o14$3o5b3o$3o5b3o$b2o5b2o$3bo3bo$bo2bobo2bo$o3bobo3bo$bo 2bobo2bo$b3o3b3o5$8b2o$8b2o!""", 514, 1887) # P46OscAlt3 really all += pattern(""" 4bo7b2o$3b2o6bo2bo$2bo8bo2b2o$3b2obo4bo2bo10bo$4b3o6bo11b3o$28bo$4b3o 6bo11b3o$bob2obo4bo2bo10bo$o10bo2b2o$o3bo6bo2bo$b4o7b2o! """, 791, 1929) # P46Osc really all += pattern(""" 8bo$9bo3bo$2o2b2o8bo$2o2bo5b2o2bo$4bobo5b2o11bo$5b2o3b3o12b3o$28bo$5b 2o3b3o12b3o$4bobo5b2o11bo$4bo5b2o2bo$4b2o8bo$9bo3bo$8bo! """, 845, 1905) # P46Osc really all += pattern(""" 10b2o$2o6b2ob2o14b2o$2o6bo2bo15b2o$8bo2bo$9b2o2$9b2o10b3ob3o$8bo2bo8bo b2ob2obo$2o6bo2bo7b2o7b2o$2o6b2ob2o7bob2ob2obo$10b2o9b3ob3o! """, 1050, 1903) # P46OscAlt2 really all += pattern(""" 9b2o$9b2o11$2b3o3b3o$bo3bobo3bo$o3b2ob2o3bo$ob2o5b2obo$2bo7bo11$2b2o5b 2o$2b2o5b2o!""", 1088, 1920) # P46OscAlt2 really all += pattern(""" 11bo$10b4o9bo$2b2o4b2o3bo9bo2b2o$2bo5b2o12bo5bo$3bo4b3o12bobo2b2o$3o 20bo3b2o3bo$o24b3o4b3o$35bo$25b3o4b3o$23bo3b2o3bo$23bobo2b2o$22bo5bo$ 7bob2o12bo2b2o$5b3ob2o12bo$4bo$5b3ob2o$7bobo2bo$11b2o! """, 1106, 1875) # P46OscAlt4 (boat-bit catcher?) really [not defined yet] all += pattern(""" 25bobo$26bo$17b2o13b2o$16b2ob2o12bo$17bo2bo11bo$3bo13bo2bo4b2o6b3o$b3o 14b2o15bo$o$b3o14b2o$3bo13bo2bo$17bo2bo$16b2ob2o$17b2o6b2obo$25b2ob3o$ 31bo$25b2ob3o$23bo2bobo$23b2o!""", 1227, 1875) # P46OscAlt4 really all += pattern("2o$obo$2bo$2b2o!", 1281, 1873) # eater all += pattern(""" 4b2o5b2o$2o2b2o5b2o2b2o$2o13b2o4$4b3o3b3o$4bo2bobo2bo$3bo3bobo3bo$3b4o 3b4o$4bo7bo7$5bo$4b3o$3bo3bo$3b2ob2o$3b2ob2o2$3b2ob2o$3b2ob2o$3bo3bo3b 2o$4b3o4b2o$5bo!""", 1375, 1980) # P46OscAlt1 really # slide 28: clean up and start over -------------------- LWSSToGlider = pattern(""" 4b2o5b2o$2obobo5bobob2o$2ob2o7b2ob2o$2b6ob6o$4bob2ob2obo2$2bo11bo$3bo 9bo$5bobobobo$5bobobobo$6b2ob2o$3bo2bo3bo2bo$4b2o5b2o13$4b2o$4b2o! """, 443, 1980) # slide 29: toggle dist [not sure what that means, actually] -------------------- BoatLatchNE = pattern(""" 78b2o5b2o$78b2o5b2o15$77b2o7b2o$77bob2o3b2obo$77bo3bobo3bo$46b2o5b2o 22b2o2bobo2b2o$46b2o5b2o23b3o3b3o$79bo5bo4$47bo5bo$46b3o3b3o$45bo2b2ob 2o2bo22b2o$45bo3bobo3bo22b2o$47bobobobo2$44b2ob2o3b2ob2o$46bo7bo5$47bo $46b3o$45bo3bo$44bo5bo$44bo5bo$45bo3bo2$45bo3bo$44bo5bo$44bo5bo2b2o$ 45bo3bo3b2o$46b3o$47bo7$45b2o$45bo$46b3o$48bo20$13b2o$15bo$2o10b2o2bo 10b2o$2o11bo2bo10b2o$14bobo$14b2o2$14b2o$14bobo$2o11bo2bo$2o10b2o2bo$ 15bo$13b2o12$47b4o$46b2o2bo14b2o$45b2o2bo15b2o$46bo2bo$47b2o2$47b2o$ 46bo2bo$38b2o5b2o2bo15b2o$38b2o6b2o2bo14b2o$47b4o!""", 120, 232) # four P46osc really BoatLatchSW = pattern(""" 76bo$75bo2bo$74b5o10b2o$73b2ob3o10b2o$74bob2o$75b2o72b2o5b2o$145b2o3bo 5bo3b2o$75b2o68bo15bo$74bob2o68bo13bo$62b2o9b2ob3o10b2o$62b2o10b5o10b 2o$75bo2bo$76bo2$149b2o5b2o$149b2obobob2o$73b2o74bo2bobo2bo$73b2o74b3o 3b3o2$82b2o$72b2o7bo2b2o11b2o$57b2o5b2o6b2o6b6o11b2o$53b2o2b2o5b2o2b2o 12b4o77b2o89bo$53b2o13b2o93b2o84bo3bo$173bo60b2o12bo8b2o2b2o$173b2o59b 2o12bo2b2o5bo2b2o$6bo75b4o76b2o7bob3o11b2o60b2o5bobo$5bobo64b2o6b6o76b 2o11b2o10b2o61b3o3b2o$5bobo64b2o7bo2b2o88b2o$4b2ob2o73b2o90bo75b3o3b2o $156b2o64b2o25b2o5bobo$57b3o3b3o7b2o81b2o16bo48bo24bo2b2o5bo2b2o$56bo 3bobo3bo6b2o99b2o47bobo22bo8b2o2b2o$55bo3b2ob2o3bo94b2o11b2o47b2o23bo 3bo$55bob2o5b2obo94b2o7bob3o78bo$57bo7bo107b2o$173bo$163b2o$163b2o3$ 57b3o$b3o5b3o45bobo$2ob2o3b2ob2o43bo3bo$2obobobobob2o43bo3bo$bo3bobo3b o$bo2bo3bo2bo45b3o4b2o$2b3o3b3o53b2o6$2b2o$2b2o37$27b2o90b2o$27b2o81b 2o7b2o79b2o$110b2o88b2o$47b3o53b3o25bobo2b2o$26b2o6b3o8b2obob2o50bo3bo 11b2o10bo3bob3o$26b2o6bo3bo5bo5b2o50b2ob2o11b2o11bo6b2o54bo5bo$34bo4bo 5b2obob2o80b5obo54b3o3b3o$35bo3bo7b3o52b2ob2o28b3o55bob2ob2obo$104bo 87b2o7b2o$35bo3bo95b3o54b2o7b2o$34bo4bo92b5obo53b3o5b3o$26b2o6bo3bo12b 2o65b2o11bo6b2o3b2o49b3ob3o$26b2o6b3o14b2o50bo7bo6b2o10bo3bob3o4b2o51b obo$102bo2bo3bo2bo18bobo2b2o55bo2bobo2bo$106bobo83bo2bo3bo2bo$27b2o77b obo10b2o72b2o5b2o$27b2o77bobo10b2o$102bo2bo3bo2bo$103b3o3b3o7$99b2o13b 2o73b2o13b2o$99b2o2b2o5b2o2b2o73b2o2b2o5b2o2b2o$103b2o5b2o81b2o5b2o! """, 1534, 1849) # really eleven P45OscAlt1 plus an eater all += BoatLatchNE + BoatLatchSW + pattern(""" 273b2o$272bo2bo$140b2o130bobobo10b2o2bobo$140b2o131bo2bo3b2o4b3obo3bo 12b2o$277bo2b2o3b2o6bo13b2o$274bobo9bob5o$287b3o2$287b3o$286bob5o$285b 2o6bo13b2o$286b3obo3bo12b2o$287b2o2bobo3$175b2o$140b3o3b3o22bobo2bo$ 140bo2bobo2bo20b3ob2o79b2o$140b2obobob2o19bo84bo2bo$140b2o5b2o20b4o80b o7bo$171bob2o13bo64bo2bo3bobo$188b2o63b2ob2ob2ob2o$189b2o66bobo$184b2o 2b2o6bo42b2o15b2ob2o$142b2ob2o28bobo18b3o40b2o$140bo2bobo2bo26bobo21bo 3bo$140bobo3bobo15bo10b2o19b3o4b3o5b2o11b4o$140b3o3b3o15b3o9bo7b2o2b2o 6bo9bo4bo3b2o6b2o2bo12b2o$140b2o5b2o18bo5b2obobo10b2o14bo3bobo3b2o5b2o 2bo13b2o12b3o3b3o$140b2o5b2o17bo11bo9b2o14bo3bobo12bo2bo26bo9bo$140b2o 5b2o17b2o6bo2bo10bo15b2ob2o15b2o27bo3bobo3bo$176b2o76b3o3b3o$224b2o29b o5bo$223bo2bo$222b2o2bo13b2o$223b2o2bo12b2o$224b4o2$11b2o226b2o$10bobo 226b2o$10bo30b2o$9b2o30b2o226b2o5b2o$33b2o4bo13bo3b3o55b2o63b2o74b2ob 2o4b2obobo5bobob2o$33bo3b3o12bobo2b5o53bo7b3o5b4o35b2o6b2ob2o15b2o57bo bo5b2ob2o7b2ob2o$34bo3bobo11bo3b2o58bo6bo7b2obo35b2o6bo2bo17b2o34b2o5b 2o13bobo7b6ob6o$31b3o5b2o12bo2bo3b2obo49b3o7b2obo7bo10bo32bo2bo16bo7b 4o21b2o2b2o5b2o2b2o10bo10bob2ob2obo$31bo22b3o3b2ob3o47bo11b2o5b2o11b3o 31b2o25bo2b2o20b2o13b2o$66bo81bo58bo2b2o55bo11bo$54b3o3b2ob3o59b2o5b2o 11b3o31b2o26bo2bo4bo52bo9bo$53bo2bo3b2obo61b2o7bo10bo32bo2bo26b2o5b3o 52bobobobo$52bo3b2o73b2obo35b2o6bo2bo36bo51bobobobo$52bobo2b5o69b4o35b 2o6b2ob2o25b2o5b3o53b2ob2o$38bob2o11bo3b3o60bo59b2o25bo2bo4bo52bo2bo3b o2bo$36b3ob2o76b6o83bo2b2o23bo7bo25b2o5b2o$35bo81bo4bo83bo2b2o$36b3ob 2o76b3ob2o82b4o23b3o7b3o$38bobo2bo76bobo2bo108b2ob2ob2ob2o$42b2o80b2o 109b3o3b3o$236bo5bo2$114bo$10b2o9b3ob3o82b2o2bo$8b2ob2o7bob2ob2obo80bo 5bo$8bo2bo7b2o7b2o78b2o2bobo$3bo4bo2bo8bob2ob2obo80b2o3bo12bo$b3o5b2o 10b3ob3o82b3o14b3o$o129bo138b2o$b3o5b2o99b3o14b3o107b2ob2o27b2o$3bo4bo 2bo97b2o3bo12bo110bobo$8bo2bo15b2o73b2o4b2o2bobo123bobo$8b2ob2o14b2o 73b2o5bo5bo123bo$10b2o98b2o2bo$114bo13$170b2o2b2o4bo2b2o12b2o$170b2ob 2o6b2obo12b2o$174bobo6bo$175b2o4b3o2$175b2o4b3o$174bobo6bo$170b2ob2o6b 2obo$170b2o2b2o4bo2b2o!""", 178, 1939) # really P46Guns and Oscs, etc. all += pattern(""" 4b2o5b2o$2o2b2o5b2o2b2o$2o13b2o8$5bo5bo$4b3o3b3o$3b2ob2ob2ob2o$2b3o7b 3o2$4bo7bo5$5bo$4b3o$3bo2bo$3bobobo$4b3o$5bo5b2o$11b2o! """, 557, 1931) # P46OscAlt1 really # this particular one reflects a B signal from the above sync-buffer circuitry; # the resulting LWSS is converted to a glider which is stored as a boat-bit. # a few more outlying LWSS reflectors: all += pattern(""" 12b3o$10bo4bo11b2o$10bo5bo10b2o$3bobobo7bo$b7o5b2o$o$b7o5b2o$3bobobo7b o$10bo5bo$10bo4bo$12b3o!""", 257,1840) + pattern(""" 15b2o$13b2o2bo$13b6o$13b4o4bo3bo$21b7o$28bo$21b7o$13b4o4bo3bo$2o11b6o$ 2o11b2o2bo$15b2o!""", 885, 2033) # both P46Osc really # slide 30: HWSS control -------------------- HWSSGun = pattern(""" 21b2o23b2o$22bo22bobo$22bobo$23b2o$36b4o8bo$36bob2o7b2o$36bo$37b2o2$ 37b2o$36bo$7b2o2bobo22bob2o7b2o$2o4b3obo3bo21b4o8bo$2o3b2o6bo$6bob5o$ 7b3o35bobo$46b2o$7b3o$6bob5o14b2o$2o3b2o6bo8bo5bo$2o4b3obo3bo7bo4bo4b 2o$7b2o2bobo12b3o3b2o$23bob2ob2o$25bo$22bo2b3o11b2o$2b2o18b2o2b2o9bo4b o$2b2o20bo2bo15bo$24b3o10bo5bo$16b2o20b6o$b2o13bobo$b2o13bob2o$17b2o$ 17bo13b2o$30bobo$17bo13bo67b2o$17b2o80b2o$b2o13bob2o29b2o2bo4b2o16b2o 3b2o8bo$b2o13bobo30bob2o6b2o14bo2bobo2bo7bo2b2o$16b2o20bo11bo6bobo14bo 9bo5bo5bo3b2o$36b3o11b3o4b2o14b2o9b2o5bobo2b2o2b2o$2b2o31bo38bo9bo6bo 3b2o$2b2o32b3o11b3o4b2o16bo2bobo2bo9b3o$38bo11bo6bobo16b2o3b2o$24bo24b ob2o6b2o32b3o$23b3o23b2o2bo4b2o31bo3b2o$23bob2o35bo12b2o14bobo2b2o2b2o $24b3o11b2o22b2o11b2o13bo5bo3b2o$24b3o11bobo20bobo27bo2b2o$20b3ob3o13b o50bo$24b3o11b3o5bo52b2o$24b2o20b3o50b2o$2b2o45bo$2b2o19bo22b3o$11bo 10bo15b3o5bo$7b2o2bo10bo17bo$b2o3bo5bo25bobo$b2o2b2o2bobo12bo13b2o$6b 2o3bo38b2o$7b3o41b2o$50bo$7b3o$6b2o3bo$b2o2b2o2bobo$b2o3bo5bo48b2o$7b 2o2bo13b2o34b2o$11bo13bobo$2b2o23bo16b3o3bo$2b2o23b2o13b5o2bobo10b2o$ 41b2o3b2o3bo10b2o$42b2o3bo2bo$43bo3b3o2$43bo3b3o$42b2o3bo2bo$41b2o3b2o 3bo10b2o$42b5o2bobo10b2o$42bob3o3bo$40b2o$34b2o4b3o18b2o$34b2o3bo3bo 17b2o$38bo5bo$39b2ob2o2$39b2ob2o$38bo5bo$39bo3bo$40b3o$40b3o7$33b2o7b 2o$33bob2o3b2obo$33bo3bobo3bo$33b2o2bobo2b2o$34b3o3b3o$35bo5bo6$34b2o 5b2o$34b2o5b2o3$40bo2bo$30b3o7bo$16b2o11bo4bo9bo$16b2o10bo5bo8b2o$29bo 8bo$30b2o8b2o2$30b2o8b2o$29bo8bo3bo$16b2o10bo5bo4bo2bo$16b2o11bo4bo4bo 2bo$30b3o7b2o4$79b2o$78bo2bo$73bo7bo$72bobo3bo2bo$22bo48b2ob2ob2ob2o$ 20b3o52bobo$19bo54b2ob2o$19b2o$33bo$31b3o$14b2o14bo$15bo14b2o40b3o3b3o $15b2obo17b2o33bo9bo$18bo17bo34bo3bobo3bo$19b2o13bobo35b3o3b3o$15b3o2b 2o12b2o37bo5bo$17b2o$15bo2bo4bo$14bobobo3bo$13bo4bo$5b2o6bo2bob3o5bo$ 4bobo7bo3b3ob2o3bo$4bo10b2o5bo4bo$3b2o10b2o3b2o2bobo$15bo4bo$20b3o51b 2ob2o$16b2o57bobo$75bobo$12b2o2b3o57bo$13bobobo$14b4o$9b2o4bo$8bobo$8b o$7b2o7bobo$17b2o$17bo3$7b2o$8bo$8bobo$9b2o2$13bob2o$13bob2o2$22bo$12b 2o4bob2obo$12b2o2bo5bo$3b2o11bo5bo$4bo7b2o6b2o4b2o$4bobo5b2o4bobo5b2o$ 5b2o11b2o5$34b2o$34bobo$36bo$36b2o$30b2o$30bo$31b3o$33bo$19b2o$19bo$ 20b3o$22bo$34b2o7b2o$32b2o2bo6b2o$32b6o4bo2bo$22bo9b4o5bob2o$20b3o18bo b2o$19bo$20b3o18bob2o$22bo9b4o5bob2o14b2o$32b6o4b3ob2o11bo$32b2o2bo6bo bobo12b3o$34b2o7b4o15bo$44b2o!""") # TODO: take this apart further LWSSFromTheBlue = pattern(""" 27b2o5b2o$23b2o2b2o5b2o2b2o$23b2o13b2o2$28bo5bo$27b3o3b3o$26bo2b2ob2o 2bo$26bo3bobo3bo$28bobobobo2$25b2ob2o3b2ob2o$27bo7bo8$10b2o$8b2ob2o$8b o2bo$3bo4bo2bo$b3o5b2o15bo$o21b5o$b3o5b2o10bo2b3o7b2o$3bo4bo2bo10b2o 10b2o$8bo2bo$8b2ob2o$10b2o$25bo$25bo!""") # P46Osc really RowOfLWSSFTB = pattern("o$3o$3bo$2b2o!", 1737, 24) for i in range(43): RowOfLWSSFTB += LWSSFromTheBlue[(i*12) % 46](40*i, 0) HWSSHalfControl = HWSSGun(106, 87) + RowOfLWSSFTB(188, 79) CellCenter = HWSSHalfControl + HWSSHalfControl(2047, 2047, swap_xy_flip) OFFcell = all + CellCenter + StateBit # The metafier-OFF and -ON files technically should not exist (we just checked # at the beginning of the script). Shouldn't do any harm to check again, though: if os.access(OFFcellFileName, os.W_OK) or not os.access(OFFcellFileName, os.F_OK): try: OFFcell.save (OFFcellFileName, "Metapixel OFF cell: Brice Due, Spring 2006") except: # if tile can't be saved, it will be rebuilt next time -- # no need for an annoying error, just a note in the status bar g.show("Failed to save file version of OFF cell: " + OFFcellFileName) os.remove (OFFcellFileName) # slide 31: display on -------------------- g.show("Building ON metacell definition...") # switch on the HWSS guns: CellCenter += pattern("2o$2o!", 171, 124) + pattern("2o$2o!", 1922, 1875) # now generate the ONcell HWSSs and LWSSs # add rest of pattern after the center area is filled in # and p184 HWSS guns are in the same phase (3680 = 184 * 40) ONcell = all + CellCenter[3680] if os.access(ONcellFileName, os.W_OK) or not os.access(ONcellFileName, os.F_OK): try: ONcell.save (ONcellFileName, "Metapixel ON cell: Brice Due, Spring 2006") except: g.show("Failed to save file version of ON cell: " + ONcellFileName) os.remove(ONcellFileName) OFFcell += RuleBits ONcell += RuleBits g.autoupdate(True) g.new(layername) g.setalgo("QuickLife") # qlife's setcell is faster for j in xrange(selheight): for i in xrange(selwidth): golly.show("Placing (" + str(i+1) + "," + str(j+1) + ") tile" + " in a " + str(selwidth) + " by " + str(selheight) + " rectangle.") if livecell[i][j]: ONcell.put(2048 * i - 5, 2048 * j - 5) else: OFFcell.put(2048 * i - 5, 2048 * j - 5) g.fit() g.show("") g.setalgo("HashLife") # no point running a metapattern without hashing g.setoption("hyperspeed", False) # avoid going too fast g.setbase(8) g.setstep(4) g.step() # save start and populate hash tables # g.run(35328) # run one full cycle (can lock up Golly if construction has failed) # # Note that the first cycle is abnormal, since it does not advance the metapattern by # one metageneration: the first set of communication signals to adjacent cells is # generated during this first cycle. Thus at the end of 35328 ticks, the pattern # is ready to start its first "normal" metageneration (where cell states may change). # # It should be possible to define a version of ONcell that is not fully populated # with LWSSs and HWSSs until the end of the first full cycle. This would be much # quicker to generate from a script definition, and so it wouldn't be necessary to # save it to a file. The only disadvantage is that ONcells would be visually # indistinguishable from OFFcells until after the initial construction phase. golly-2.7-src/Scripts/Python/p1100-MWSS-gun.py0000644000175000017500000001037312536111364015625 00000000000000# Bill Gosper's pure-period p1100 double MWSS gun, circa 1984. import golly as g from glife import * g.new("P1100 gun") g.setalgo("HashLife") g.setrule("B3/S23") # update status bar now so we don't see different colors when # g.show is called g.update() glider = pattern("bo$bbo$3o!") block = pattern("oo$oo!") eater = pattern("oo$bo$bobo$bboo!") bhept = pattern("bbo$boo$oo$boo!") twobits = eater + bhept(8,3) half = twobits + twobits[1](51,0,flip_x) centinal = half + half(0,16,flip_y) passthrough = centinal[1](16,3,rcw) + centinal[19](52,0,rcw) \ + centinal[81](55,51,rccw) + centinal[99](91,54,rccw) # build the source signal -- the most compact set of gliders # from which all other gliders and spaceships can be generated MWSSrecipes = glider(5759,738,rccw) + glider(6325,667,flip_x) \ + glider[3](5824,896,flip_x) + glider[2](5912,1264) \ + glider[2](6135,1261,flip_x) + glider[1](5912,1490,flip_y) \ + glider(6229,4717,flip_x) + glider[1](6229,5029,flip) \ + glider[1](5920,5032,flip_y) + glider(6230,5188,flip) \ + glider[3](6230,5306,flip) + glider[3](5959,5309,flip_y) # suppress output MWSSes as long as gliders are being added MWSSrecipes += pattern("o!",6095,-65) + pattern("o!",6075,228) # add the first four centinals to guide the recipe gliders all = centinal[44](6185,5096,flip_x) + centinal[73](5897,1066) all += centinal[42](5782,690) + centinal[25](5793,897,rcw) # generate the MWSSes for the glider-fanout ladder for i in range(7): g.show("Building rung " + str(i+1) + " of ladder...") all = (all + MWSSrecipes)[1100] # add the actual glider-fanout ladder -- six rungs for i in range(6): all += glider(6030,1706+550*i,swap_xy_flip) \ + centinal[15](6102,1585+550*i) \ + block(6029,1721+550*i) + centinal[34](5996,1725+550*i,rccw) \ + block(6087,1747+550*i) + centinal[87](6122,1745+550*i,rcw) \ # add the rest of the centinals to guide the ladder's output gliders g.show("Adding centinal reflectors...") all += centinal[88](5704,0) + centinal[29](6423,295,flip_x) \ + centinal[74](5616,298) + centinal[40](6361,613,rcw) \ + centinal[23](6502,620,flip_x) + centinal[36](5636,986) \ + centinal[38](6370,1008,rcw) + centinal[19](5747,1347,rcw) \ + centinal[67](5851,1516) + centinal(4061,2605,rccw) \ + centinal[10](5376,3908,rccw) + centinal[77](8191,4407,flip_x) \ + centinal[6](4988,4606) + centinal[34](6357,4608,flip_x) \ + centinal[27](8129,4621,flip_x) + centinal[92](5159,5051) \ + centinal[53](7991,5201,flip_x) + centinal[94](7038,5370,rccw) \ + centinal[13](5591,5379,rccw) + centinal[3](5858,5428,rccw) \ + centinal[87](7805,5511,flip_x) + centinal[98](401,5557,rccw) \ + centinal[14](955,5561,rccw) + centinal[8](6592,5584,rccw) \ + centinal[39](6933,5698,flip_x) + centinal[32](6230,5881) \ + centinal[47](11676,5854,rccw) + centinal[68](0,5748,rccw) \ + centinal[89](6871,5912,flip_x) + centinal[45](12095,6027,rccw) \ + centinal[86](6209,6134) + centinal[55](6868,6357,flip_x) \ + centinal[95](9939,6491,rccw) + centinal[23](8782,6548,rccw) \ + centinal[58](3066,6572,rccw) + centinal[21](9326,6596,rccw) \ + centinal[80](3628,6626,rccw) + centinal[45](6821,6528,flip_x) \ + centinal[33](10373,6649,rccw) + centinal[16](2587,6685,rccw) # to change behavior at center, comment out one of the lines below all += eater(6018,5924,rccw) + eater(6037,5943,rccw) # true p1100 gun # all += block(6018,6787) # synch center to recreate original p1100x5 center = block(1081,6791) + block(2731,6791) + block(3831,6791) \ + block(9108,6791) + block(10208,6791) + block(11308,6791) \ + passthrough(8475,6737) + passthrough[39](3365,6737,flip_x) \ + passthrough(9575,6737) + passthrough[39](2265,6737,flip_x) \ + passthrough(10675,6737) + passthrough[39](1715,6737,flip_x) # add asymmetric Equator to mirror-symmetric North and South MWSSrecipes += MWSSrecipes(0,13583,flip_y) all += all(0,13583,flip_y) + center g.putcells(all) g.fit() # Different glider paths are different lengths, so incomplete # glider recipes must be overwritten for a while to prevent disaster. for i in range(46): g.show("Filling glider tracks -- " \ + str(49500 - i*1100) + " ticks left.") g.update() g.putcells(MWSSrecipes) g.run(1100) g.show("") # reset gen count to 0 g.setgen("0") golly-2.7-src/Scripts/Python/goto.py0000644000175000017500000001057112536111364014456 00000000000000# Go to a requested generation. The given generation can be an # absolute number like 1,000,000 (commas are optional) or a number # relative to the current generation like +9 or -6. If the target # generation is less than the current generation then we go back # to the starting generation (normally 0) and advance to the target. # Authors: Andrew Trevorrow and Dave Greene, April 2006. # Updated Sept-Oct 2006 -- XRLE support and reusable default value. # Updated April 2010 -- much faster, thanks to PM 2Ring. # Save and restore step setting after PM 2Ring algorithm (Munafo) from glife import validint from time import time import golly as g # -------------------------------------------------------------------- def intbase(n, b): # convert integer n >= 0 to a base b digit list (thanks to PM 2Ring) digits = [] while n > 0: digits += [n % b] n //= b return digits or [0] # -------------------------------------------------------------------- def goto(gen): currgen = int(g.getgen()) if gen[0] == '+': n = int(gen[1:]) newgen = currgen + n elif gen[0] == '-': n = int(gen[1:]) if currgen > n: newgen = currgen - n else: newgen = 0 else: newgen = int(gen) if newgen < currgen: # try to go back to starting gen (not necessarily 0) and # then forwards to newgen; note that reset() also restores # algorithm and/or rule, so too bad if user changed those # after the starting info was saved; # first save current location and scale midx, midy = g.getpos() mag = g.getmag() g.reset() # restore location and scale g.setpos(midx, midy) g.setmag(mag) # current gen might be > 0 if user loaded a pattern file # that set the gen count currgen = int(g.getgen()) if newgen < currgen: g.error("Can't go back any further; pattern was saved " + "at generation " + str(currgen) + ".") return if newgen == currgen: return g.show("Hit escape to abort...") oldsecs = time() # before stepping we advance by 1 generation, for two reasons: # 1. if we're at the starting gen then the *current* step size # will be saved (and restored upon Reset/Undo) rather than a # possibly very large step size # 2. it increases the chances the user will see updates and so # get some idea of how long the script will take to finish # (otherwise if the base is 10 and a gen like 1,000,000,000 # is given then only a single step() of 10^9 would be done) g.run(1) currgen += 1 # use fast stepping (thanks to PM 2Ring) oldstep = g.getstep() for i, d in enumerate(intbase(newgen - currgen, g.getbase())): if d > 0: g.setstep(i) for j in xrange(d): if g.empty(): g.show("Pattern is empty.") return g.step() newsecs = time() if newsecs - oldsecs >= 1.0: # do an update every sec oldsecs = newsecs g.update() g.setstep(oldstep) g.show("") # -------------------------------------------------------------------- def savegen(filename, gen): try: f = open(filename, 'w') f.write(gen) f.close() except: g.warn("Unable to save given gen in file:\n" + filename) # -------------------------------------------------------------------- # use same file name as in goto.pl GotoINIFileName = g.getdir("data") + "goto.ini" previousgen = "" try: f = open(GotoINIFileName, 'r') previousgen = f.readline() f.close() if not validint(previousgen): previousgen = "" except: # should only happen 1st time (GotoINIFileName doesn't exist) pass gen = g.getstring("Enter the desired generation number,\n" + "or -n/+n to go back/forwards by n:", previousgen, "Go to generation") if len(gen) == 0: g.exit() elif gen == "+" or gen == "-": # clear the default savegen(GotoINIFileName, "") elif not validint(gen): g.exit('Sorry, but "' + gen + '" is not a valid integer.') else: # best to save given gen now in case user aborts script savegen(GotoINIFileName, gen) oldstep = g.getstep() goto(gen.replace(",","")) g.setstep(oldstep) golly-2.7-src/Scripts/Python/goto_expression.py0000644000175000017500000003211712536111364016735 00000000000000# Go to a requested generation. The given generation can be: # # * an absolute number like 1,000,000 (commas are optional) # * a number relative to the current generation like +9 or -6 # * an expression like "17*(2^(3*143)+2^(2*3*27))" # * an expression starting with + or -, indicating a relative move # * any of the above preceded by "f" (fast). This wil set the base # step to 2 and provide less visual feedback of progress # # If the target generation is less than the current generation then # we go back to the starting generation (normally 0) and advance to # the target. # # If the input is preceded by F "fast" or q "quick" then we use the # algorithm of goto-fast.py, which sets the base to 2 and jumps by # powers of 2. # # Authors: # Original goto.py by Andrew Trevorrow and Dave Greene, April 2006. # Updated Sept-Oct 2006 -- XRLE support and reusable default value. # Updated April 2010 -- much faster, thanks to PM 2Ring. # goto-expression.py by Robert Munafo, using regexp expression # evaluation like Hypercalc (mrob.com/pub/perl/hypercalc.html) # 20111103 First stand-alone version of "expr.py" written as an # exercise to learn me some Python # 20111105 Add expr_2 using re.sub (a cleaner implementation) # 20120624 Remove whitespace before evaluating # 20130213 Move expr_2 code to "goto-expression.py" for Golly. # 20130214 Fix precedednce bugs, add expr_3 # 20130215 Remove redundant g.getstep and g.setstep calls. Full handling # of scientific notation and leading signs (like "300+-3") # # TODO: # Allow decimal point in EE notation, so "6.02e23" would work (right # now you have to do "602e21") # Make - and / associate left-to-right, so 100-10+1 gives 91 instead of 89 # Remove use of deprecated string.find and string.replace functions # Why is it much faster when you start from gen 0? For example, start # with puffer-train.rle, use this script to goto 10^100 then goto 2*10^100 # it's much faster if you start from gen 0 and go directly to 2*10^100 # Given that gofast saves and restores the base, should we use it always? # Note that patterns with a lot of period-P oscillators run more # efficiently when the base is set to P or a factor of P, so this # is not a simple decision. from glife import validint from time import time import golly as g import re # -------------------------------------------------------------------- # Regexp-based expression evaluator. The main loop contains match # cases for each type of operation, and performs one operation per # loop until there are none left to match. We use re.sub and pass # functions for the repl parameter. See: # http://docs.python.org/2/library/re.html#re.sub # http://docs.python.org/2/library/re.html#re.MatchObject.group p_whitespace = re.compile('[ \t]+') p_paren = re.compile('\((\d+)\)') p_parexp = re.compile('\((\d+[*/+-^][^()]*\d)\)') p_exp = re.compile('(\d+)\^(\d+)') p_mul = re.compile('(\d+)([*/])(n?\d+)') p_add = re.compile('(\d+)([-+])(n?\d+)') p_ee = re.compile('([.0-9]+)e([+-]?\d+)') p_mantissa = re.compile('^n?\d*\.?\d+$') p_leadn = re.compile('^n') p_digits = re.compile('^[+-]?\d+$') p_dot = re.compile('\.') p_plusminus = re.compile('([-+])([-+])') # erf = expression replace function def erf_paren(match): "Remove parentheses: (123) -> 123" a = match.group(1) return a # ee_approx - Python-like integer approximation of a number in scientific # notation. The mantissa and exponent are given separately and # may be either numeric or string. (the caller is expected to # generate them separately, e.g. by using a regexp to match # parts of a string). The exponent must be an integer or an # equivalent string; more flexibility is available for the # mantissa (see examples) # All of the following examples evaluate to True: # ee_approx(2.0, 20) == 2*10**20 # ee_approx('2.', 20) == 2*10**20 # ee_approx('12000', -3) == 12 # ee_approx(12e+03, '-3') == 12 # The following return 0 because of an error: # ee_approx(2.3, 4.0) # Exponent may not be a float # ee_approx(6.02, '23.') # Exponent may not contain '.' # The following evaluate to False because of roundoff error: # ee_approx('.02', 22) == 2*10**20 def ee_approx(m, e): "Integer approximation of m*10^e given m and e" m = str(m) # Make sure mantissa matches its pattern if p_dot.search(m): m = m + '0' else: m = m + '.0' if not p_mantissa.search(m): return 0 m = float(m) m = int(m * float(2**64) * (1.0+2.0**-52.0)) e = str(e) if not p_digits.search(e): return 0 e = int(e) if e<0: e = 10**(-e) return m/(e*2**64) else: e = 10**e return (m*e)/(2**64) def erf_ee(match): "Scientific notation: 1.2e5 -> 120000" a = match.group(1) b = match.group(2) return str(ee_approx(a,b)) def erf_exp(match): "Exponentiation: 2^24 -> 16777216" a = int(match.group(1)) b = int(match.group(2)) return str(a**b) def erf_mul(match): "Multiplication and (integer) division" a = int(match.group(1)) # match.group(2) is operator b = match.group(3) # Check for leading 'n' if p_leadn.search(b): b = p_leadn.sub('-', b) b = int(b) if(match.group(2) == '*'): return str(a*b) else: return str(a//b) def erf_add(match): "Addition and subtraction" a = int(match.group(1)) # match.group(2) is operator b = match.group(3) # Check for leading 'n' if p_leadn.search(b): b = p_leadn.sub('-', b) b = int(b) if(match.group(2) == '+'): return str(a+b) else: return str(a-b) """ Evaluate an expression without parentheses, like 2+3*4^5 = 3074 The precedence is: If we match something like "6.02e23", expand it Else if we match something like "4^5", expand it Else if we match something like "3*17", expand it Else if we match something like "2+456", expand it Else return It loops in all cases but the last """ def expr_2(p): going = 1 # print 'e2:', p while going: if p_ee.search(p): p = p_ee.sub(erf_ee, p, count=1) # print 'e2 ee, got:', p elif p_exp.search(p): p = p_exp.sub(erf_exp, p, count=1) # print 'e2 exp, got:', p elif p_mul.search(p): p = p_mul.sub(erf_mul, p, count=1) # print 'e2 mul, got:', p elif p_add.search(p): p = p_add.sub(erf_add, p, count=1) # print 'e2 add, got:', p else: # print 'e2 done' going = 0 # print 'e2 return:', p return p def erf_e2(match): "Parenthesized bare expression" a = expr_2(match.group(1)) return str(a) def erf_plusminus(match): "--, -+, +-, or ++" if match.group(2) == '-': return match.group(1)+'n' return match.group(1) """ Evaluate an expression possibly including parenthesized sub-expressions and numbers in scientific notation, like 17*4^((7^2-3)*6^2+2e6)+602e21 The precedence is: If we match something like "6.02e23", expand it Else if we match something like "(3+4*5)", expand it using expr_2 Else if we match something like "(23456)", remove the parens Else expand the whole string using expr_2 and return It loops in all cases but the last """ def expr_3(p): p = p_whitespace.sub('', p) if p_plusminus.search(p): p = p_plusminus.sub(erf_plusminus, p) going = 1 while going: if p_ee.search(p): p = p_ee.sub(erf_ee, p, count=1) elif p_parexp.search(p): p = p_parexp.sub(erf_e2, p, count=1) elif p_paren.search(p): p = p_paren.sub(erf_paren, p, count=1) else: p = expr_2(p) going = 0 return p # -------------------------------------------------------------------- """ gt_setup computes how many generations to move forwards. If we need to move backwards, it rewinds as far as possible, then returns the number of generations we need to move forwards. """ def gt_setup(gen): currgen = int(g.getgen()) # Remove leading '+' or '-' if any, and convert rest to int or long if gen[0] == '+': n = int(gen[1:]) newgen = currgen + n elif gen[0] == '-': n = int(gen[1:]) if currgen > n: newgen = currgen - n else: newgen = 0 else: newgen = int(gen) if newgen < currgen: # try to go back to starting gen (not necessarily 0) and # then forwards to newgen; note that reset() also restores # algorithm and/or rule, so too bad if user changed those # after the starting info was saved; # first save current location and scale midx, midy = g.getpos() mag = g.getmag() g.reset() # restore location and scale g.setpos(midx, midy) g.setmag(mag) # current gen might be > 0 if user loaded a pattern file # that set the gen count currgen = int(g.getgen()) if newgen < currgen: g.error("Can't go back any further; pattern was saved " + "at generation " + str(currgen) + ".") return 0 return newgen - currgen elif newgen > currgen: return newgen - currgen else: return 0 # -------------------------------------------------------------------- def intbase(n, b): # convert integer n >= 0 to a base b digit list (thanks to PM 2Ring) digits = [] while n > 0: digits += [n % b] n //= b return digits or [0] def goto(newgen, delay): g.show("goto running, hit escape to abort...") oldsecs = time() # before stepping we advance by 1 generation, for two reasons: # 1. if we're at the starting gen then the *current* step size # will be saved (and restored upon Reset/Undo) rather than a # possibly very large step size # 2. it increases the chances the user will see updates and so # get some idea of how long the script will take to finish # (otherwise if the base is 10 and a gen like 1,000,000,000 # is given then only a single step() of 10^9 would be done) if delay <= 1.0: g.run(1) newgen -= 1 # use fast stepping (thanks to PM 2Ring) for i, d in enumerate(intbase(newgen, g.getbase())): if d > 0: g.setstep(i) for j in xrange(d): if g.empty(): g.show("Pattern is empty.") return g.step() newsecs = time() if newsecs - oldsecs >= delay: # time to do an update? oldsecs = newsecs g.update() g.show("") # -------------------------------------------------------------------- # This is the "fast goto" algorithm from goto-fast.py that uses # binary stepsizes and does not do that initial step by 1 generation. def intbits(n): ''' Convert integer n to a bit list ''' bits = [] while n: bits += [n & 1] n >>= 1 return bits def gofast(newgen, delay): ''' Fast goto ''' #Save current settings oldbase = g.getbase() # oldhash = g.setoption("hashing", True) g.show('gofast running, hit escape to abort') oldsecs = time() #Advance by binary powers, to maximize advantage of hashing g.setbase(2) for i, b in enumerate(intbits(newgen)): if b: g.setstep(i) g.step() g.dokey(g.getkey()) newsecs = time() if newsecs - oldsecs >= delay: # do an update every sec oldsecs = newsecs g.update() if g.empty(): break g.show('') #Restore settings # g.setoption("hashing", oldhash) g.setbase(oldbase) # -------------------------------------------------------------------- def savegen(filename, gen): try: f = open(filename, 'w') f.write(gen) f.close() except: g.warn("Unable to save given gen in file:\n" + filename) # -------------------------------------------------------------------- # use same file name as in goto.pl GotoINIFileName = g.getdir("data") + "goto.ini" previousgen = "" try: f = open(GotoINIFileName, 'r') previousgen = f.readline() f.close() if not validint(previousgen): previousgen = "" except: # should only happen 1st time (GotoINIFileName doesn't exist) pass gen = g.getstring("Enter the desired generation number as an\n" + "expression, prepend -/+ for relative\n" + "move back/forwards, prepend f to use faster\n" "powers-of-2 steps:", previousgen, "Go to generation") # Evaluate the expression. This leaves leading "f" and/or "+/-" # intact. gen = expr_3(gen) # Find out if they want to get there quickly # %%% TODO: Use re instead of string.find and string.replace (which are # deprecated in later versions of Python) fastmode = 0 if(gen.find("f") == 0): gen = gen.replace("f","") fastmode = 1 if len(gen) == 0: g.exit() elif gen == "+" or gen == "-": # clear the default savegen(GotoINIFileName, "") elif not validint(gen): g.exit('Sorry, but "' + gen + '" is not a valid integer.') else: # best to save given gen now in case user aborts script savegen(GotoINIFileName, gen) oldstep = g.getstep() # %%% TODO: Use re instead of string.replace to remove the commas newgen = gt_setup(gen.replace(",","")) if newgen > 0: if fastmode: gofast(newgen, 10.0) else: goto(newgen, 1.0) g.setstep(oldstep) golly-2.7-src/Scripts/Python/slide-show.py0000644000175000017500000000452712536111364015570 00000000000000# Display all patterns in Golly's Patterns folder. # Author: Andrew Trevorrow (andrew@trevorrow.com), March 2006. import golly as g import os from os.path import join from time import sleep # ------------------------------------------------------------------------------ def slideshow (): oldalgo = g.getalgo() oldrule = g.getrule() message = "Hit space to continue or escape to exit the slide show..." g.show(message) for root, dirs, files in os.walk(g.getdir("app") + "Patterns"): for name in files: if name.startswith("."): # ignore hidden files (like .DS_Store on Mac) pass else: fullname = join(root, name) g.open(fullname, False) # don't add file to Open/Run Recent submenu g.update() if name.endswith(".pl") or name.endswith(".py"): # reshow message in case it was changed by script g.show(message) while True: event = g.getevent() if event == "key space none": break g.doevent(event) # allow keyboard/mouse interaction sleep(0.01) # avoid hogging cpu # if all patterns have been displayed then restore original algo and rule # (don't do this if user hits escape in case they want to explore pattern) g.new("untitled") g.setalgo(oldalgo) g.setrule(oldrule) # ------------------------------------------------------------------------------ # show status bar but hide other info to maximize viewport oldstatus = g.setoption("showstatusbar", True) oldtoolbar = g.setoption("showtoolbar", False) oldlayerbar = g.setoption("showlayerbar", False) oldeditbar = g.setoption("showeditbar", False) oldscripts = g.setoption("showscripts", False) oldpatterns = g.setoption("showpatterns", False) try: slideshow() finally: # this code is always executed, even after escape/error; # clear message line in case there was no escape/error g.show("") # restore original state g.setoption("showstatusbar", oldstatus) g.setoption("showtoolbar", oldtoolbar) g.setoption("showlayerbar", oldlayerbar) g.setoption("showeditbar", oldeditbar) g.setoption("showscripts", oldscripts) g.setoption("showpatterns", oldpatterns) golly-2.7-src/Scripts/Python/envelope.py0000644000175000017500000000767312536111364015334 00000000000000# Use multiple layers to create a history of the current pattern. # The "envelope" layer remembers all live cells. # Author: Andrew Trevorrow (andrew@trevorrow.com), December 2006. # Updated for better compatibility with envelope.pl, June 2007. # Updated to use new setcolors command, September 2008. import golly as g if g.empty(): g.exit("There is no pattern.") currindex = g.getlayer() startindex = 0 envindex = 0 startname = "starting pattern" envname = "envelope" if currindex > 1 and g.getname(currindex - 1) == startname \ and g.getname(currindex - 2) == envname : # continue from where we left off startindex = currindex - 1 envindex = currindex - 2 elif currindex + 2 < g.numlayers() \ and g.getname(currindex + 1) == startname \ and g.getname(currindex) == envname : # switch from envelope layer to current layer and continue currindex += 2 g.setlayer(currindex) startindex = currindex - 1 envindex = currindex - 2 elif currindex + 1 < g.numlayers() \ and g.getname(currindex) == startname \ and g.getname(currindex - 1) == envname : # switch from starting layer to current layer and continue currindex += 1 g.setlayer(currindex) startindex = currindex - 1 envindex = currindex - 2 else: # start a new envelope using pattern in current layer if g.numlayers() + 1 > g.maxlayers(): g.exit("You need to delete a couple of layers.") if g.numlayers() + 2 > g.maxlayers(): g.exit("You need to delete a layer.") # get current layer's starting pattern startpatt = g.getcells(g.getrect()) envindex = g.addlayer() # create layer for remembering all live cells g.setcolors([-1,100,100,100]) # set all states to darkish gray g.putcells(startpatt) # copy starting pattern into this layer startindex = g.addlayer() # create layer for starting pattern g.setcolors([-1,0,255,0]) # set all states to green g.putcells(startpatt) # copy starting pattern into this layer # move currindex to above the envelope and starting pattern g.movelayer(currindex, envindex) g.movelayer(envindex, startindex) currindex = startindex startindex = currindex - 1 envindex = currindex - 2 # name the starting and envelope layers so user can run script # again and continue from where it was stopped g.setname(startname, startindex) g.setname(envname, envindex) # ------------------------------------------------------------------------------ def envelope (): # draw stacked layers using same location and scale g.setoption("stacklayers", 1) g.show("Hit escape key to stop script...") while True: g.run(1) if g.empty(): g.show("Pattern died out.") break # copy current pattern to envelope layer; # we temporarily disable event checking so thumb scrolling # and other mouse events won't cause confusing changes currpatt = g.getcells(g.getrect()) g.check(0) g.setlayer(envindex) g.putcells(currpatt) g.setlayer(currindex) g.check(1) step = 1 exp = g.getstep() if exp > 0: step = g.getbase()**exp if int(g.getgen()) % step == 0: # display all 3 layers (envelope, start, current) g.update() # ------------------------------------------------------------------------------ # show status bar but hide layer & edit bars (faster, and avoids flashing) oldstatus = g.setoption("showstatusbar", True) oldlayerbar = g.setoption("showlayerbar", False) oldeditbar = g.setoption("showeditbar", False) try: envelope() finally: # this code is always executed, even after escape/error; # restore original state of status/layer/edit bars g.setoption("showstatusbar", oldstatus) g.setoption("showlayerbar", oldlayerbar) g.setoption("showeditbar", oldeditbar) golly-2.7-src/Scripts/Python/make-Banks-IV-constructor.py0000644000175000017500000001117012536111364020352 00000000000000# Make a pattern from states 3 and 0, select it and then # run this script to make a Banks-IV CA pattern that will then # construct the pattern. # # The machine will attempt to activate the pattern by injecting # a signal at a special trigger point. # See: Patterns/Banks/Banks-IV-constructor.rle.gz # # You may need to change trigger_row for your pattern, or disable # triggering. # # Tim Hutton from glife import rect from time import time import golly as g r = rect( g.getselrect() ) if r.empty: g.exit("There is no selection.") oldsecs = time() maxstate = g.numstates() - 1 top_tape = '00' bottom_tape = '00' # write a state 3 to the required position, relative to the centre of the face def write_cell(x,y): global top_tape global bottom_tape # delay one of the tapes, to select the correct row if y<0: top_tape += '00'*abs(y) elif y>0: bottom_tape += '00'*y # send out a write arm to the right length arm_length=2 while arm_length < x: top_tape += '120' + '00'*arm_length + '12000' bottom_tape += '120' + '00'*arm_length + '12000' arm_length += 1 # send an erasing wing down the arm, to write a cell at the end top_tape += '120' + '00'*(arm_length-3) + '120000' bottom_tape += '120' + '00'*(arm_length-3) + '120000' # undo the delay on the tapes (could just add the difference but this is simpler) if y<0: bottom_tape += '00'*abs(y) elif y>0: top_tape += '00'*y # we first write the commands to 2 strings, and then to the grid H_OFFSET = 10 # how far from the construction face should the new pattern be? half_height = (r.height-(r.height%2))/2 # write the cells that are in state 1 (can ignore the zeros) # (still plenty of room for optimisation here) for col in xrange(r.left + r.width-1, r.left-1,-1): # if large selection then give some indication of progress newsecs = time() if newsecs - oldsecs >= 1.0: oldsecs = newsecs g.update() for row in xrange(r.top, r.top + r.height): if g.getcell(col,row)==3: write_cell(H_OFFSET + col-r.left,row - r.top - half_height) # trigger trigger_row = 3 # from the vertical middle write_cell(H_OFFSET + 2,trigger_row) # (optional) restore the trigger input write_cell(H_OFFSET-3, trigger_row-1) write_cell(H_OFFSET-2, trigger_row+2) write_cell(H_OFFSET-2, trigger_row+1) # actually just sends an erasing wing write_cell(H_OFFSET, trigger_row-2) write_cell(H_OFFSET, trigger_row+2) fx = r.left-20 # constructing face fy = r.top+r.height*2 # centre of constructing face half_height += 10 # draw the constructing face for cy in range(fy-(half_height-6),fy+(half_height-6)+1): g.setcell(fx,cy,3) # draw the top shoulder g.setcell(fx,fy-half_height,3) g.setcell(fx,fy-half_height-3,3) g.setcell(fx-1,fy-half_height-3,3) g.setcell(fx+1,fy-half_height-3,3) g.setcell(fx-1,fy-half_height-2,3) g.setcell(fx+1,fy-half_height-2,3) g.setcell(fx+1,fy-half_height-1,3) g.setcell(fx+1,fy-half_height+1,3) g.setcell(fx+1,fy-half_height+2,3) g.setcell(fx+1,fy-half_height+3,3) g.setcell(fx+1,fy-half_height+4,3) g.setcell(fx+1,fy-half_height+5,3) g.setcell(fx-1,fy-half_height+2,3) g.setcell(fx-1,fy-half_height+3,3) g.setcell(fx-1,fy-half_height+4,3) g.setcell(fx-1,fy-half_height+5,3) g.setcell(fx+2,fy-half_height-1,3) g.setcell(fx+3,fy-half_height-1,3) g.setcell(fx+3,fy-half_height,3) g.setcell(fx+2,fy-half_height+1,3) g.setcell(fx+3,fy-half_height+1,3) g.setcell(fx+2,fy-half_height+4,3) g.setcell(fx-2,fy-half_height+5,3) # draw the bottom shoulder g.setcell(fx,fy+half_height,3) g.setcell(fx,fy+half_height+3,3) g.setcell(fx-1,fy+half_height+3,3) g.setcell(fx+1,fy+half_height+3,3) g.setcell(fx-1,fy+half_height+2,3) g.setcell(fx+1,fy+half_height+2,3) g.setcell(fx+1,fy+half_height+1,3) g.setcell(fx+1,fy+half_height-1,3) g.setcell(fx+1,fy+half_height-2,3) g.setcell(fx+1,fy+half_height-3,3) g.setcell(fx+1,fy+half_height-4,3) g.setcell(fx+1,fy+half_height-5,3) g.setcell(fx-1,fy+half_height-2,3) g.setcell(fx-1,fy+half_height-3,3) g.setcell(fx-1,fy+half_height-4,3) g.setcell(fx-1,fy+half_height-5,3) g.setcell(fx+2,fy+half_height-1,3) g.setcell(fx+3,fy+half_height-1,3) g.setcell(fx+3,fy+half_height,3) g.setcell(fx+2,fy+half_height+1,3) g.setcell(fx+3,fy+half_height+1,3) g.setcell(fx+2,fy+half_height-4,3) g.setcell(fx-2,fy+half_height-5,3) # draw the tapes x = fx-1 for c in range(0,len(top_tape)): g.setcell(x,fy-half_height-1,3) g.setcell(x,fy-half_height,int(top_tape[c])) g.setcell(x,fy-half_height+1,3) x -= 1 x = fx-1 for c in range(0,len(bottom_tape)): g.setcell(x,fy+half_height-1,3) g.setcell(x,fy+half_height,int(bottom_tape[c])) g.setcell(x,fy+half_height+1,3) x -= 1 golly-2.7-src/Scripts/Python/tile-with-clip.py0000644000175000017500000000362412536111364016342 00000000000000# Tile current selection with clipboard pattern. # Author: Andrew Trevorrow (andrew@trevorrow.com), March 2006. # Updated to use exit command, Nov 2006. # Updated to handle multi-state patterns, Aug 2008. from glife import * import golly as g # assume one-state cell list (may change below) inc = 2 # ------------------------------------------------------------------------------ def clip_rb (patt, right, bottom): # remove any cells outside given right and bottom edges clist = list(patt) # remove padding int if present if (inc == 3) and (len(clist) % 3 == 1): clist.pop() x = 0 y = 1 while x < len(clist): if (clist[x] > right) or (clist[y] > bottom): # remove cell from list clist[x : x+inc] = [] else: x += inc y += inc # append padding int if necessary if (inc == 3) and (len(clist) & 1 == 0): clist.append(0) return pattern(clist) # ------------------------------------------------------------------------------ selrect = rect( g.getselrect() ) if selrect.empty: g.exit("There is no selection.") cliplist = g.getclip() # 1st 2 items are wd,ht pbox = rect( [0, 0] + cliplist[0 : 2] ) cliplist[0 : 2] = [] # remove wd,ht p = pattern( cliplist ) if len(cliplist) & 1 == 1: inc = 3 # multi-state? g.clear(inside) if len(cliplist) > 0: # tile selrect with p, clipping right & bottom edges if necessary y = selrect.top while y <= selrect.bottom: bottom = y + pbox.height - 1 x = selrect.left while x <= selrect.right: right = x + pbox.width - 1 if (right <= selrect.right) and (bottom <= selrect.bottom): p.put(x, y) else: clip_rb( p(x, y), selrect.right, selrect.bottom ).put() x += pbox.width y += pbox.height if not selrect.visible(): g.fitsel() golly-2.7-src/Scripts/Python/bricklayer.py0000644000175000017500000000145712536111364015640 00000000000000# Based on bricklayer.py from PLife (http://plife.sourceforge.net/). from glife import * rule () # Life p22_half = pattern("2o$bo$bobo$2b2o3bo$6bob2o$5bo4bo$6bo3bo$7b3o!") p22 = p22_half + p22_half(26, 9, flip) gun22 = p22 + p22[1](-18, 11) gun154 = gun22[27] + gun22[5](49, 12, rcw) + gun22(5, 53, flip_y) p7_reflector = pattern(""" 2b2o5b2o$2b2o5bo$7bobo$7b2o$3b2o$3bobo$4bo3$13bo$10bo2b3o3b2o$3b5o 2b3o3bo2bo$b3obob3o4b2obobo$o4bo4b4obobo2b2o$2ob2ob4o3bobob2obo$ 4bobobobobo2bo2bobo$4bobobo2bo2bob3ob2o$3b2obob4o6bobo$7bo4b6o2b o$9bo2bo2bo4b2o$8b2o!""") pre_lom = pattern("2bo$2ob2o$2ob2o2$b2ob2o$b2ob2o$3bo!") all = gun154[210](-52, -38) + gun154[254](52, -38, flip_x) + p7_reflector(8, 23) \ + pre_lom(-3, 30) ### all.save ("bricklayer.lif", "David Bell, 29 Sep 2002") all.display("bricklayer") golly-2.7-src/Scripts/Python/glife/0000755000175000017500000000000012536111546014300 500000000000000golly-2.7-src/Scripts/Python/glife/EmulateHexagonal.py0000644000175000017500000001171012536111364020013 00000000000000import os from glife.RuleTree import * def HexagonalTransitionsToRuleTree(neighborhood,n_states,transitions,rule_name): '''Convert a set of hexagonal neighborhood transitions to a Moore neighborhood rule tree.''' tree = RuleTree(n_states,8) for t in transitions: # C,S,E,W,N,SE,(SW),(NE),NW tree.add_rule([t[0],t[4],t[2],t[5],t[1],t[3],range(n_states),range(n_states),t[6]],t[7][0]) tree.write( golly.getdir('rules')+rule_name+".tree" ) def MakePlainHexagonalIcons(n_states,rule_name): '''Make some monochrome hexagonal icons.''' width = 31*(n_states-1) height = 53 pixels = [[(0,0,0) for x in range(width)] for y in range(height)] huge = [[0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0]] big = [[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,0,0,0]] small = [[0,1,1,0,0,0,0], [1,1,1,1,1,0,0], [1,1,1,1,1,1,0], [0,1,1,1,1,1,0], [0,1,1,1,1,1,1], [0,0,1,1,1,1,1], [0,0,0,0,1,1,0]] fg = (255,255,255) bg = (0,0,0) for s in range(1,n_states): for row in range(31): for column in range(31): pixels[row][(s-1)*31+column] = [bg,fg][huge[row][column]] for row in range(15): for column in range(15): pixels[31+row][(s-1)*31+column] = [bg,fg][big[row][column]] for row in range(7): for column in range(7): pixels[46+row][(s-1)*31+column] = [bg,fg][small[row][column]] return pixels def EmulateHexagonal(neighborhood,n_states,transitions,input_filename): '''Emulate a hexagonal neighborhood rule table with a Moore neighborhood rule tree.''' rule_name = os.path.splitext(os.path.split(input_filename)[1])[0] HexagonalTransitionsToRuleTree(neighborhood,n_states,transitions,rule_name) pixels = MakePlainHexagonalIcons(n_states,rule_name) # use rule_name.tree and icon info to create rule_name.rule ConvertTreeToRule(rule_name, n_states, pixels) return rule_name golly-2.7-src/Scripts/Python/glife/gun24.py0000644000175000017500000000140312536111364015525 00000000000000from glife import * # an aligned gun shooting SE: gun24 = pattern (""" 23bo2bo$21b6o$17b2obo8bo$13b2obobobob8o2bo$11b3ob2o3bobo7b3o$10bo 4b3o2bo3bo3b2o$11b3o3b2ob4obo3bob2o$12bobo3bo5bo4bo2bo4b2obo$10b o8bob2o2b2o2b2o5bob2obo$10b5ob4obo4b3o7bo4bo$15b2o4bo4bob3o2b2ob ob2ob2o$12b5ob3o4b2ob2o3bobobobobo$11bo5b2o4b2obob2o5bo5bo$12b5o 6b2obo3bo3bobob2ob2o$2ob2o9b2o2bo5bobo4bo2b3obobo$bobobobob2o3b3o bo6bo2bobo4b3o2bo$o2bo7bo6b2o3b3o8bobob2o$3o2bo4b2o11bo10bo$5b4o bo17b2o4b2o$2b2obo6bo14bo3bo2b2o$bo4bo3bo16bo6b2o$b3obo4bo16bo3b o2bo$11bo2bo3bo9b2o4bobob2o$b3obo4bo8b2o3bo10b3o2bo$bo4bo3bo7bo6b o8b3obobo$2b2obo6bo10b3o8bobob2ob2o$5b4obo24bo5bo$3o2bo4b2o21bob obobobo$o2bo7bo9b2o10b2obob2ob2o$bobobobob2o10bo8bo5bo4bo$2ob2o17b 3o6bo4bob2obo$24bo4b3o5b2obo!""", -32, -32) golly-2.7-src/Scripts/Python/glife/EmulateTriangular.py0000644000175000017500000004602312536111364020222 00000000000000# Inspired by Andrew Trevorrow's work on TriLife.py try: set except NameError: # use sets module if Python version is < 2.4 from sets import Set as set import golly import os from glife.RuleTree import * # We support two emulation methods: # 1) square-splitting: each square holds two triangles: one up, one down # 2) checkerboard: each square holds one triangle, either up or down # # The first method has better appearance but requires N*N states. The second requires only 2N # states but user must respect the checkerboard when drawing. For triangularMoore emulation, only # the first is possible (since Golly only natively supports vonNeumann and Moore). Thus we choose # the first where possible, only using the second for triangularVonNeumann when N>16. # # 1) Square-splitting emulation: (following Andrew Trevorrow's TriLife.py) # # triangularVonNeumann -> vonNeumann: # # lower upper # +--+ +--+ # |\ | |\ | # | \| |2\| (any rotation would work too) # +--+--+--+ +--+--+--+ # |\3|\1|\ | |\ |\0|\ | # | \|0\| \| | \|1\|3\| # +--+--+--+ +--+--+--+ # |\2| |\ | # | \| | \| # +--+ +--+ # # triangularMoore -> Moore: # # lower upper # +--+--+--+ +--+--+--+ # |\B|\ |\ | |\6|\7|\ | where A=10, B=11, C=12 # |A\|C\| \| |5\|2\|8\| # +--+--+--+ +--+--+--+ # |\3|\1|\ | |\4|\0|\9| # |9\|0\|4\| | \|1\|3\| # +--+--+--+ +--+--+--+ # |\8|\2|\5| |\ |\C|\A| # | \|7\|6\| | \| \|B\| # +--+--+--+ +--+--+--+ # # 2) Checkerboard emulation: (drawn using A and V to represent triangles in two orientations) # # A V A V A V A V where each A has 3 V neighbors: V A V # V A V A V A V A V # A V A V A V A V # V A V A V A V A and each V has 3 A neighbors: A # A V A V A V A V A V A # V A V A V A V A def TriangularTransitionsToRuleTree_SplittingMethod(neighborhood,n_states,transitions_list,rule_name): # each square cell is j*N+i where i is the lower triangle, j is the upper triangle # each i,j in (0,N] # (lower and upper are lists) def encode(lower,upper): return [ up*n_states+low for up in upper for low in lower ] # what neighbors of the lower triangle overlap neighbors of the upper triangle? lower2upper = { "triangularVonNeumann": [(0,1),(1,0)], "triangularMoore": [(0,1),(1,0),(2,12),(3,4),(4,3),(5,10),(6,11),(10,5),(11,6),(12,2)], } numNeighbors = { "triangularVonNeumann":4, "triangularMoore":8 } # convert transitions to list of list of sets for speed transitions = [[set(e) for e in t] for t in transitions_list] tree = RuleTree(n_states*n_states,numNeighbors[neighborhood]) # for each transition pair, see if we can apply them both at once to a square for i,t1 in enumerate(transitions): # as lower golly.show("Building rule tree... (pass 1 of 2: "+str(100*i/len(transitions))+"%)") for t2 in transitions: # as upper # we can only apply both rules at once if they overlap to some extent ### AKT: any() and isdisjoint() are not available in Python 2.3: ### if any( t1[j].isdisjoint(t2[k]) for j,k in lower2upper[neighborhood] ): ### continue any_disjoint = False for j,k in lower2upper[neighborhood]: if len(t1[j] & t2[k]) == 0: any_disjoint = True break if any_disjoint: continue # take the intersection of their inputs if neighborhood=="triangularVonNeumann": tree.add_rule( [ encode(t1[0]&t2[1],t1[1]&t2[0]), # C encode(range(n_states),t1[2]), # S encode(t2[3],range(n_states)), # E encode(range(n_states),t1[3]), # W encode(t2[2],range(n_states)) ], # N encode(t1[4],t2[4])[0] ) # C' elif neighborhood=="triangularMoore": tree.add_rule( [ encode(t1[0]&t2[1],t1[1]&t2[0]), # C encode(t1[7],t1[2]&t2[12]), # S encode(t1[4]&t2[3],t2[9]), # E encode(t1[9],t1[3]&t2[4]), # W encode(t1[12]&t2[2],t2[7]), # N encode(t1[6]&t2[11],t1[5]&t2[10]), # SE encode(range(n_states),t1[8]), # SW encode(t2[8],range(n_states)), # NE encode(t1[10]&t2[5],t1[11]&t2[6]) ], # NW encode(t1[13],t2[13])[0] ) # C' # apply each transition to an individual triangle, leaving the other unchanged for i,t in enumerate(transitions): golly.show("Building rule tree... (pass 2 of 2: "+str(100*i/len(transitions))+"%)") for t_1 in t[1]: if neighborhood=="triangularVonNeumann": # as lower triangle: tree.add_rule( [ encode(t[0],[t_1]), # C encode(range(n_states),t[2]), # S range(n_states*n_states), # E encode(range(n_states),t[3]), # W range(n_states*n_states) ], # N encode(t[4],[t_1])[0] ) # C' # as upper triangle: tree.add_rule( [ encode([t_1],t[0]), # C range(n_states*n_states), # S encode(t[3],range(n_states)), # E range(n_states*n_states), # W encode(t[2],range(n_states)) ], # N encode([t_1],t[4])[0] ) # C' elif neighborhood=="triangularMoore": # as lower triangle: tree.add_rule( [encode(t[0],[t_1]), # C encode(t[7],t[2]), # S encode(t[4],range(n_states)), # E encode(t[9],t[3]), # W encode(t[12],range(n_states)), # N encode(t[6],t[5]), # SE encode(range(n_states),t[8]), # SW range(n_states*n_states), # NE encode(t[10],t[11]) ], # NW encode(t[13],[t_1])[0] ) # C' # as upper triangle: tree.add_rule( [encode([t_1],t[0]), encode(range(n_states),t[12]), # S encode(t[3],t[9]), # E encode(range(n_states),t[4]), # W encode(t[2],t[7]), # N encode(t[11],t[10]), # SE range(n_states*n_states), # SW encode(t[8],range(n_states)), # NE encode(t[5],t[6]) ], # NW encode([t_1],t[13])[0] ) # C' # output the rule tree golly.show("Compressing rule tree and saving to file...") tree.write(golly.getdir('rules') + rule_name + '.tree') def TriangularTransitionsToRuleTree_CheckerboardMethod(neighborhood,n_states,transitions,rule_name): # Background state 0 has no checkerboard, we infer it from its neighboring cells. def encode_lower(s): return s def encode_upper(s): ### AKT: this code causes syntax error in Python 2.3: ### return [0 if se==0 else n_states+se-1 for se in s] temp = [] for se in s: if se==0: temp.append(0) else: temp.append(n_states+se-1) return temp total_states = n_states*2 - 1 if total_states>256: golly.warn("Number of states exceeds Golly's limit of 256!") golly.exit() tree = RuleTree(total_states,4) for t in transitions: # as lower tree.add_rule([encode_lower(t[0]), # C encode_upper(t[2]), # S encode_upper(t[1]), # E encode_upper(t[3]), # W range(total_states)], # N encode_lower(t[4])[0]) # C' # as upper tree.add_rule([encode_upper(t[0]), # C range(total_states), # S encode_lower(t[3]), # E encode_lower(t[1]), # W encode_lower(t[2])], # N encode_upper(t[4])[0]) # C' # output the rule tree golly.show("Compressing rule tree and saving to file...") tree.write(golly.getdir('rules') + rule_name + '.tree') def MakeTriangularIcons_SplittingMethod(n_states,colors,force_background,rule_name): width = 31*(n_states*n_states-1) if force_background and n_states>2: width+=31 height = 53 pixels = [[(0,0,0) for x in range(width)] for y in range(height)] for row in range(height): for column in range(width): if force_background and n_states>2 and column>=width-31: # add extra 'icon' filled with the intended background color pixels[row][column] = background_color else: # decide if this pixel is a lower or upper triangle iState = int(column/31) upper = int((iState+1) / n_states) lower = (iState+1) - upper*n_states is_upper = False is_lower = False if row<31: # 31x31 icon if (column-iState*31) > row: is_upper = True elif (column-iState*31) < row: is_lower = True elif row<46 and (column-iState*31)<15: # 15x15 icon if (column-iState*31) > row-31: is_upper = True elif (column-iState*31) < row-31: is_lower = True elif (column-iState*31)<7: # 7x7 icon if (column-iState*31) > row-46: is_upper = True elif (column-iState*31) < row-46: is_lower = True if is_upper: pixels[row][column] = colors[upper] elif is_lower: pixels[row][column] = colors[lower] else: pixels[row][column] = 0,0,0 return pixels def MakeTriangularIcons_CheckerboardMethod(n_states,colors,force_background,rule_name): width = 31*(n_states*2-1) if force_background and n_states>2: width+=31 height = 53 pixels = [[(0,0,0) for x in range(width)] for y in range(height)] lower31x31 = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] lower15x15 = [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,1,1,1,0,0,0,0,0,0], [0,0,0,0,0,1,1,1,1,1,0,0,0,0,0], [0,0,0,0,1,1,1,1,1,1,1,0,0,0,0], [0,0,0,1,1,1,1,1,1,1,1,1,0,0,0], [0,0,1,1,1,1,1,1,1,1,1,1,1,0,0], [0,1,1,1,1,1,1,1,1,1,1,1,1,1,0], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]] lower7x7 = [[0,0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,1,0,0,0], [0,0,1,1,1,0,0], [0,1,1,1,1,1,0], [1,1,1,1,1,1,1], [0,0,0,0,0,0,0]] if force_background: bg_color = colors[0] else: bg_color = (0,0,0) for i in range(1,n_states): fg_color = colors[i] # draw 31x31 icons for row in range(31): for column in range(31): # draw lower triangle icons pixels[row][31*(i-1) + column] = [bg_color,fg_color][lower31x31[row][column]] # draw upper triangle icons pixels[row][31*(n_states+i-2) + column] = [bg_color,fg_color][lower31x31[28-row][column]] # draw 15x15 icons for row in range(15): for column in range(15): # draw lower triangle icons pixels[31+row][31*(i-1) + column] = [bg_color,fg_color][lower15x15[row][column]] # draw upper triangle icons pixels[31+row][31*(n_states+i-2) + column] = [bg_color,fg_color][lower15x15[13-row][column]] # draw 7x7 icons for row in range(7): for column in range(7): # draw lower triangle icons pixels[46+row][31*(i-1) + column] = [bg_color,fg_color][lower7x7[row][column]] # draw upper triangle icons pixels[46+row][31*(n_states+i-2) + column] = [bg_color,fg_color][lower7x7[6-row][column]] return pixels def EmulateTriangular(neighborhood,n_states,transitions_list,input_filename): '''Emulate a triangularVonNeumann or triangularMoore neighborhood rule table with a rule tree.''' input_rulename = os.path.splitext(os.path.split(input_filename)[1])[0] # read rule_name+'.colors' file if it exists force_background = False background_color = [0,0,0] cfn = os.path.split(input_filename)[0] + "/" + input_rulename + ".colors" try: cf = open(cfn,'r') except IOError: # use Golly's default random colours random_colors=[[0,0,0],[0,255,127],[127,0,255],[148,148,148],[128,255,0],[255,0,128],[0,128,255],[1,159,0], [159,0,1],[255,254,96],[0,1,159],[96,255,254],[254,96,255],[126,125,21],[21,126,125],[125,21,126], [255,116,116],[116,255,116],[116,116,255],[228,227,0],[28,255,27],[255,27,28],[0,228,227], [227,0,228],[27,28,255],[59,59,59],[234,195,176],[175,196,255],[171,194,68],[194,68,171], [68,171,194],[72,184,71],[184,71,72],[71,72,184],[169,255,188],[252,179,63],[63,252,179], [179,63,252],[80,9,0],[0,80,9],[9,0,80],[255,175,250],[199,134,213],[115,100,95],[188,163,0], [0,188,163],[163,0,188],[203,73,0],[0,203,73],[73,0,203],[94,189,0],[189,0,94]] colors = dict(zip(range(len(random_colors)),random_colors)) else: # read from the .colors file colors = {0:[0,0,0]} # background is black for line in cf: if line[0:6]=='color ': entries = map(int,line[6:].replace('=',' ').replace('\n',' ').split()) if len(entries)<4: continue # too few entries, ignore if entries[0]==0: force_background = True background_color = [entries[1],entries[2],entries[3]] else: colors.update({entries[0]:[entries[1],entries[2],entries[3]]}) # (we don't support gradients in .colors) rule_name = input_rulename + '_emulated' # (we use a special suffix to avoid picking up any existing .colors or .icons) # make a rule tree and some icons if n_states <= 16: TriangularTransitionsToRuleTree_SplittingMethod(neighborhood,n_states,transitions_list,rule_name) pixels = MakeTriangularIcons_SplittingMethod(n_states,colors,force_background,rule_name) total_states = n_states * n_states elif neighborhood=='triangularVonNeumann' and n_states <= 128: TriangularTransitionsToRuleTree_CheckerboardMethod(neighborhood,n_states,transitions_list,rule_name) pixels = MakeTriangularIcons_CheckerboardMethod(n_states,colors,force_background,rule_name) total_states = n_states * 2 - 1 else: golly.warn('Only support triangularMoore with 16 states or fewer, and triangularVonNeumann\n'+\ 'with 128 states or fewer.') golly.exit() if n_states==2: # the icons we wrote are monochrome, so we need a .colors file to avoid # them all having different colors or similar from Golly's preferences c = open(golly.getdir('rules')+rule_name+".colors",'w') if force_background: c.write('color = 0 '+' '.join(map(str,background_color))+'\n') for i in range(1,total_states): c.write('color = '+str(i)+' '+' '.join(map(str,colors[1]))+'\n') c.flush() c.close() # use rule_name.tree and rule_name.colors and icon info to create rule_name.rule ConvertTreeToRule(rule_name, total_states, pixels) return rule_name golly-2.7-src/Scripts/Python/glife/EmulateOneDimensional.py0000644000175000017500000000117012536111364021010 00000000000000import os from glife.RuleTree import * def EmulateOneDimensional(neighborhood,n_states,transitions,input_filename): '''Emulate a oneDimensional neighborhood rule table with a vonNeumann neighborhood rule tree.''' rule_name = os.path.splitext(os.path.split(input_filename)[1])[0] tree = RuleTree(n_states,4) for t in transitions: tree.add_rule([t[0],range(n_states),t[2],t[1],range(n_states)],t[3][0]) # C,S,E,W,N,C' tree.write( golly.getdir('rules')+rule_name+".tree" ) # use rule_name.tree to create rule_name.rule (no icon info) ConvertTreeToRule(rule_name, n_states, []) return rule_name golly-2.7-src/Scripts/Python/glife/herschel.py0000644000175000017500000000324112536111364016365 00000000000000from glife.base import * herschel_ghost = pattern (""" *** . .*.* """) # A Herschel conduit is represented by its pattern and # the transformation it applies to the Herschel. # Hence the additional .transform field. hc64 = block (14, -8) + block (9, -13) + block (13, -15) + block (7, -19) hc64.transform = (-9, -9, rccw) hc77 = block (9, -13) + eater (10, 0, swap_xy) + eater (-7, -12, swap_xy_flip) hc77.transform = (10, -25, flip_x) hc112 = block (16, -10) + block (-3, -11) + aircraft_carrier (13, -3, swap_xy) + \ eater (10, 1) + eater (-3, -14, flip) + eater (9, -16, flip_y) hc112.transform = (35, -12, rcw) hc117 = eater (10, 1) + eater (13, -9, swap_xy) + eater (0, -12, swap_xy_flip) + block (8, -22) + snake (15, -19) hc117.transform = (6, -40, identity) hc119 = block (-14, -3) + block (-13, -8) + block (-19, -9) + eater (-17, -2, rcw) hc119.transform = (-12, -20, flip_x) hc156 = eater (10, 0, swap_xy) + eater (12, -9, swap_xy) + eater (0, -12, swap_xy_flip) + eater (17, -21, flip_y) + \ snake (21, -5, rccw) + block (24, -15) + tub (11, -24) hc156.transform = (43, -17, rcw) hc158 = eater (-2, -13, flip) + eater (-3, -8, rcw) + eater (20, -19, rccw) + pattern (""" .....** .....*.* .......* .......*.*.** ..**.*.*.**.* ..**.**.* ........* ..**.*** ...*.* ...*.* **.** *.* ..* ..** """, 14, -12) hc158.transform = (7, -27, flip_x) hc190 = eater (-3, -8, rcw) + eater (-10, -12, swap_xy) + eater (-3, -12, swap_xy_flip) + \ eater (-8, -17) + eater (11, -27, flip_y) + block (2, -25) + snake (5, -31, rccw) + \ pattern (""" ..**.* ..**.*** ........* ..**.*** ...*.* ...*.* **.** *.* ..* ..** """, 14, -8) hc190.transform = (-16, -22, rccw) golly-2.7-src/Scripts/Python/glife/BuiltinIcons.py0000644000175000017500000002523512536111364017201 00000000000000# This module defines strings containing XPM data that matches # Golly's built-in icons (see the XPM data in wxalgos.cpp). # The strings are used by icon-importer.py and icon_exporter.py. circles = ''' XPM /* width height num_colors chars_per_pixel */ "31 31 5 1" /* colors */ ". c #000000" "B c #404040" "C c #808080" "D c #C0C0C0" "E c #FFFFFF" /* icon for state 1 */ "..............................." "..............................." "..........BCDEEEEEDCB.........." ".........CEEEEEEEEEEEC........." ".......BEEEEEEEEEEEEEEEB......." "......DEEEEEEEEEEEEEEEEED......" ".....DEEEEEEEEEEEEEEEEEEED....." "....BEEEEEEEEEEEEEEEEEEEEEB...." "....EEEEEEEEEEEEEEEEEEEEEEE...." "...CEEEEEEEEEEEEEEEEEEEEEEEC..." "..BEEEEEEEEEEEEEEEEEEEEEEEEEB.." "..CEEEEEEEEEEEEEEEEEEEEEEEEEC.." "..DEEEEEEEEEEEEEEEEEEEEEEEEED.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..EEEEEEEEEEEEEEEEEEEEEEEEEEE.." "..DEEEEEEEEEEEEEEEEEEEEEEEEED.." "..CEEEEEEEEEEEEEEEEEEEEEEEEEC.." "..BEEEEEEEEEEEEEEEEEEEEEEEEEB.." "...CEEEEEEEEEEEEEEEEEEEEEEEC..." "....EEEEEEEEEEEEEEEEEEEEEEE...." "....BEEEEEEEEEEEEEEEEEEEEEB...." ".....DEEEEEEEEEEEEEEEEEEED....." "......DEEEEEEEEEEEEEEEEED......" ".......BEEEEEEEEEEEEEEEB......." ".........CEEEEEEEEEEEC........." "..........BCDEEEEEDCB.........." "..............................." "..............................." XPM /* width height num_colors chars_per_pixel */ "15 15 5 1" /* colors */ ". c #000000" "B c #404040" "C c #808080" "D c #C0C0C0" "E c #FFFFFF" /* icon for state 1 */ "..............." "....BDEEEDB...." "...DEEEEEEED..." "..DEEEEEEEEED.." ".BEEEEEEEEEEEB." ".DEEEEEEEEEEED." ".EEEEEEEEEEEEE." ".EEEEEEEEEEEEE." ".EEEEEEEEEEEEE." ".DEEEEEEEEEEED." ".BEEEEEEEEEEEB." "..DEEEEEEEEED.." "...DEEEEEEED..." "....BDEEEDB...." "..............." XPM /* width height num_colors chars_per_pixel */ "7 7 6 1" /* colors */ ". c #000000" "B c #404040" "C c #808080" "D c #C0C0C0" "E c #FFFFFF" "F c #E0E0E0" /* icon for state 1 */ ".BFEFB." "BEEEEEB" "FEEEEEF" "EEEEEEE" "FEEEEEF" "BEEEEEB" ".BFEFB." ''' diamonds = ''' XPM /* width height num_colors chars_per_pixel */ "31 31 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "..............................." "..............................." "...............B..............." "..............BBB.............." ".............BBBBB............." "............BBBBBBB............" "...........BBBBBBBBB..........." "..........BBBBBBBBBBB.........." ".........BBBBBBBBBBBBB........." "........BBBBBBBBBBBBBBB........" ".......BBBBBBBBBBBBBBBBB......." "......BBBBBBBBBBBBBBBBBBB......" ".....BBBBBBBBBBBBBBBBBBBBB....." "....BBBBBBBBBBBBBBBBBBBBBBB...." "...BBBBBBBBBBBBBBBBBBBBBBBBB..." "..BBBBBBBBBBBBBBBBBBBBBBBBBBB.." "...BBBBBBBBBBBBBBBBBBBBBBBBB..." "....BBBBBBBBBBBBBBBBBBBBBBB...." ".....BBBBBBBBBBBBBBBBBBBBB....." "......BBBBBBBBBBBBBBBBBBB......" ".......BBBBBBBBBBBBBBBBB......." "........BBBBBBBBBBBBBBB........" ".........BBBBBBBBBBBBB........." "..........BBBBBBBBBBB.........." "...........BBBBBBBBB..........." "............BBBBBBB............" ".............BBBBB............." "..............BBB.............." "...............B..............." "..............................." "..............................." XPM /* width height num_colors chars_per_pixel */ "15 15 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "..............." ".......B......." "......BBB......" ".....BBBBB....." "....BBBBBBB...." "...BBBBBBBBB..." "..BBBBBBBBBBB.." ".BBBBBBBBBBBBB." "..BBBBBBBBBBB.." "...BBBBBBBBB..." "....BBBBBBB...." ".....BBBBB....." "......BBB......" ".......B......." "..............." XPM /* width height num_colors chars_per_pixel */ "7 7 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "...B..." "..BBB.." ".BBBBB." "BBBBBBB" ".BBBBB." "..BBB.." "...B..." ''' hexagons = ''' XPM /* width height num_colors chars_per_pixel */ "31 31 3 1" /* colors */ ". c #000000" "B c #FFFFFF" "C c #808080" /* icon for state 1 */ ".....BBC......................." "....BBBBBC....................." "...BBBBBBBBC..................." "..BBBBBBBBBBBC................." ".BBBBBBBBBBBBBBC..............." "BBBBBBBBBBBBBBBBBC............." "BBBBBBBBBBBBBBBBBBBC..........." "CBBBBBBBBBBBBBBBBBBBBC........." ".BBBBBBBBBBBBBBBBBBBBBB........" ".CBBBBBBBBBBBBBBBBBBBBBC......." "..BBBBBBBBBBBBBBBBBBBBBB......." "..CBBBBBBBBBBBBBBBBBBBBBC......" "...BBBBBBBBBBBBBBBBBBBBBB......" "...CBBBBBBBBBBBBBBBBBBBBBC....." "....BBBBBBBBBBBBBBBBBBBBBB....." "....CBBBBBBBBBBBBBBBBBBBBBC...." ".....BBBBBBBBBBBBBBBBBBBBBB...." ".....CBBBBBBBBBBBBBBBBBBBBBC..." "......BBBBBBBBBBBBBBBBBBBBBB..." "......CBBBBBBBBBBBBBBBBBBBBBC.." ".......BBBBBBBBBBBBBBBBBBBBBB.." ".......CBBBBBBBBBBBBBBBBBBBBBC." "........BBBBBBBBBBBBBBBBBBBBBB." ".........CBBBBBBBBBBBBBBBBBBBBC" "...........CBBBBBBBBBBBBBBBBBBB" ".............CBBBBBBBBBBBBBBBBB" "...............CBBBBBBBBBBBBBB." ".................CBBBBBBBBBBB.." "...................CBBBBBBBB..." ".....................CBBBBB...." ".......................CBB....." XPM /* width height num_colors chars_per_pixel */ "15 15 3 1" /* colors */ ". c #000000" "B c #FFFFFF" "C c #808080" /* icon for state 1 */ "...BBC........." "..BBBBBC......." ".BBBBBBBBC....." "BBBBBBBBBBB...." "BBBBBBBBBBBB..." "CBBBBBBBBBBBC.." ".BBBBBBBBBBBB.." ".CBBBBBBBBBBBC." "..BBBBBBBBBBBB." "..CBBBBBBBBBBBC" "...BBBBBBBBBBBB" "....BBBBBBBBBBB" ".....CBBBBBBBB." ".......CBBBBB.." ".........CBB..." XPM /* width height num_colors chars_per_pixel */ "7 7 3 1" /* colors */ ". c #000000" "B c #FFFFFF" "C c #808080" /* icon for state 1 */ ".BBC..." "BBBBB.." "BBBBBB." "CBBBBBC" ".BBBBBB" "..BBBBB" "...CBB." ''' triangles = ''' XPM /* width height num_colors chars_per_pixel */ "31 93 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "..............................." "B.............................." "BB............................." "BBB............................" "BBBB..........................." "BBBBB.........................." "BBBBBB........................." "BBBBBBB........................" "BBBBBBBB......................." "BBBBBBBBB......................" "BBBBBBBBBB....................." "BBBBBBBBBBB...................." "BBBBBBBBBBBB..................." "BBBBBBBBBBBBB.................." "BBBBBBBBBBBBBB................." "BBBBBBBBBBBBBBB................" "BBBBBBBBBBBBBBBB..............." "BBBBBBBBBBBBBBBBB.............." "BBBBBBBBBBBBBBBBBB............." "BBBBBBBBBBBBBBBBBBB............" "BBBBBBBBBBBBBBBBBBBB..........." "BBBBBBBBBBBBBBBBBBBBB.........." "BBBBBBBBBBBBBBBBBBBBBB........." "BBBBBBBBBBBBBBBBBBBBBBB........" "BBBBBBBBBBBBBBBBBBBBBBBB......." "BBBBBBBBBBBBBBBBBBBBBBBBB......" "BBBBBBBBBBBBBBBBBBBBBBBBBB....." "BBBBBBBBBBBBBBBBBBBBBBBBBBB...." "BBBBBBBBBBBBBBBBBBBBBBBBBBBB..." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBB.." "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB." /* icon for state 2 */ ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "..BBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "...BBBBBBBBBBBBBBBBBBBBBBBBBBBB" "....BBBBBBBBBBBBBBBBBBBBBBBBBBB" ".....BBBBBBBBBBBBBBBBBBBBBBBBBB" "......BBBBBBBBBBBBBBBBBBBBBBBBB" ".......BBBBBBBBBBBBBBBBBBBBBBBB" "........BBBBBBBBBBBBBBBBBBBBBBB" ".........BBBBBBBBBBBBBBBBBBBBBB" "..........BBBBBBBBBBBBBBBBBBBBB" "...........BBBBBBBBBBBBBBBBBBBB" "............BBBBBBBBBBBBBBBBBBB" ".............BBBBBBBBBBBBBBBBBB" "..............BBBBBBBBBBBBBBBBB" "...............BBBBBBBBBBBBBBBB" "................BBBBBBBBBBBBBBB" ".................BBBBBBBBBBBBBB" "..................BBBBBBBBBBBBB" "...................BBBBBBBBBBBB" "....................BBBBBBBBBBB" ".....................BBBBBBBBBB" "......................BBBBBBBBB" ".......................BBBBBBBB" "........................BBBBBBB" ".........................BBBBBB" "..........................BBBBB" "...........................BBBB" "............................BBB" ".............................BB" "..............................B" "..............................." /* icon for state 3 */ ".BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "B.BBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BB.BBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBB.BBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBB.BBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBB.BBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBB.BBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBB.BBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBB.BBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBB.BBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBB.BBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBB.BBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBB.BBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBB.BBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBB.BBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBB.BBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBB.BBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBB.BBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBB.BBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBB.BBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBB.BBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBB.BBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBB.BBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBB.BBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBB.BBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBB.BBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBB.BBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBB.BBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBB.BB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBB.B" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB." XPM /* width height num_colors chars_per_pixel */ "15 45 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "..............." "B.............." "BB............." "BBB............" "BBBB..........." "BBBBB.........." "BBBBBB........." "BBBBBBB........" "BBBBBBBB......." "BBBBBBBBB......" "BBBBBBBBBB....." "BBBBBBBBBBB...." "BBBBBBBBBBBB..." "BBBBBBBBBBBBB.." "BBBBBBBBBBBBBB." /* icon for state 2 */ ".BBBBBBBBBBBBBB" "..BBBBBBBBBBBBB" "...BBBBBBBBBBBB" "....BBBBBBBBBBB" ".....BBBBBBBBBB" "......BBBBBBBBB" ".......BBBBBBBB" "........BBBBBBB" ".........BBBBBB" "..........BBBBB" "...........BBBB" "............BBB" ".............BB" "..............B" "..............." /* icon for state 3 */ ".BBBBBBBBBBBBBB" "B.BBBBBBBBBBBBB" "BB.BBBBBBBBBBBB" "BBB.BBBBBBBBBBB" "BBBB.BBBBBBBBBB" "BBBBB.BBBBBBBBB" "BBBBBB.BBBBBBBB" "BBBBBBB.BBBBBBB" "BBBBBBBB.BBBBBB" "BBBBBBBBB.BBBBB" "BBBBBBBBBB.BBBB" "BBBBBBBBBBB.BBB" "BBBBBBBBBBBB.BB" "BBBBBBBBBBBBB.B" "BBBBBBBBBBBBBB." XPM /* width height num_colors chars_per_pixel */ "7 21 2 1" /* colors */ ". c #000000" "B c #FFFFFF" /* icon for state 1 */ "......." "B......" "BB....." "BBB...." "BBBB..." "BBBBB.." "BBBBBB." /* icon for state 2 */ ".BBBBBB" "..BBBBB" "...BBBB" "....BBB" ".....BB" "......B" "......." /* icon for state 3 */ ".BBBBBB" "B.BBBBB" "BB.BBBB" "BBB.BBB" "BBBB.BB" "BBBBB.B" "BBBBBB." ''' golly-2.7-src/Scripts/Python/glife/__init__.py0000644000175000017500000002045512536111364016335 00000000000000# Initialization script executed by using "import glife". # Based on python/life/__init__.py in Eugene Langvagen's PLife. import golly import sys import time __doc__ = """High-level scripting aids for Golly."""; # -------------------------------------------------------------------- class rect(list): """A simple class to make it easier to manipulate rectangles.""" def visible(self): """Return true if rect is completely visible in viewport.""" return golly.visrect( [self.x, self.y, self.wd, self.ht] ) def __init__(self, R = []): if len(R) == 0: self.empty = True elif len(R) == 4: self.empty = False self.x = self.left = R[0] self.y = self.top = R[1] self.wd = self.width = R[2] self.ht = self.height = R[3] if self.wd <= 0: raise ValueError("rect width must be > 0") if self.ht <= 0: raise ValueError("rect height must be > 0") self.right = self.left + self.wd - 1 self.bottom = self.top + self.ht - 1 else: raise TypeError("rect arg must be [] or [x,y,wd,ht]") list.__init__(self, R) # -------------------------------------------------------------------- # Define some useful synonyms: # for golly.clear and golly.advance inside = 0 outside = 1 # for golly.flip left_right = 0 top_bottom = 1 up_down = 1 # for golly.rotate clockwise = 0 anticlockwise = 1 # for golly.setcursor (must match strings in Cursor Mode submenu) draw = "Draw" pick = "Pick" select = "Select" move = "Move" zoomin = "Zoom In" zoomout = "Zoom Out" # -------------------------------------------------------------------- # Define some transformation matrices: identity = ( 1, 0, 0, 1) flip = (-1, 0, 0, -1) flip_x = (-1, 0, 0, 1) flip_y = ( 1, 0, 0, -1) swap_xy = ( 0, 1, 1, 0) swap_xy_flip = ( 0, -1, -1, 0) # Rotation: rcw = ( 0, -1, 1, 0) rccw = ( 0, 1, -1, 0) # -------------------------------------------------------------------- def rule(s = "B3/S23"): """\ Set the rule for the Game of Life. Although it affects subsequent calls to pattern.evolve(), only the last call to this function matters for the viewer.""" golly.setrule(s) # -------------------------------------------------------------------- def description(s): """Supply a textual description to the whole pattern.""" for line in s.split("\n"): print "#D", line # -------------------------------------------------------------------- def compose(S, T): """\ Return the composition of two transformations S and T. A transformation is a tuple of the form (x, y, A), which denotes multiplying by matrix A and then translating by vector (x, y). These tuples can be passed to pattern.__call__().""" x = S[0]; y = S[1]; A = S[2] s = T[0]; t = T[1]; B = T[2] return (x * B[0] + y * B[1] + s, x * B[2] + y * B[3] + t, (A[0] * B[0] + A[2] * B[1], A[1] * B[0] + A[3] * B[1], A[0] * B[2] + A[2] * B[3], A[1] * B[2] + A[3] * B[3])) # -------------------------------------------------------------------- class pattern(list): """This class represents a cell list.""" def __add__(self, q): """Join patterns.""" return pattern(golly.join(self, q)) def __getitem__(self, N): """\ The __getitem__() function is an alias to evolve(). It allows to access the pattern's phases as elements of an array.""" return self.evolve(N) def __call__(self, x, y, A = identity): """The same as 'apply(A).translate(x, y)'.""" return pattern(golly.transform(self, x, y, *A)) def translate(self, x, y): """Translate the pattern.""" return self(x, y) def apply(self, A): """\ Apply a matrix transformation to the pattern. Predefined matrices are: identity, flip, flip_x, flip_y, swap_xy, swap_xy_flip, rcw (rotate clockwise) and rccw (rotate counter-clockwise).""" return self(0, 0, A) def put(self, x = 0, y = 0, A = identity): """Paste pattern into current universe.""" golly.putcells(self, x, y, *A) def display(self, title = "untitled", x = 0, y = 0, A = identity): """Paste pattern into new universe and display it all.""" golly.new(title) golly.putcells(self, x, y, *A) golly.fit() golly.setcursor(zoomin) def save(self, fn, desc = None): """\ Save the pattern to file 'fn' in RLE format. An optional description 'desc' may be given.""" golly.store(self, fn, desc) def evolve(self, N): """\ Return N-th generation of the pattern. Once computed, the N-th generation is remembered and quickly accessible. It is also the base for computing generations subsequent to N-th.""" if N < 0: raise ValueError("backward evolving requested") if self.__phases.has_key(N): return self.__phases[N] M = 0 for k in self.__phases.keys(): if M < k < N: M = k p = self.__phases[N] = pattern(golly.evolve(self.__phases[M], N - M)) return p def __init__(self, P = [], x0 = 0, y0 = 0, A = identity): """\ Initialize a pattern from argument P. P may be another pattern, a cell list, or a multi-line string. A cell list should look like [x1, y1, x2, y2, ...]; a string may be in one of the two autodetected formats: 'visual' or 'RLE'. o 'visual' format means that the pattern is represented in a visual way using symbols '*' (on cell), '.' (off cell) and '\\n' (newline), just like in Life 1.05 format. (Note that an empty line should contain at least one dot). o 'RLE' format means that a string is Run-Length Encoded. The format uses 'o' for on-cells, 'b' for off-cells and '$' for newlines. Moreover, any of these symbols may be prefixed by a number, to denote that symbol repeated that number of times. When P is a string, an optional transformation (x0, y0, A) may be specified. """ self.__phases = dict() if type(P) == list: list.__init__(self, P) elif type(P) == pattern: list.__init__(self, list(P)) elif type(P) == str: list.__init__(self, golly.parse(P, x0, y0, *A)) else: raise TypeError("list or string is required here") self.__phases[0] = self # -------------------------------------------------------------------- def load(fn): # note that top left cell of bounding box will be at 0,0 return pattern(golly.load(fn)) # -------------------------------------------------------------------- def getminbox(patt): # return a rect which is the minimal bounding box of given pattern; # note that if the pattern is a multi-state list then any dead cells # are included in the bounding box minx = sys.maxint maxx = -sys.maxint miny = sys.maxint maxy = -sys.maxint clist = list(patt) clen = len(clist) inc = 2 if clen & 1 == 1: # multi-state list (3 ints per cell) inc = 3 # ignore padding int if it is present if clen % 3 == 1: clen -= 1 for x in xrange(0, clen, inc): if clist[x] < minx: minx = clist[x] if clist[x] > maxx: maxx = clist[x] for y in xrange(1, clen, inc): if clist[y] < miny: miny = clist[y] if clist[y] > maxy: maxy = clist[y] return rect( [ minx, miny, maxx - minx + 1, maxy - miny + 1 ] ) # -------------------------------------------------------------------- def validint(s): # return True if given string represents a valid integer if len(s) == 0: return False s = s.replace(",","") if s[0] == '+' or s[0] == '-': s = s[1:] return s.isdigit() # -------------------------------------------------------------------- def getposint(): # return current viewport position as integer coords x, y = golly.getpos() return int(x), int(y) # -------------------------------------------------------------------- def setposint(x,y): # convert integer coords to strings and set viewport position golly.setpos(str(x), str(y)) # -------------------------------------------------------------------- def getstring(prompt): # this routine is deprecated golly.warn("Change the script to use the getstring() command\n"+ "from golly rather than from glife.") golly.exit("") golly-2.7-src/Scripts/Python/glife/gun46.py0000644000175000017500000000046012536111364015533 00000000000000from glife.base import * rule() # use Life rule to evolve phases __half = bheptomino (0, 2, flip_x) + bheptomino (0, -2, flip) + block (16, -4) + block (16, 3) gun46_double = __half (7, -2) + __half (-8, 2, flip_x) gun46 = __half[1] (1, -7) + __half (-13, -4, flip_x) # aligned version shooting SE golly-2.7-src/Scripts/Python/glife/base.py0000644000175000017500000001041712536111364015505 00000000000000from glife import * block = pattern (""" ** ** """) blinker = pattern ("***", -1, 0) glider = pattern (""" .** **. ..* """) lwss = pattern (""" ****. *...* *.... .*..* """) mwss = pattern (""" *****. *....* *..... .*...* ...*.. """) hwss = pattern (""" ******. *.....* *...... .*....* ...**.. """) eater = hook = pattern (""" ** * .*** ...* """) queenbee = pattern (""" **.. ..*. ...* ...* ...* ..*. **.. """) herschel = pattern (""" ***. .*.. .*** """) bheptomino = pattern (""" **. .** **. *.. """) tub = pattern (""" .*. *.* .*. """, -1, -1) boat = pattern (""" **. *.* .*. """) long_boat = pattern (""" **. *.* .*.* ..* """) ship = pattern (""" **. *.* .** """, -1, -1) beehive = pattern (""" .**. *..* .**. """, 0, -1) loaf = pattern (""" .**. *..* *.*. .*.. """) snake = pattern (""" *.** **.* """) aircraft_carrier = pattern (""" **.. *..* ..** """) honeyfarm = pattern (""" ......*...... .....*.*..... .....*.*..... ......*...... ............. .**.......**. *..*.....*..* .**.......**. ............. ......*...... .....*.*..... .....*.*..... ......*...... """, -6, -6) beacon = pattern (""" **.. *... ...* ..** """) blocker = pattern (""" ......*.*. .....*.... **..*....* **.*..*.** ....**.... """) clock = pattern (""" ..*. **.. ..** .*.. """) dart = pattern (""" ........*. .......*.* ......**.. .........* .....*...* ..*..*.... .*.*..**** *..*...... .*.*..**** ..*..*.... .....*...* .........* ......**.. .......*.* ........*. """, 0, -7) big_beacon = pattern (""" ***... ***... ***... ...*** ...*** ...*** """) middleweight_volcano = pattern (""" ...*******... .***.***.***. *....***....* .****.*.***.* ...........*. *.**.*.*.*... **.*.*.*.**.. ....*..*.*... .....**..*... .........**.. """, -6, 0) heavyweight_volcano = pattern (""" .........*.......................... ........*.*......................... ......***.*......................... .....*....**.*...................... .....*.**...**......**.............. ....**.*.**.........*.*............. .........*.*****......*..*.**....... ..*.**.**.*.....*....**.*.**.*...... .....**.....****........*....*...... *...*.*..*...*.*....**.*.****.**.... *...*.*..**.*.**.**....*.*....*.*... .....**...***.**.*.***.*..***...*... ..*.**.**.**.............*.*..*.*.** ...........*......*.*.*.*..**.*.*.*. ....**.*.*.**......**.*.*.*...*.*.*. .....*.**.*..*.......*.**..****.**.. .....*....*.*........*...**......... ....**....**........**...*..*....... ...........................**....... """) galaxy = pattern (""" ******.** ******.** .......** **.....** **.....** **.....** **....... **.****** **.****** """, -4, -4) orion = pattern (""" ...**......... ...*.*........ ...*.......... **.*.......... *....*........ *.**......***. .....***....** ......***.*.*. .............* ......*.*..... .....**.*..... ......*....... ....**.*...... .......*...... .....**....... """) pentadecathlon = pattern (""" ..*....*.. **.****.** ..*....*.. """, 0, -1) pi = pattern (""" *** *.* *.* """) pond = pattern (""" .**. *..* *..* .**. """) pulsar = pattern (""" ..***...***.. ............. *....*.*....* *....*.*....* *....*.*....* ..***...***.. ............. ..***...***.. *....*.*....* *....*.*....* *....*.*....* ............. ..***...***.. """, -6, -6) rpentomino = pattern (""" .** ** .* """) rabbits = pattern (""" *...*** ***..*. .*..... """) spider = pattern (""" .........*.......*......... ...**.*.*.**...**.*.*.**... ***.*.***.........***.*.*** *...*.*.....*.*.....*.*...* ....**......*.*......**.... .**.........*.*.........**. .**.**...............**.**. .....*...............*..... """, -13, 0) lightweight_volcano = pattern (""" ...**..**... .***.**.***. *..........* .****..****. ....*..*.... .**......**. .*..*..*..*. ..***..***.. ............ ****.**.**** *..**..**..* """) unix = pattern (""" ..**.... ....*.** *..*..** *.*..... .*...... ........ .**..... .**..... """) biblocker = pattern (""" ..................*........... .................*.**......... .................*.**......... ..................**.......... .............................. .......**............**....... .......**............**....... .............................. .............................. ......*.*..................... .....*..................**.... **..*....*..........**.*..*.** **.*..*.**..........**..*....* ....**...................*.... ..........................*.*. """) golly-2.7-src/Scripts/Python/glife/gun256.py0000644000175000017500000000042112536111364015613 00000000000000from glife.herschel import * __c64 = hc64 (9, 0) __stub = eater (4, -16, rccw) gun256_full = herschel (9, 0) + __c64 + __c64.apply (rcw) + __c64.apply (flip) + __c64.apply (rccw) gun256 = (gun256_full + __stub + __stub.apply (rccw) + __stub.apply (flip)) (-25, -12) golly-2.7-src/Scripts/Python/glife/WriteBMP.py0000644000175000017500000000603612536111364016226 00000000000000# Just to save the user having to install PIL. # BMP code from: http://pseentertainmentcorp.com/smf/index.php?topic=2034.0 # Distributed with kind permission from James Main import struct def WriteBMP(pixels,filename): ''' Write a BMP to filename from the (r,g,b) triples in pixels[row][column]. Usage example: WriteBMP( [[(255,0,0),(0,255,0),(255,255,0)],[(0,0,255),(0,0,0),(0,255,255)]], "test.bmp" ) ''' # Here is a minimal dictionary with header values. d = { 'mn1':66, 'mn2':77, 'filesize':0, 'undef1':0, 'undef2':0, 'offset':54, 'headerlength':40, 'width':len(pixels[0]), 'height':len(pixels), 'colorplanes':1, 'colordepth':24, 'compression':0, 'imagesize':0, 'res_hor':0, 'res_vert':0, 'palette':0, 'importantcolors':0 } # Build the byte array. This code takes the height # and width values from the dictionary above and # generates the pixels row by row. The row_mod and padding # stuff is necessary to ensure that the byte count for each # row is divisible by 4. This is part of the specification. bytes = '' for row in range(d['height']-1,-1,-1): # (BMPs are encoded left-to-right from the bottom-left) for column in range(d['width']): r,g,b = pixels[row][column] pixel = struct.pack(''] = pattern("$bo$2bo$3bo$2bo$bo!") __mfont['?'] = pattern("b3o$o3bo$4bo$2b2o$2bo2$2bo!") __mfont['@'] = pattern("b3o$o3bo$ob3o$obobo$ob2o$o$b3o!") __mfont['A'] = pattern("b3o$o3bo$o3bo$5o$o3bo$o3bo$o3bo!") __mfont['B'] = pattern("4o$o3bo$o3bo$4o$o3bo$o3bo$4o!") __mfont['C'] = pattern("b3o$o3bo$o$o$o$o3bo$b3o!") __mfont['D'] = pattern("4o$o3bo$o3bo$o3bo$o3bo$o3bo$4o!") __mfont['E'] = pattern("5o$o$o$3o$o$o$5o!") __mfont['F'] = pattern("5o$o$o$3o$o$o$o!") __mfont['G'] = pattern("b3o$o3bo$o$o2b2o$o3bo$o3bo$b3o!") __mfont['H'] = pattern("o3bo$o3bo$o3bo$5o$o3bo$o3bo$o3bo!") __mfont['I'] = pattern("b3o$2bo$2bo$2bo$2bo$2bo$b3o!") __mfont['J'] = pattern("2b3o$3bo$3bo$3bo$3bo$o2bo$b2o!") __mfont['K'] = pattern("o3bo$o2bo$obo$2o$obo$o2bo$o3bo!") __mfont['L'] = pattern("o$o$o$o$o$o$5o!") __mfont['M'] = pattern("o3bo$2ob2o$obobo$obobo$o3bo$o3bo$o3bo!") __mfont['N'] = pattern("o3bo$2o2bo$obobo$o2b2o$o3bo$o3bo$o3bo!") __mfont['O'] = pattern("b3o$o3bo$o3bo$o3bo$o3bo$o3bo$b3o!") __mfont['P'] = pattern("4o$o3bo$o3bo$4o$o$o$o!") __mfont['Q'] = pattern("b3o$o3bo$o3bo$o3bo$obobo$o2bo$b2obo!") __mfont['R'] = pattern("4o$o3bo$o3bo$4o$o2bo$o3bo$o3bo!") __mfont['S'] = pattern("b3o$o3bo$o$b3o$4bo$o3bo$b3o!") __mfont['T'] = pattern("5o$2bo$2bo$2bo$2bo$2bo$2bo!") __mfont['U'] = pattern("o3bo$o3bo$o3bo$o3bo$o3bo$o3bo$b3o!") __mfont['V'] = pattern("o3bo$o3bo$o3bo$o3bo$o3bo$bobo$2bo!") __mfont['W'] = pattern("o3bo$o3bo$o3bo$obobo$obobo$2ob2o$o3bo!") __mfont['X'] = pattern("o3bo$o3bo$bobo$2bo$bobo$o3bo$o3bo!") __mfont['Y'] = pattern("o3bo$o3bo$bobo$2bo$2bo$2bo$2bo!") __mfont['Z'] = pattern("5o$4bo$3bo$2bo$bo$o$5o!") __mfont['['] = pattern("2b2o$2bo$2bo$2bo$2bo$2bo$2b2o!") __mfont['\\'] = pattern("bo$bo$2bo$2bo$2bo$3bo$3bo!") __mfont[']'] = pattern("b2o$2bo$2bo$2bo$2bo$2bo$b2o!") __mfont['^'] = pattern("2bo$bobo$o3bo!") __mfont['_'] = pattern("6$5o!") __mfont['`'] = pattern("o$bo!") __mfont['a'] = pattern("2$b4o$o3bo$o3bo$o3bo$b4o!") __mfont['b'] = pattern("o$o$4o$o3bo$o3bo$o3bo$4o!") __mfont['c'] = pattern("2$b4o$o$o$o$b4o!") __mfont['d'] = pattern("4bo$4bo$b4o$o3bo$o3bo$o3bo$b4o!") __mfont['e'] = pattern("2$b3o$o3bo$5o$o$b4o!") __mfont['f'] = pattern("2b2o$bo2bo$bo$3o$bo$bo$bo!") __mfont['g'] = pattern("2$b3o$o3bo$o3bo$o3bo$b4o$4bo$b3o!") __mfont['h'] = pattern("o$o$ob2o$2o2bo$o3bo$o3bo$o3bo!") __mfont['i'] = pattern("$2bo2$2bo$2bo$2bo$2b2o!") __mfont['j'] = pattern("$3bo2$3bo$3bo$3bo$3bo$o2bo$b2o!") __mfont['k'] = pattern("o$o$o2bo$obo$3o$o2bo$o3bo!") __mfont['l'] = pattern("b2o$2bo$2bo$2bo$2bo$2bo$2b2o!") __mfont['m'] = pattern("2$bobo$obobo$obobo$o3bo$o3bo!") __mfont['n'] = pattern("2$4o$o3bo$o3bo$o3bo$o3bo!") __mfont['o'] = pattern("2$b3o$o3bo$o3bo$o3bo$b3o!") __mfont['p'] = pattern("2$4o$o3bo$o3bo$o3bo$4o$o$o!") __mfont['q'] = pattern("2$b4o$o3bo$o3bo$o3bo$b4o$4bo$4bo!") __mfont['r'] = pattern("2$ob2o$2o2bo$o$o$o!") __mfont['s'] = pattern("2$b4o$o$b3o$4bo$4o!") __mfont['t'] = pattern("$2bo$5o$2bo$2bo$2bo$3b2o!") __mfont['u'] = pattern("2$o3bo$o3bo$o3bo$o3bo$b4o!") __mfont['v'] = pattern("2$o3bo$o3bo$o3bo$bobo$2bo!") __mfont['w'] = pattern("2$o3bo$o3bo$obobo$2ob2o$o3bo!") __mfont['x'] = pattern("2$o3bo$bobo$2bo$bobo$o3bo!") __mfont['y'] = pattern("2$o3bo$o3bo$o3bo$o3bo$b4o$4bo$b3o!") __mfont['z'] = pattern("2$5o$3bo$2bo$bo$5o!") __mfont['{'] = pattern("3bo$2bo$2bo$bo$2bo$2bo$3bo!") __mfont['|'] = pattern("2bo$2bo$2bo$2bo$2bo$2bo$2bo!") __mfont['}'] = pattern("bo$2bo$2bo$3bo$2bo$2bo$bo!") __mfont['~'] = pattern("2$bo$obobo$3bo!") for key in __mfont: __mfont[key].width = 6 # Snakial font (all chars are stable Life patterns) __sfont = dict () __sfont['0'] = pattern ("2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$o5bo$bo5bo$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!", 0, -14) __sfont['0'].width = 10 __sfont['1'] = pattern ("2o$bo$o$2o2$2o$bo$o$2o2$2o$bo$o$2o!", 1, -14) __sfont['1'].width = 6 __sfont['2'] = pattern ("2b2obo$2bob2o$6b2o$6bo$7bo$6b2o$2b2obo$2bob2o$2o$o$bo$2o$2b2obo$2bob2o!", 0, -14) __sfont['2'].width = 10 __sfont['3'] = pattern ("2obo$ob2o$4b2o$4bo$5bo$4b2o$2obo$ob2o$4b2o$4bo$5bo$4b2o$2obo$ob2o!", 0, -14) __sfont['3'].width = 8 __sfont['4'] = pattern ("2o3b2o$2o3b2o2$2o3b2o$obobobo$2bobo$b2obo$5b2o$6bo$5bo$5b2o$6bo$5bo$5b2o!", 0, -14) __sfont['4'].width = 9 __sfont['5'] = pattern ("2b2obo$2bob2o$2o$o$bo$2o$2b2obo$2bob2o$6b2o$6bo$7bo$6b2o$2b2obo$2bob2o!", 0, -14) __sfont['5'].width = 10 __sfont['6'] = pattern ("2b2obo$2bob2o$2o$o$bo$2o$2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!", 0, -14) __sfont['6'].width = 10 __sfont['7'] = pattern ("ob2o$2obo$4b2o$5bo$4bo$4b2o$2b2o$3bo$2bo$2b2o$2o$bo$o$2o!", 0, -14) __sfont['7'].width = 8 __sfont['8'] = pattern ("2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!", 0, -14) __sfont['8'].width = 10 __sfont['9'] = pattern ("2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o$6b2o$6bo$7bo$6b2o$2b2obo$2bob2o!", 0, -14) __sfont['9'].width = 10 __sfont['-'] = pattern ("2obo$ob2o!", 0, -8) __sfont['-'].width = 6 def make_text (string, font='Snakial'): p = pattern () x = 0 if lower(font[:2]) == "ea": f = __eafont unknown = '-' elif lower(font) == "mono": f = __mfont unknown = '?' else: f = __sfont unknown = '-' for c in string: if not f.has_key (c): c = unknown symbol = f[c] p += symbol (x, 0) x += symbol.width return p golly-2.7-src/Scripts/Python/glife/ReadRuleTable.py0000644000175000017500000002532412536111364017251 00000000000000try: set except NameError: # use sets module if Python version is < 2.4 from sets import Set as set import golly # generate permutations where the input list may have duplicates # e.g. [1,2,1] -> [[1, 2, 1], [1, 1, 2], [2, 1, 1]] # (itertools.permutations would yield 6 and removing duplicates afterwards is less efficient) # http://code.activestate.com/recipes/496819/ (PSF license) def permu2(xs): if len(xs)<2: yield xs else: h = [] for x in xs: h.append(x) if x in h[:-1]: continue ts = xs[:]; ts.remove(x) for ps in permu2(ts): yield [x]+ps # With some neighborhoods we permute after building each transition, to avoid # creating lots of copies of the same rule. The others are permuted explicitly # because we haven't worked out how to permute the Margolus neighborhood while # allowing for duplicates. PermuteLater = ['vonNeumann','Moore','hexagonal','triangularVonNeumann', 'triangularMoore','oneDimensional'] SupportedSymmetries = { "vonNeumann": { 'none':[[0,1,2,3,4,5]], 'rotate4':[[0,1,2,3,4,5],[0,2,3,4,1,5],[0,3,4,1,2,5],[0,4,1,2,3,5]], 'rotate4reflect':[[0,1,2,3,4,5],[0,2,3,4,1,5],[0,3,4,1,2,5],[0,4,1,2,3,5], [0,4,3,2,1,5],[0,3,2,1,4,5],[0,2,1,4,3,5],[0,1,4,3,2,5]], 'reflect_horizontal':[[0,1,2,3,4,5],[0,1,4,3,2,5]], 'permute':[[0,1,2,3,4,5]], # (gets done later) }, "Moore": { 'none':[[0,1,2,3,4,5,6,7,8,9]], 'rotate4':[[0,1,2,3,4,5,6,7,8,9],[0,3,4,5,6,7,8,1,2,9],[0,5,6,7,8,1,2,3,4,9],[0,7,8,1,2,3,4,5,6,9]], 'rotate8':[[0,1,2,3,4,5,6,7,8,9],[0,2,3,4,5,6,7,8,1,9],[0,3,4,5,6,7,8,1,2,9],[0,4,5,6,7,8,1,2,3,9],\ [0,5,6,7,8,1,2,3,4,9],[0,6,7,8,1,2,3,4,5,9],[0,7,8,1,2,3,4,5,6,9],[0,8,1,2,3,4,5,6,7,9]], 'rotate4reflect':[[0,1,2,3,4,5,6,7,8,9],[0,3,4,5,6,7,8,1,2,9],[0,5,6,7,8,1,2,3,4,9],[0,7,8,1,2,3,4,5,6,9],\ [0,1,8,7,6,5,4,3,2,9],[0,7,6,5,4,3,2,1,8,9],[0,5,4,3,2,1,8,7,6,9],[0,3,2,1,8,7,6,5,4,9]], 'rotate8reflect':[[0,1,2,3,4,5,6,7,8,9],[0,2,3,4,5,6,7,8,1,9],[0,3,4,5,6,7,8,1,2,9],[0,4,5,6,7,8,1,2,3,9],\ [0,5,6,7,8,1,2,3,4,9],[0,6,7,8,1,2,3,4,5,9],[0,7,8,1,2,3,4,5,6,9],[0,8,1,2,3,4,5,6,7,9],\ [0,8,7,6,5,4,3,2,1,9],[0,7,6,5,4,3,2,1,8,9],[0,6,5,4,3,2,1,8,7,9],[0,5,4,3,2,1,8,7,6,9],\ [0,4,3,2,1,8,7,6,5,9],[0,3,2,1,8,7,6,5,4,9],[0,2,1,8,7,6,5,4,3,9],[0,1,8,7,6,5,4,3,2,9]], 'reflect_horizontal':[[0,1,2,3,4,5,6,7,8,9],[0,1,8,7,6,5,4,3,2,9]], 'permute':[[0,1,2,3,4,5,6,7,8,9]] # (gets done later) }, "Margolus": { 'none':[[0,1,2,3,4,5,6,7]], 'reflect_horizontal':[[0,1,2,3,4,5,6,7],[1,0,3,2,5,4,7,6]], 'reflect_vertical':[[0,1,2,3,4,5,6,7],[2,3,0,1,6,7,4,5]], 'rotate4': [[0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6]], 'rotate4reflect':[ [0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6], [1,0,3,2,5,4,7,6],[0,2,1,3,4,6,5,7],[2,3,0,1,6,7,4,5],[3,1,2,0,7,5,6,4]], 'permute':[p+map(lambda x:x+4,p) for p in permu2(range(4))] }, "square4_figure8v": # same symmetries as Margolus { 'none':[[0,1,2,3,4,5,6,7]], 'reflect_horizontal':[[0,1,2,3,4,5,6,7],[1,0,3,2,5,4,7,6]], 'reflect_vertical':[[0,1,2,3,4,5,6,7],[2,3,0,1,6,7,4,5]], 'rotate4': [[0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6]], 'rotate4reflect':[ [0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6], [1,0,3,2,5,4,7,6],[0,2,1,3,4,6,5,7],[2,3,0,1,6,7,4,5],[3,1,2,0,7,5,6,4]], 'permute':[p+map(lambda x:x+4,p) for p in permu2(range(4))] }, "square4_figure8h": # same symmetries as Margolus { 'none':[[0,1,2,3,4,5,6,7]], 'reflect_horizontal':[[0,1,2,3,4,5,6,7],[1,0,3,2,5,4,7,6]], 'reflect_vertical':[[0,1,2,3,4,5,6,7],[2,3,0,1,6,7,4,5]], 'rotate4': [[0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6]], 'rotate4reflect':[ [0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6], [1,0,3,2,5,4,7,6],[0,2,1,3,4,6,5,7],[2,3,0,1,6,7,4,5],[3,1,2,0,7,5,6,4]], 'permute':[p+map(lambda x:x+4,p) for p in permu2(range(4))] }, "square4_cyclic": # same symmetries as Margolus { 'none':[[0,1,2,3,4,5,6,7]], 'reflect_horizontal':[[0,1,2,3,4,5,6,7],[1,0,3,2,5,4,7,6]], 'reflect_vertical':[[0,1,2,3,4,5,6,7],[2,3,0,1,6,7,4,5]], 'rotate4': [[0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6]], 'rotate4reflect':[ [0,1,2,3,4,5,6,7],[2,0,3,1,6,4,7,5],[3,2,1,0,7,6,5,4],[1,3,0,2,5,7,4,6], [1,0,3,2,5,4,7,6],[0,2,1,3,4,6,5,7],[2,3,0,1,6,7,4,5],[3,1,2,0,7,5,6,4]], 'permute':[p+map(lambda x:x+4,p) for p in permu2(range(4))] }, "triangularVonNeumann": { 'none':[[0,1,2,3,4]], 'rotate':[[0,1,2,3,4],[0,3,1,2,4],[0,2,3,1,4]], 'rotate_reflect':[[0,1,2,3,4],[0,3,1,2,4],[0,2,3,1,4],[0,3,2,1,4],[0,1,3,2,4],[0,2,1,3,4]], 'permute':[[0,1,2,3,4]] # (gets done later) }, "triangularMoore": { 'none':[[0,1,2,3,4,5,6,7,8,9,10,11,12,13]], 'rotate':[[0,1,2,3,4,5,6,7,8,9,10,11,12,13], [0,2,3,1,7,8,9,10,11,12,4,5,6,13], [0,3,1,2,10,11,12,4,5,6,7,8,9,13]], 'rotate_reflect':[[0,1,2,3,4,5,6,7,8,9,10,11,12,13], [0,2,3,1,7,8,9,10,11,12,4,5,6,13], [0,3,1,2,10,11,12,4,5,6,7,8,9,13], [0,3,2,1,9,8,7,6,5,4,12,11,10,13], [0,2,1,3,6,5,4,12,11,10,9,8,7,13], [0,1,3,2,12,11,10,9,8,7,6,5,4,13]], 'permute':[[0,1,2,3,4,5,6,7,8,9,10,11,12,13]], # (gets done later) }, "oneDimensional": { 'none':[[0,1,2,3]], 'reflect':[[0,1,2,3],[0,2,1,3]], 'permute':[[0,1,2,3]], # (gets done later) }, "hexagonal": { 'none':[[0,1,2,3,4,5,6,7]], 'rotate2':[[0,1,2,3,4,5,6,7],[0,4,5,6,1,2,3,7]], 'rotate3':[[0,1,2,3,4,5,6,7],[0,3,4,5,6,1,2,7],[0,5,6,1,2,3,4,7]], 'rotate6':[[0,1,2,3,4,5,6,7],[0,2,3,4,5,6,1,7],[0,3,4,5,6,1,2,7], [0,4,5,6,1,2,3,7],[0,5,6,1,2,3,4,7],[0,6,1,2,3,4,5,7]], 'rotate6reflect':[[0,1,2,3,4,5,6,7],[0,2,3,4,5,6,1,7],[0,3,4,5,6,1,2,7], [0,4,5,6,1,2,3,7],[0,5,6,1,2,3,4,7],[0,6,1,2,3,4,5,7], [0,6,5,4,3,2,1,7],[0,5,4,3,2,1,6,7],[0,4,3,2,1,6,5,7], [0,3,2,1,6,5,4,7],[0,2,1,6,5,4,3,7],[0,1,6,5,4,3,2,7]], 'permute':[[0,1,2,3,4,5,6,7]], # (gets done later) }, } def ReadRuleTable(filename): ''' Return n_states, neighborhood, transitions e.g. 2, "vonNeumann", [[0],[0,1],[0],[0],[1],[1]] Transitions are expanded for symmetries and bound variables. ''' f=open(filename,'r') vars={} symmetry_string = '' symmetry = [] n_states = 0 neighborhood = '' transitions = [] numParams = 0 for line in f: if line[0]=='#' or line.strip()=='': pass elif line[0:9]=='n_states:': n_states = int(line[9:]) if n_states<0 or n_states>256: golly.warn('n_states out of range: '+n_states) golly.exit() elif line[0:13]=='neighborhood:': neighborhood = line[13:].strip() if not neighborhood in SupportedSymmetries: golly.warn('Unknown neighborhood: '+neighborhood) golly.exit() numParams = len(SupportedSymmetries[neighborhood].items()[0][1][0]) elif line[0:11]=='symmetries:': symmetry_string = line[11:].strip() if not symmetry_string in SupportedSymmetries[neighborhood]: golly.warn('Unknown symmetry: '+symmetry_string) golly.exit() symmetry = SupportedSymmetries[neighborhood][symmetry_string] elif line[0:4]=='var ': line = line[4:] # strip var keyword if '#' in line: line = line[:line.find('#')] # strip any trailing comment # read each variable into a dictionary mapping string to list of ints entries = line.replace('=',' ').replace('{',' ').replace(',',' ').\ replace(':',' ').replace('}',' ').replace('\n','').split() vars[entries[0]] = [] for e in entries[1:]: if e in vars: vars[entries[0]] += vars[e] # vars allowed in later vars else: vars[entries[0]].append(int(e)) else: # assume line is a transition if '#' in line: line = line[:line.find('#')] # strip any trailing comment if ',' in line: entries = line.replace('\n','').replace(',',' ').replace(':',' ').split() else: entries = list(line.strip()) # special no-comma format if not len(entries)==numParams: golly.warn('Wrong number of entries on line: '+line+' (expected '+str(numParams)+')') golly.exit() # retrieve the variables that repeat within the transition, these are 'bound' bound_vars = [ e for e in set(entries) if entries.count(e)>1 and e in vars ] # iterate through all the possible values of each bound variable var_val_indices = dict(zip(bound_vars,[0]*len(bound_vars))) while True: ### AKT: this code causes syntax error in Python 2.3: ### transition = [ [vars[e][var_val_indices[e]]] if e in bound_vars \ ### else vars[e] if e in vars \ ### else [int(e)] \ ### for e in entries ] transition = [] for e in entries: if e in bound_vars: transition.append([vars[e][var_val_indices[e]]]) elif e in vars: transition.append(vars[e]) else: transition.append([int(e)]) if symmetry_string=='permute' and neighborhood in PermuteLater: # permute all but C,C' (first and last entries) for permuted_section in permu2(transition[1:-1]): permuted_transition = [transition[0]]+permuted_section+[transition[-1]] if not permuted_transition in transitions: transitions.append(permuted_transition) else: # expand for symmetry using the explicit list for s in symmetry: tran = [transition[i] for i in s] if not tran in transitions: transitions.append(tran) # increment the variable values (or break out if done) var_val_to_change = 0 while var_val_to_change= len(bound_vars): break f.close() return n_states, neighborhood, transitions golly-2.7-src/Scripts/Python/glife/EmulateMargolus.py0000644000175000017500000001671312536111364017706 00000000000000# We emulate Margolus and related partitioning neighborhoods by making a 2-layer CA, with a # background layer (0,1) that alternates a sort-of-checker pattern, and the normal states on top. # # For the Margolus neighborhood there is only one 'phase'; one background pattern, that alternates # between top-left and bottom-right of a 2x2 region. # # For the square4_* neighborhoods we need two phases since the background shifts in different # directions to make a figure-8 or cyclic pattern. # # By looking at the nearby background states, each cell can work out where in the partition it is # and what the current phase is. It can therefore update the cell states layer correctly, and also # update the background layer for the next phase. import golly import os from glife.RuleTree import * # state s (0,N-1) on background state b (0,1) becomes 1+b+2s with 0 = off-grid def encode(s,b): # (s is a list) return [ 1+b+2*se for se in s ] # The BackgroundInputs array tells us where we are in the block: # # Phase 1: 0 1 (the lone 0 is the top-left of the block to be updated) # 1 1 # # Phase 2: 1 0 (the lone 1 is the top-left of the block to be updated) # 0 0 # # (imagine the blocks stacked together to see why this gives the values below) # BackgroundInputs = [ # each C,S,E,W,N,SE,SW,NE,NW [0,1,1,1,1,1,1,1,1], # this pattern of background states means that this is top-left, phase 1 [1,1,0,0,1,1,1,1,1], # top-right, phase 1 [1,0,1,1,0,1,1,1,1], # bottom-left, phase 1 [1,1,1,1,1,0,0,0,0], # bottom-right, phase 1 [1,0,0,0,0,0,0,0,0], # top-left, phase 2 [0,0,1,1,0,0,0,0,0], # top-right, phase 2 [0,1,0,0,1,0,0,0,0], # bottom-left, phase 2 [0,0,0,0,0,1,1,1,1], # bottom-right, phase 2 ] # The BackgroundOutputs array tells us how the background pattern changes: # # Margolus: 0 1 become 1 1 (block moves diagonally) # 1 1 1 0 # # square4_figure8v: 0 1 becomes 0 0 (block moves diagonally) # 1 1 0 1 # # 1 0 becomes 1 0 (block moves horizontally) # 0 0 1 1 # # square4_figure8h: 0 1 becomes 0 0 (block moves diagonally) # 1 1 0 1 # # 1 0 becomes 1 1 (block moves vertically) # 0 0 0 1 # # square4_cyclic : 0 1 becomes 0 0 (block moves vertically) # 1 1 1 0 # # 1 0 becomes 1 0 (block moves horizontally) # 0 0 1 1 # # (Following Tim Tyler: http://www.cell-auto.com/neighbourhood/square4/index.html) # BackgroundOutputs = { # (top-left, top-right, bottom-left, bottom-right)*2 (or *1 for Margolus) "Margolus": [1,1,1,0], # phase 1 -> phase 1 "square4_figure8v":[0,0,0,1,1,0,1,1], # phase 1 <--> phase 2 "square4_figure8h":[0,0,0,1,1,1,0,1], # phase 1 <--> phase 2 "square4_cyclic": [0,0,1,0,1,0,1,1], # phase 1 <--> phase 2 } # The ForegroundInputs array tells us, for each of the 4 positions (0=top-left, 1=top-right, # 2=bottom-left, 3=bottom-right), where the other positions are found in our Moore neighborhood # e.g. if we're 0 (top-left) then the first row tells us that to our South is position 2 (bottom-left) # and to our South-East is position 3 (bottom-right). # (N.B. these values don't depend on the phase or the background pattern) ForegroundInputs = [ [0,2,1,-1,-1,3,-1,-1,-1], # what surrounds this entry? [1,3,-1,0,-1,-1,2,-1,-1], # (C,S,E,W,N,SE,SW,NE,NW) [2,-1,3,-1,0,-1,-1,1,-1], # (-1 = anything) [3,-1,-1,2,1,-1,-1,-1,0] # (0,1,2,3 = index of Margolus input) ] def EmulateMargolus(neighborhood,n_states,transitions,input_filename): '''Emulate a Margolus or square4_* neighborhood rule table with a Moore neighborhood rule tree.''' rule_name = os.path.splitext(os.path.split(input_filename)[1])[0] total_states = 1+2*n_states tree = RuleTree(total_states,8) # now work through the transitions for tr in transitions: for iOutput,background_output in enumerate(BackgroundOutputs[neighborhood]): bg_inputs = BackgroundInputs[iOutput] iEntry = iOutput % 4 # (0=top-left, 1=top-right, 2=bottom-left, 3=bottom-right) rule_inputs = [] for i in range(9): if ForegroundInputs[iEntry][i]==-1: rule_inputs.append(encode( range(n_states), bg_inputs[i] ) + [0]) # wildcard else: rule_inputs.append(encode( tr[ForegroundInputs[iEntry][i]], bg_inputs[i] )) tree.add_rule( rule_inputs, encode( tr[iEntry+4], background_output )[0] ) # supply default behaviour: background still changes even if the state doesn't for iState in range(n_states): for iOutput,background_output in enumerate(BackgroundOutputs[neighborhood]): bg_inputs = BackgroundInputs[iOutput] tree.add_rule( [ encode( [iState], bg_inputs[0] ) ] + [ encode( range(n_states), bg_inputs[i] )+[0] for i in range(1,9) ], # wildcard encode( [iState], background_output )[0] ) # output the rule tree golly.show("Compressing rule tree and saving to file...") tree.write(golly.getdir('rules') + rule_name + '.tree') # also save a .colors file golly.show("Generating colors...") # read rule_name+'.colors' file if it exists cfn = os.path.split(input_filename)[0] + '/' + os.path.splitext(os.path.split(input_filename)[1])[0] + ".colors" try: cf = open(cfn,'r') except IOError: # use Golly's default random colours random_colors=[[90,90,90],[0,255,127],[127,0,255],[148,148,148],[128,255,0],[255,0,128],[0,128,255],[1,159,0], [159,0,1],[255,254,96],[0,1,159],[96,255,254],[254,96,255],[126,125,21],[21,126,125],[125,21,126], [255,116,116],[116,255,116],[116,116,255],[228,227,0],[28,255,27],[255,27,28],[0,228,227], [227,0,228],[27,28,255],[59,59,59],[234,195,176],[175,196,255],[171,194,68],[194,68,171], [68,171,194],[72,184,71],[184,71,72],[71,72,184],[169,255,188],[252,179,63],[63,252,179], [179,63,252],[80,9,0],[0,80,9],[9,0,80],[255,175,250],[199,134,213],[115,100,95],[188,163,0], [0,188,163],[163,0,188],[203,73,0],[0,203,73],[73,0,203],[94,189,0],[189,0,94]] colors = dict(zip(range(len(random_colors)),random_colors)) else: # read from the .colors file colors = {} for line in cf: if line[0:5]=='color': entries = map(int,line[5:].replace('=',' ').replace('\n',' ').split()) if len(entries)<4: continue # too few entries, ignore colors.update({entries[0]:[entries[1],entries[2],entries[3]]}) # (TODO: support gradients in .colors) # provide a deep blue background if none provided if not 0 in colors: colors.update({0:[0,0,120]}) c = open(golly.getdir('rules')+rule_name+".colors",'w') for col in colors.items()[:n_states]: c.write('color='+str(col[0]*2+1)+' '+' '.join(map(str,col[1]))+'\n') c.write('color='+str(col[0]*2+2)+' '+' '.join([ str(int(x*0.7)) for x in col[1] ])+'\n') # (darken slightly) c.flush() c.close() # use rule_name.tree and rule_name.colors to create rule_name.rule (no icon info) ConvertTreeToRule(rule_name, total_states, []) return rule_name golly-2.7-src/Scripts/Python/glife/RuleTree.py0000644000175000017500000004276712536111364016337 00000000000000# Only the neighborhoods supported by ruletree_algo are supported: # a) vonNeumann: 4 neighbors: C,S,E,W,N, # b) Moore: 8 neighbors: C,S,E,W,N,SE,SW,NE,NW # # This file contains two ways of building rule trees: # # 1) RuleTree Usage example: # # tree = RuleTree(14,4) # 14 states, 4 neighbors = von Neumann neighborhood # tree.add_rule([[1],[1,2,3],[3],[0,1],[2]],7) # inputs: [C,S,E,W,N], output # tree.write("Test.tree") # # 2) MakeRuleTreeFromTransitionFunction usage example: # # MakeRuleTreeFromTransitionFunction( 2, 4, lambda a:(a[0]+a[1]+a[2])%2, 'Parity.tree' ) # import golly import os from tempfile import mkstemp from shutil import move # ------------------------------------------------------------------------------ class RuleTree: ''' Usage example: tree = RuleTree(14,4) # 14 states, 4 neighbors = von Neumann neighborhood tree.add_rule([[1],[1,2,3],[3],[0,1],[2]],7) # inputs: [C,S,E,W,N], output tree.write("Test.tree") For vonNeumann neighborhood, inputs are: C,S,E,W,N For Moore neighborhood, inputs are: C,S,E,W,N,SE,SW,NE,NW ''' def __init__(self,numStates,numNeighbors): self.numParams = numNeighbors + 1 ; self.world = {} # dictionary mapping node tuples to node index (for speedy access by value) self.seq = [] # same node tuples but stored in a list (for access by index) # each node tuple is ( depth, index0, index1, .. index(numStates-1) ) # where each index is an index into self.seq self.nodeSeq = 0 self.curndd = -1 self.numStates = numStates self.numNeighbors = numNeighbors self.cache = {} self.shrinksize = 100 self._init_tree() def _init_tree(self): self.curndd = -1 for i in range(self.numParams): node = tuple( [i+1] + [self.curndd]*self.numStates ) self.curndd = self._getNode(node) def _getNode(self,node): if node in self.world: return self.world[node] else: iNewNode = self.nodeSeq self.nodeSeq += 1 self.seq.append(node) self.world[node] = iNewNode return iNewNode def _add(self,inputs,output,nddr,at): if at == 0: # this is a leaf node if nddr<0: return output # return the output of the transition else: return nddr # return the node index if nddr in self.cache: return self.cache[nddr] # replace the node entry at each input with the index of the node from a recursive call to the next level down ### AKT: this code causes syntax error in Python 2.3: ### node = tuple( [at] + [ self._add(inputs,output,self.seq[nddr][i+1],at-1) if i in inputs[at-1] \ ### else self.seq[nddr][i+1] for i in range(self.numStates) ] ) temp = [] for i in range(self.numStates): if i in inputs[at-1]: temp.append( self._add(inputs,output,self.seq[nddr][i+1],at-1) ) else: temp.append( self.seq[nddr][i+1] ) node = tuple( [at] + temp ) r = self._getNode(node) self.cache[nddr] = r return r def _recreate(self,oseq,nddr,lev): if lev == 0: return nddr if nddr in self.cache: return self.cache[nddr] # each node entry is the node index retrieved from a recursive call to the next level down node = tuple( [lev] + [ self._recreate(oseq,oseq[nddr][i+1],lev-1) for i in range(self.numStates) ] ) r = self._getNode(node) self.cache[nddr] = r return r def _shrink(self): self.world = {} oseq = self.seq self.seq = [] self.cache = {} self.nodeSeq = 0 ; self.curndd = self._recreate(oseq, self.curndd, self.numParams) self.shrinksize = len(self.seq) * 2 def add_rule(self,inputs,output): self.cache = {} self.curndd = self._add(inputs,output,self.curndd,self.numParams) if self.nodeSeq > self.shrinksize: self._shrink() def _setdefaults(self,nddr,off,at): if at == 0: if nddr<0: return off else: return nddr if nddr in self.cache: return self.cache[nddr] # each node entry is the node index retrieved from a recursive call to the next level down node = tuple( [at] + [ self._setdefaults(self.seq[nddr][i+1],i,at-1) for i in range(self.numStates) ] ) node_index = self._getNode(node) self.cache[nddr] = node_index return node_index def _setDefaults(self): self.cache = {} self.curndd = self._setdefaults(self.curndd, -1, self.numParams) def write(self,filename): self._setDefaults() self._shrink() out = open(filename,'w') out.write("num_states=" + str(self.numStates)+'\n') out.write("num_neighbors=" + str(self.numNeighbors)+'\n') out.write("num_nodes=" + str(len(self.seq))+'\n') for rule in self.seq: out.write(' '.join(map(str,rule))+'\n') out.flush() out.close() # ------------------------------------------------------------------------------ class MakeRuleTreeFromTransitionFunction: ''' Usage example: MakeRuleTreeFromTransitionFunction( 2, 4, lambda a:(a[0]+a[1]+a[2])%2, 'Parity.tree' ) For vonNeumann neighborhood, inputs are: N,W,E,S,C For Moore neighborhood, inputs are NW,NE,SW,SE,N,W,E,S,C ''' def __init__(self,numStates,numNeighbors,f,filename): self.numParams = numNeighbors + 1 ; self.numStates = numStates self.numNeighbors = numNeighbors self.world = {} self.seq = [] self.params = [0]*self.numParams self.nodeSeq = 0 self.f = f self._recur(self.numParams) self._write(filename) def _getNode(self,node): if node in self.world: return self.world[node] else: iNewNode = self.nodeSeq self.nodeSeq += 1 self.seq.append(node) self.world[node] = iNewNode return iNewNode def _recur(self,at): if at == 0: return self.f(self.params) node = tuple([at]) for i in range(self.numStates): self.params[self.numParams-at] = i node += tuple( [self._recur(at-1)] ) return self._getNode(node) def _write(self,filename): out = open(filename,'w') out.write("num_states=" + str(self.numStates)+'\n') out.write("num_neighbors=" + str(self.numNeighbors)+'\n') out.write("num_nodes=" + str(len(self.seq))+'\n') for rule in self.seq: out.write(' '.join(map(str,rule))+'\n') out.flush() out.close() # ------------------------------------------------------------------------------ def ReplaceTreeSection(rulepath, newtree): # replace @TREE section in existing .rule file with new tree data try: rulefile = open(rulepath,'r') except: golly.exit('Failed to open existing .rule file: '+rulepath) # create a temporary file for writing new rule info temphdl, temppath = mkstemp() tempfile = open(temppath,'w') skiplines = False for line in rulefile: if line.startswith('@TREE'): tempfile.write('@TREE\n\n') tempfile.write(newtree) skiplines = True elif skiplines and line.startswith('@'): tempfile.write('\n') skiplines = False if not skiplines: tempfile.write(line) # close files rulefile.close() tempfile.flush() tempfile.close() os.close(temphdl) # remove original .rule file and rename temporary file os.remove(rulepath) move(temppath, rulepath) # ------------------------------------------------------------------------------ def GetColors(icon_pixels, wd, ht): colors = [] multi_colored = False for row in xrange(ht): for col in xrange(wd): R,G,B = icon_pixels[row][col] if R != G or G != B: multi_colored = True # not grayscale found = False index = 0 for count, RGB in colors: if (R,G,B) == RGB: found = True break index += 1 if found: colors[index][0] += 1 else: colors.append([1, (R,G,B)]) return colors, multi_colored # ------------------------------------------------------------------------------ def hex2(i): # convert number from 0..255 into 2 hex digits hexdigit = "0123456789ABCDEF" result = hexdigit[i / 16] result += hexdigit[i % 16] return result # ------------------------------------------------------------------------------ def CreateXPMIcons(colors, icon_pixels, iconsize, yoffset, xoffset, numicons, rulefile): # write out the XPM data for given icon size rulefile.write("\nXPM\n") cindex = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" numcolors = len(colors) charsperpixel = 1 if numcolors > 26: charsperpixel = 2 # AABA..PA, ABBB..PB, ... , APBP..PP rulefile.write("/* width height num_colors chars_per_pixel */\n") rulefile.write("\"" + str(iconsize) + " " + str(iconsize*numicons) + " " + \ str(numcolors) + " " + str(charsperpixel) + "\"\n") rulefile.write("/* colors */\n") n = 0 for count, RGB in colors: R,G,B = RGB if R == 0 and G == 0 and B == 0: # nicer to show . or .. for black pixels rulefile.write("\".") if charsperpixel == 2: rulefile.write(".") rulefile.write(" c #000000\"\n") else: hexcolor = "#" + hex2(R) + hex2(G) + hex2(B) rulefile.write("\"") if charsperpixel == 1: rulefile.write(cindex[n]) else: rulefile.write(cindex[n % 16] + cindex[n / 16]) rulefile.write(" c " + hexcolor + "\"\n") n += 1 for i in xrange(numicons): rulefile.write("/* icon for state " + str(i+1) + " */\n") for row in xrange(iconsize): rulefile.write("\"") for col in xrange(iconsize): R,G,B = icon_pixels[row + yoffset][col + xoffset*i] if R == 0 and G == 0 and B == 0: # nicer to show . or .. for black pixels rulefile.write(".") if charsperpixel == 2: rulefile.write(".") else: n = 0 thisRGB = (R,G,B) for count, RGB in colors: if thisRGB == RGB: break n += 1 if charsperpixel == 1: rulefile.write(cindex[n]) else: rulefile.write(cindex[n % 16] + cindex[n / 16]) rulefile.write("\"\n") # ------------------------------------------------------------------------------ def ConvertTreeToRule(rule_name, total_states, icon_pixels): ''' Convert rule_name.tree to rule_name.rule and delete the .tree file. If rule_name.colors exists then use it to create an @COLORS section and delete the .colors file. If icon_pixels is supplied then add an @ICONS section. Format of icon_pixels (in this example there are 4 icons at each size): --------------------------------------------------------- | | | | | | | | | | | 31x31 | 31x31 | 31x31 | 31x31 | | | | | | | | | | | --------------------------------------------------------- | |.....| |.....| |.....| |.....| | 15x15 |.....| 15x15 |.....| 15x15 |.....| 15x15 |.....| | |.....| |.....| |.....| |.....| --------------------------------------------------------- |7x7|.........|7x7|.........|7x7|.........|7x7|.........| --------------------------------------------------------- The top layer of 31x31 icons is optional -- if not supplied (ie. the height is 22) then there are no gaps between the 15x15 icons. ''' rulepath = golly.getdir('rules')+rule_name+'.rule' treepath = golly.getdir('rules')+rule_name+'.tree' colorspath = golly.getdir('rules')+rule_name+'.colors' # get contents of .tree file try: treefile = open(treepath,'r') treedata = treefile.read() treefile.close() except: golly.exit('Failed to open .tree file: '+treepath) # if the .rule file already exists then only replace the @TREE section # so we don't clobber any other info added by the user if os.path.isfile(rulepath): ReplaceTreeSection(rulepath, treedata) os.remove(treepath) if os.path.isfile(colorspath): os.remove(colorspath) return # create a new .rule file rulefile = open(rulepath,'w') rulefile.write('@RULE '+rule_name+'\n\n') rulefile.write('@TREE\n\n') # append contents of .tree file, then delete that file rulefile.write(treedata) os.remove(treepath) # if .colors file exists then append @COLORS section and delete file if os.path.isfile(colorspath): colorsfile = open(colorspath,'r') rulefile.write('\n@COLORS\n\n') for line in colorsfile: if line.startswith('color') or line.startswith('gradient'): # strip off everything before 1st digit line = line.lstrip('colorgadient= \t') rulefile.write(line) colorsfile.close() os.remove(colorspath) # if icon pixels are supplied then append @ICONS section if len(icon_pixels) > 0: wd = len(icon_pixels[0]) ht = len(icon_pixels) iconsize = 15 # size of icons in top row if ht > 22: iconsize = 31 # 31x31 icons are present numicons = wd / iconsize # get colors used in all icons (we assume each icon size uses the same set of colors) colors, multi_colored = GetColors(icon_pixels, wd, ht) if len(colors) > 256: golly.warn('Icons use more than 256 colors!') rulefile.flush() rulefile.close() return if multi_colored: # create @COLORS section using color info in icon_pixels (not grayscale) rulefile.write('\n@COLORS\n\n') if numicons >= total_states: # extra icon is present so use top right pixel to set the color of state 0 R,G,B = icon_pixels[0][wd-1] rulefile.write('0 ' + str(R) + ' ' + str(G) + ' ' + str(B) + '\n') numicons -= 1 # set colors for each live state to the average of the non-black pixels # in each icon on top row (note we've skipped the extra icon detected above) for i in xrange(numicons): nbcount = 0 totalR = 0 totalG = 0 totalB = 0 for row in xrange(iconsize): for col in xrange(iconsize): R,G,B = icon_pixels[row][col + i*iconsize] if R > 0 or G > 0 or B > 0: nbcount += 1 totalR += R totalG += G totalB += B if nbcount > 0: rulefile.write(str(i+1) + ' ' + str(totalR / nbcount) + ' ' \ + str(totalG / nbcount) + ' ' \ + str(totalB / nbcount) + '\n') else: # avoid div by zero rulefile.write(str(i+1) + ' 0 0 0\n') # create @ICONS section using (r,g,b) triples in icon_pixels[row][col] rulefile.write('\n@ICONS\n') if ht > 22: # top row of icons is 31x31 CreateXPMIcons(colors, icon_pixels, 31, 0, 31, numicons, rulefile) CreateXPMIcons(colors, icon_pixels, 15, 31, 31, numicons, rulefile) CreateXPMIcons(colors, icon_pixels, 7, 46, 31, numicons, rulefile) else: # top row of icons is 15x15 CreateXPMIcons(colors, icon_pixels, 15, 0, 15, numicons, rulefile) CreateXPMIcons(colors, icon_pixels, 7, 15, 15, numicons, rulefile) rulefile.flush() rulefile.close() # ------------------------------------------------------------------------------ def ConvertRuleTableTransitionsToRuleTree(neighborhood,n_states,transitions,input_filename): '''Convert a set of vonNeumann or Moore transitions directly to a rule tree.''' rule_name = os.path.splitext(os.path.split(input_filename)[1])[0] remap = { "vonNeumann":[0,3,2,4,1], # CNESW->CSEWN "Moore":[0,5,3,7,1,4,6,2,8] # C,N,NE,E,SE,S,SW,W,NW -> C,S,E,W,N,SE,SW,NE,NW } numNeighbors = len(remap[neighborhood])-1 tree = RuleTree(n_states,numNeighbors) for i,t in enumerate(transitions): golly.show("Building rule tree... ("+str(100*i/len(transitions))+"%)") tree.add_rule([ t[j] for j in remap[neighborhood] ],t[-1][0]) tree.write(golly.getdir('rules')+rule_name+".tree" ) # use rule_name.tree to create rule_name.rule (no icons) ConvertTreeToRule(rule_name, n_states, []) return rule_name golly-2.7-src/Scripts/Python/density.py0000644000175000017500000000066412536111364015167 00000000000000# Calculates the density of live cells in the current pattern. # Author: Andrew Trevorrow (andrew@trevorrow.com), March 2006. # Updated to use exit command, Nov 2006. from glife import rect import golly as g bbox = rect( g.getrect() ) if bbox.empty: g.exit("The pattern is empty.") d = float( g.getpop() ) / ( float(bbox.wd) * float(bbox.ht) ) if d < 0.000001: g.show("Density = %.1e" % d) else: g.show("Density = %.6f" % d) golly-2.7-src/Scripts/Python/Margolus/0000755000175000017500000000000012536111546015003 500000000000000golly-2.7-src/Scripts/Python/Margolus/import.py0000644000175000017500000000077412536111364016615 00000000000000# Change the selected area from N states to emulated-Margolus states: # s -> 1+2s (if in the top-left of the partition) # s -> 2+2s (if not) from glife import rect import golly as g r = rect( g.getselrect() ) if r.empty: g.exit("There is no selection.") for row in xrange(r.top, r.top + r.height): for col in xrange(r.left, r.left + r.width): if (col%2) and (row%2): g.setcell(col, row, 1+g.getcell(col,row)*2) else: g.setcell(col, row, 2+g.getcell(col,row)*2) golly-2.7-src/Scripts/Python/Margolus/export.py0000644000175000017500000000053212536111364016614 00000000000000# Change the entire pattern from emulated-Margolus states to N-state: from glife import rect import golly as g r = rect( g.getrect() ) if r.empty: g.exit("There is no pattern.") for row in xrange(r.top, r.top + r.height): for col in xrange(r.left, r.left + r.width): s = g.getcell(col,row) g.setcell(col, row, (s+s%2)/2-1) golly-2.7-src/Scripts/Python/Margolus/convert-MCell-string.py0000644000175000017500000000537312536111364021261 00000000000000# We owe a lot to MCell's implementation of the Margolus neighbourhood. Thanks Mirek! # # Tim Hutton import os import golly from glife.ReadRuleTable import * from glife.EmulateMargolus import * # ask the user for the MCell string to convert (comma-separated works too) s = golly.getstring( '''Enter a specification string. This can either be an MCell format Margolus string or just a comma-separated list of the 16 case indices. See: http://psoup.math.wisc.edu/mcell/rullex_marg.html ''', "MS,D0;8;4;3;2;5;9;7;1;6;10;11;12;13;14;15","Enter Margolus specification") # defaults to BBM # pull out the 16 numeric tokens that tell us what each partition becomes becomes = map(int,s.replace('M',' ').replace('S',' ').replace(',',' ').replace('D',' ').replace(';',' ').split()) # write straight into the user's rules folder, so we can call setrule immediately folder = golly.getdir('rules') # construct a rule_name from next case indices rule_name = 'Margolus-' + '-'.join(map(str,becomes)) # ask the user to confirm this name or suggest a more readable one (e.g. "BBM") rule_name = golly.getstring("Enter a name for the rule:",rule_name,"Enter rule name") # todo: detect slashes and tildes, tell user that can't change dir like that # open the rule table file for writing tablepath = folder + rule_name + '.table' f = open(tablepath,'w') # write the initial descriptors and some variables f.write('# Emulation of Margolus neighbourhood for MCell string:\n# %s\n\n'%s) f.write('# (see: http://psoup.math.wisc.edu/mcell/rullex_marg.html )\n') f.write('#\n') f.write('# Rule table produced by convert-MCell-string.py, which can\n') f.write('# convert any MCell Margolus specification into a rule table.\n') f.write('#\n') f.write('n_states:2\nneighborhood:Margolus\nsymmetries:none\n\n') # the 16 cases of the (two-state) Margolus partition are: dot = (0,0,0,0),(1,0,0,0),(0,1,0,0),(1,1,0,0),(0,0,1,0),(1,0,1,0),(0,1,1,0),(1,1,1,0),\ (0,0,0,1),(1,0,0,1),(0,1,0,1),(1,1,0,1),(0,0,1,1),(1,0,1,1),(0,1,1,1),(1,1,1,1) # cell order: 1 2 # 3 4 # (see: http://psoup.math.wisc.edu/mcell/rullex_marg.html ) for i in range(16): if not i==becomes[i]: # (we can skip no-change transitions) f.write(','.join(map(str,dot[i]))+' : '+\ ','.join(map(str,dot[becomes[i]]))+\ ' # '+str(i)+' -> '+str(becomes[i])+'\n') f.flush() f.close() # emulate the rule table with tree data in a .rule file n_states, neighborhood, transitions = ReadRuleTable(tablepath) golly.show("Building rule...") rule_name = EmulateMargolus(neighborhood, n_states, transitions, tablepath) os.remove(tablepath) golly.new(rule_name+'-demo.rle') golly.setalgo('RuleLoader') golly.setrule(rule_name) golly.show('Created '+rule_name+'.rule and selected that rule.') golly-2.7-src/Scripts/Python/pd-glider.py0000644000175000017500000000063112536111364015351 00000000000000# Creates a large set of pentadecathlon + glider collisions. # Based on pd_glider.py from PLife (http://plife.sourceforge.net/). from glife.base import * rule("B3/S23") def collision (i, j): return pentadecathlon + glider[i + 11] (-8 + j, -10, flip) all = pattern () for i in xrange (-7, 8): for j in xrange (-9, 10): all += collision (i, j) (100 * i, 100 * j) all.display ("pd-glider") golly-2.7-src/Scripts/Python/life-integer-gun30.py0000644000175000017500000000315212536111364017007 00000000000000# Based on text_test.py from PLife (http://plife.sourceforge.net/). # Universal* font described by Eric Angelini on SeqFan list # Construction universality* demonstrated by Dean Hickerson # # Integers can be written in this font that stabilize into # (almost*) any Life pattern known to be glider-constructible. # # * Possible caveats involve a very small percentage # (possibly zero percent!) of glider constructions -- in # particular, constructions that require large numbers # of very closely spaced gliders. The existence of objects # whose constructions require non-integer-constructable # closely-packed fleets of gliders is an open question; # no such objects are currently known. from glife.text import * rule() all = make_text (""" 411-31041653546-11-31041653546-1144444444444444444444444444444 31041653546-11-31041653546-11444444444444444-31041653546-11 31041653546-11444444444444444444-31041653546-11-31041653546 111444444444444-15073-114444-5473-11444444444-2474640508-444444 2474640508-444444444444444444444-2474640508-444444-2474640508-4444 2474640508-444444-2474640508-4444444444444444444444-2474640508 444444-2474640508-414-7297575-114-9471155613-414444444444 31041653546-11-2534474376-1-9471155613-414444444444-31041653546-114 7297575-114-9471155613-414444444444-31041653546-114-7297575-118 9471155613-414444444444-31041653546-18-6703-1444-107579-1114444 2474640508-51-947742-414444444441-947742-414444444444-2474640508 51-947742-414444444441-947742-41444-2474640508-51-947742-414 2474640508-414444444444444-2474640508-51-947742-414444444441 947742-414""","EAlvetica") all.display ("Eric Angelini integer glider gun") golly-2.7-src/Scripts/Python/gun-demo.py0000644000175000017500000000252312536111364015217 00000000000000# Glider guns used in this script are 'aligned', which means gliders start in the # origin and go SE. # Based on gun_demo.py from PLife (http://plife.sourceforge.net/). from glife.base import * from glife.gun24 import * from glife.gun30 import * from glife.gun46 import * rule () # Life def mirror_gun (glider_gun): """mirror an 'aligned' glider gun and preserve its timing""" return glider_gun[2] (-1, 0, swap_xy) def compose_lwss_gun (glider_gun, A = -1, B = -1, C = -1): """construct an lwss gun using 3 copies of an 'aligned' glider gun. A, B and C are distances from the glider collision point to NE, NW and SW guns respectively""" if (A < 0): A = 40 if (B < 0): B = A; if (C < 0): C = A; m = min (A, B, C) a = A - m b = B - m c = C - m return \ glider_gun[4 * a] ( A, -A - 3, flip_x) + \ glider_gun[4 * b] (-B + 2, -B + 1) + \ glider_gun[4 * c + 1] (-C + 6, C, flip_y) lwss_eater = eater (4, 2, swap_xy) all = \ compose_lwss_gun (mirror_gun (gun24), 12, 11, 12) (0, -100) + lwss_eater (100, -100) + \ compose_lwss_gun (gun24, 11, 13, 4) + lwss_eater (100, 0) + \ compose_lwss_gun (gun30, 13, 11, 4) (0, 70) + lwss_eater (100, 70) + \ compose_lwss_gun (gun46, 22, 13, 3) (0, 130) + lwss_eater (100, 130) all.display ("gun-demo") golly-2.7-src/Scripts/Python/heisenburp.py0000644000175000017500000005727512536111364015666 00000000000000# Stable pseudo-Heisenburp device. # Show several views of a multi-stage signal-processing circuit, # optionally using Golly 1.2+'s layer-cloning system. # Author: Dave Greene, 27 February 2007. # Latest changes: # - corrected timing of signal-tracking selection highlight # - switched to three spaces per indent # - replaced long instruction message with Help note # - added rule() to be sure to run in the right universe (B3/S23) # - removed "x = ..." lines from pattern strings from glife import getstring, validint from time import sleep import os import golly as g from glife import * from string import * import sys def burp(): test_signal=pattern(""" 40bo$41bo$39b3o17$40bo4bo4bo4bo4bo$41bo4bo4bo4bo4bo$39b3o2b3o2b3o2b3o 2b3o3$40bo4bo4bo4bo4bo$41bo4bo4bo4bo4bo$39b3o2b3o2b3o2b3o2b3o3$40bo4bo 4bo4bo4bo$41bo4bo4bo4bo4bo$39b3o2b3o2b3o2b3o2b3o3$40bo4bo4bo4bo4bo$41b o4bo4bo4bo4bo$39b3o2b3o2b3o2b3o2b3o3$bo38bo4bo4bo4bo4bo18bo$2bo38bo4bo 4bo4bo4bo18bo$3o36b3o2b3o2b3o2b3o2b3o16b3o37$40bo$41bo$39b3o!""") prepare_burp() ticks=0 tickstep=5 last_signal=-99999 viewport_speed=16 sel_speed=0.0 delta_sel=0.0 delay=-1.0 run_flag=False ch="" selx=600.0 sely=365.0 place_signal=3 helpstring="""Use ENTER and SPACE to run or halt the pattern; use + and - to change the step size or delay value; use arrow keys and mouse tools to pan and zoom in any pane; T toggles between a tiled view and a single-pane view; S creates another signal fleet near the detection mechanism; R resets the Heisenburp device to its initial state; Q quits out of the script and restores original settings.""" instr="Press H for help. " g.show(instr + str(tickstep)) g.select([selx,sely,50,50]) # keyboard handling while ch<>"q": if place_signal>0: if ticks-last_signal>1846: test_signal.put(-150,60) last_signal=ticks place_signal-=1 if place_signal>0 and run_flag==True: show_status_text("Next signal placement in " \ + str(1847 - ticks + last_signal) + " ticks. " + instr, delay, tickstep) else: show_status_text(instr,delay,tickstep) event = g.getevent() if event.startswith("key"): evt, ch, mods = event.split() else: ch = "" if ch=="r": prepare_burp() ticks=0 last_signal=-99999 viewport_speed=16 sel_speed=0 run_flag=False selx=600.0 sely=365.0 place_signal=3 g.select([selx,sely,50,50]) elif ch=="h": g.note(helpstring) elif ch=="t": g.setoption("tilelayers",1-g.getoption("tilelayers")) elif ch=="=" or ch=="+": if delay>.01: delay/=2 elif delay==.01: delay=-1 else: if tickstep==1: tickstep=3 elif tickstep<250: tickstep=(tickstep-1)*2+1 elif ch=="-" or ch=="_": if delay==-1: if tickstep==1: delay=.01 else: if tickstep==3: tickstep=1 else: tickstep=(tickstep-1)/2+1 else: if delay<1: delay*=2 elif ch=="space": run_flag=False elif ch=="return": run_flag=not run_flag elif ch=="s": place_signal+=1 else: # just pass any other keyboard/mouse event through to Golly g.doevent(event) # generation and selection speed handling if ch=="space" or run_flag==True: g.run(tickstep) currlayer = g.getlayer() if currlayer != 4: # user has switched layer so temporarily change it back # so we only change location of bottom right layer g.check(False) g.setlayer(4) x, y = getposint() oldticks=ticks ticks+=tickstep delta_view=int(ticks/viewport_speed) - int(oldticks/viewport_speed) if delta_view <> 0: # assumes diagonal motion for now setposint(x + delta_view, y + delta_view) sel = g.getselrect() if len(sel)<>0: x, y, w, h = sel if int(selx)<>x: # user changed selection # prepare to move new selection instead (!?!) # -- use floating-point selx, sely to account for fractional speeds selx=x sely=y else: selx+=sel_speed*tickstep sely+=sel_speed*tickstep g.select([selx, sely, w, h]) else: g.select([selx, sely, 50, 50]) if currlayer != 4: g.setlayer(currlayer) g.check(True) # change viewport speed at appropriate times to follow the action if oldticks<4570 and ticks>=4570: sel_speed=.666667 # one-time correction to catch up with the signal at high sim speeds g.select([600+(ticks-4570)*1.5, 365+(ticks-4570)*1.5, w, h]) if selx>2125: sel_speed=0 g.select([2125, sely+2125-selx, w, h]) if oldticks<4750 and ticks>=4750: viewport_speed=1.5 if oldticks<6125 and ticks>=6125: viewport_speed=16 if oldticks>=11995: viewport_speed=99999.9 # stop automatically after the last signal passes through the device if oldticks - last_signal<8705 and ticks - last_signal>=8705: run_flag=False if run_flag==True and delay>0: sleep(delay) g.update() # ----------------------------------------------------- def prepare_burp(): highway_robber=pattern(""" 143bo$143b3o$146bo$145b2o2$126bo42bo$126b3o38b3o$129bo36bo$128b2o11b2o 23b2o7b2o$141b2o32bo$108bo64bobo$108b3o6b2o54b2o$111bo5b2o$110b2o3$ 111b2o$111b2o3b2o$116b2o35b2o23bo$154bo22bobo$151b3o8b2o14bo$151bo11bo $98bo7bo53b3o$86bo11b3o5b3o51bo$84b3o14bo7bo32b2o$68bo14bo16b2o6b2o32b obo30b2o$68b3o12b2o59bo30bobo$71bo72b2o31bo$70b2o105b2o$159bob2o$159b 2obo$71b2o$71b2o17b2o76b2o$90b2o76b2o5$104b2o$87b2o14bobo$87bo15bo74b 2o$88b3o11b2o74bo$90bo85bobo$84b2o90b2o$84bo$85b3o$87bo2$158b2o$159bo$ 68b2o89bobo$67bobo90b2o$67bo25b2o$66b2o25bo$74b2o15bobo$74b2o15b2o98b 2o6bo$187bobo2bo4b3o$185b3ob2o5bo$184bo11b2o$185b3ob2o$177b2o8bob2o$ 177b2o2$161b2o32b2o3b2o$161b2o32b2o3b2o$153b2o$88b2o2b2ob2o57bo18b2ob 2o$73b2o13bobo2bobo58bobo16b2obo$72bobo16b2o3bo58b2o21bo26bo$72bo19bob 2o76bob5o25bobo$71b2o16bo2bobo77b2o31bo$88bobobobo80b2o$89b2ob2o82bo$ 173b3o$173bo33bo$171bobo31b3o$171b2o31bo$187b2o14bobo$187b2o15bo$83b2o $83b2o$202b2o$202b2o2$175b2o$175b2o$72b2o123b2o$73bo19b2o102bo$73bobo 17bo76b2o26b3o$74b2o15bobo60b2o14b2o28bo$86bo4b2o62bo$85bobo64b3o$54bo 30bobo64bo$54b3o17b2o10bo$57bo15bobo$56b2o15bo116b2o$72b2o116bo$36b2o 49b2o102b3o$29b2o5b2o49bo105bo$29b2o57b3o6bo$90bo4b3o$94bo$31b2o17b2o 29b2o11b2o14b2o$31b2o17bo30b2o27b2o$25b2o21bobo$25b2o21b2o$116b2o$116b 2o36b2o$112b2o41bo$112b2o41bobo$156b2o$56b2o122b2o$56b2o11b2o109b2o$ 69bo47b2o$70b3o44b2o$72bo2$22bo$22b3o55b2o96b2o$25bo53bobo96bo$24b2o 47b2o4bo99b3o$73b2o3b2o101bo$179b2o$76b4o99bo$75bo3bo97bobo$75b2o100b 2o$53b2o33bo22b2o$19b2o32b2o33b3o20bo$20bo70bo20b3o$20bobo67b2o22bo44b o$21b2o136b3o$162bo$115bo45b2o$35b2o28b2o46b3o$35bobo27b2o45bo$37bo41b 2o6b2o23b2o$37b2o40b2o6bo2b2o$83b2o3b2obo$83b2o4bo89b2o$17bob2o68bo89b o$17b2obo67b2obob2o18b2o62bobo$87bo2b2ob2o18bobo61b2o$26b2o60bo26bo$ 26b2o33b2o26b3ob2o20b2o$60bo2bo27bobo66b2o$61bobo29bo66b2o15b2o$62bo 29b2ob2o80bobo$94bobo82bo$94bo84b2o$93b2o3$160b2o$160bo$158bobo$158b2o 2$16bo$16b3o$19bo33bo121b2obo$18b2o33b3o53b2o64bob2o$56bo52b2o$11bo43b obo110b2o$11b3o42bo111b2o$14bo123bo$13b2o121b3o$57b2o19bo56bo$57b2o17b 3o19b2o20bo14b2o$75bo23bo19bobo$75b2o22bobo17bobo$100b2o15bobobobo34b 2o$10b2o19b2o79bo4b2o3b2o10bo24bo$10b2o19b2o47b2o29bobo19bobo23bobo$ 80b2o29bobo19bobo24b2o$4bo95b2o10bo21bo4b2o$4b3o25b2o65bobo20b2o15bobo $2o5bo24bo57b2o7bo21bobo17bo$bo4b2o25b3o54bo7b2o21bo19b2o36bo$bobo31bo 52bobo22b2o5b2o55b3o$2b2o29b2o53b2o23bo62bo$33bo17b2o61b3o28b2o29b2o$ 31bobo4bo11bobo63bo28bo$31b2o3b3o11bo92bobo$35bo13b2o92b2o$35b2o94b2o$ 61b2o68b2o$61b2o$b2o178b2o$b2o178bo$36b2o141bobo$36b2o141b2o3$27b2o37b 2o97b2o$27b2o36bobo51b2o43bobo$65bo54bo43bo$64b2o54bobo40b2o$121b2o2$ 181b2obo$181bob2o2$40bo133b2o$38b3o133b2o$37bo$37b2o$138b2o$138b2o$42b 2o$42b2o78b2o$122b2o$114b2o$52b2o61bo18b2ob2o$52bo62bobo16b2obo$50bobo 63b2o21bo$50b2o81bob5o$13b2o118b2o$12bobo121b2o$12bo124bo$11b2o99bobo 19b3o$112b2obo18bo$23b2o90b3o$23b2o87b2o4bo$112bob5o$114bo$113bo3b2o$ 108bo3bo3bobo$106b3o3b2o3bo$105bo$28b2o75b2o29b2o39b2o$27bobo106b2o38b o2bo$27bo149b2o$26b2o2$131b2o$131b2o$135b2o$14b2o119b2o$14b2o35bo$49b 3o$48bo80b2o$48b2o63b2o14b2o$79bo33bo$68b2o7b3o34b3o$69bo6bo39bo$69bob o4b2o$70b2o$109b2o$109bobo$111bo$111b2o7$103b2o$103bo$104b3o$106bo$13b o19b2o$12bobo10b2o6bo5b2o41b2o$11bo2bo10bo8b3obobo41bo$12b2o9bobo10bob o7b2o28b2obo3b3o$23b2o12b2o7b2o28b2ob4o2bo$82bo$64b2o6b2o2b2ob2o$63bob o6bo4bobo$63bo9b4o2bo$62b2o7bobo2bobo$71b2o4bo!""") connecting_neck=pattern(""" 24bo$22b3o$21bo$21b2o$6b2o$7bo$7bobo$8b2o10bo$19bobo$19bobo$20bo4b2o$ 8b2o15bobo$7bobo17bo$7bo19b2o$6b2o6$17b2o$17b2o7$23b2ob2o$22bobobobo$ 5b2o16bo2bobo$6bo19bob2o$6bobo16b2o3bo$7b2o13bobo2bobo$22b2o2b2ob2o11$ 8b2o15b2o$8b2o15bobo$2o25bo$bo25b2o$bobo$2b2o4$21bo107bo$19b3o106bobo$ 18bo109bobo$18b2o106b3ob2o$24bo100bo$22b3o12bo84bo2b4ob2o$21bo15b3o82b 3o3bob2o$21b2o17bo84bo$39b2o83b2o26b2o$152bo$150bobo$150b2o2$24b2o$5b 2o17b2o76bo$5b2o95b3o6b2o$105bo5b2o41b2obo$104b2o48bob2o$4b2o$5bo141b 2o$2b3o12b2o86b2o40b2o$2bo14bo16b2o6b2o61b2o3b2o$18b3o14bo7bo66b2o$20b o11b3o5b3o$32bo7bo$78bo51b2o3b2o$76b3o13bo38bo3bo$75bo16b3o33b3o5b3o$ 50b2o23b2o18bo32bo9bo$45b2o3b2o42b2o42bobo$45b2o92b2o3$44b2o76b2o$45bo 5b2o69b2o$42b3o6b2o104b2o$42bo41b2o71bo$84b2o69bobo$61b2o92b2o$60bobo 62bo$60bo62b3o$59b2o10b2o49bo$72bo48bobo$69b3o9b2o39bo43b2o$69bo11bo 19b2o56b2o6bo$82bo17bobo56bo6bo$81b2o17bo19b2o35bobo6b2o$99b2o19b2o35b 2o$116b2o$116bo$117b3o24b2o$119bo23bobo$143bo25b2o$142b2o25b2o4$146b2o $145bobo$145bo4b2o$144b2o5bo$148b3o5bo$148bo6bobo$156bo!""") transmitter2c3=pattern(""" 180b2o$180b2o$219bo$219b3o$178b2o42bo$116bo61b2o41b2o$115bobo47b2o99b 2o14bo$116bo49bo74b2o24bo14b3o$166bobo73bo13b2o6b3o18bo$167b2o73bobo 11b2o6bo19b2o12bo$110b2o51b2o78b2o53b3o$110b2o23b2o26b2o136bo$102b2o 31bo164b2o$103bo29bobo$103bobo27b2o$104b2o4b2o$110b2o162b2o$274b2o$ 144b2o30b2o$102b2o40bo31b2o$102bo39bobo$104bob2o34b2o43b2o144b2o$103b 2ob2o78bo2bo143b2o$124b2o60bobo23b2o57b2o$103b2ob2o16b2o61bo20bo3b2o 57bo20b2o$104bobo100bobo26b2o14b2o3b2o13bo20bo$104bobo99bobo21b2o5bo 15bo3bo13b2o17b3o61b2o$105bo100bo23bobob3o13b3o5b3o29bo63b2o5b2o$205b 2o16b2o7bobo15bo9bo100b2o$223b2o7b2o152b2o6bo$169b2o125b2o84bobo2bo4b 3o$169b2o124bobo61b2o19b3ob2o5bo$295bo63b2o18bo11b2o$294b2o69b2o13b3ob 2o$365b2o15bob2o$131b2o151bo$131b2o149b3o12b2o$281bo16bo91b2o3b2o$271b 2o8b2o12b3o92b2o3b2o$272bo22bo$272bobo27b2o30b2o$273b2o28bo17b2o11b2o$ 39bo82bo136bo27b2o11b3o19bo77bo$38bobo79b3o136b3o25b2o11bo18b3o77bobo$ 39bo79bo142bo56bo80bo$108bo10b2o140b2o$37b5o65bobo228b2o$37bo4bo64bobo 177b2o50bo28b2o$40bo2bo61b3ob2o20bo155b2o47b3o29bo$12bo27b2obo60bo24b 3o204bo29bobo$12b3o10b2o10bo5bob2obo49bo6b3ob2o17bo104bo132b2o$15bo9b 2o9bobo4bobob2o49b3o6bob2o17b2o103b3o146b2o$4b2o8b2o20bo2bo2b2obo30b2o 23bo134bo145b2o$5bo31b2o6bo31bo6b2o14b2o133b2o11b2o13b2o$5bobo37b3o29b obo4b2o39b2o121b2o13b2o$6b2o40bo23b2o4b2o44bo2bo87bo73b2o$47b2o23bobo 50b2o88b3o5b2o64bo$70bobob3o141bo4b2o62bobo$66b2o2b2o5bo139b2o68b2o81b 2o$4bob2o58b2o8b2o292b2o$2b3ob2o384b2o$bo216b2o172bo$2b3ob2o80b2o128b 2o3b2o123b2o15b2o26b3o$4bobo30b2o49b2o23b2o108b2o122bobo15b2o28bo$4bob o30b2o74bo233bo$5bo108b3o229b2o$116bo77b2o7b2o$100b2o24b2o66b2o7bobo$ 28b2o66bo3b2o24bo30b2o42bobob3o$28b2o65bobo29b3o2b2o24bo42b2o5bo40b2o 18b2obo112b2o$34b2o58bobo32bo3bo13b2o6b3o49b2o40bobo17bob2o112bo$34bo 19b2o38bo38bobo11b2o6bo95bo134b3o$30bo5bo16bobo37b2o24b2o13b2o115b2o 135bo$29bobo3b2o16bo65b2o164b2obo$30bo21b2o231bob2o$31b3o$33bo79b2o 163b2o$113b2o163b2o$117b2o46b2o$66b2o49b2o46b2o$66b2o$349b2o$350bo$71b 2o39b2o98b2o136bobo$70bobo39b2o99bo54b2o81b2o$70bo91b2o46b3o56bo105b2o $69b2o91bo47bo58bobo103b2o$143b2o3b2o13bo106b2o$82b2o60bo3bo13b2o$82b 2o57b3o5b3o$141bo9bo40b2o$193bo$27bo162b3o180b2o$26bobo161bo182bo$26bo 2bo262b2o80b3o$27b2o263bo83bo$118b2o22bo147bobo81b2o$119bo20b3o99bo18b o28b2ob2o79bo$116b3o20bo102b3o7b2o5b3o31bobo76bobo$116bo22b2o104bo6b2o 4bo34bobo76b2o$5b2o237b2o12b2o10b2o20b2ob2o$5b2o264bo24bo$9b2o104bo 155bobo18b2obo$9b2o104b3o139b2o13b2o18b2obobo56bo$23b2o93bo133b2o3b2o 37b2o56b3o$23b2o92b2o23b2o108b2o103bo$139b2o2bo212b2o28b2o$139bob2o71b 2o56b2o112bo$141bo71bobo55bobo110bobo$141bo71bo49bo7bo108b2o2b2o$116b 2o18b2obob2o69b2o47b3o5b3o108b2o$35b2o78bobo18b2ob2o2bo116bo7bo$35b2o 78bo26bo117b2o6b2o$13b2o99b2o20b2ob3o$14bo122bobo239b2o4b2o$11b3o123bo 241b2o4b2o$11bo90b2o30b2ob2o$102bo31bobo$100bobo5b2o26bo$99bobo6b2o26b 2o140b2o$95b2o3bo177b2o72b2o35bo$95b2o254bobo33b3o$20b2o69b2o194b2o62b o34bo$21bo70bo194bo62b2o34b2o$18b3o71bobo193b3o63b2o$18bo74b2o195bo63b 2o3bo$233bo47b2o75bobo6b2o$233b3o46bo76bobo5b2o$236bo44bo79bo$235bobo 43b2o78b2o$120b2o4b2o108bo30bo$120b2o4b2o139b3o$270bo$237b2o30b2o8b2o 74bo$237b2o40bo61bo13b3o35b2o$121b2o154bobo59b3o16bo34b2o$121b2o2b2o 150b2o59bo18b2o$125bobo93bo41b2o73b2o$127bo92bobo40b2o26b2o$97b2o28b2o 91bobo68bo23bo72b2o$98bo119b3ob2o65bobo23b3o70b2o$95b3o119bo71b2o27bo 73b2o$95bo118bo2b4ob2o39b2o52b2o73b2o$214b3o3bob2o39b2o$217bo130b2o$ 175bo40b2o26b2o102b2o36b2o$113b2o60b3o66bo126b2o13b2o$113bobo46b2o3b2o 9bo14b2o47bobo126bobo$77bo37bo2bo2bo40b2o3b2o8b2o15bo47b2o43b2o84bo$ 77b3o35b7o71bo93b2o72b2o10b2o$80bo112b2o113b2o51bo$38b2o39b2o36b5o33b 2o151b2o41b2o9b3o$38b2o77bo4bo2b2o29bo174b2o19bo11bo$120bo2bo2bo29bobo 87b2obo81bobo17bo$120b2obobo31b2o87bob2o83bo17b2o$117bo5bob2o194b2o10b 2o$105b2o9bobo4bo72b2o41b2o80bo$105b2o9bo2bo2b2o72b2o41b2o70b2o9b3o$ 117b2o193bo11bo$96b2obo211bo$96bob2o211b2o$160b2o$61b2o98bo60b2o3b2o$ 61b2o8b2o85b3o28b2o32bo3bo$72bo85bo31bo15b2o12b3o5b3o29b2o$69b3o117bo 17bo12bo9bo28bobo$47b2o20bo119b2o13b3o23bobo26bo$48bo155bo26b2o25b2o 14b2o$10b2o33b3o70b2o153bo2bo$10b2o33bo29b2o41b2o154b2o$6bo50b2o15bobo $6b3o48bo16bo98b2o$9bo48b3o12b2o98b2o54b2o$8b2o11bo38bo103b2o64bo$20bo bo7b2o131bobo51b2o11bobo$20bobo7b2o44b2o85bo54bo12b2o$21bo55bo84b2o54b obo$74b3o142b2o2b2o$74bo148b2o$81b2o34b2o$82bo34bobo$18b2o59b3o37bo$ 18b2o59bo39b2o97b2o4b2o$4b2o212b2o4b2o$4b2o$2o$2o162bo$107bob2o3b2o48b 3o$105b3ob2o3bo52bo$104bo10b3o48b2o$105b3ob2o6bo101b2o$107b2o2bo106bob o$110b2o106bo$217b2o2$164b2o$164b2o$188b2o$188bobo$190bo$24b2o164b2o$ 23bobo$24bo4$132bo4b2o$131bobo2bobo7b2o$130bo2b4o9bo$26b2obo100bobo4bo 6bobo$26bob2o99b2ob2o2b2o6b2o$127bo$19b2o103bo2b4ob2o$19b2o103b3o3bob 2o$127bo40b2o$126b2o39bobo$52b2o103bo9bo$52b2o49b2o52b3o5b3o54b2o$104b o55bo3bo57b2o$91bo11bo55b2o3b2o$9b2o39b2o39b3o9b2o$10bo39b2o42bo$10bob o24b2o42b2o10b2o$11b2o25bo43bo150b2o$38bobo41bobo91b2o55bo$39b2o42b2o 91b2o53bobo$35b2o69b2o123b2o$35b2o69b2o75bob2o$29b2o152b2obo$29bo188b 2o$27bobo187bobo$27b2o109b2o77bo$132b2o4bobo75b2o$133bo6bo38b2o$48b2o 66b2o12b3o7b2o37bobo$48b2o47b2o18bo12bo50bo$97bo16b3o36b2o26b2o$59b2o 37b3o13bo39bo$58bo2bo38bo50b3o3bob2o59b2o$58bobo23b2o65bo2b4ob2o58bobo $59bo20bo3b2o68bo64bo$79bobo73b3ob2o57b2o$7b2o69bobo76b2o2bo$7b2o17b2o 50bo81b2o84bo$26b2o49b2o165b3o$243bo$41b2o200b2o$41b2o2$219bo$219b3o$ 222bo$221b2o23b2o$243b2o2bo$243bob2o$245bo$245bo$220b2o18b2obob2o$219b obo18b2ob2o2bo$219bo26bo$218b2o20b2ob3o$241bobo$51bo189bo$12b2o35b3o 186b2ob2o$12b2o34bo189bobo$48b2o190bo$81bo158b2o$81b3o$17b2o65bo$17b2o 64b2o$13b2o$13b2o2$57b2o159b2o$19b2o36b2o158bobo$19b2o13b2o181bo$33bob o180b2o$33bo181bo$32b2o10b2o74bo94b3o$45bo72b3o97bo$42b3o9b2o61bo99b2o $42bo11bo20b2o40b2o17bo39bo$55bo20bo59b3o37b3o$54b2o17b3o63bo39bo$73bo 64b2o38b2o12bo$192b3o$159bo35bo19b2o$79b2o78b3o32b2o19b2o$78bobo81bo 76b2o$78bo82b2o11b2o63bobo$77b2o95b2o65bo$241b2o2$80b2o$81bo$78b3o$78b o$85b2o30b2o$86bo17b2o11b2o$83b3o19bo80b2o$83bo18b3o82bo$102bo81b3o$ 184bo2$153b2o$147b2o5bo20b2o13b2o$147bobob3o21bobo11bobo$140b2o7bobo 25bo11bo$140b2o7b2o26b2o9b2o3$191b2o$192bo$189b3o19b2o21b2o$189bo20bob o21b2o$196b2o12bo17b2o$197bo11b2o17b2o$194b3o$194bo$230b2o$223b2o5b2o$ 223b2o5$89b2o$89b2o8$63bo$62bobo$62bobo$61b2ob2o16b2o$82b2o$61b2ob2o$ 62bob2o34b2o$60bo39bobo$60b2o40bo$102b2o2$68b2o$62b2o4b2o$61bobo27b2o$ 61bo29bobo$60b2o31bo$68b2o23b2o$68b2o$86b2o$82bo3b2o$74bo6bobo$73bobo 4bobo$74bo5bo$79b2o!""") head2c3=pattern("8b2o$3bo2bo2bo$3b6o2$3b6o$2bo6bo$2bo2b5o$obobo$2o2bo$4bo$3b2o!") body2c3=pattern("6bo$b6o$o$o2b6o$obo6bo$obo2b5o$b2obo$4bo$4bo$3b2o!") tail2c3=pattern("5b2o$5b2o2$b6o$o5bo$o2b3o$obo$o2bo$b2o!") wire2c3=head2c3(625,388) + tail2c3(2143,1905) for i in range(631,2142,6): # 251 body segments wire2c3+=body2c3(i,i-236) # first one at (631, 395) receiver2c3=pattern(""" 208bo$207bobo$208bo3$213b2o$188b2o23b2o$189bo31b2o$189bobo29bo$190b2o 27bobo$213b2o4b2o$213b2o2$179b2o$180bo40b2o$180bobo39bo$181b2o34b2obo$ 217b2ob2o$199b2o$199b2o16b2ob2o$218bobo$218bobo$219bo8$192b2o$192b2o8$ 55b2o$48b2o5b2o$48b2o$85bo$83b3o$50b2o17b2o11bo$50b2o17bo12b2o$44b2o 21bobo20bo$44b2o21b2o19b3o$87bo$87b2o3$90b2o9b2o26b2o7b2o$90bo11bo25bo bo7b2o$88bobo11bobo21b3obobo$88b2o13b2o20bo5b2o39bo$125b2o45b3o$175bo 14bo$95bo78b2o12b3o$41bo51b3o91bo$41b3o48bo94b2o$44bo47b2o$43b2o$186b 2o$167b2o17b2o$167b2o3$61b2o$61bo$59bobo42b2o$59b2o43b2o11b2o51b2o$ 117bo53bo$84b2o32b3o48bo$42b2o40bo35bo48b2o$42b2o15b2o24b3o85b2o$59bob o25bo12b2o38b2o32bo$61bo38bo39bo30b3o$61b2o38b3o37b3o27bo$103bo39bo3$ 42b2o$42bo$40bobo$40b2o4$57b2obo$57bob2o2$50b2o$50b2o122b2o$173bobo$ 173bo29b2o$172b2o29bobo$205bo$178b2o25b2o$177bobo4b2o$40b2o135bo7bo$ 41bo134b2o4b3o$41bobo138bo$42b2o146b2o$189bobo$189bo$188b2o$61bo$59b3o $58bo$58b2o$206b2o$182bo23bobo$63b2o117b3o23bo$63b2o120bo22b2o$184b2o 14b2o$200b2o$73b2o$73bo$71bobo$71b2o$34b2o$33bobo$33bo$32b2o2$44b2o$ 44b2o$160b2o7b2o30b2o$92b2o66b2o7bobo29bobo$92b2o45bo27bobob3o29bo$ 139b3o25b2o5bo28b2o$142bo30b2o$90b2o49b2o$49b2o39b2o$48bobo26b2o43bo$ 48bo29bo43b3o$47b2o29bobo44bo$79b2o43b2o11b2o$75b2o60b2o$75b2o4$177b2o 21b2o$66b2o108bobo21b2o$66bo109bo17b2o$64bobo21b2o85b2o17b2o$48b2o14b 2o22b2o$48b2o93b2o$52bo46b2o39b2o2bo2b2o47b2o$48b2o2b3o43bo2bo38b2obo 3bo41b2o5b2o$48b2o5bo42bobo23b2o17bobobo10b2o29b2o$54b2o43bo20bo3b2o 14b2obob2o12bo$119bobo12b2o4bo2bo12b3o$118bobo13b2o6b2o12bo$67b2o49bo$ 66bobo48b2o$67bo$81b2o$81b2o4$47b2o$47b2o5$49bo$19b2o28b3o$12b2o5b2o 31bo92bo$12b2o37b2o90b3o11bo$47b2o93bo14b3o$47bo94b2o16bo14bo$14b2o33b o109b2o12b3o$14b2o32b2o69bo52bo$8b2o109b3o50b2o$8b2o112bo$121b2o$171b 2o$152b2o17b2o$45b2o105b2o$45b2o17b2o$64b2o3$65b2o$65bo89b2o$52b2o12b 3o41bo23b2o20bo$35b2o16bo14bo40bobo22bo19bo$35bo14b3o57bo14b2o8b3o16b 2o$28bo7b3o11bo74bo11bo20b2o$26b3o9bo87b3o30bo$25bo102bo27b3o$25b2o 129bo$17b2o93b2o$17b2o92bobo$111bo$110b2o62b2o$126b2obo44bobo$126bob2o 46bo$176b2o$34b2o83b2o$34bo84b2o$32bobo$32b2o3$166b2o$166b2o2$157b2obo $157bob2o2$36b2o$36bobo$38bo91b2o44b2o$38b2o90bo44bobo$28b2o98bobo44bo $28b2o98b2o44b2o$9bob2o$9b2obo2$18b2o135b2o$18b2o136bo$156bobo$157b2o 15b2o$114b2o58b2o$114bo2b2o$115b2obo$116bo40b2o$28b2o86bobo4b2o31bobo$ 28bo88b2o5bo31bo$26bobo94bo31b2o$26b2o68b2o25b2o$70bo25bo$58bo11b3o21b obo$56b3o14bo20b2o$40bo14bo16b2o$40b3o12b2o70b2o44b2o$43bo58b2o24bo44b o$4b2o36b2o59bo13b2o6b3o46b3o$5bo97bobo11b2o6bo50bo$5bobo96b2o$3b2ob2o 35b2o$2bobo38b2o17b2o$2bobo57b2o$b2ob2o20b2o$bo24bo$2bob2o18bobo108b2o $obob2o18b2o109b2o$2o$59b2o32b2o$59bo20b2o11b2o$24b2o35bo19bo67b2o21b 2o$24bobo33b2o16b3o67bobo21b2o$26bo29b2o20bo53b2o14bo17b2o$26b3o27bo 75bo14b2o17b2o$29bo27b3o37b2o14b2o3b2o13bo$28b2o29bo38bo15bo3bo13b2o$ 95b3o13b3o5b3o46b2o$95bo15bo9bo39b2o5b2o$161b2o4$18b2o$18b2o2$9b2o$10b o$7b3o45b2o$7bo47b2o$15b2o32b2o$15bo33b2o$16bo$15b2o$51b2o$44b2o5b2o$ 44b2o!""") inserter2c3=pattern(""" 51bo$49b3o$23b2o23bo$24bo23b2o$24bobo$25b2o2b2o37bo$29b2o35b3o15bo9bo$ 65bo18b3o5b3o$52b2o11b2o20bo3bo$52b2o32b2o3b2o8$23b2o52b2o$22bobo16b2o 34b2o$22bo18bobo45b2o$21b2o20bo44bo2bo$37b2o4b2o44b2o4b2o$37bo2bo54bob o$39b2o56bo$30b2o65b2o$30b2o20b2o33b2o$53bo34bo$50b3o32b3o$50bo34bo2$ 19bo$19b3o$22bo$21b2o2$85b2o$85bo$86b3o$88bo2$40b2o$40bo$38bobo$38b2o 12$20b2o15b2o$19bobo15b2o$19bo$18b2o6$25bo$25b3o$28bo$27b2o28b2o$57bo$ 55bobo$51b2o2b2o$51b2o4$50b2o4b2o$50b2o4b2o5$23b2o35bo$22bobo33b3o$22b o34bo$21b2o34b2o$25b2o$25b2o3bo$29bobo6b2o$30bobo5b2o$32bo$32b2o$24b2o $25bo$25bobo$26b2o2b2o$30b2o32b2o$64b2o4$59b2o$59b2o$63b2o$63b2o3$24b 2o31b2o$23bobo16b2o13b2o$23bo18bobo$22b2o20bo$38b2o4b2o$38bo2bo$40b2o$ 31b2o$31b2o7$21b2o$22bo$22bobo$23b2o$39bo$37b3o$36bo$36b2o3$10b2o$10b 2o7$43b2o$43b2o4$38b2o$38b2o$2o40b2o$2o40b2o3$36b2o$21b2o13b2o$21bobo$ 23bo$23b2o!""") all=highway_robber(86,0) + connecting_neck(195,262) + transmitter2c3(347,219) \ + wire2c3 + receiver2c3(2103,1763) + inserter2c3(2024,2042) while g.numlayers()>1: g.dellayer() all.display("Stable Pseudo-Heisenburp Device") g.setmag(0) setposint(120,200) g.setname("Highway Robber") g.clone() g.setname("2c/3 Transmitter") setposint(500,400) g.clone() g.setname("2c/3 Receiver") setposint(2175,2000) g.clone() g.setname("Stable Pseudo-Heisenburp Device") g.clone() g.setname("Glider Fleet") setposint(330,290) # since the tiles change size depending on how many layers have been created, # have to create all five layers before checking visibility of components -- # now go back and check that the critical areas are all visible: g.setlayer(0) while not g.visrect([100,100,150,175]): g.setmag(g.getmag()-1) g.setlayer(1) while not g.visrect([350,225,400,350]): g.setmag(g.getmag()-1) g.setlayer(2) while not g.visrect([2100,1750,225,300]): g.setmag(g.getmag()-1) g.setlayer(3) g.fit() g.setlayer(4) while not g.visrect([0,200,300,400]): g.setmag(g.getmag()-1) g.update() # ----------------------------------------------------- def show_status_text(s, d, t): if d==-1: if t==1: g.show(s + "Speed is " + str(t) + " tick per step.") else: g.show(s + "Speed is " + str(t) + " ticks per step.") else: g.show(s + "Delay between ticks is " + str(d) + " seconds.") # ----------------------------------------------------- # if there are multiple layers, get permission to remove them if g.numlayers() > 1: answer = g.getstring("All existing layers will be removed. OK?") if lower(answer[:1]) == "n": g.exit() oldswitch = g.setoption("switchlayers", True) # allow user to switch layers oldtile = g.setoption("tilelayers", True) rule() try: burp() finally: # remove the cloned layers added by the script while g.numlayers() > 1: g.dellayer() g.setname("Stable Pseudo-Heisenburp Device") g.setoption("tilelayers", oldtile) g.setoption("switchlayers", oldswitch) g.show("") golly-2.7-src/Scripts/Python/shift.py0000644000175000017500000000476712536111364014635 00000000000000# Shift current selection by given x y amounts using optional mode. # Author: Andrew Trevorrow (andrew@trevorrow.com), June 2006. # Updated to use exit command, Nov 2006. # Updated to check for bounded grid, Oct 2010. from glife import validint, inside from string import lower import golly as g selrect = g.getselrect() if len(selrect) == 0: g.exit("There is no selection.") # use same file name as in shift.pl INIFileName = g.getdir("data") + "shift.ini" oldparams = "0 0 or" try: f = open(INIFileName, 'r') oldparams = f.readline() f.close() except: # should only happen 1st time (INIFileName doesn't exist) pass answer = g.getstring("Enter x y shift amounts and an optional mode\n" + "(valid modes are copy/or/xor, default is or):", oldparams, "Shift selection") xym = answer.split() # extract x and y amounts if len(xym) == 0: g.exit() if len(xym) == 1: g.exit("Supply x and y amounts separated by a space.") if not validint(xym[0]): g.exit("Bad x value: " + xym[0]) if not validint(xym[1]): g.exit("Bad y value: " + xym[1]) x = int(xym[0]) y = int(xym[1]) # extract optional mode if len(xym) > 2: mode = lower(xym[2]) if mode=="c": mode="copy" if mode=="o": mode="or" if mode=="x": mode="xor" if not (mode == "copy" or mode == "or" or mode == "xor"): g.exit("Unknown mode: " + xym[2] + " (must be copy/or/xor)") else: mode = "or" # given parameters are valid so save them for next run try: f = open(INIFileName, 'w') f.write(answer) f.close() except: g.warn("Unable to save given parameters in file:\n" + INIFileName) # abort shift if the new selection would be outside a bounded grid if g.getwidth() > 0: gridl = -int(g.getwidth()/2) gridr = gridl + g.getwidth() - 1 newl = selrect[0] + x newr = newl + selrect[2] - 1 if newl < gridl or newr > gridr: g.exit("New selection would be outside grid.") if g.getheight() > 0: gridt = -int(g.getheight()/2) gridb = gridt + g.getheight() - 1 newt = selrect[1] + y newb = newt + selrect[3] - 1 if newt < gridt or newb > gridb: g.exit("New selection would be outside grid.") # do the shift by cutting the current selection and pasting it into # the new position without changing the current clipboard pattern selcells = g.getcells(selrect) g.clear(inside) selrect[0] += x selrect[1] += y g.select(selrect) if mode == "copy": g.clear(inside) g.putcells(selcells, x, y, 1, 0, 0, 1, mode) if not g.visrect(selrect): g.fitsel() golly-2.7-src/Scripts/Python/move-object.py0000644000175000017500000002454312536111364015724 00000000000000# Allow user to move a connected group of live cells. # Author: Andrew Trevorrow (andrew@trevorrow.com), Jan 2011. import golly as g from glife import rect, getminbox ncells = [] # list of neighboring live cells # set edges of bounded grid for later use if g.getwidth() > 0: gridl = -int(g.getwidth()/2) gridr = gridl + g.getwidth() - 1 if g.getheight() > 0: gridt = -int(g.getheight()/2) gridb = gridt + g.getheight() - 1 helpmsg = " (hit 'h' for help)" # -------------------------------------------------------------------- def showhelp1(): g.note( """Hit the escape key to abort the script. Note that alt-clicking on an object allows you to COPY it to another location (the original object is not deleted).""") # -------------------------------------------------------------------- def showhelp2(): g.note( """While moving the object the following keys can be used: x -- flip object left-right y -- flip object top-bottom > -- rotate object clockwise < -- rotate object anticlockwise h -- show this help escape -- abort and restore the object""") # ------------------------------------------------------------------------------ def getstate(x, y): # first check if x,y is outside bounded grid if g.getwidth() > 0 and (x < gridl or x > gridr): return 0 if g.getheight() > 0 and (y < gridt or y > gridb): return 0 return g.getcell(x, y) # ------------------------------------------------------------------------------ def findlivecell(x, y): if g.getcell(x, y) > 0: return [x, y] # spiral outwards from x,y looking for a nearby live cell; # the smaller the scale the smaller the area searched maxd = 10 mag = g.getmag() if mag > 0: # mag can be 1..5 (ie. scales 1:2 to 1:32) maxd = 2 * (6 - mag) # 10, 8, 6, 4, 2 d = 1 while d <= maxd: x -= 1 y -= 1 for i in xrange(2*d): x += 1 # move east if getstate(x, y) > 0: return [x, y] for i in xrange(2*d): y += 1 # move south if getstate(x, y) > 0: return [x, y] for i in xrange(2*d): x -= 1 # move west if getstate(x, y) > 0: return [x, y] for i in xrange(2*d): y -= 1 # move north if getstate(x, y) > 0: return [x, y] d += 1 return [] # failed to find a live cell # ------------------------------------------------------------------------------ def checkneighbor(x, y): # first check if x,y is outside bounded grid if g.getwidth() > 0 and (x < gridl or x > gridr): return if g.getheight() > 0 and (y < gridt or y > gridb): return if g.getcell(x, y) == 0: return # no need for next test because we kill cell after adding it to ncells # if (x, y) in ncells: return False ncells.append( (x, y, g.getcell(x,y)) ) g.setcell(x, y, 0) # ------------------------------------------------------------------------------ def getobject(x, y): object = [] ncells.append( (x, y, g.getcell(x,y)) ) g.setcell(x, y, 0) while len(ncells) > 0: # remove cell from end of ncells and append to object x, y, s = ncells.pop() object.append(x) object.append(y) object.append(s) # add any live neighbors to ncells checkneighbor(x , y+1) checkneighbor(x , y-1) checkneighbor(x+1, y ) checkneighbor(x-1, y ) checkneighbor(x+1, y+1) checkneighbor(x+1, y-1) checkneighbor(x-1, y+1) checkneighbor(x-1, y-1) # append padding int if necessary if len(object) > 0 and (len(object) & 1) == 0: object.append(0) g.putcells(object) return object # ------------------------------------------------------------------------------ def underneath(object): # return list of live cells underneath given object (a multi-state list) cells = [] objlen = len(object) if objlen % 3 == 1: objlen -= 1 # ignore padding int i = 0 while i < objlen: x = object[i] y = object[i+1] s = g.getcell(x, y) if s > 0: cells.append(x) cells.append(y) cells.append(s) i += 3 # append padding int if necessary if len(cells) > 0 and (len(cells) & 1) == 0: cells.append(0) return cells # ------------------------------------------------------------------------------ def rectingrid(r): # return True if all of given rectangle is inside grid if g.getwidth() > 0 and (r[0] < gridl or r[0] + r[2] - 1 > gridr): return False if g.getheight() > 0 and (r[1] < gridt or r[1] + r[3] - 1 > gridb): return False return True # ------------------------------------------------------------------------------ def lookforkeys(event): global oldcells, object # look for keys used to flip/rotate object if event == "key x none" or event == "key y none": # flip floating object left-right or top-bottom g.putcells(object, 0, 0, 1, 0, 0, 1, "xor") # erase object if len(oldcells) > 0: g.putcells(oldcells) obox = getminbox(object) if event == "key x none": # translate object so that bounding box doesn't change xshift = 2 * (obox.left + int(obox.wd/2)) if obox.wd % 2 == 0: xshift -= 1 object = g.transform(object, xshift, 0, -1, 0, 0, 1) else: # translate object so that bounding box doesn't change yshift = 2 * (obox.top + int(obox.ht/2)) if obox.ht % 2 == 0: yshift -= 1 object = g.transform(object, 0, yshift, 1, 0, 0, -1) oldcells = underneath(object) g.putcells(object) g.update() return if event == "key > none" or event == "key < none": # rotate floating object clockwise or anticlockwise # about the center of the object's bounding box obox = getminbox(object) midx = obox.left + int(obox.wd/2) midy = obox.top + int(obox.ht/2) newleft = midx + obox.top - midy newtop = midy + obox.left - midx rotrect = [ newleft, newtop, obox.ht, obox.wd ] if not rectingrid(rotrect): g.warn("Rotation is not allowed if object would be outside grid.") return g.putcells(object, 0, 0, 1, 0, 0, 1, "xor") # erase object if len(oldcells) > 0: g.putcells(oldcells) if event == "key > none": # rotate clockwise object = g.transform(object, 0, 0, 0, -1, 1, 0) else: # rotate anticlockwise object = g.transform(object, 0, 0, 0, 1, -1, 0) # shift rotated object to same position as rotrect obox = getminbox(object) object = g.transform(object, newleft - obox.left, newtop - obox.top) oldcells = underneath(object) g.putcells(object) g.update() return if event == "key h none": showhelp2() return g.doevent(event) # ------------------------------------------------------------------------------ def moveobject(): global oldcells, object, object1 # wait for 1st click in live cell while True: event = g.getevent() if event.startswith("click"): # event is a string like "click 10 20 left none" evt, xstr, ystr, butt, mods = event.split() result = findlivecell(int(xstr), int(ystr)) if len(result) > 0: prevx = int(xstr) prevy = int(ystr) oldmouse = xstr + ' ' + ystr g.show("Extracting object...") x, y = result object = getobject(x, y) object1 = list(object) # save in case user aborts script if mods == "alt": # don't delete object oldcells = list(object) break else: g.warn("Click on or near a live cell belonging to the desired object.") elif event == "key h none": showhelp1() else: g.doevent(event) # wait for 2nd click while moving object g.show("Move mouse and click again..." + helpmsg) gotclick = False while not gotclick: event = g.getevent() if event.startswith("click"): evt, x, y, butt, mods = event.split() mousepos = x+' '+y gotclick = True else: if len(event) > 0: lookforkeys(event) mousepos = g.getxy() if len(mousepos) > 0 and mousepos != oldmouse: # mouse has moved, so move object g.putcells(object, 0, 0, 1, 0, 0, 1, "xor") # erase object if len(oldcells) > 0: g.putcells(oldcells) xstr, ystr = mousepos.split() x = int(xstr) y = int(ystr) if g.getwidth() > 0: # ensure object doesn't move beyond left/right edge of grid obox = getminbox( g.transform(object, x - prevx, y - prevy) ) if obox.left < gridl: x += gridl - obox.left elif obox.right > gridr: x -= obox.right - gridr if g.getheight() > 0: # ensure object doesn't move beyond top/bottom edge of grid obox = getminbox( g.transform(object, x - prevx, y - prevy) ) if obox.top < gridt: y += gridt - obox.top elif obox.bottom > gridb: y -= obox.bottom - gridb object = g.transform(object, x - prevx, y - prevy) oldcells = underneath(object) g.putcells(object) prevx = x prevy = y oldmouse = mousepos g.update() # ------------------------------------------------------------------------------ if len(g.getrect()) == 0: g.exit("There are no objects.") g.show("Click on or near live cell in object, move mouse and click again..." + helpmsg) oldcursor = g.getcursor() g.setcursor("Move") oldcells = [] # cells under moved object object = [] # cells in moving object object1 = [] # cells in initial object try: aborted = True moveobject() aborted = False finally: g.setcursor(oldcursor) if aborted: # erase object if it moved if len(object) > 0: g.putcells(object, 0, 0, 1, 0, 0, 1, "xor") if len(oldcells) > 0: g.putcells(oldcells) if len(object1) > 0: g.putcells(object1) else: g.show(" ") golly-2.7-src/gui-ios/0000755000175000017500000000000012536111545011655 500000000000000golly-2.7-src/gui-ios/Golly.xcodeproj/0000755000175000017500000000000012536111546014740 500000000000000golly-2.7-src/gui-ios/Golly.xcodeproj/project.pbxproj0000644000175000017500000016013012536111364017733 00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 0D02E13E1568A14800581DCC /* PatternView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D02E13D1568A14800581DCC /* PatternView.m */; }; 0D068EB715D93F4300A4EAB3 /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D068EB415D93F4300A4EAB3 /* Icon@2x.png */; }; 0D068EB815D93F4300A4EAB3 /* iTunesArtwork in Resources */ = {isa = PBXBuildFile; fileRef = 0D068EB515D93F4300A4EAB3 /* iTunesArtwork */; }; 0D068EB915D93F4300A4EAB3 /* iTunesArtwork@2x in Resources */ = {isa = PBXBuildFile; fileRef = 0D068EB615D93F4300A4EAB3 /* iTunesArtwork@2x */; }; 0D068EC115D9DD3A00A4EAB3 /* Default-Portrait~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D068EBF15D9DD3A00A4EAB3 /* Default-Portrait~ipad.png */; }; 0D068EC215D9DD3A00A4EAB3 /* Default-Landscape~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D068EC015D9DD3A00A4EAB3 /* Default-Landscape~ipad.png */; }; 0D078728156881080051973C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D078727156881080051973C /* UIKit.framework */; }; 0D07872A156881080051973C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D078729156881080051973C /* Foundation.framework */; }; 0D07872C156881080051973C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D07872B156881080051973C /* CoreGraphics.framework */; }; 0D078732156881080051973C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0D078730156881080051973C /* InfoPlist.strings */; }; 0D078734156881080051973C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D078733156881080051973C /* main.m */; }; 0D078738156881080051973C /* GollyAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D078737156881080051973C /* GollyAppDelegate.m */; }; 0D07873B156881080051973C /* PatternViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D07873A156881080051973C /* PatternViewController.m */; }; 0D07873D156881080051973C /* pattern.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D07873C156881080051973C /* pattern.png */; }; 0D07873F156881080051973C /* pattern@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D07873E156881080051973C /* pattern@2x.png */; }; 0D078742156881080051973C /* HelpViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D078741156881080051973C /* HelpViewController.m */; }; 0D105F0F159EABDF006350CA /* InfoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D105F0D159EABDF006350CA /* InfoViewController.m */; }; 0D105F10159EABDF006350CA /* InfoViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D105F0E159EABDF006350CA /* InfoViewController.xib */; }; 0D10CE96156A3CF2001DC67F /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D10CE95156A3CF2001DC67F /* Icon.png */; }; 0D1E9E6D17420EE2002C1270 /* triangle-right.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D1E9E6B17420EE2002C1270 /* triangle-right.png */; }; 0D1E9E6E17420EE2002C1270 /* triangle-down.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D1E9E6C17420EE2002C1270 /* triangle-down.png */; }; 0D2D9AAF156A00F3005B8D19 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D2D9AAE156A00F3005B8D19 /* libz.dylib */; }; 0D41CD35157C225F0032B05A /* StateView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D41CD34157C225F0032B05A /* StateView.m */; }; 0D602F38157320D200F51C02 /* beep.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 0D602F37157320D200F51C02 /* beep.aiff */; }; 0D602F3A1573210000F51C02 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D602F391573210000F51C02 /* AudioToolbox.framework */; }; 0D62F87115B8343B002E3EF8 /* StatePickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D62F87015B8343A002E3EF8 /* StatePickerView.m */; }; 0D62F87615B8355B002E3EF8 /* StatePickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D62F87415B8355B002E3EF8 /* StatePickerController.m */; }; 0D62F87715B8355B002E3EF8 /* StatePickerController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D62F87515B8355B002E3EF8 /* StatePickerController.xib */; }; 0D62FCF3159BCDCC005506CA /* SaveViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D62FCF1159BCDCC005506CA /* SaveViewController.m */; }; 0D62FCF4159BCDCC005506CA /* SaveViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D62FCF2159BCDCC005506CA /* SaveViewController.xib */; }; 0D64693E1599D04A00433025 /* OpenViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D64693C1599D04A00433025 /* OpenViewController.m */; }; 0D64693F1599D04A00433025 /* OpenViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D64693D1599D04A00433025 /* OpenViewController.xib */; }; 0D71520A181A0C9D00840795 /* Help in Resources */ = {isa = PBXBuildFile; fileRef = 0D715209181A0C9D00840795 /* Help */; }; 0D8A223F1798EA17006044E7 /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 0D8A22371798EA17006044E7 /* ioapi.c */; }; 0D8A22411798EA17006044E7 /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 0D8A223B1798EA17006044E7 /* unzip.c */; }; 0D8A22421798EA17006044E7 /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 0D8A223D1798EA17006044E7 /* zip.c */; }; 0D8F770715D097CD00EF43AF /* HelpViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D8F770615D097CD00EF43AF /* HelpViewController.xib */; }; 0D8F770915D097DA00EF43AF /* PatternViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D8F770815D097DA00EF43AF /* PatternViewController.xib */; }; 0D96C6411575C652006C8EBC /* settings.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D96C63F1575C651006C8EBC /* settings.png */; }; 0D96C6421575C652006C8EBC /* settings@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D96C6401575C651006C8EBC /* settings@2x.png */; }; 0D96C6461575C824006C8EBC /* RuleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D96C6441575C824006C8EBC /* RuleViewController.m */; }; 0D96C6471575C824006C8EBC /* RuleViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D96C6451575C824006C8EBC /* RuleViewController.xib */; }; 0D96C64B1575CBF8006C8EBC /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D96C6491575CBF8006C8EBC /* SettingsViewController.m */; }; 0D96C64C1575CBF8006C8EBC /* SettingsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D96C64A1575CBF8006C8EBC /* SettingsViewController.xib */; }; 0D9AA82815D099D8003BEBD5 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D9AA82715D099D8003BEBD5 /* QuartzCore.framework */; }; 0D9AA82B15D099F2003BEBD5 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D9AA82A15D099F2003BEBD5 /* OpenGLES.framework */; }; 0D9D15B915B67E340081C8AB /* help.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D9D15B715B67E340081C8AB /* help.png */; }; 0D9D15BA15B67E340081C8AB /* help@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0D9D15B815B67E340081C8AB /* help@2x.png */; }; 0D9D4DC4156E1F97005DD91D /* StatusView.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D9D4DC3156E1F97005DD91D /* StatusView.m */; }; 0DA5B31D15F03332005EBBE8 /* Patterns in Resources */ = {isa = PBXBuildFile; fileRef = 0DA5B31C15F03332005EBBE8 /* Patterns */; }; 0DA5B31F15F0336C005EBBE8 /* Rules in Resources */ = {isa = PBXBuildFile; fileRef = 0DA5B31E15F0336C005EBBE8 /* Rules */; }; 0DA5B34715F03654005EBBE8 /* bigint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B32315F03654005EBBE8 /* bigint.cpp */; }; 0DA5B34815F03654005EBBE8 /* generationsalgo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B32515F03654005EBBE8 /* generationsalgo.cpp */; }; 0DA5B34915F03654005EBBE8 /* ghashbase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B32715F03654005EBBE8 /* ghashbase.cpp */; }; 0DA5B34A15F03654005EBBE8 /* ghashdraw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B32915F03654005EBBE8 /* ghashdraw.cpp */; }; 0DA5B34B15F03654005EBBE8 /* hlifealgo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B32A15F03654005EBBE8 /* hlifealgo.cpp */; }; 0DA5B34C15F03654005EBBE8 /* hlifedraw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B32C15F03654005EBBE8 /* hlifedraw.cpp */; }; 0DA5B34D15F03654005EBBE8 /* jvnalgo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B32D15F03654005EBBE8 /* jvnalgo.cpp */; }; 0DA5B34E15F03654005EBBE8 /* lifealgo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B32F15F03654005EBBE8 /* lifealgo.cpp */; }; 0DA5B34F15F03654005EBBE8 /* lifepoll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B33115F03654005EBBE8 /* lifepoll.cpp */; }; 0DA5B35015F03654005EBBE8 /* liferender.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B33315F03654005EBBE8 /* liferender.cpp */; }; 0DA5B35115F03654005EBBE8 /* liferules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B33515F03654005EBBE8 /* liferules.cpp */; }; 0DA5B35215F03654005EBBE8 /* qlifealgo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B33815F03654005EBBE8 /* qlifealgo.cpp */; }; 0DA5B35315F03654005EBBE8 /* qlifedraw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B33A15F03654005EBBE8 /* qlifedraw.cpp */; }; 0DA5B35415F03654005EBBE8 /* readpattern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B33B15F03654005EBBE8 /* readpattern.cpp */; settings = {COMPILER_FLAGS = "-DZLIB"; }; }; 0DA5B35515F03654005EBBE8 /* ruletable_algo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B33D15F03654005EBBE8 /* ruletable_algo.cpp */; }; 0DA5B35615F03654005EBBE8 /* ruletreealgo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B33F15F03654005EBBE8 /* ruletreealgo.cpp */; }; 0DA5B35715F03654005EBBE8 /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B34115F03654005EBBE8 /* util.cpp */; }; 0DA5B35815F03654005EBBE8 /* viewport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B34315F03654005EBBE8 /* viewport.cpp */; }; 0DA5B35915F03654005EBBE8 /* writepattern.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DA5B34515F03654005EBBE8 /* writepattern.cpp */; settings = {COMPILER_FLAGS = "-DZLIB"; }; }; 0DD0EF97178017020061E9A1 /* algos.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF81178017020061E9A1 /* algos.cpp */; }; 0DD0EF98178017020061E9A1 /* control.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF83178017020061E9A1 /* control.cpp */; }; 0DD0EF99178017020061E9A1 /* file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF85178017020061E9A1 /* file.cpp */; }; 0DD0EF9A178017020061E9A1 /* layer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF87178017020061E9A1 /* layer.cpp */; }; 0DD0EF9B178017020061E9A1 /* prefs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF89178017020061E9A1 /* prefs.cpp */; }; 0DD0EF9C178017020061E9A1 /* render.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF8B178017020061E9A1 /* render.cpp */; }; 0DD0EF9D178017020061E9A1 /* select.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF8D178017020061E9A1 /* select.cpp */; }; 0DD0EF9E178017020061E9A1 /* status.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF8F178017020061E9A1 /* status.cpp */; }; 0DD0EF9F178017020061E9A1 /* undo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF91178017020061E9A1 /* undo.cpp */; }; 0DD0EFA0178017020061E9A1 /* utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF93178017020061E9A1 /* utils.cpp */; }; 0DD0EFA1178017020061E9A1 /* view.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD0EF95178017020061E9A1 /* view.cpp */; }; 0DD5D56715A3083700CF2627 /* open.png in Resources */ = {isa = PBXBuildFile; fileRef = 0DD5D56515A3083700CF2627 /* open.png */; }; 0DD5D56815A3083700CF2627 /* open@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0DD5D56615A3083700CF2627 /* open@2x.png */; }; 0DD820DA1632A321008DF0FD /* ruleloaderalgo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0DD820D91632A321008DF0FD /* ruleloaderalgo.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 0D02E13C1568A14800581DCC /* PatternView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PatternView.h; sourceTree = ""; }; 0D02E13D1568A14800581DCC /* PatternView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PatternView.m; sourceTree = ""; }; 0D068EB415D93F4300A4EAB3 /* Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Icon@2x.png"; sourceTree = ""; }; 0D068EB515D93F4300A4EAB3 /* iTunesArtwork */ = {isa = PBXFileReference; lastKnownFileType = file; path = iTunesArtwork; sourceTree = ""; }; 0D068EB615D93F4300A4EAB3 /* iTunesArtwork@2x */ = {isa = PBXFileReference; lastKnownFileType = file; path = "iTunesArtwork@2x"; sourceTree = ""; }; 0D068EBF15D9DD3A00A4EAB3 /* Default-Portrait~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Portrait~ipad.png"; sourceTree = ""; }; 0D068EC015D9DD3A00A4EAB3 /* Default-Landscape~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-Landscape~ipad.png"; sourceTree = ""; }; 0D078723156881080051973C /* Golly.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Golly.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0D078727156881080051973C /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 0D078729156881080051973C /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 0D07872B156881080051973C /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 0D07872F156881080051973C /* Golly-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Golly-Info.plist"; sourceTree = ""; }; 0D078731156881080051973C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 0D078733156881080051973C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 0D078735156881080051973C /* Golly-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Golly-Prefix.pch"; sourceTree = ""; }; 0D078736156881080051973C /* GollyAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GollyAppDelegate.h; sourceTree = ""; }; 0D078737156881080051973C /* GollyAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GollyAppDelegate.m; sourceTree = ""; }; 0D078739156881080051973C /* PatternViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PatternViewController.h; sourceTree = ""; }; 0D07873A156881080051973C /* PatternViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PatternViewController.m; sourceTree = ""; }; 0D07873C156881080051973C /* pattern.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = pattern.png; sourceTree = ""; }; 0D07873E156881080051973C /* pattern@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pattern@2x.png"; sourceTree = ""; }; 0D078740156881080051973C /* HelpViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HelpViewController.h; sourceTree = ""; }; 0D078741156881080051973C /* HelpViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelpViewController.m; sourceTree = ""; }; 0D105F0C159EABDF006350CA /* InfoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InfoViewController.h; sourceTree = ""; }; 0D105F0D159EABDF006350CA /* InfoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InfoViewController.m; sourceTree = ""; }; 0D105F0E159EABDF006350CA /* InfoViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = InfoViewController.xib; sourceTree = ""; }; 0D10CE95156A3CF2001DC67F /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Icon.png; sourceTree = ""; }; 0D1E9E6B17420EE2002C1270 /* triangle-right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "triangle-right.png"; sourceTree = ""; }; 0D1E9E6C17420EE2002C1270 /* triangle-down.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "triangle-down.png"; sourceTree = ""; }; 0D2D9AAE156A00F3005B8D19 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 0D41CD33157C225F0032B05A /* StateView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StateView.h; sourceTree = ""; }; 0D41CD34157C225F0032B05A /* StateView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StateView.m; sourceTree = ""; }; 0D602F37157320D200F51C02 /* beep.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; path = beep.aiff; sourceTree = ""; }; 0D602F391573210000F51C02 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 0D62F86F15B8343A002E3EF8 /* StatePickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatePickerView.h; sourceTree = ""; }; 0D62F87015B8343A002E3EF8 /* StatePickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatePickerView.m; sourceTree = ""; }; 0D62F87315B8355B002E3EF8 /* StatePickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatePickerController.h; sourceTree = ""; }; 0D62F87415B8355B002E3EF8 /* StatePickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatePickerController.m; sourceTree = ""; }; 0D62F87515B8355B002E3EF8 /* StatePickerController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = StatePickerController.xib; sourceTree = ""; }; 0D62FCF0159BCDCC005506CA /* SaveViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SaveViewController.h; sourceTree = ""; }; 0D62FCF1159BCDCC005506CA /* SaveViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SaveViewController.m; sourceTree = ""; }; 0D62FCF2159BCDCC005506CA /* SaveViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SaveViewController.xib; sourceTree = ""; }; 0D64693B1599D04A00433025 /* OpenViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenViewController.h; sourceTree = ""; }; 0D64693C1599D04A00433025 /* OpenViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenViewController.m; sourceTree = ""; }; 0D64693D1599D04A00433025 /* OpenViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OpenViewController.xib; sourceTree = ""; }; 0D715209181A0C9D00840795 /* Help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Help; path = "../../gui-common/Help"; sourceTree = ""; }; 0D8A22361798EA17006044E7 /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = ""; }; 0D8A22371798EA17006044E7 /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = ""; }; 0D8A22381798EA17006044E7 /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = ""; }; 0D8A223B1798EA17006044E7 /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = ""; }; 0D8A223C1798EA17006044E7 /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = ""; }; 0D8A223D1798EA17006044E7 /* zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip.c; sourceTree = ""; }; 0D8A223E1798EA17006044E7 /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; 0D8F770615D097CD00EF43AF /* HelpViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = HelpViewController.xib; sourceTree = ""; }; 0D8F770815D097DA00EF43AF /* PatternViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PatternViewController.xib; sourceTree = ""; }; 0D96C63F1575C651006C8EBC /* settings.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = settings.png; sourceTree = ""; }; 0D96C6401575C651006C8EBC /* settings@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "settings@2x.png"; sourceTree = ""; }; 0D96C6431575C823006C8EBC /* RuleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RuleViewController.h; sourceTree = ""; }; 0D96C6441575C824006C8EBC /* RuleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuleViewController.m; sourceTree = ""; }; 0D96C6451575C824006C8EBC /* RuleViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RuleViewController.xib; sourceTree = ""; }; 0D96C6481575CBF8006C8EBC /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = ""; }; 0D96C6491575CBF8006C8EBC /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = ""; }; 0D96C64A1575CBF8006C8EBC /* SettingsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsViewController.xib; sourceTree = ""; }; 0D9AA82715D099D8003BEBD5 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 0D9AA82A15D099F2003BEBD5 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; 0D9D15B715B67E340081C8AB /* help.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = help.png; sourceTree = ""; }; 0D9D15B815B67E340081C8AB /* help@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "help@2x.png"; sourceTree = ""; }; 0D9D4DC2156E1F97005DD91D /* StatusView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatusView.h; sourceTree = ""; }; 0D9D4DC3156E1F97005DD91D /* StatusView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatusView.m; sourceTree = ""; }; 0DA5B31C15F03332005EBBE8 /* Patterns */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Patterns; path = ../../Patterns; sourceTree = ""; }; 0DA5B31E15F0336C005EBBE8 /* Rules */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Rules; path = ../../Rules; sourceTree = ""; }; 0DA5B32315F03654005EBBE8 /* bigint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bigint.cpp; sourceTree = ""; }; 0DA5B32415F03654005EBBE8 /* bigint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bigint.h; sourceTree = ""; }; 0DA5B32515F03654005EBBE8 /* generationsalgo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = generationsalgo.cpp; sourceTree = ""; }; 0DA5B32615F03654005EBBE8 /* generationsalgo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = generationsalgo.h; sourceTree = ""; }; 0DA5B32715F03654005EBBE8 /* ghashbase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ghashbase.cpp; sourceTree = ""; }; 0DA5B32815F03654005EBBE8 /* ghashbase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ghashbase.h; sourceTree = ""; }; 0DA5B32915F03654005EBBE8 /* ghashdraw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ghashdraw.cpp; sourceTree = ""; }; 0DA5B32A15F03654005EBBE8 /* hlifealgo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hlifealgo.cpp; sourceTree = ""; }; 0DA5B32B15F03654005EBBE8 /* hlifealgo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hlifealgo.h; sourceTree = ""; }; 0DA5B32C15F03654005EBBE8 /* hlifedraw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hlifedraw.cpp; sourceTree = ""; }; 0DA5B32D15F03654005EBBE8 /* jvnalgo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = jvnalgo.cpp; sourceTree = ""; }; 0DA5B32E15F03654005EBBE8 /* jvnalgo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jvnalgo.h; sourceTree = ""; }; 0DA5B32F15F03654005EBBE8 /* lifealgo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lifealgo.cpp; sourceTree = ""; }; 0DA5B33015F03654005EBBE8 /* lifealgo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lifealgo.h; sourceTree = ""; }; 0DA5B33115F03654005EBBE8 /* lifepoll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lifepoll.cpp; sourceTree = ""; }; 0DA5B33215F03654005EBBE8 /* lifepoll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lifepoll.h; sourceTree = ""; }; 0DA5B33315F03654005EBBE8 /* liferender.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = liferender.cpp; sourceTree = ""; }; 0DA5B33415F03654005EBBE8 /* liferender.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = liferender.h; sourceTree = ""; }; 0DA5B33515F03654005EBBE8 /* liferules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = liferules.cpp; sourceTree = ""; }; 0DA5B33615F03654005EBBE8 /* liferules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = liferules.h; sourceTree = ""; }; 0DA5B33715F03654005EBBE8 /* platform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = platform.h; sourceTree = ""; }; 0DA5B33815F03654005EBBE8 /* qlifealgo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = qlifealgo.cpp; sourceTree = ""; }; 0DA5B33915F03654005EBBE8 /* qlifealgo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = qlifealgo.h; sourceTree = ""; }; 0DA5B33A15F03654005EBBE8 /* qlifedraw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = qlifedraw.cpp; sourceTree = ""; }; 0DA5B33B15F03654005EBBE8 /* readpattern.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = readpattern.cpp; sourceTree = ""; }; 0DA5B33C15F03654005EBBE8 /* readpattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = readpattern.h; sourceTree = ""; }; 0DA5B33D15F03654005EBBE8 /* ruletable_algo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ruletable_algo.cpp; sourceTree = ""; }; 0DA5B33E15F03654005EBBE8 /* ruletable_algo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ruletable_algo.h; sourceTree = ""; }; 0DA5B33F15F03654005EBBE8 /* ruletreealgo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ruletreealgo.cpp; sourceTree = ""; }; 0DA5B34015F03654005EBBE8 /* ruletreealgo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ruletreealgo.h; sourceTree = ""; }; 0DA5B34115F03654005EBBE8 /* util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = util.cpp; sourceTree = ""; }; 0DA5B34215F03654005EBBE8 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; }; 0DA5B34315F03654005EBBE8 /* viewport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = viewport.cpp; sourceTree = ""; }; 0DA5B34415F03654005EBBE8 /* viewport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = viewport.h; sourceTree = ""; }; 0DA5B34515F03654005EBBE8 /* writepattern.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = writepattern.cpp; sourceTree = ""; }; 0DA5B34615F03654005EBBE8 /* writepattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = writepattern.h; sourceTree = ""; }; 0DD0EF81178017020061E9A1 /* algos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = algos.cpp; sourceTree = ""; }; 0DD0EF82178017020061E9A1 /* algos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = algos.h; sourceTree = ""; }; 0DD0EF83178017020061E9A1 /* control.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = control.cpp; sourceTree = ""; }; 0DD0EF84178017020061E9A1 /* control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = control.h; sourceTree = ""; }; 0DD0EF85178017020061E9A1 /* file.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file.cpp; sourceTree = ""; }; 0DD0EF86178017020061E9A1 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file.h; sourceTree = ""; }; 0DD0EF87178017020061E9A1 /* layer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = layer.cpp; sourceTree = ""; }; 0DD0EF88178017020061E9A1 /* layer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = layer.h; sourceTree = ""; }; 0DD0EF89178017020061E9A1 /* prefs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = prefs.cpp; sourceTree = ""; }; 0DD0EF8A178017020061E9A1 /* prefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = prefs.h; sourceTree = ""; }; 0DD0EF8B178017020061E9A1 /* render.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = render.cpp; sourceTree = ""; }; 0DD0EF8C178017020061E9A1 /* render.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = render.h; sourceTree = ""; }; 0DD0EF8D178017020061E9A1 /* select.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = select.cpp; sourceTree = ""; }; 0DD0EF8E178017020061E9A1 /* select.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = select.h; sourceTree = ""; }; 0DD0EF8F178017020061E9A1 /* status.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = status.cpp; sourceTree = ""; }; 0DD0EF90178017020061E9A1 /* status.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = status.h; sourceTree = ""; }; 0DD0EF91178017020061E9A1 /* undo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = undo.cpp; sourceTree = ""; }; 0DD0EF92178017020061E9A1 /* undo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = undo.h; sourceTree = ""; }; 0DD0EF93178017020061E9A1 /* utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utils.cpp; sourceTree = ""; }; 0DD0EF94178017020061E9A1 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = ""; }; 0DD0EF95178017020061E9A1 /* view.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = view.cpp; sourceTree = ""; }; 0DD0EF96178017020061E9A1 /* view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = view.h; sourceTree = ""; }; 0DD5D56515A3083700CF2627 /* open.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = open.png; sourceTree = ""; }; 0DD5D56615A3083700CF2627 /* open@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "open@2x.png"; sourceTree = ""; }; 0DD820D71632A307008DF0FD /* ruleloaderalgo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ruleloaderalgo.h; sourceTree = ""; }; 0DD820D91632A321008DF0FD /* ruleloaderalgo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ruleloaderalgo.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 0D078720156881080051973C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 0D9AA82B15D099F2003BEBD5 /* OpenGLES.framework in Frameworks */, 0D9AA82815D099D8003BEBD5 /* QuartzCore.framework in Frameworks */, 0D2D9AAF156A00F3005B8D19 /* libz.dylib in Frameworks */, 0D602F3A1573210000F51C02 /* AudioToolbox.framework in Frameworks */, 0D078728156881080051973C /* UIKit.framework in Frameworks */, 0D07872A156881080051973C /* Foundation.framework in Frameworks */, 0D07872C156881080051973C /* CoreGraphics.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 0D078718156881080051973C = { isa = PBXGroup; children = ( 0D07872D156881080051973C /* Golly */, 0D078726156881080051973C /* Frameworks */, 0D078724156881080051973C /* Products */, ); sourceTree = ""; }; 0D078724156881080051973C /* Products */ = { isa = PBXGroup; children = ( 0D078723156881080051973C /* Golly.app */, ); name = Products; sourceTree = ""; }; 0D078726156881080051973C /* Frameworks */ = { isa = PBXGroup; children = ( 0D2D9AAE156A00F3005B8D19 /* libz.dylib */, 0D9AA82715D099D8003BEBD5 /* QuartzCore.framework */, 0D9AA82A15D099F2003BEBD5 /* OpenGLES.framework */, 0D602F391573210000F51C02 /* AudioToolbox.framework */, 0D078727156881080051973C /* UIKit.framework */, 0D078729156881080051973C /* Foundation.framework */, 0D07872B156881080051973C /* CoreGraphics.framework */, ); name = Frameworks; sourceTree = ""; }; 0D07872D156881080051973C /* Golly */ = { isa = PBXGroup; children = ( 0DD0EF80178017020061E9A1 /* gui-common */, 0DA5B32215F03654005EBBE8 /* gollybase */, 0D078736156881080051973C /* GollyAppDelegate.h */, 0D078737156881080051973C /* GollyAppDelegate.m */, 0D078739156881080051973C /* PatternViewController.h */, 0D07873A156881080051973C /* PatternViewController.m */, 0D8F770815D097DA00EF43AF /* PatternViewController.xib */, 0D02E13C1568A14800581DCC /* PatternView.h */, 0D02E13D1568A14800581DCC /* PatternView.m */, 0D9D4DC2156E1F97005DD91D /* StatusView.h */, 0D9D4DC3156E1F97005DD91D /* StatusView.m */, 0D41CD33157C225F0032B05A /* StateView.h */, 0D41CD34157C225F0032B05A /* StateView.m */, 0D62F87315B8355B002E3EF8 /* StatePickerController.h */, 0D62F87415B8355B002E3EF8 /* StatePickerController.m */, 0D62F87515B8355B002E3EF8 /* StatePickerController.xib */, 0D62F86F15B8343A002E3EF8 /* StatePickerView.h */, 0D62F87015B8343A002E3EF8 /* StatePickerView.m */, 0D96C6431575C823006C8EBC /* RuleViewController.h */, 0D96C6441575C824006C8EBC /* RuleViewController.m */, 0D96C6451575C824006C8EBC /* RuleViewController.xib */, 0D105F0C159EABDF006350CA /* InfoViewController.h */, 0D105F0D159EABDF006350CA /* InfoViewController.m */, 0D105F0E159EABDF006350CA /* InfoViewController.xib */, 0D62FCF0159BCDCC005506CA /* SaveViewController.h */, 0D62FCF1159BCDCC005506CA /* SaveViewController.m */, 0D62FCF2159BCDCC005506CA /* SaveViewController.xib */, 0D64693B1599D04A00433025 /* OpenViewController.h */, 0D64693C1599D04A00433025 /* OpenViewController.m */, 0D64693D1599D04A00433025 /* OpenViewController.xib */, 0D96C6481575CBF8006C8EBC /* SettingsViewController.h */, 0D96C6491575CBF8006C8EBC /* SettingsViewController.m */, 0D96C64A1575CBF8006C8EBC /* SettingsViewController.xib */, 0D078740156881080051973C /* HelpViewController.h */, 0D078741156881080051973C /* HelpViewController.m */, 0D8F770615D097CD00EF43AF /* HelpViewController.xib */, 0D07872E156881080051973C /* Supporting Files */, ); path = Golly; sourceTree = ""; }; 0D07872E156881080051973C /* Supporting Files */ = { isa = PBXGroup; children = ( 0D715209181A0C9D00840795 /* Help */, 0DA5B31E15F0336C005EBBE8 /* Rules */, 0DA5B31C15F03332005EBBE8 /* Patterns */, 0D10CE95156A3CF2001DC67F /* Icon.png */, 0D068EB415D93F4300A4EAB3 /* Icon@2x.png */, 0D068EB515D93F4300A4EAB3 /* iTunesArtwork */, 0D068EB615D93F4300A4EAB3 /* iTunesArtwork@2x */, 0D068EBF15D9DD3A00A4EAB3 /* Default-Portrait~ipad.png */, 0D068EC015D9DD3A00A4EAB3 /* Default-Landscape~ipad.png */, 0D07872F156881080051973C /* Golly-Info.plist */, 0D078730156881080051973C /* InfoPlist.strings */, 0D078733156881080051973C /* main.m */, 0D078735156881080051973C /* Golly-Prefix.pch */, 0D602F37157320D200F51C02 /* beep.aiff */, 0D9D15B715B67E340081C8AB /* help.png */, 0D9D15B815B67E340081C8AB /* help@2x.png */, 0D07873C156881080051973C /* pattern.png */, 0D07873E156881080051973C /* pattern@2x.png */, 0DD5D56515A3083700CF2627 /* open.png */, 0DD5D56615A3083700CF2627 /* open@2x.png */, 0D96C63F1575C651006C8EBC /* settings.png */, 0D96C6401575C651006C8EBC /* settings@2x.png */, 0D1E9E6B17420EE2002C1270 /* triangle-right.png */, 0D1E9E6C17420EE2002C1270 /* triangle-down.png */, ); name = "Supporting Files"; sourceTree = ""; }; 0D8A22351798EA17006044E7 /* MiniZip */ = { isa = PBXGroup; children = ( 0D8A22361798EA17006044E7 /* crypt.h */, 0D8A22371798EA17006044E7 /* ioapi.c */, 0D8A22381798EA17006044E7 /* ioapi.h */, 0D8A223B1798EA17006044E7 /* unzip.c */, 0D8A223C1798EA17006044E7 /* unzip.h */, 0D8A223D1798EA17006044E7 /* zip.c */, 0D8A223E1798EA17006044E7 /* zip.h */, ); path = MiniZip; sourceTree = ""; }; 0DA5B32215F03654005EBBE8 /* gollybase */ = { isa = PBXGroup; children = ( 0DA5B32315F03654005EBBE8 /* bigint.cpp */, 0DA5B32415F03654005EBBE8 /* bigint.h */, 0DA5B32515F03654005EBBE8 /* generationsalgo.cpp */, 0DA5B32615F03654005EBBE8 /* generationsalgo.h */, 0DA5B32715F03654005EBBE8 /* ghashbase.cpp */, 0DA5B32815F03654005EBBE8 /* ghashbase.h */, 0DA5B32915F03654005EBBE8 /* ghashdraw.cpp */, 0DA5B32A15F03654005EBBE8 /* hlifealgo.cpp */, 0DA5B32B15F03654005EBBE8 /* hlifealgo.h */, 0DA5B32C15F03654005EBBE8 /* hlifedraw.cpp */, 0DA5B32D15F03654005EBBE8 /* jvnalgo.cpp */, 0DA5B32E15F03654005EBBE8 /* jvnalgo.h */, 0DA5B32F15F03654005EBBE8 /* lifealgo.cpp */, 0DA5B33015F03654005EBBE8 /* lifealgo.h */, 0DA5B33115F03654005EBBE8 /* lifepoll.cpp */, 0DA5B33215F03654005EBBE8 /* lifepoll.h */, 0DA5B33315F03654005EBBE8 /* liferender.cpp */, 0DA5B33415F03654005EBBE8 /* liferender.h */, 0DA5B33515F03654005EBBE8 /* liferules.cpp */, 0DA5B33615F03654005EBBE8 /* liferules.h */, 0DA5B33715F03654005EBBE8 /* platform.h */, 0DA5B33815F03654005EBBE8 /* qlifealgo.cpp */, 0DA5B33915F03654005EBBE8 /* qlifealgo.h */, 0DA5B33A15F03654005EBBE8 /* qlifedraw.cpp */, 0DA5B33B15F03654005EBBE8 /* readpattern.cpp */, 0DA5B33C15F03654005EBBE8 /* readpattern.h */, 0DD820D91632A321008DF0FD /* ruleloaderalgo.cpp */, 0DD820D71632A307008DF0FD /* ruleloaderalgo.h */, 0DA5B33D15F03654005EBBE8 /* ruletable_algo.cpp */, 0DA5B33E15F03654005EBBE8 /* ruletable_algo.h */, 0DA5B33F15F03654005EBBE8 /* ruletreealgo.cpp */, 0DA5B34015F03654005EBBE8 /* ruletreealgo.h */, 0DA5B34115F03654005EBBE8 /* util.cpp */, 0DA5B34215F03654005EBBE8 /* util.h */, 0DA5B34315F03654005EBBE8 /* viewport.cpp */, 0DA5B34415F03654005EBBE8 /* viewport.h */, 0DA5B34515F03654005EBBE8 /* writepattern.cpp */, 0DA5B34615F03654005EBBE8 /* writepattern.h */, ); name = gollybase; path = ../../gollybase; sourceTree = ""; }; 0DD0EF80178017020061E9A1 /* gui-common */ = { isa = PBXGroup; children = ( 0D8A22351798EA17006044E7 /* MiniZip */, 0DD0EF81178017020061E9A1 /* algos.cpp */, 0DD0EF82178017020061E9A1 /* algos.h */, 0DD0EF83178017020061E9A1 /* control.cpp */, 0DD0EF84178017020061E9A1 /* control.h */, 0DD0EF85178017020061E9A1 /* file.cpp */, 0DD0EF86178017020061E9A1 /* file.h */, 0DD0EF87178017020061E9A1 /* layer.cpp */, 0DD0EF88178017020061E9A1 /* layer.h */, 0DD0EF89178017020061E9A1 /* prefs.cpp */, 0DD0EF8A178017020061E9A1 /* prefs.h */, 0DD0EF8B178017020061E9A1 /* render.cpp */, 0DD0EF8C178017020061E9A1 /* render.h */, 0DD0EF8D178017020061E9A1 /* select.cpp */, 0DD0EF8E178017020061E9A1 /* select.h */, 0DD0EF8F178017020061E9A1 /* status.cpp */, 0DD0EF90178017020061E9A1 /* status.h */, 0DD0EF91178017020061E9A1 /* undo.cpp */, 0DD0EF92178017020061E9A1 /* undo.h */, 0DD0EF93178017020061E9A1 /* utils.cpp */, 0DD0EF94178017020061E9A1 /* utils.h */, 0DD0EF95178017020061E9A1 /* view.cpp */, 0DD0EF96178017020061E9A1 /* view.h */, ); name = "gui-common"; path = "../../gui-common"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 0D078722156881080051973C /* Golly */ = { isa = PBXNativeTarget; buildConfigurationList = 0D07874F156881080051973C /* Build configuration list for PBXNativeTarget "Golly" */; buildPhases = ( 0D07871F156881080051973C /* Sources */, 0D078720156881080051973C /* Frameworks */, 0DC9D3EE15984E05008937DC /* ShellScript */, 0D078721156881080051973C /* Resources */, ); buildRules = ( ); dependencies = ( ); name = Golly; productName = Golly; productReference = 0D078723156881080051973C /* Golly.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 0D07871A156881080051973C /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0420; }; buildConfigurationList = 0D07871D156881080051973C /* Build configuration list for PBXProject "Golly" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = 0D078718156881080051973C; productRefGroup = 0D078724156881080051973C /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 0D078722156881080051973C /* Golly */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 0D078721156881080051973C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 0D078732156881080051973C /* InfoPlist.strings in Resources */, 0D07873D156881080051973C /* pattern.png in Resources */, 0D07873F156881080051973C /* pattern@2x.png in Resources */, 0D10CE96156A3CF2001DC67F /* Icon.png in Resources */, 0D602F38157320D200F51C02 /* beep.aiff in Resources */, 0D96C6411575C652006C8EBC /* settings.png in Resources */, 0D96C6421575C652006C8EBC /* settings@2x.png in Resources */, 0D96C6471575C824006C8EBC /* RuleViewController.xib in Resources */, 0D96C64C1575CBF8006C8EBC /* SettingsViewController.xib in Resources */, 0D64693F1599D04A00433025 /* OpenViewController.xib in Resources */, 0D62FCF4159BCDCC005506CA /* SaveViewController.xib in Resources */, 0D105F10159EABDF006350CA /* InfoViewController.xib in Resources */, 0DD5D56715A3083700CF2627 /* open.png in Resources */, 0DD5D56815A3083700CF2627 /* open@2x.png in Resources */, 0D9D15B915B67E340081C8AB /* help.png in Resources */, 0D9D15BA15B67E340081C8AB /* help@2x.png in Resources */, 0D62F87715B8355B002E3EF8 /* StatePickerController.xib in Resources */, 0D8F770715D097CD00EF43AF /* HelpViewController.xib in Resources */, 0D8F770915D097DA00EF43AF /* PatternViewController.xib in Resources */, 0D068EB715D93F4300A4EAB3 /* Icon@2x.png in Resources */, 0D068EB815D93F4300A4EAB3 /* iTunesArtwork in Resources */, 0D068EB915D93F4300A4EAB3 /* iTunesArtwork@2x in Resources */, 0D068EC115D9DD3A00A4EAB3 /* Default-Portrait~ipad.png in Resources */, 0D068EC215D9DD3A00A4EAB3 /* Default-Landscape~ipad.png in Resources */, 0DA5B31D15F03332005EBBE8 /* Patterns in Resources */, 0DA5B31F15F0336C005EBBE8 /* Rules in Resources */, 0D1E9E6D17420EE2002C1270 /* triangle-right.png in Resources */, 0D1E9E6E17420EE2002C1270 /* triangle-down.png in Resources */, 0D71520A181A0C9D00840795 /* Help in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 0DC9D3EE15984E05008937DC /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/tcsh; shellScript = "touch -cm ${SRCROOT}/Help\ntouch -cm ${SRCROOT}/Patterns\ntouch -cm ${SRCROOT}/Rules\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 0D07871F156881080051973C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 0D078734156881080051973C /* main.m in Sources */, 0D078738156881080051973C /* GollyAppDelegate.m in Sources */, 0D07873B156881080051973C /* PatternViewController.m in Sources */, 0D078742156881080051973C /* HelpViewController.m in Sources */, 0D02E13E1568A14800581DCC /* PatternView.m in Sources */, 0D9D4DC4156E1F97005DD91D /* StatusView.m in Sources */, 0D96C6461575C824006C8EBC /* RuleViewController.m in Sources */, 0D96C64B1575CBF8006C8EBC /* SettingsViewController.m in Sources */, 0D41CD35157C225F0032B05A /* StateView.m in Sources */, 0D64693E1599D04A00433025 /* OpenViewController.m in Sources */, 0D62FCF3159BCDCC005506CA /* SaveViewController.m in Sources */, 0D105F0F159EABDF006350CA /* InfoViewController.m in Sources */, 0D62F87115B8343B002E3EF8 /* StatePickerView.m in Sources */, 0D62F87615B8355B002E3EF8 /* StatePickerController.m in Sources */, 0DA5B34715F03654005EBBE8 /* bigint.cpp in Sources */, 0DA5B34815F03654005EBBE8 /* generationsalgo.cpp in Sources */, 0DA5B34915F03654005EBBE8 /* ghashbase.cpp in Sources */, 0DA5B34A15F03654005EBBE8 /* ghashdraw.cpp in Sources */, 0DA5B34B15F03654005EBBE8 /* hlifealgo.cpp in Sources */, 0DA5B34C15F03654005EBBE8 /* hlifedraw.cpp in Sources */, 0DA5B34D15F03654005EBBE8 /* jvnalgo.cpp in Sources */, 0DA5B34E15F03654005EBBE8 /* lifealgo.cpp in Sources */, 0DA5B34F15F03654005EBBE8 /* lifepoll.cpp in Sources */, 0DA5B35015F03654005EBBE8 /* liferender.cpp in Sources */, 0DA5B35115F03654005EBBE8 /* liferules.cpp in Sources */, 0DA5B35215F03654005EBBE8 /* qlifealgo.cpp in Sources */, 0DA5B35315F03654005EBBE8 /* qlifedraw.cpp in Sources */, 0DA5B35415F03654005EBBE8 /* readpattern.cpp in Sources */, 0DA5B35515F03654005EBBE8 /* ruletable_algo.cpp in Sources */, 0DA5B35615F03654005EBBE8 /* ruletreealgo.cpp in Sources */, 0DA5B35715F03654005EBBE8 /* util.cpp in Sources */, 0DA5B35815F03654005EBBE8 /* viewport.cpp in Sources */, 0DA5B35915F03654005EBBE8 /* writepattern.cpp in Sources */, 0DD820DA1632A321008DF0FD /* ruleloaderalgo.cpp in Sources */, 0DD0EF97178017020061E9A1 /* algos.cpp in Sources */, 0DD0EF98178017020061E9A1 /* control.cpp in Sources */, 0DD0EF99178017020061E9A1 /* file.cpp in Sources */, 0DD0EF9A178017020061E9A1 /* layer.cpp in Sources */, 0DD0EF9B178017020061E9A1 /* prefs.cpp in Sources */, 0DD0EF9C178017020061E9A1 /* render.cpp in Sources */, 0DD0EF9D178017020061E9A1 /* select.cpp in Sources */, 0DD0EF9E178017020061E9A1 /* status.cpp in Sources */, 0DD0EF9F178017020061E9A1 /* undo.cpp in Sources */, 0DD0EFA0178017020061E9A1 /* utils.cpp in Sources */, 0DD0EFA1178017020061E9A1 /* view.cpp in Sources */, 0D8A223F1798EA17006044E7 /* ioapi.c in Sources */, 0D8A22411798EA17006044E7 /* unzip.c in Sources */, 0D8A22421798EA17006044E7 /* zip.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 0D078730156881080051973C /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 0D078731156881080051973C /* en */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 0D07874D156881080051973C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.0; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 2; }; name = Debug; }; 0D07874E156881080051973C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 2; VALIDATE_PRODUCT = YES; }; name = Release; }; 0D078750156881080051973C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_C_LANGUAGE_STANDARD = gnu99; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Golly/Golly-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = IOS_GUI; "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( IOS_GUI, "DEBUG=1", ); GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; INFOPLIST_FILE = "Golly/Golly-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = 2; WRAPPER_EXTENSION = app; }; name = Debug; }; 0D078751156881080051973C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_C_LANGUAGE_STANDARD = gnu99; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Golly/Golly-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = IOS_GUI; GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; INFOPLIST_FILE = "Golly/Golly-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = 2; VALIDATE_PRODUCT = NO; WRAPPER_EXTENSION = app; }; name = Release; }; 0DBF0CFD15DA801A004A5509 /* AppStore */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; COPY_PHASE_STRIP = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 5.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 2; VALIDATE_PRODUCT = YES; }; name = AppStore; }; 0DBF0CFE15DA801A004A5509 /* AppStore */ = { isa = XCBuildConfiguration; buildSettings = { GCC_C_LANGUAGE_STANDARD = gnu99; GCC_INPUT_FILETYPE = sourcecode.cpp.objcpp; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Golly/Golly-Prefix.pch"; GCC_PREPROCESSOR_DEFINITIONS = IOS_GUI; GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; INFOPLIST_FILE = "Golly/Golly-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 5.0; PRODUCT_NAME = "$(TARGET_NAME)"; TARGETED_DEVICE_FAMILY = 2; WRAPPER_EXTENSION = app; }; name = AppStore; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 0D07871D156881080051973C /* Build configuration list for PBXProject "Golly" */ = { isa = XCConfigurationList; buildConfigurations = ( 0D07874D156881080051973C /* Debug */, 0D07874E156881080051973C /* Release */, 0DBF0CFD15DA801A004A5509 /* AppStore */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 0D07874F156881080051973C /* Build configuration list for PBXNativeTarget "Golly" */ = { isa = XCConfigurationList; buildConfigurations = ( 0D078750156881080051973C /* Debug */, 0D078751156881080051973C /* Release */, 0DBF0CFE15DA801A004A5509 /* AppStore */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 0D07871A156881080051973C /* Project object */; } golly-2.7-src/gui-ios/Golly.xcodeproj/project.xcworkspace/0000755000175000017500000000000012536111546020736 500000000000000golly-2.7-src/gui-ios/Golly.xcodeproj/project.xcworkspace/contents.xcworkspacedata0000644000175000017500000000022612536111364025616 00000000000000 golly-2.7-src/gui-ios/Golly/0000755000175000017500000000000012536111546012744 500000000000000golly-2.7-src/gui-ios/Golly/settings@2x.png0000644000175000017500000000170712536111364015607 00000000000000‰PNG  IHDR<<:üÙrŽIDAThíšßq›@Æ¿ÅNoÖ¤O°gôb&¤‚ÐII*ˆ:°;°\AÔAäq<‘àœ”73–Ù<e%‚;8þó{ÓÜêö>í²·wˆ˜Ï «ëì›ÁOÁOg'ø•‰Iâ8þ `æ!€K"J™ù†™çƒÁ`6~™ðÕj²'Ir˜eÙ"ËX8Bœw-¼QJ‹OL‡&Y–¥‹Å⸉Ϧ4Šðš8Ž?2ó¹¢ù2Ïsßó¼ëÆŽk`D0DQtJDSEó!ÄIém¬JÇãKfͲ,SÍ£‹ðÍH¹®ûÓè*0¾ëDš™?™ö_E+‡ªh"òÛð_F¥`)å(ŠNu'Ç—¦fUû·qJK)¿8!¢iÑ}¤TðfÊéŠ.lÃÚ+k‰RÁÌìo~V­Y©÷ŠvѪ­)v©ë¿)µªô.Ѻ‘%"•>Ü(U‚wF`[´”ò¢FÏ4íSz.δ~ÉøTJ¹uÛ¶=ÕýNSª.fü ›°¦ïiï]D m*QQ[=ïLî3Ò•Uz0L v«Q‡ ˲y’$‡-Íÿ•‚G£Ñ¯<ÏC´·gždYv³¯«¥}Øó¼ë<Ï}´é¡eYs)åû–æÿƒrãáyÞµÂ0z´—&EO^õ!€YÛ‡”Z7I’ÞÞÞDàáˆw´1œH·ï£ã8~ËÌsES×u?h/LãW´,+Õ)f½ÜäTVܯ)Ùö%¥×höÜÛTöཉðÇq®4Þ3oV¥wïJ/âf«ÕêÍjµzƒ­çžˆ&es÷.¥7ÙU¹ó<íyÞúØyÌÌß7Ç]×¥]sö2ÂkT*÷ÝÝV‘ëu„`±X[–5ÇC? ¢ËûûûÏppppÆÌ=·eî½`@¯rÑÜqœw»Æ{Òk4+÷¤lðQÔþBÁÌ¡ã8We6F0MÅÿ YJD~ñ£”ò(ža“<ª›àEðSçEðSçÙ þ åß±$§ŠëXIEND®B`‚golly-2.7-src/gui-ios/Golly/help@2x.png0000644000175000017500000000207512536111364014676 00000000000000‰PNG  IHDR<<:üÙrIDAThíšÏã6Æ¿Ç L߯¬:˜ |²ÆÀªƒu*Xuwoq:P:p:Ðu í@© ÞÛx“9„Ιdi½ûw©G~"ùøøDRJáš`—îÀ÷æ&ø­süÖ¹:Á? i¼(Š÷J©ˆˆ"¥T 8QµPQºßïÓù|þe¨>Qßû°âRjID1€IG35€@†áß=u @‚…ï¬Ä½üFÂ9_N§Ó¯};[pY–÷»Ýn‰ÿÄÅ–ˆV³Ùìs %8˲ÆXàñÜŽ¸@Déh4Zœ3Úk‡´A÷uÚ•ZJ¹èêØ:mKyžTJ¥øþb `Œ¥Y–=tyÙ{„õȦ]ë™­”2òi¯βìAOã clS–å½ÏK^‡vP]¦qED €j4UM§S–åýËËË£”rAD œPš»Ý.ð‹kGœ§´â7øo=5ųÙì3ðMØ~¿ßš¦bžç‰h ÷»Ãð/—ŠN‚uPQ;6~ âœG‡ÑÌóüw"Z•½­ÞßS¸my[Îyà²]¹®á•c½õ±XСæ1c,ÕóÓéô+ç<°uho¢ƒ+VÁºC±‹±J©UókѪ¥ê†©m¬›]º80«`¥”Ó—;æéééÏæ3Ö-Õs‰c³“ççg›-»à–©Ø™[šÑ1ùœ–c±µŽ©PG3ÞÛЩ©ED.ë±3J©È6­‚cÖ)ÒÆn·{µîtGb_[§œš¡íÈTn g¯1pºèR‚«C4¦ ìW/\D°ÉCpƒ#¥¦rÛ®ûêÈ1J© úë‚Q0ÕC4:ŸÏ¿!>`±¶|›QðÀɺ¡œSe*4 –R’°+Šâ=rRœóÔTnMñ!þÁeòÏ]¨Â0üÙTÁ%ôÖ9x. ׋ ["ŠÂ0¤0 ©‘Ô;Ûöx<¶.A«`ë&}ôHJR¶ÀÿiŸU¶¬/™µl£nKÉöä·œs§™è$Xòêœ Lìú Õù´†á'Xö8 A[ºæîî.:Ã&l\ÿ:žÇC)e ·Äø)6Ç¢…”R«3ìÕœóØç…ÛïR³Ùì³R*ö}¯g:‰®ðÊÃíR‹/Wum阫¹˜Öäj®¶q—Kt®î¾ôMð[ç&ø­su‚ÿ`øþ>6EIEND®B`‚golly-2.7-src/gui-ios/Golly/Icon@2x.png0000644000175000017500000000515712536111364014642 00000000000000‰PNG  IHDRh$uï!tEXtSoftwareGraphicConverter (Intel)w‡ú IDATxœìœ L•çÇßçý8`™V\¢©íœ›·‚I×ÖÕ) Û‘‚("§Z#2ÛÂbmí0µ“‹ 6¨Ðµ\]]§€\¹‰Ê‚XÁ㥴-W¼T{ ÙwÎQ£VÈgx’÷}oòË žü}<ÿ"øËCú~˜/Â|Éc!  Y˜`ÈÂC&²0Á… †,L0da‚! ŒÇ.¬û²Wå!¿š*ß«W^`ì§Ûž'O,ª(óíh[,z FÐ7laU‡WÅGl¬ÎÊ>“¾·íí·Ž„Gµ_òÐØ­žïǽ˜¾#ùóܼöíÛšW,ÿäã” õï#\ FÐ7D(,éÃàù•ÅÅ=u _Õ×÷Ô7\ih¸’™õõì™…û²ô÷ÆŒ½<æ%nxïLm:y¥ÞLuõ7¯·¼ìÕÛã!P FÐ7D(¬¢,`„¢5kZSRΤ¤´§¤tXØ‘|ú•WNMœ¸÷t«Ÿ:öã­®®[ž}¶6)éÂýc)Éíññg§N© ðß J FÐ7Ä)ÌÝ=ÂiÌ_Ÿª°Ð†°ÐÏÌ4††6¾Vç6§RýRЪ·Ô±´=£Fç<5¾(,´É<Ópwò³ ¦1¿,52µ±n‰Aß¡0ãE_ÍGŠ’æä”áæzÐÝ­ÜÝ­ÌLù¬ÙiвÛqĶï®û,ó[G•4e³s‘yìî¤{Å„‰yŠ’ª({־ʠöÂÐ7D(¬¼d1…Ý@²r‡ËrzbŸÓè•Ñ£rìtÙ@r2)ý÷éVç©›²€äPš5ÒQËã¤Nf°WgÔÉ}2æÏ‹à?P{aè"v°Ô—’\BJU€((1=š>µwNŒ:–•¹\Z€‡î|¤…Ò’œÌUBj}CœÂj*ìtGí äüϱµÍ-+]ÙgþQÖÞWÀ@¨á“ôäsÏGs¡Aß§0•IÁÃìÔ·R·™¯ tÓ_ÚÙ–lŠyóÞØ—Æ…³f~ P+æ1 Ý ==}z|ǽ@Aß§0•c~ÞÞÑvº ZlH«­Mñ¬Y›‹ ƒS–üGbÈo³S¡M 9©~Ç7öÓ Âz¯..P#èâf¡·Ççh£C­ÿ%cÀÀ“çÏ.­¯Yzª5àö o¡µƒ¾á  SßGÙúwßÙž¾>)|Ý{eÅþóº¾ðŽßòÚúw¶ý-L z䯥ùÔú†ƒ-ÌxÑËû¥„-qgO·k8÷Áp½¥µwíÚæ•Ëcz¯>ð Óÿì ôô((.í9{îšáܳ†ë{3Œž›öÐfüj}ÃÁv£×ëOܺúµ¶¼üμ‚‹yù]yùù]¹ù]K|[–ùEÜû„ÿ t™V¾cçEó˜Q³LÆÆž™T\Z¼T”@í oˆPXtä«ãŸªXý—æÍ±'ccZcc[,›cZü—{rüÿî2ý“´ó‚דã?qq©Š‹m‹9i³LÆ´DF¶Oøuù”II7{¨ô  S¿íŽ·ÕÞ!gÆ ôú#z}¥^_e¦zÙË•“§Ú;dÏx>JŒÜ<Ü!{¤c†ß’*óØÉ}µÇÂÃö™ÃíÓví\Á öÂÐ7D(¬©~©B?’ªÓí<©À噢éÎ…&üj?¥i©ŠòQ÷åųgFì’>zt¶ó4uàÎä´©Eö2ÔÉË×ñ¨½0ô  +-ò¡$È~J uº|[]ž­n¿N) æ'ò(ìnn\>uò& …æÉB…ÚÚªc* ì·< 4ßuvÿÚ Cß¡°cM‹šKHå}!pˆÀa˧”T)t×yC€»[4ê&Mc‡Ló¦±J Õ>>ïò¨½0ô  ûñ¶çر)š€4ÒDÈQbúà˜ùQå(£O?ðÃ-¯è¨€ó3–±&Õ'VÇņð¨½0ô  SÙóº =Aà í¡Ðêè¨7Աˋ~á˜N¡À™ŸQhstÜÑyÁ_ˆ@ oˆSØíž/ÎH Êy€.JT.érÀ¨À9—í×îþÒl÷§«tJ5Q:)1RÓŒeò£Î¦$!ñ¯¢j}C„ÂT¾ºä=oîVJ[zþÐKé7 múÝsqíü°™‘èôD@'ÐoÕIªB¿p‘šðÁꟾ_ P vÐ7D(ÌBi±HðF×Ùÿœùû$½>*=uåÍkx_ôt{%nZä³íÅ’çÏÛñ÷PCÇ2A5‚¾!Na’àNÕ–ôª¶¤?xTµ%ýÁ©ª-éUmÉð¨jK€GU[2PaªÚ’àTÕ–ô§ª¶¤?øUµ%ýÁ¯ª-é®UmÉX¹ªmMX¿ªmMX¿ªmM UÛjª6óW‘!¡j3•ª6óW‘!¡j3•ª6óW‘¡¢j[ CEÕ¶&†ŠªmM !UÛjàWÕfu³š¸SµYݬæUmV7«ù‡GU›ÕÍjþáTÕfu³šxTµÞ¬æUm†7«ù‡GU›áÍjþáQÕfx³š8UµYݬæNUmV7«ù‡_U›ÕÍjþáWÕfu³š¸VµÞ¬æ©j ƒTµEBªÚ"!Um‘ª¶`HU[0¤ª-RÕ ©j †TµCªÚâ!Umñª¶xHU[òh¤ª-RÕ ©j †TµCªÚ‚!UmÁª¶`HU[0¤ª-RÕ ©j †TµCªÚ‚!†ª.Bó8ØÂªÚè"4ÿƒ-Œ¡ª.BóˆP+U]„æ?¡0†ª6ºÍ Ba Umtšÿ@„ªÚè"4ÿ…1TµÑEhþ c¨j£‹Ðü"ÖÇNÕF¡ùÄ)Œ¡ª.BóˆPXSU]„æ?¡0 ¬Tmtšÿ@œÂúØ©Úè7«ùla¬Tmô›Õü"ÆJÕF¿YÍ Ba¬Tmô›ÕüâÆJÕF¿YÍ Ba Umô›Õü"ÆPÕF¿YÍ Ba Umô›Õü"ÆPÕF¿YÍ Ba}ìTmô›ÕüâÆJÕF¿YÍ Na}ìTmô›ÕüâÖÇNÕF¿YÍ NaªÚè7«ùD(LÂY˜`ÈÂC&²0Áø?ÿÿìÑ € ÿ¯Û!>ð0Ìa˜Ã0‡aÆ ÿÿeªŒæüIEND®B`‚golly-2.7-src/gui-ios/Golly/open@2x.png0000644000175000017500000000177312536111364014713 00000000000000‰PNG  IHDR<<:üÙrÂIDAThíšAOÛH†ß7M»•ˆƒ¶ÝUw#!`#zXäÊ17N@Ä/kNÜÐþÔpN¥ s€Kv¥¶"C¬¸Z(®ñÌ"¯ÚÝ”õd’š?’ocÏ<šùÞÇ!B<$hÜøÞ¤ÂI'N:©pÒI…“΃~¤rs¿ß×c%×uõ(ís¹\¿X,vt]ï«ô«‚’0c¬´¿¿¿ÓjµV¢´/—ËÇ[[[¯u]?VéW%a×uõV«µrppP‰zÏæææï*}ª’Öð]ü»fÛíöŠã8‘êÇÑÛív¤å…Q2ȼŸŸŸ¯|Y³Žãè¶m—.//#I …¾išÙÙÙ±„V˜ Ñ3Aùj6›•jµú€¸WµZ}Ól6+2i ¸—jTÊåòq.—“ês,¦ivvww_[–õ]÷×0´dîQxù|þýòòòÛùùù¶ÌÉK×uu×uÿ“úw¥·ª° G)í !>Ëž¼&Å]'ºq3ÇqÜ“““§„Ÿ_ý¦ø\e¾u¢‡p×¶í«z½þÀsÛ¶P|æD‹0cìc£Ñ0ü à©ú°&‡ê>|  À0à‰ê &ɨ3ð Ãè---ý¡iZ϶헌±9Ù1Žo¤q !® !·ÃŒ:ÀžeYîíímoo0Mó3§ðW»Æ°*ÂŒrÉ9÷(¥Y!D@ñ 3Î9ãœ{ÃŒº¤¿Jç  §§§¿0¿p—Â4M¿ðéü+²qoI€.çüÂ÷ý›a F]Ò÷5ot5Mëf2õ&„Ü !®ïk:‡ãZ[[{gƧa ¥„…Ÿ)¥=˲>Öjµ3ιW¯××FÜÂÿìµZílcc£S*•®†5”æœ{œsFy|Ó9ŸÏ¿_\\¼(•Jß|G–Ö4Í#„0Û¶õiKç)aß÷o8çŒ1:mé"%œÉd0 à9¦(C¤NZ¾ïgƒ ˜ðƒ—ý©IçÙÐzB)ýÀ yLQ:‡HÍpY!Dñ×nHät‘Mé,¥´ˆøkP(>Y–õ.J:‡È¾<<月¿v¦i^ïììt*•Êÿ¦sˆ”ðÌÌÌ_«««g„¸kÀà÷õõõN”t‘ú>,û'–I3ñâIàÁ}N…“N*œtRᤓ ''ü7çN PÅ:²IEND®B`‚golly-2.7-src/gui-ios/Golly/iTunesArtwork@2x0000644000175000017500000033150512536111364016007 00000000000000‰PNG  IHDRð¼Ô!tEXtSoftwareGraphicConverter (Intel)w‡ú²ßIDATxœì×1 ÀÀW‡= 0ô’еsö"æ{ðŒ€!B „1b Ä@ˆ€!B „1b Ä@ˆ€ ÿÿì× € ÿ¯’à FFFFFFFFFFFFFFFFFFFÿÿì× € ÿ¯’à FFFFFFFFFFFFFFFFFFFÿÿì× € ÿ¯’à FFFFFFFFFFFFFFFFFFFÿÿìÜPÓ÷Çñwò ’Š[Û³S =×êt³wZí r,XW¢XÔ–ŠÚDT@Û:©m7çæâÄóWqwk«½¶g×Ù›µ]W»‚?b $‘„„üþE¡€øYâꟻú³IÍëîq¹äûý'ß罿¼ï› €(‚ Š`ˆ"X¢€(‚ Š`ˆ"X~¶»îtØ¿'úD&ôAôAˆL˜ôùÉÁpÕן_¾üðøŸ½D4hhTIlì‹D%­âÓj¢—‰‚§–- äQ QŸ¿˜Hø\á®ÊÎÙ¿g¯!ìW>è™Ð}ÐÂóƒ>?uXî¼êǦO«HŒŽõ">­ˆ”'Å×<°%Q\-âd'ãxåēŠ7ÅÄlð*ùüÊQ\6É‚·Ç”Ÿo‘®þ ì×…>è Ð}ÐÂóƒ>÷ ,wÌî½ÿš5kÑüàÜ ©blü1mQ­ˆ¶ŽÙöȘíSÛ9ëɺÔÔ}ié{Òæþå7Yû3refIŸûNjú‘Ù© S§ÕOþÅ”äýII»8ÚNTË£?Ä v•s´f´H:cú[oÖ6…ýJÑ}Ð'Ò úÀ݃ùAŸ{€; Lú× ÉeDÙÂØ—J|h=ÑÆûx;'Ž9œöägË ÒÒfÙª³µ¯ªŽ¿ë»x‘)5¬¹“i ¬ÃÒv9t伊ÕÕ»kß4®‘6/YÒ¸ ïÌ3OŸLžðN‚x׃£ë8ÚJTɧµD’„ûJ*ÖûU£ú O$@ô»óƒ>÷*,·¥fËßù‚…<*ƾ;*8£5B®ö‰”†ù™ÿ~¡@^±æÒ[[{ŽýíŠJΓÑo1 :lÌë ­Î—ôlW½oqÉÉÒ³ÅÅ­©OŸ7öÈhÑŸùT% W8*ÊÎþ}Ø› ú úDôÛùAŸ(àæìÙ÷ŸI“¤D‹cc*chk¢¸nÆôÏ òÛs²>ÿÕëÛtÿüŠlÌèbÚnG—Ãfpš cW±³Ë¬ërMƒN;³šFÌÝÃ&ý€QßoÔûOÑk6yÌ=.‹ÙÔct›º]ÁƒV³ßfcêfñ°F9ÛX£ÊÎù¤`ÑùÂ|Í3³¾~èþCBþÛB®šH2&ñ…‡èƒ>èƒ>èƒ>p 0?èU°Ü„Òµï¯PWE´1^´oRòÉœLÝRI÷s¹ŸnZÿí‡Ç´¦7°V kiëï4ôw<—.HïÑéýº®€îòÐåï}w] ¤«ïÿºhïè62»“µw°Ã‡{–ŸÌÊü´hQ[^NûìgE‚}D›Æ$¼SV°è(ú ú ú ÜÌúD,7jêÌ N´<.á5¢ê”GOd¤·ÍËèÈ›¯ÏÊüæw¯*¿k¼ÐÄZULÝÊ:;ƒ“:¤P:5—¼×ù4Ú>6 Ñ\¸þñ‡_µZŸ¾«WÝjV(ljõ°RÅŽ}Ð/“)RýI13½ýW“O9Eüb¯ˆ…ëÓRÿ„>èƒ>èƒ>è7óƒ>Q À Iz8”¸„èÅ8ñŽ'?‘ÿ[CúœsYóäy¹çW—µ|qŠ}ûõˆê"Ó¨YKóU¹Ü/¿èR5»*û÷”N…Ò­Pz HðÍÿ>ÞÀ«RéÔ¶¹[T¶¦&SÓ9¯¶5«YÃÑá•+Õs3Ÿ_Ð5^{V†zÊc>2v/…þ'«0ùÑ—Ð}Ð}Ð}àa~Ð':ýÿÿìyTSg‡?Tö„$¬BØ7"ˆ¨ÅêÑ:Õ¶3mpETTPAE—VÐQ«Z KÂ@ ‰Y!ì!ìÈâ†KíL§=íœ27©ŽcÇ¡Á3s¦â{ÎsÞóÝ˽Üï>¼¿?Þ“Àð°Jºô WèêMÑÜ­­“äá^þÞÒöeK[Þ_![´„³qS­X:ÖÒÐ?àçm€ñÈe¶ ä‡Í”zz‡5§žöñª_´ ««>íY¼¤ì“N9wìÿgþÍkjþ.‘üPU=Êåß—Õ[[ÿ¨šß/”+‘Œ%w…’ûBñC¡ø±ªŽ*ÕC,¾/¨©=”Õ<I ÄßÜ”þ$ŽñDc_\[þ^Õ<Ÿr¿…âE ¤ó¼¸ ½ù†Ú'5Q8ŽÐRfÞ0ø?àü€Ÿ·Ðý~€q€`:}@Å >¬ªÊ“jBÌʼ«äÚ`½7+«#+[NÏi¦çȯewf3\Ëúá@Ì'­Ô‹VçéÞEsî›;sxÎŒ.¯YÍS:–a„Bôp«#£sÀø?àüLb?ôø|© /‘‘YgBXP†F‚…ÙuWW¾‡›ÌÕ¥ÞÝ­qÖì:Ï9'çœÕâ” O¿¸ò€Nðõ×·¿úª'-­ó%Ò;þå°[Eï3¾ìSòÏCuPÞ2 »±;=­==]žžÑ”–Ñœ‘Ù‘™=r%íqBÒãåK%3]žÎ]³gôÒ<Úi3Z\y¶Ós4§Å ô‰.î“ìë ð~Àø?“Òý~ _êÀKÐh» @hŸ±I¦ƒ}µ½½ÈÚJHµ•º¹6ÐfÕΠ•Ù9¤‡íj¿rõûÔóCi÷®^îÿò‹¾K—.uüº¾ ë¿‡âòÅŽË—Z/_jƸrµ-=c %uøó”ïÖ®ípq*§yÈ]œäîn-n®N޵înRW§*²é H„>vu ?àü€ð3)ýÐ?àò¥>0¼àh_}¢§©£sÊÒºÐÍMêè\GµkptjÁ¶Ô.nEv_î¸üÅ_>;ÓñüÀùÏ»/ï=ŸÒ•šªHMýUýŠ×ç|;ÆùTö  çº.¤(.¦´]Hm=ŸÚvñbOò©ž” ßmÛ6àèÀöp¯ÁúžêÀ·wP®®2G‡›v6¥–féíÀæàðð<ð~Àø?“Ìýù‚|M^@&…èhîÔÒŒ5%§[Ûc=dK­±³kquU897[ÙTÚ98»^;phð\Ê詓ݧOÞ:›ØvîLçÙSgNË™vm/Ó®^•Ÿ9Ûˆqötö Ï’;1Î%wœKn?›ÜŠ]Øyú³';w 98ç;9s©\Kj‰Û¿ƒ“ÔfºÐv:ºE–ÆñiÛ,ÌBØì!ð~Àø?“Éýù‚|Mž±ÊÿBk tŽè뜥Ú3mJ¬l*Èæ<3s™m«½½œj/™nâÍÎÚןП” ˆ‹•%Å5žJlMŒ—'œh{òç4'$4%$4<§IÉ/'»6Ä'I%‰'°%ëHŽëLÆê±¶“ñ­ Ç[ŽwÆÇlëstaPíKmÊ,ìLª3×Ú†om)¶·•Y’8†º—´4öékoðöŠ?àü€ð3iüÐ?/È×D๕x£h-t‚B̶µgÛ8”ZQ«Ì,yd3…Rca!µ¶â[Yzy—FDôÆêIŒï:-9~¤.é¸ühlóÑØ–WÑüŒ#GÔ«©j£úÄ­“b`7ÆnŽ;ÜŠqìPKÜá–qmØSâ÷ÇÝÚëìV0ʶ¶+µ²g‘­ó,m+H”–VbWçV ¾…¥§™¨¶èh¾ÎŸÅ?àü€ðóûô@ÿ@¾ _þ¹ÿßwð{àÅÇZ¥©yt J±´(£X”-KÈ7ÈU3ž¹’j sÎt«BÏYå[Bz¢ööîß×ÛvøP]ÜѦƒÑ4KãËŒñ¿#> ö}bê£Öˆ©Åê¡ØæÝQ ‘íÑ1÷¶‡Ý³£æ™›XYr(æ7(æUÏ©Æ6¯Ü¿Y9Á(¡mY0/ü€ð~ÀÏ$ð@ÿ@¾ _¯ J¤Íªß9J0aZXaSoÉ¢Œd^I6«4£(1§T˜›[™å9Úç­_«Ø½«/joGddÃý²}ûköî•íÝ[¿wO£ZõMjÕÝ-{öÜRѲgo}D”$bŸPI”xOtÃöpYXDGäþÑ€€.kK&Å4ÏœRfFá’)2VÍ*Aùf6–SÑçSQ4Ñx'ø?àü€ŸIà€þ|A¾^–트ŽÐ‡Z:Ñ%aã/‰RI$q”"©ƒdZA2-'›rÈ$–9‰I&f|¸²nWXoÄÎÖm[Eáá¢íÛy;vˆÃvHÃvÔ¨WŸ&S«†Õ‡moR‚-vH·ínÛÅ{F¸$x‹$d[[øî»~~B²i6`±˜dZI"VIªWà``¯@"qìmª Ó¦¢ƒ††f‚ð~Àøy£ýÐ?/È×ëÀ2G§­SÖië16I'‹ ŒŠðÄb¼)Û˜PŠA0áLJ‰&ÅDB!‰popÅwî°í!›B6‰CCùÁÁ•![!!¢‰ ™5!›ë”`‹ѦPÞ¦ÐjŒà­¼àPÁÚ ù–­ƒÎN…ãLc|.¶UÕžËUû/6&²1„b SB…˜ƒPŒ®vÕv3ø?àü€Ÿ7Úýù‚|½oû–Ѥ©ý'-Ý0míx9‡ËÓÇáð…8ã|#6†‘a‘‘!oXˆ7b¯c¤“}nȦ^éæM²õëyëÖU ‚‚D`£x"H7l¬U$Ý$ÚÌßÌ]¿ ƒ¿>Xä¿V²ncÛjÿvŠù5< ƒ`\¤Ú3–äB|¾ž©¬F…Ø[àô˜Æ†YÅ™œ6僌¯šÁø?àü¼¡~èÈäëµyÛ€þ˜¬¥ˆÐv}½3ººi8ýBCŽ._Ç WW?C_¯§—ÓËÅdŒ¯™‘3>\Qÿчâuëdþ|ÿÕUkoNŒáDH”ŠÖÜ XÃó_ËU-$Ÿú×øÊßyG`„ÿÒÐ0ÓÐ ×ÈÛ0¶í|]\®..çúLì] q…ÚÓÒô´>ך5mÊê+Àø?àü¼¡~èÈäëµùÿÿìûs”ÕÇŸsÎ{Û Ù DbT.’!j rI@É@;SmÑéXu´íŒ3TÔŽÖZDZbÈmw³÷ì-ÙÜ6Ù$@3¶Smÿ…þÖÿ¢Ï9›„ÉnâèèÎ>3ŸyæÝ…¼{Îw¾ß¾söMò½”o|Æf½ð›’â+\tizÀ*2m³À#§-`³‚H(°|–ÙWZì,-éÞ¹#ÒÞ>÷ÔÓ7OÿäÆÉ“©ï“™ŽŽë ¼H:=uêtçÓ§Sgn>ujîdÇ7Û¶cqï²Y}¦é¶L¿Í Øl>›Ím+pš·ióá^0Æï)´]xÓ4^(.>Cú>¤éCúä¨>ù‡òEùúÖä{8¡óWm懥%}–åpê¦O7=júLÃX†Ï2<ï+\ç*)ê)]ßÙÖöuë¡éÓ§ÿuôØd{[ª½}òûoÞ6ÓÞ6‹³­=Õvb9~"uüÄ̉§æž<ñcmߔڻ-«K׺9ïçÌe>Óô˜¦Ó´út[¯ŽSmGðÜ…©]ÕµLãu€¶Ï.}Cú>¤éCúä¢>ù‡òEùúöùÁWðrî%¯½ä€WJK¾ÐD@·iÅ„æÖ§¦“k§`ý_| ìÓŠJ÷ÆÙcǾjiM=:ýÄ‘ä‘Ç#x/>1ù]ÑÔ4zäÈôñãן|r¶µuì`ÓÈÁ¦±æ–©“§þ³§>¹ac?—¾à¼ÝÐÏÁÅÁÉXã_‚èœr;¸…Cxt¼géç‹ Ï56f:#}HÒ‡ô!}~œú™!ÿP¾(_™Éë°·î‚/¼iÓ¿@ôêf”iàÌ¥2pàrqqoUõð†¹ÃGÿÙÚ2ÝÚœlišhno:8†Á—ßMÉ–æTkKª¥yª©yª±i²¹y¦ùÐ\ýþÙmÆ ¯áz:…pbÇE—s‰‹±>Æ®I÷/€ƒÏÐz>æpAð—w<ô6éCú>¤é“sú™!ÿP¾(_™Éë`ˆ3X5øHcWTµuq=à–¾G÷`‰„tÒpæÆŠÉy?‹ñÎÂ"gõŽdë¡7ìŸ>°Ù¿o|_ýRÿø(’¾^Ž‘5q°ao^_?±o_²¡a¦ñà†Æ¿høêÞÊ`‘üãvWTz¸æá‡.çàårÁ²«` 0ÌŒM=¢q7ÀßÞxÑîxÃüéCú>¤é“[ú™!ÿP¾(_™Éßàóþ—ÁO ô …æç:ë@'yÑ%òâ¶ , €TÖu·<`b׎ð®Úë»ë&÷ìÛûØøã{&pâõîGGêI.Oî:ÑýÀݶ[`àç€5×ÏT VîŸ@@×£šð0Yâ?xMèçÞýý,éCú>¤é“Cú™!ÿP¾(_YÉßðÎ…d‘ùR‘ù. è7ôã~€>啾; ³!ãá“OÉ€S7‚†îº§¤$P½=±³&þðÎDÝÃc»´v¯wízd×ÈòÔ¯‰Ú]Cµ»×b®Ru»gkj’›î‰!×)ËÝBó -¨¶€ 8„P+wï‘00Ü‚_ˆ°`~Cï3ô¿œgüµgϺIÒ‡ô!}HŸÒ‡È ù‡òEùÊJþ€3—‹Í×¹< ú3ú^A~ù]1Ñ¿bÀ/È`@ÓC¶‚˜n b!ÆZ^æ«Ü4°ms¸f{lgÍÈΚáUÃÕFªNc"$Ÿ—GKɧO®®³])³;++|[ˆlÝÞ|øþÊ^oy`p¹9¸espõoõÀ}8C›Ê}ÅÅ.Óè弋¯zÞÅ'[/ ,,O®CTƒhúL=þÒw+ C; ënݸ¬é¼±³ö-Ò‡ô!}HÒ'‡ô!2Cþ¡|Q¾²’¿`Û–W~ðÞ:­¿ØŠÉ3#- ,4Ð5õ£Ÿ}Á™6–4™aÄt=à‘È$ ª/Ï]ø¼Àìµ—ú+Ê#‘ŠòÁòòPå&¼¬Ü4xû VV+î ¬vVï½'|Oydƒ=`³ð³ºÎÜ6+Ý¿=éÖ»ÐÑqI1…<“îç‹À-„å³>¸Av‘s€ÊûÞ }HÒ‡ô!}rH"3äÊå++ù[6–='àUjÐ¥1¿Æ"œGd•TFa·ÝzèÖÄw”ó<÷Bþá ›ústeö¸Ã-³GŽp™#ì( •9Bjeþe§ÝásØ81K¥v/Îõëƒ:÷h< ó€`~lê—57¸ìÚD$ Í/Œ9e8N¯fÄUüšðhZ'ÀÎ[ÖYŸï&éCú>¤é“+ú™!ÿP¾(_YÉßP昀€.´”Æbœ ©¢´ÖH« â…€°Î£¦µŒ¨ÍŒÆŠ #ŠpQQh@f ýȺu¾y BÄå!¢i¸¬¹‘Öc0ŠP^÷*ëc\KÔ„ÏÏÄàmËzÞíºNú>¤éCúäŠ>DfÈ?”/ÊWVò·8ìgoÀgÃ1Š® ^DSJƒ¢M à ˜zÄІ2ô€¡ûÞ|™Ñ5oYUyÛ9.O“>äZa=Kà—‡_2Xî5}Dmpï¹4=Ý“¤éCú>¤O®èCd†üCù¢|e% €½ôKÒ`˜3ôG\Y$Æ×@œ©É•5•Sc؃¼múÄJ]q¯B“©wBwƒMwñ:}È¥H×ße°Òz8ŒqÀ½¨=îQ°ÜkÚ8À`JyÈà×>fð.àê•Ò‡ô!}HÒ'Wô!2Cþ¡|Q¾²’ÇÀþó…t ù{£FÐ7 }3¤b°TãL“Xøþ¾ç<ÆyD1ÈEh¼VmûnO ‹/Õ}$w¿“q=à ˆÉgb¸OÂS¤MŒâÿÁ¤¼à€_~~)Nú>¤éCúäŠ>DfÈ?”/ÊWVò·8ÏÞ4Í$ÀÌûxhÕ3Áaa0Τ½ÐyÃ*ECiC >,D\•àK>*ظ`É;¦Æ'5>sñuç1¬æ*#‹Ÿ«>"¾ÒzŒ ¹‹8caà˜ð8°„&fÔG41xßb.~%}HÒ‡ô!}rE"3äÊå++ù[ÊÊžpŽÃ*QMZ "’¶rb¡Ñfèæ)  ™ŽP:KjñÐêþHòމ÷Q¾ŸR¾Ÿ\|>0¶ø¹Kî¿ÜzdÆåg±¨üË8þì&@ `L~QïVž_6¤éCú>¤ÏS"3äÊå++ù[6lü™`/rx_~n>³Ó |¬œ4¾º‰nK!¦Ù|‡S` ÆÕL“XÂè’½5à~|bñýù,“9ºÐ³åiÝÊëIŠù Ç•ûãê>X¯çfdæð1ƒ·,ëì¥KÒ‡ô!}HÒ'Wô!2Cþ¡|Q¾²’¿ ªú%€çθuUÏŒ£}g9ÜTè˜äêfRÕÊ”òVúbò.’·s§õ3ÎEVµ&Ý?)æ3œ6¤"‡k˜±ô¯›SÉÁÍ^øÀo7l|Ùë½Aú>¤éCúäŠ>DfÈ?”/ÊWVþÿÿìÛo”E†ß™ù»,`QBôÎ$^(/4Ñ £Fð@ÄD‹XN‚D œ Ñ &`DE@ÀAART"â–v»ÛnôDéV¨(.Œÿ„3óí¶¥Ñ=Ô vÙ7y2Ùn»ÛÙ'ï{ñË7_[¾Àý3^WòE Za¯2úJŒIßm³!þ9Üœk4“þ†aAôêõ§a“qNk–ï~„™ÈÓs|æôï+´ 4ÛK`ß |¤”.ÀÊ[o[^[ÛL?ôC?ôC?¥â‡d‡ùa¿Ø¯œ”ï°tùA߯X¼§Dí·Ašˆ´¸R Qg.‡å³b¹¨Zõ«ÄiÈSù¢ؼ$ßýÔKijš³tBœæ`_&úI ¡‡cßýVa—ë×HgÙ]ÓÖœ<ÙA?ôC?ôC?¥â‡d‡ùa¿Ø¯œ”ïðñgÝÀÓ!°ÃUÇ"^LOÀ6%qKýÈàþçZ(:©Që<‰«YîU˜«xqqi; úùÐ4鿉¨ïص²òžû6ÒýÐýÐO ù!Ùa~Ø/ö+'å;˜Ç\wmØßcþ_ˆJ“û$Òq‰Ùä¹f'~5±L ó'–ÿ~„‰~ÂABš&˜X¤Çß6»6†Ý:×9 ÔK€g}âmú¡ú¡ú)-?$;ÌûÅ~åèÈ5ßÁ5dìøùÀŠHxëNøªE¢U‰B#…И•‚Þêÿ"ѤtÍšPæTŸ&!Ð*Ðn‡àƱ¡¨R€ ÀBzfáÒOè‡~è‡~è§´üì0?ìû•²~d§T¯úÞGé‰ðxØÜþÒdïIŠ ù.@ÃÕüwÌ«’6‘yRÈfД)@RÙHƒ~¾] æÝâãÇœQj?°Þâo^°ùSôC?ôC?ôSZ~Hv˜ö‹ýÊNY›jÆŒ[ê¨×ù8â{M0Œ:tæ`Ê‘©MŽÌåUCpâ_âž~íp‚7iÏ›Ö̯Î5,ýÁ`Æß ±ñãëgPWuÛUû¿HÒýÐýÐOiù!Ùa~Ø/ö+;e=h¤÷8ð2ð†ëqT½½M¤×œ“ö¦rY¡Ä27‘œµ1ê²k[æ¨\ðÝfûÁš“¶Éç=i–朹&s6®Ùî\S¯œÇýÆí…×xîìªþîûvú¡ú¡ú)9?$;ÌûÅ~e¡Ü€;§/3_ƒnèpB‰n)ú!’P CÈFˆ`ˆìÎ œèåà"Ìɹö"AOÌö²—9ý¦'xÈ&ÈVÈ]ÚåÇ„úØ TN¨˜óÒ‚môC?ôC?ôSŠ~óÃ~±_£¦Ü€UëÂyÚ o€øâWõçÍ€«; Co¯‚ÙÉLtôÏe Ð\Õ*¾4Gßì§h5ÑfU­Ž•òs˜¿þûÔ”) ¶n=J?ôC?ôC?¥è‡0?ìû5jÊ}ÐŒ­xÎToG"§í%0“r{‘«ÃFªuX¾ƒtg PünG1¬zWÒt`pc&ýéO”ò„2þVsg<°îð×1ú¡ú¡ú)Q?„ùa¿Ø¯ÑÁ`æ½÷½ Ì6†¼o€¨‚‚û2ôÂ|ÙeA’º†ž$xæZ¯ ]Ê<è²›ïM#:•JQ+åN`Ù¸±ó^¬|—~è‡~è‡~J×a~Ø/öktp˜¹u»žzgzÞãÉÓ¯G"\~±¤lzF&>¯AºŠfÕûïUè•è“fç™ý‹¶p¸QÉCöÜÂ)SªÞzëýÐýÐý”®Âü°_ì×èà`˜:ý `%ð¾+jÇ8MÊDç× ¥©Á°ȳ¶=v²LY‚A¹HÖ ú)½m™îpŸ‹EÜSÇÝÀꊊªY³j¾>šïõ/ú¡ú¡ú)N?„ùa¿Ø¯QÀÀ°zíOJ-šP±Ø%q\¡Óæ>(À%½"Ý賃òÅLúŠcí ¢T×6¡G‰fGö5R,š<ù•U¯í£ú¡ú¡ŸR÷C˜ö‹ýÒLšôŠï¯•Ø¢Sr“®IR2Ñ¿ TDþÖñâœ]PЫ<Ñ\Ò\H ôÇÚooyéUrÀzógZÂ~Lɯ€mÀŠ›&.š=gÛÁƒõôC?ôC?ôsø!ÌûÅ~ €4ì8︕R®¶Ü2©%ÒJ*¤\ü.ð[ع›0ÈnS¥ p&^¿Ylò.ÇzA =”÷;ê¢+SöÿbÔ…¼ãŽØ-°ÁQ•·O®Z±|ýÐýÐý\~óÃ~±_…Â`ˆ»ï~˜ë{=ÀIàŒ¯zÃê2̵¤?|ù§N˜|Íl u.[‚!x HVÇÑs¹ž†S®êˆ+yÂs(Yã8‹'N|~æÃköîýŽ~è‡~è‡~®?„ùa¿Ø¯‚à0Ä/zo¨xRª݃?z²-¤~W¸â;éxA¤ º-ƒøÓ` x°'öôßå¹g}ÿŒ£ {ñ+™7uÚKÕk?¤ú¡ú¡ŸëÉa~Ø/ö« þÿÿì{pTÕÇ¿çq»›I†—¶Sý§2Ói;¶:Ó™*ˆV¨¶Ò`L €J@)„g€R$¼l´¼¡äýH%V#PÀABؼ—lBÈÛžs’¥ B"“ä7ó™;»wÏ=»û™ïïßÜ{ýÌ::Þ×»Àã¬g涸^Qhጠ:‡ŸñY‡!Aœ÷ƒå1ø9N‡ §Ìj˜À¿<ÞO<ž­À<³Æ¿G»û»Ç÷xuõšmä‡üòC~š˜‚òCõEõÕp¨¸‘=2@eE5Á>ßÊ7ØkÚÊB ˜#±SÇ ³Â¶Ô/äâ„9I÷‰ãÙm9«I@_oT÷'žò§×ïvñ;ù!?ä‡üŸðôCP~ÈÕW¡àF–¬ÚÓJÕÀ@°9Ñ;ͽ¥ %Ê ¹J¼<ë(¬Ï ³!r!ò9Ëaç9Ž›ÍìC@øF°…À(OÄ€>˜Ô=qÊÛ‹Ö“òC~ÈùiÂ~Êù¡újÔÜœ§»Lëj‰dóàèe>k¯¨yìE.—eÂ9 øu%xòôŠ]5pä…(š"‰€Ä‰ ¡Œ#È`(b(‘Â_‹ë;ÕÈr† † ~ÍN3v² [ðÇ*µÕOb%@±`³\‰}¶¸|‘%ROŒkó|×øQ¯Ï^L~Èù!?ä§Éû!(?ä‡êë¶PpKºt<5ÖkÍÞ±‘¥ãžg–½€ð<¸ùp ÌepµáÿG7ÀCÀpÆ`5•pC1ÔžªÈŒTé¯b(3ãýŒ2Tß‚·@åÞP`ÞæH±±]b¡ÀDŸÓ¿mÛîžz)õµ¹;32Èù!?ä‡ü4?å‡üP}Õ5õѱãD³ æÀõ1‘G¢|~°Ü2ð3º F¾ðV@¯‘¯&`¨iÝ W—Dh«3 Cœ©K îÛ`-ôÌ&è×'©Ž~!ô·œâ¨`%ß)õ™¯±/·iÓ÷ÉÎCÆM™—žù1ù!?ä‡üŸæã‡ üª¯z à6üü±T W¤ûGŽùÀ É>”üy>v®I^‰ã^*BœJÕN°3`Å`…àù†\ƒß¯èaõs¶VªgãÅ=­Ê})GGeuýè{ôН“åq3…ܸJÿ(‹õnÙ²×ã†üæÖîaïK~Èù!?ä'<ý”òÓè1 [¨¸=¿|fC/`ˆdi¶X%±ÈøÜu‚ŽT),Î…¨4˜J`%¡àæ›Åòæš9ßD¹¤.¥·¦¢PS}”®ŠJŽóÕI”yD¾J¿ë¤ƒ/fªß öÛV­»vxrਠ³7¥ï"?ä‡üòÓ<ý”òCÜjD|üü–-“ß“¼ÖÊhO†Ä^ '¼¢˜é3S*ôç¿R¦å%úd™Ê®q~ ÕíìõŽö–`jCÏ /Öó°ÒPœ¨(u絎Ú|;ð60ßú¾gŸèÜgÜÔ´»¶“òC~ÈùiÎ~ˆú¡üŸæ 5 eLʦvm“€D`T„³„c-°#JóèÛQÁ*Áª4øBÃjS^©å† D¢È0ùV e†`ó‘Ïͼš2Æ‚%6+8îʹ ø30x©E\¿Û÷y®[òÔ™iä‡üòC~Èq[(?ä§B À°v]Á#?Õ—Ä9|¢ƒ¹6–E¾Rœd¼ˆñã%Œ••›bP•p©v ¦t 0“{=^gZRÎTßÌ*õk½GW‚SV3›ª1µGqÚÇy@°]û=G¾Œ^ðEwûñ£ƒžaLêk³wdì ?ä‡üòC~ˆ†@ù!?Í jî˜Ä„Å ^‰´§Ó–[¥åñe3~ܬ)PM*PjË«Àè‹Õ.êìšy{¾ú×—Êé“Y¨¹ í¢Äe† fOC9綨°­ æó/÷¸¯7Ûu÷ ¾XÂØ|`0ÐñônÕ.ñÑÇ’’GÌ~wÅFòC~Èù!?䇸S(?ä§ù@ À×aéb«¸~@|´£ZÏáÀ_À7Ønºí|dÉ}Rf ž äJvVâœ`—$ÿRŠÿHñ_U—.|!õö’Ä+W®Z¸¦^ÈšO+%«°y¹‚£\ Äæ§]ë°e¥3±x f²O‹ØžßÿA¿çâÇŸ²pݦÝ.‡üòC~ÈOØú!ê‡òC~š Ô|}¾¼è5Ȳ&¨V˜¡+jçÁ?ô:YÀa (æúQvU:îüª+¾´pÑÂyGo/;&÷®Yº6ôõsUª<¼Â•g½²ÄkùDž 5Û.`©YçžÂ­dÇ××Õýþzvè4,ihÚ»K·6ºòC~Èù Èq7P~ÈO“‡€»åWÏNóEö…ì–Ìe cSY’/Þ×â`Lä±÷¤¥Ÿ¡ý¹A?;ÃFÀÑ”8:(3”«­­÷¨ýy;-ñð)°ø‡Ä6‰Õ\¯sW“' Ù;"º[\«_ÿìñ½^œ<#ío›·ímtä‡üònân üŸ& 5ß ICÖÅ|;èìºýcb&>  Ìþ ü]`‹%v»ÖGgŸÏsÐb{,ì7´ðoÃ!µuŧ®ÜçÈÚ2]ðÍŒ­V ,Ìz¶$†¯÷7ß{ ¡C§Á=GÏœ³êýÍ™þßÉù!?ä'œ!?ÄÝ@ù!?Mj¾IÞHËxø'#TÝZD¥H>Ža Ç,ËzËç]æñ,gl± ´à«[-±F°5k[k¶k„Žû"èGîMªKh´nyõ£øz´n™ðÐC½ŸþÅW†ÏZºlK£ÿYòC~ÈOXA~Èqï üŸ&5÷„ÁɾsßÐoÅµä  ¿ 1c)–“ L^Ÿ¬Ð'Ëø4Ʀ…¶Smg*¬5xè §—Õ'*.¡}ûß=ÓeØÈó¾óþ¶™þïÈù!?á ù!?ĽƒòC~šÿÿÿìÝPÔuÇñ÷îw‘]@µc©AãÝYR6§iµÄ”`ZÎ)°€¡DËòSµ²ôÌÓÁXÇŸx3Úas5^¥eVvv©)Á*¸,첿Ã.,â§]眹n.µ«ûšy ³|÷Ÿïç9ïïïÙY,·ÖŽ]¹¹ÿ!qsÜ£•“cJÆF½B´˜/ȼjÉÉ#ÊF¤GMȘôÐË¿ªxaú{yÅõk«ìÝ÷ù‘#'ü~ôAŸ@ƒ>èƒ>à/˜ô¹­aøU5ü¾NþÙú ªªëË+ä……[¥ÒÍùù[¼/JJkÞªÚ»~ÃþmïÚÿÁñÏ*ü~·èhÐ}Ð} 0a~Ðçö‚ ˆ`"X‚€ ‚ ˆ`"X~=µòïþ,ݹ`áúä¹ï‰ç¼=}ZQÌ䜘)Ë㦿öL|ùóÏWV¬nØZ{Ìï÷‰> }Ð}Ðæ}n;Xn!¹ü̲e»'=ð ÑsD/ˆÆd‡†¾L”ÍQ.ß÷óx¯yßZF´Ô{‘GÙDé|~'ð¹´ wç&§l¯Ù¦ñû)Ð}ú ú€¿`~Ðçv‡àæ+_Ù0#®(:b©ïGïhy˜ `\DÅ„È5Ñáå"NÆ£\_Æ ŠB¸"NPÂð9Ç+ ž,L¸*$¤TÀ+áóKÆpeÿfôµý~.ôAŸ@€>èƒ>à/˜ô¹c`¸i¶nûföìR¢yÞ¹RÑ=ÃiˆªETRuÿøu?´iöãµbq]|BMü³ïÿqîöÄ”]IÉ{žÝ+NØ3G\?=N>푱1ÛÇÛÂÑ:¢jý%T°‘¨€£¼(‘tæŒwß©>å÷“¢ú O Aô[óƒ>w,7Á éß&Ǭ J†¾zoô›DÅD+Çò6M¿;þñ#KS›¤9çd¹§«×*pýø#kV²sL©a:Ÿ ]¾+g¬Vî¨~G›'=—™yò…'ž~òpÌ佑á[娒¨„OùD’ȱÙE…‡ü~jôAô èƒ>pë`~ÐçN…à†T¬ù„/XÈ£ÂÐ7BÇxg´BÈUÿ.¶~^Ò·/¥6å]|·Rß°ÿ’¢‘9ldˆ 0³™ÌÖÏ\ÃÌs™ \b}?1K/3XÙàb6;;{–Õïé[]Ö˜³üË,É׉ωR¶Q$¬â¨ôÊ·è–N¼O*ËÿÈïÐ}Ð}úÀÀü Ï ÀuÚ±³ãѸÕDéáa%tåãªð°šxñ×éi’´……M;w9ÏŸgZ-s»Y¿‡ÙLo¼l4]²9F-Ž!«k¸·´w¹¼o¹™Õ1j°^¶Ø˜FÏt:Öëò=-F#û꨻vk{šäXÆ’æE‹~˜5ëãqwm"ß3 ã‘ÔûLš˜'—Ÿ÷{ ôAôAŸÀ>p#0?è °\ùó7q¼4¢ïÓ®Ò)“>zâ‰Só_TH²‹ËÎíû»Cq‘Yܬo˜{‡T:‹ªÇ¤7º­öa›uÔd1/™MÃã°Åp#0?è$°\›šºO*%Ê ) ¡ÊèðÚ™3¾L]Ôž’|r៎¿Y¥úâ8Ó˜™ÖÎÚz¬ÝV³Æ¦ÓXµÝzmg·AÕmÓê†lfÒzFtêA­z@«vk5N½¶× sôv£Áá¥×:t=vïE“Ám6³Öft²“le…"9埩‹Ï¤-R>=û_÷ÞµKÈ_/äʉ$ã£_Ú±« }Ð}Ð}Юæ}‚ €k“ÿñÒDaeD+#DuSc§$©–Hz^œÿéªâïÿqp°MÉÔÖ¢dç/ tj:4Î]å¥vªÔnU·GÕ5Üõ?]åñéîÿŸº<íƒ=Zf±±ö¶{·>3ëðܤOÓ_XÒ>gæi‘ ŽhÕøÈ·CCV¤.Þ‡>èƒ>èƒ>è×óƒ>Á À/5}V'ZùQy샇.<—ر`žznÒwo­m>x@{ökQ°ÖÖÙéÔá¦f›òbïU.e[¿²Í£l¼Âsõßÿÿ·­Í¥îîkm145™[[Gš¬áÙ¬IüÔg’TmRBûcÓNþ6ö(‘÷Æ^Ç‹ÿŠ>èƒ>èƒ>è¿æ}‚ÐÏÿÿìyTSg‡?T!aß4Š R-VGëLm;ÓŽKÇ QAEET¥€¸´‚ŽZ­`1€$ KØ“²@ da ;²¨ˆb—éLÏt¦™›TDZӡÑ3s¦Å÷œç¼ç»—{¹ß}x¼‡C€@/¬ÈïÍØˆP¨éŒ4wö{¿½üºtÅrÙª·##Zj«4bÁߕ͚Ž6M‹ê;™ì+Yó#¥j\®|ðÅC¹b\®x,—¥[|¨GU(ªÛÇ[”£õõÃõÒÏÕ]U›æúgßnÝÚö«¥’ß½Ýÿëå]+–¶y9ߢ/ íçd­vr ?àü€ð~€Ÿúü¼šÀð°J»LÍßš>#dŠánc“T_ŸŠ7—·¯X®üÍ[Ò%Ë8›ÃDR¡©}'®ûF.û®Yö¡ðP4¬P>nÞÕq_ÇhCㆆÇ:°Å˜¾HG¥’»mª/ZT_ ÅÂ?I5ü:MA‘æƒuò߬”-_*-Pòö¯U´RŠu:BSÐj¼Õð~Àø?¯²`b ÀÏ« ‘ÏT"ŒÍ”¦¦G §žôoZ²¨««ß³tYùûë8\Mÿ;þí¿Ö×ÿM,þ¦¦vŒË•6}ÙÐô¨–ß_'Ö"©ß«Ö‰Ö‰ÆuuL{¨"Ѩ v¤AøPZÿH(~$}~[ò­@¢á 5Ÿ\Õ¬|³fa`EðbÑ’E’…þÜÅ|s㓆(š€‹Fh9³`ü€ð~ÀÏ+è€þ?ÀÀ0ÓM—!ôît£¸)è$Í[üZ@÷Vÿua€,0°jÕ»œ?^-®þ’U>RÃ}Ìã}ÁãÎå=â ÆÂ<ÁHUm÷ö Ža.ÿ. .o »@[±5ÿžžðy£·¹cÕ#•ƒÚú‡Õ¼ñJùšÊjMüá%ÁœeK…o,®k…ú5ÿ_®ößæí"XÄ"´ü€ð~ÀÏ+è€þ?ÀÀð±Ä¯ÂY†MÛc€’–½Þ¹xA¿ÿœn_Ù›ËÚƒ‚J7l®©®ÓT •󆫹clöPqÉ?Ž57«¸“U¬®åp*útôs*îpÊG8å÷8œûZ´ë!½©©/+¾WÂ,ã r*‹Ëû±Ô•VÁ*ý–]¦ÙÞÀư<¸Ãͼ@=ß[ˆ7»ŒÐS“8Üÿêwaàü€ð~~ž~èðùš~¿ùû¦®E(ÄÄ(y>­.8¨oIÐÝZOP@[ÐÁËJ?Ëù[~уÝÍd·Ýdª‹‹‡KËF˜]ùŒv»·”ÓÏ.éawck»ŸÅ¾Ãb ³XwYE÷µ•5¨=£'¬á’¢‡¬‚ÑÂBí#*kFÊ«ï–tÓ™ôü¡’rÍÙ³‚.ðãù+–-^8²x~op`+B‰Ó|`iõø?àü€ŸWÄý~ _? ?›+ÓHä}E˜›¥zº•Ð|$~³[ô¾ ö£‰æÍe?ñðzö×9ùwsougçÉ=Œ‚~FA¯ŽžçéÕ~‰y‡Áb0‡Œ»Úª]ßÑ›!fþ-Œa&³ŸY f¶bäªéŒ¾\æã›ùš˜˜~7*#Яy¾Oç\ϾÀ9ó}Ûüf‹¦¦ idüÁÂE±àü€ð~&½úü@¾ô€ŸoŽÛ6uê~3Ó4w—¢@ÿ¦y4¥góßæ…òÙ¾åK–Tœ<5ž™õ87ï~ÎÍÞlz=·“žÓýŒç{é9}tú€ŽA:}XW´'õ„>˜“}OËÁzoNNGN®Šž§ ç©nävæ2ÜÈùæ`ü­ÌŸÖèçÓEóè[0gxþì.ÿ¹ ²5Ë0Bá¦fkbãòÀø?àüLb?ôø|é Ï‘•Ýh…_ƒPˆA2Åæ¦—ß×[êåÙäãÝC=è¹® éê‹é­2ZÎg´^¼Ø“vª'ýÂב‘n®l_Ÿz¬ï©®|wÕUàå%us½íìXfg“‰ÐlŽŽ.?àü€ð3ÉüÐ?/È× À3HÄpÃF† Ö¤L笇œ¨õÎÎJ//µ»‡ÂÞ±ÚÙµÐÃëÆÁÃçÒÇNì>}²ílJë¹3gOuœ9=!gÚu´>O»~Uuæl3ÆÙӭ؃>JëÄ8—Öq.­ýlZ vArJçéïÜ5äêqË݃KuåÚQKÝ9Øþ]Ý%޳êœfñgQ NL3ˆ¤Ø„³ÙCàü€ð~&“úòùz!`xÂêµúÃL“£3LÎR]˜Ž®¥öŽ•$[ž­ÔÑ©ÅÅEEuÏrdÑæÝÚ·¿?9¹?5Y˜ MMl>•Ò’’¤Jþ°õÇP=E‘œ,ON–=E®åû“?]eI©âäqʇ2ìA©Ç;Ò;Ó°z¼õdRKò eò‰Î¤¤‘íQ}nž ªK™£k9Å™AqeR=¸Ž|;‘‹“ÔŽÈ1Ÿ~ÉÈ`ÿ ãMþ1àü€ð~&úòùzQ`x*Â`Î"Î}H&ä:¹°]Ëì©56v<’L®§P$ö|{û"ÿ€²˜˜Þ„Ã=)I]‡âÄ'Ž6¦žPKPKPþŠ'm>v´I‡TW›õ'áXSB¢»1ñˆ"ñH ÆñÃÊÄ#Ê[±§$è?<±­×ûp•íà\fïÂ"9Ø9UÉUvö"/G ßžÌ25L1@[M _æcqÁø?àüü<ýÐ?/È× ÿÜÿï;ø9ðúÒã­64<6¥ÛQÊÉ”R’])‰RE¢Ômx¶Zj)¶œYöE~s+¶†÷ìÛÛ{`KbBë‘ÉÇä‡âšTLHóóL|ñ¿£Š;¨zò}â›â5ŒoÀêáÅî}²˜Øö¸øûÛ£î;S lm íí8dÛ*²mÍSj±Ík÷oS·ÈFè B[-L?àü€ð3 üÐ?/È×K€qÌþ:-ûD{âdÛ£¥Q1±ÆÖ­ër°c’­ lÉå6d.‰, aÕ¦ú{´oaSéhW9}<Å,w‚ð~Àø™~èÈäë%€`Å®˜›½cd‡P*6þÉÕ"O.%+0ˆÖ•Dë ’5‡DdÙ™$BÖ;«wEõÆìl‰Ü&ŒŽnßÎÛ±CµCµ£^¿ú”(©^5ª)j»\ ¶Ø!‰ÜY¹‹÷„hqèVqxdkôî{ÁÁu$ë\,ÀDB ѺšH¨%+u¯ÀÁÀ^Hä¸8ÖZš_›Š!ôADD6ø?àü€Ÿ_´úòùz9`Xáæ¾Í`Êc“£–V™BñL‹b¡gͶėaà­8x«2‚U _DÄßÄͼ´ *jû@x˜,|K£l. ‹à…EÔb„nã…FÖo® WmÝ6èá^„·Ì¶Äåc[Õí¹B·ÿK/Á°Æ“ yÅO7Ž¢:m?àü€ðó‹ö@ÿ@¾ _/Ç«>\Ë’ÿÎhz”±q‘”gfV0Ã¬Ø Wdfyk¦üØÂœ3/ÂY0 –7± ÒÝ%?<¬wíZÉ–0鯼 jBB!!Â`³èElÚÜ %D²)D¸)”¿)”»1 ƒ¿1T¸v½xÃæÖ5kÛɶ7p8, ¼e±nÏX’‹fânÍÄ1µÕ¢{ 3S¦¥yB‰V‡¦My;ëºü€ð~ÀÏ/Ôýù‚|½4ÿÿÿìûs”ÕÇŸsÎ{ÝìnH6‰QAä&DA®¹‚$\*-u:VEmgꌵ£UÇ:¶VA Én²ûî%{K6÷+ Õ^lû'ô·þ}ÎÙ$I6ÄÑÑ}f>óÌ» y÷œï|¿?|çì›z8pð†yàT‘ë#Û¾ä.Š{¼Ë³<Ž]CŠ\ˆÛs»œž_‰QyËþÆ¿Øí©§¾>z|ôèƒ'ŽÍcWæÃµcǾ”¿vìÄØ±#GŸVàÅ—GŽþõèñÿÔÔŒ/hòzÛ¼§Øƒ ÆeÇl·c»ƒEp/^wÜÔ.¹Œ ñ[?Ѹ÷=Ò‡ô!}HÒ'Oõ!È?”/Ê×w¦Ð @ù¶õ,Àoнç¹hÒôˆåê2íˆé ÊiGl+Џ¬ˆËr,³µÄë/)n^½*ÑØx}ÿk‡vuß¾C‡F~Hƺ¢À‹‘ƒ‡‡ÄyàðÈ¡#×ö¼¾ïÐ7K—aqo²­VÓl·Ì°mElÛ±ívÛå7%í¦íà^0ÆoqÛç^5g¼Þ#¤éCú>¤OžêC(_”¯ïL¡€½:Ñ6ß/)nµ¬€xT7Ý ªé˜F± Ç2‚ouŠ=-% .64ü³~ûèáÃÿص{¨±a¤±qè‡oÞ0ÖØ0޳¡q¤aï²gïÈž½c{÷_|ï×»¾))m¶¬&]kæ¼³€i8¦4M¿iµêöe§ÚŽà¸ S» kïšÆË Ÿžý†ô!}HÒ‡ôÉG}òå‹òõÝò£¯àGäÔs¡Òâ^()þ\Mͦ•z˜X«š~Iü‚µ|ð °O**Û·TïÞýU]ýÈ®]£íܹc`Çö~/ðå®Ç†¾/jjzwîݳçÊã××÷m«éÙVÓW[7¼ïà¿×o¼cag>çü2º C€ƒŸ±Æ¿qpÊíà: pàmKÍã>U]ëŒô!}HÒ‡ôùiêCä†üCù¢|妠 À†µ§uxàU[ÿ pY7“L‹Ì€€`• ç¼ÞËËWtoÙz}Ç®¿Õ×Ö×ÖÕ ÔV÷×lëÉàËêÁºÚ‘úº‘ºÚášÚáêš¡ÚÚ±Úí×7n_zÊ径ë¸(„;.ºœKŒµ2vIº2CphøÃiÁŸ_õÀ¤éCú>¤OÞéCä†üCù¢|妠 €!Ž`ýÕàWÕ6Àõ(@»ô=ºK$dБ…³v¬˜œ·¡±¿èöøW¬¬ßþ¯­›G·l@6oêß´±Ùøh/’½ž‰žy±mëÞ|ãÆM›·n«Þvukõ—[¶~uWeÔ#ÿ¸Ýy€®¹pÐåB\.X–`Œ†¹ƒñ¨©'4Þð€7ž-õ½Žþô!}HÒ‡ôÉ/}ˆÜ(_”¯ÜnpBÿeð„K?í6?ÓY3:)„.‘7 cZ‚ ª°®·Ë&vÉ狯©º²níÐúu}étýN¼^÷pÏÚ‡2¬í…̼ÀÛâ=×>Ü»aýðæMW7n¸ZU5²|y¿e·ryrwݼ]Ãv+" °憙*ÁÊýˆèzRA&Küû/ ýÔ[¿'}HÒ‡ô!}òH"7äÊåkN ·¼yzÐc>ç1ÿ Ãm†a< Ъ¼Òú­ÈlÈx8ò)ðëFÔ°"ÀBGV,ˬ^™~pufíƒ}ë긪¯×¬êzhMÏÌTuÏ‹ª5]Uk2Va®FÖ®_¹rpÑI»C¹N™XÞ.´°Ð¢j Ø€c˜µr?ð Ã-„…ˆ 6ôVCÿà5Æ_zòd;éCú>¤é“Gú¹!ÿP¾(_sR¸àÈ¡s^óe.O‚þ„¾×EDX~WL´ÍË2èÐô˜íJéF'b, åeN墎¥‹ã+—¥V¯ìY½²{Õòî÷'X‘y`E×LIÝþ\vbù²äÊåÝ«VôÞw_¦|aܶðs›úžwpá õ•û£j…€¸q¡[àã4Œ€iÚ;Lüº~ÇŸIÒ‡ô!}HŸ<Ò‡È ù‡òEùš“Â-ÖýN‡çN|ªAH0 @ŒðæYVDIŸ1“ÏË£¥äÓ'Šìóe¥þÊ gɽ‰ûÇß¿§2‚×Kîíœiv.Y½ý‰·º÷nœ±EåŽ×0Ëœ_Æâ«žwqdëe‘ÉåÉrHjÌž‚©Ç_Zo€ah;t½]7Îiú»¯¬®zô!}HÒ‡ôÉ#}ˆÜ(_”¯9)ܰtÉ ¿x»HkóZ)yf¤E„…º¤~cÔÔ³/Ø#³Æ’&3Œ”®§‚™„Nõå¹3Ÿ¹ÌË¥%áŠòDEE¢¢¼³¼¸Av†s€Ê»_!}HÒ‡ô!}òH"7äÊåkN ·,,û…€9¼¯A“ÆÂKpžUR…Ý v è¡ßQÎ rè_²¬4éóÅË|q_Y¬ÌS3ê+ Ï8K}ޝ4‚³TR¹`ATçAGt,ŒMá²æFg\ƒ$ƒ ƒ®‰…1¿ ÇÒŒ´ @XAM»ðÀk–uÒq®‘>¤éCú>ù¢‘òå‹ò5'…[Ê|Є–ÒXг.uB”µÑ<iµN¼×yÒÔ“–‘´Í„Çò¸ЏÇ›$’·;Œ9¸bïÄå!’Y¸¬¹‰YÖ“bЋP^)ëcÓÕ„cÈÇç?`ð†e=ݸBú>¤éCúä‹>DnÈ?”/Êלn𕞼9]œu¤@z(9/@zM) Š65D 3`ê C‹ZÌÐ#†î(B“8¹ÑµPYUyÛ9.Î’=äše=Ó–‡_2Xî5½Gm°ï9=-ÍC¤éCú>¤O¾èCä†üCù¢|ÍIá€Ò’ŸO @LƒnÎÐie‘Ÿi¦&WÖTNMaFð¶Ù+ytÅC yL¦Þ‰Ý 6Ý©ëì!—"[gÀlëáÐÇ÷¢NôxPÁr¯iý]€)å1ƒ_øÁ[€ ç{HÒ‡ô!}HŸ|Ñ‡È ù‡òEùš“.¥OM YÈßÕƒ¾é›.ƒy g–Ìä÷ÏðÍ4ç)ΊN.bàµjÛ·"x™z©î#¹õœëéž @J>à ëL‘6 Ћÿ“fð€T~ùÙÙ4éCú>¤é“/ú¹!ÿP¾(_sR¸Àç{òæ i†`ÂÇ]·=3ýLÚ ×­RÔ•5´àÝB¤I ¾ä½‚õ 6ø­©ñ!àœzGݹ«¹ @ÏÔçªH϶ýBî"ÍX8f < ,£‰1µÁ% Þ:€3Ÿ&IÒ‡ô!}HŸ|Ñ‡È ù‡òEùš“Â-ee'œâð® @R“Vˆd­œ™l´sNtó0†a0˜P6Ójq×42êþÈà·&ÞGù~Xù~hêý‰ @ßÔçN»ÿLë‘è—ŸÅ’ò/_àdø#°k#}ò‹z7ðôŒ }HÒ‡ô!}~šú¹!ÿP¾(_sR¸àŽ…Ç{–Ã;ò;påcå¤þۛ趄Ã(›èÐ} ŒA¿šY2Óèö¯7æTÔL½?уe2{'{¶<­›}=ƒb"Ãiåþ´ºÖëëc2 øÁë–uòìÙéCú>¤é“/ú¹!ÿP¾(_sòÿÿìÙoTUÇ¿çœ{çδÐE¢o†`õA¼ð  5bQ#&RIJ#aßB°,Œ¨„Ý…  [Ê&°Li§3ít¡¥­€ Ÿü'<çÜ™ÒV™™Öf˜oòÉÉtÚ™žùäû}øåžÛæïPòô,à#`eQÁ!Wž¶÷ŒëøF$böNÌåÌÖËv¬¼b³å?ÿ‹Ë}éý”kíG˜ô‡U¢Ãç!ÎÚÊé=TÝf%êlsô‡Ý|,~lÄì#G¢ôC?ôC?ô“+~Hj˜ö‹ýJKþ/[«ät`¹Â^eþô•k$âžÛhC|9Ü´k8™þê^èG¸ïz±×dœ–žšeºa&òÄŸ|ý{£ uöØ)ÝJé,zr䂊Š:ú¡ú¡úÉ?$5ÌûÅ~¥%€¹ z^©ÀJà+%* Üji"RïJ]€D¥¹–Éjˆ¤£êÞª_%.A^ÈýÃæ%™îG J"â˜Õœ¥â’0û¢0Ñ1={î)…®W.yϽ°ìüùfú¡ú¡úÉ?$5ÌûÅ~¥%€oh¦½uÀvW( DôlSµTõî}×¢“¶±Îp¯š¥_…¹Šu•¶ Ÿõ@­þhöÜÛ VB–¾8v ýÐýÐýä’æ‡ýb¿Ò’¿€ùðxÓuW„¼=æÿÕ‰°4¹#—ˆ­A†kj¢}‰$9‘Ì÷#LôcbÒ4Á Ä"1þ6Úµ&äVºÎa ˜¼÷ÆÛ›é‡~è‡~è'·üÔ0?ìû•¦#|!EÓ€……¡=®s 8ç©z‰=& ˆ „š” è­þ/µ q׬1eNõib Mv® +uX Ì”ÁwgÎýŽ~è‡~è‡~rËI óÃ~±_©Éë`Âë;¤úÔ lw”žÏ„Ìí/µöN‘¸ðk ‰T÷åþ0¯ŠÛDfÈ@6ƒÚdâÊv@ôóMÍ0ï-*¸¢Ô~`³y|ÆÆ/.ÐýÐýÐOnù!©a~Ø/ö+5y=¬+¯.:×Qå®ó=pÌ ÔÂ\0jÖ™ƒ +ú§6Þ?—}†àØÄ=ñÚÞøoÒ”1 É_)ªWúý ÀŒ¿~"EE•޳XZ6ò™²ý?Åé‡~è‡~è'·üÔ0?ìû•š¼42ðð °ÞõŽ9ªÊÞ&ÒaÎÀI{S¹¬„Ð"É›H®ÚµÚµ1yTÎÿnýMKãÉä={¨“朹&y6®Îî\S¥œjÇ=éwCËî¤W_[~ú—&ú¡ú¡úÉ9?$5ÌûÅ~¥ ߀gGÏ3MƒnðpN‰6)º!âPÕ÷5þÙ\¸.ÐæÊþE.˜“sMY‚ž˜íe/súMOðµ ͺ´õÊ‹õ3°(V<ùã[é‡~è‡~è'ýæ‡ýb¿M¾KV‡35Z ±⬫ÚëfÀÕС·WÁìƒx²:ú×’hð¯je_jý£oöS4˜è‹³ª'–òG˜¿þûNIÉŒ-[ŽÓýÐýÐO.ú!ÌûÅ~ š|4CŠ?ð —› /ÙK`&åö"W³TC¯|ûhKÀ? ÖóÝælXõ®¤é@ÏÆZLúŸ(&ä9eü-¦Œ{eåá£ú¡ú¡úÉQ?„ùa¿Ø¯ÁÁ`üKc?¦k‚“@XAÁI:`¾l5?I­÷ðŸéÁæA¯- ­ÊÏ“,&!ˆNv’ßÌgvvß<ûîæ3ßï¿yßw_¾dáâ¬øݸø :°„a³Í?vE¶@@ À‘Å*^`Ç ® h =˜3öÔÿ©míwœR,gæà—çïußýÏ u6ù!?ä‡üŸ¦ä‡ üP¿¨_· uè?pÐÉñv}óò¼MÀs¯wõLìõêÊU›Éù!?ä‡ü41?å‡úEýj84\Ϩ²¢†`¿yŒ›ì1cePÄ‘ÇØ)ˆ£YQ[õ ¹8aÒ}äx;-g%0èç‹ëùèãCþüú^üN~Èù!?ä':ý”òCýj 4\Ï¢ûÚ¨ ›³ øÐü¶TD™@W‰—'`u 2""ÈY®ˆ8ÏqÜlf2Á×ÍFx1ïàåá£ænÚ¾ƒüòC~ÈO“ôCP~Èõ«ÐpƤíŒmù’ê€doZØ#»<À« À‚9:ú +V.düFYD°u Ö¡þLë5E†‚Èâ@„¯~ZãÙ'¤Ü ¼ ÌÒÀûïž”žÉ“ß^°–üòC~ÈOöCP~Èõ«!Ðpcžè: ¬»%RÍ£—ø­=¢æ¶¹\– ç ÐMðòô'º5päEÈ—šB‰D±DØPÆæ12äGÈ‹¨Åµje9CCX?g§;Y -x¾c•Úê+± H-°Y®Ä^]¾ÀiŒ'·j÷t÷įÏ\H~Èù!?ä§Éû!(?ä‡úuKh¸)]»Žžl7ÆgÍþfcWœŽ{ž¹ì=äƒçÁ ÂÍ7§Áå׆‰.7à‘0B¬¦ ו¡ö® ÍJ•þ*†2³>ÀØ)CõOðæ«ÜòÍˉÃ6¶H̘àw´oß³ããϧ½6{[f&ù!?ä‡üŸæà‡ üêWýÐP:M0Äü˜%°6!öpœ?à¹!Ë-/ÖC0‚ÂW}|5!CíLëQ¸º‘Gi ¡¸.¡º/õÐ{6A¿¶“êè@Ê)!Žv@òmRù#ðB»výë2dìä9»>$?ä‡üòÓ|ü”òCýªnÁÏNzǺä˜ ,“ì}Éšûcçšä•8îy " Tm+++r CP/ÐËêçL ¬TïiônUîK9*8*«û££Wäøœ,ÏÝ%äFÆUúGX¬OëÖ½éH¢ÌA•~×É_ LWßì·mÚvïøØ ãg®ÏØN~Èù!?ä§yú!(?䇸!44ˆÄĹ­[§¿&ú¬åñ^¦Ä '|¢ˆé#S*ôç¾R3¿ò}°LeW‡8XCõ8{m¢½iL7ôÔÛ‹ô~Xi¤g*Jäù¬#6ß¼ Œƒ%¶ýîSvé;vJúºí[Èù!?ä‡ü4g?DýP~ÈO󄀆2jôúíS€d`DŒ³ˆc5°5NõôÏQ…Á*Áª4ø\ÃjS^©å†0D¢Ð2ùV„ e†pó'µž›7òjÊ K”Ø,_â¸+÷{r3ð`ð|‹Výïùaßn=R§LO'?ä‡üòC~ˆ[Bù!?ÍnƒÕkòü©>%Îá̶±$F¨ðm•â$ã…Œ‡/a¬ ¬Ü”A5áb ìçMt˜É½^¯3­ÞRÎÔÜÌ*õs½E7Á¬)«Ù›ê˜Ú"ò…8m‹ãŽÜ/ØvÏ~בoÃgüñ=~üÐà§Ÿ•öÚÌ­™[Éù!?ä‡ü¢!P~ÈOsƒ€Û&9i¡@’ƒWbí©ÀTEÀ&igyþlÆ›ëcòÕ ”Úò púdµ ú »j^ž«>@Æõ©rú`jNh» q‰á¼ÙRÁPÎy…-*lë¼yË9‹—{nÈçËvÝ}‚o16 r¼>m:$?ôpJê°™ï,[G~Èù!?ä‡ü· å‡ü4hø:,^hÓª?ï¨Ñs(ðWð÷l7Ãv>°ä^)³Ïr%;#qV°‹’!Å¥øƒêÀ%óŸKýxQâ²Àe‰+W,\UOdÍ_+%«°y¹‚£\ Äæ§]ëee0± x ¼Èdß-ŸýÁ}ý»%Ž7yþšõ;]ù!?ä‡üŸ¨õCÔå‡ü4høú za)ЩeÜ`˯Fa`šnÔÆ÷ßçd‡€ ˆë[ÙUé¸ó+®øÂ çýxÉ1¹wpÕÒÝÐçÏITY¨òx…+Ïød‰Ï*ô‹<joÛÅæ:÷ÑÜJuüý|q=ïºûÙŽ_Ny)ýÅ›]ù!?ä‡üD 䇸(?ä§ÉCÀò«§þäí9,•ËÑŒMfH¾´eüÎV-$ÄqOZúÚŸô½3l„M‰ƒ°ƒ2C¹z´õµ=Ïa§%ŽŸ»Kl–XÉõuîjç©Bö‰‰ïѪͯöÈ ÞÏMš–þ ›÷4ºòC~Èù‰6Èq'P~ÈO†€o†”!k¾“tqÝ ãŸŒæþ)°Ñ;]ëÏÙë÷Xl·…}†>5T®øÄ•{ù[f¾±ÕÀr`ž…iRï-…!ÉçûÍ÷ïNêØùÅ^É#§ÏZñ¯ »ý'?ä‡üŸh†üwå‡ü4Ihø&y#=óŸ S5z´ˆ-ùX†É3,ë-¿o‰ç-el¡ ´à+[)±J°U«[mW ÷зܛ TWh¤yõ­øzµmtï½}žøÅW†ÎX¼dc£ÿ³ä‡üŸ¨‚üâÛƒòC~šÿÿÿìÝLÔuÇñ÷Ý÷Ž»„4 6[¥4[šš ¥%¤–KãGàL¤ãàù¡&‚? uº Æ9Å6-mÕ쇚YY–?2R´DÁŽûý9~ŠŸîZ¶Úr­6;ô^Ûc·Û÷{Üç¹ïŸ÷Ýwûb¸+äYÃB!Á ¡ “h©ë"æñV EkˆV­‹ûÏ2~9W~ûu½h= Wº>L”F”B¢TŸ€…C’Gž?{fNAþ¶êš=éñÕ¡ú Ï@†>èw®ô¹?`¸»vìlNOÿè¹i›#ž,ž;(pÑ<¾ ñ¶ä?Iô‘$‰ýã'„>²ðégsæÄoÌÈ©]Y²o÷ž#‡ŸðøZÐ}ôAôOÁõƒ>÷4 ÿ«ýNV)?++ßWRZ[X¤ÌÎÞ*“mÎÌÜâz“›W±ºdwYùÞmoÜûîñ#Gë=þmÑg AôAô ×úÜ[0x ^€ÁàE0x ^ÀW©üîuÙÎÙsÊ¢glŒœ¸fÌãŠðiáa "Æ,U8sfqÑòý[+yü{¢üÀ¿ Tž?¿&ôáED/½,ñI‰¥p”Îw?þv1‘ëÔ|¢T×A¥Åóù œ@ÊçâIŽÙ^±MíñU 7ÃðÏ —í¡òOu?Ô–ø ²‚ý‹¬ò+”pr¥ ørN r N%ä²øœœãeOî+Î ó¼\>?ׇ+àQ>‘ܵý}âѲ¥ï{|]èã…0ÜÑÖm_O˜Gô’k_+&ÅPÿ ~´VB¥* –<²ö‰G6Mxª22²*jjEÔ o??cû´˜êéÑ»¦¾°;rꮉ‘µc"”Þ12|{pðŽÖ•òè-‘`QGÙ¸±ëוžöøJÑÇ{`øKdïŒ_B--´Š(‡hÙ Þ¦°š¨§§Æž“¥]§Ÿ)]Y`_ÇO?±ó ìÂUÖ fMZ·KÍî#gëY¥Ò^ºN“!»˜xêåÙ'&O:>bw€ß–!•åò)“H0(E‘}Ðã«Fo€à/ŠV|ÂÌáѱèM‘kZ$æJYûÒôo^‹­Sd\Y_¬Û¿÷f}sØÙ^ÖÕÅL6fr0k'ëècÝ·X×Mví:3·3½…õÜ`=½Ìjc?þÈjw][^P—¶à‹$éWÓ¦Vëï»A".á(ï·»äS‡?(“g~èñèsÃð»;›žŒXNïç›K¿ÝŽâç[ùU|\4îDvö¹ÕŽ‹™FÜNÖÙÍlv¦3Ü2oZíýf{¯¥£¯½³¿½‡u¸N9™ÅÞ¯·Ü2[™ZÇ´ZÖÞáÞ  ìË£ÎÊ­qÒc ÉççÎýaüø‚ØDî=®œG2×67tx†RyÑã5Ðç~…ÀmÖ¬M/Ž(Mྛ%/,ôÃgž9=ë•ziR]NÁ…=ïÙë¯0³“]ëc†ö^•Ö¬j3ê N‹­Ïjé7êo˜ 7MÆ>³¡Ïlê5»ÆN£þšÁà°YºM¦.½¶C«q´½k·º¿Òʶ(;RNH“Ï$%ý9éØð¡»%›ùT  78ŠŽ.÷xô¹/aoWQõý¨Q2¢‘0WHÅA~•ãÆ~;·1&úÔœW¯*Q}~œ©MLcc—Û,-“ÚªU[4-:ÍÕ½ªÅªÑöZĮ́í×·ÝжöhZ»4­NÚ¡Ó´ëµ½ÎfÐÛ]t»¶Íæ:hÔ;M&öK38Ø©:¶¬¨>:æãØygãæ6Lžðí°ªÅü21WH$ zmGõ9ôà}î9À«¥e¾K¼8‰oÑ2IÕ¨ðC1ÓUÉÒ¶Wf}šŸsòƒ=—X«šýÜÀ.^꺪îjR;šÔ6•K«CÕêTµt«šûšwý¶n·–Î;jînlêiÓ0³•56±š]bÒ¡Ó?ŸwivLãÄqg$‚*¢ü€5"á’Øy{ÐgÀö¹ý ÿÿìÝyTSWð‹ "Z’@!ì›FDÔBePÛÚvF«ÕÚŽ"¢€ŠŠˆ.€¸´‚ŽZ­¨P„„%ìI !@ÈÂ’°#‹Š .­mOÛiæ%ÕéØéiiv ¿s>çwî}¼Ç½ïû×ý4½Ü½¶°Æhò>„¢(6¬~Í Ú–¼Þ½0@#£göÖU«åê¦Fu{;výZ*R¶<|æ±Rõ¹Rõ…Rõ¥ÖϦ¿\UªÇÝ]šoK¥MMßÈäê,Æ“°0é<ßÂ÷Þí ðkî"r¢”"„m,t¢áöùóŽC>Â|þ¢ À(eJZj0ñC„ÖMLvvb-ýû-¿WÅ %KÞ¬ n¨(U ùÿ–׫•MêÅwÉg’úûrŰT~ï)ÙT6,•=J?ÓÀßOGPe²!Uópƒ| ºº¯ZüPÕªV4©/_ùfãÆ¦¿-ýã­®×[.hrµ»A&œFšïÁ\nk³òùSåó× FfA«Ñä7'L\;FÛxÃ$÷âEÍ åo¼)ö`¯Y_S%RËeêêªï„•_I%ßÕK¾î ªúdò5âÛZwµjjî×Ô<Ѓ#%‹n7)5( „C|Áç¢Z5¯R«^µRúÆbIàé\Ñ[¯+¼©d³„‚Ç å8ÓÏŸ!Ÿ¿:h0ºd1äù!´ÜÈhŸþØc>^uþóZ°ºüÝöEËV²‹9êRÞw¼›_WW+~U^1Èá ˆë×ÔݯàuUŠú4„ý•Â;•Âʪ¡ÊªamÔLG¦ªj€_Ñ_#Wßïó«Þ}é¹õ'Ô‹•Ïñ)ö›_å?O4Ç‹3ß›7yü}Ž7G(‘Ýùüùèh0ºL0 @è QcЪ›p®wÛûË¿žã-ññ)]òû_òÊ3‹úË9¸ÜG\ÞC÷>?ÈÜãòûK+:97{´ú8¼ÛØÁ—ÃÄnÐTlÌ»3B<îÀMÎ`YqIqfZ9TÆ.á|QÆS—”©£cºýýØ ¯Í¯~s¡j®W—GOóoqÃðS"Z ùüùèh0Š˜à–›¬3·] xµeþì.¯émÎ’E;¾¬)/«T—ðïqûÊ8ƒ,Vo^~/—7Œ^™y-ÌÞ,ì€è§t´æúÍVÍrà&Ch»‘ácã—õYÈg4€£…ç¬ãôßCh­¡AÂ,j¥Ÿo§¿ïmoj»¯w“ïlþkW2¾Íʤ³Ú¬¦ë U^^_Aa?#»5‹ÞÌdu°»Xùí̼6lÌdu1Y·˜Ì>&ó63÷®¦2{4WFˆÙ—Ÿ;ÄÌÈÉÑ,QRÞ_Tv+'¿Æh¡eõæ©Oœ¸ï;'g¶'Ç×K0¯Ïß§þ¬?ŸF„â'Äèé­21] ùüÎùè h0*,ZœL$íD(xò¤$Ç|ª»ÈsZÃÞ*OjÕ̬‡.§?ÉȺy£-ýš”žÝNÏî¢gwhµ?¯Có#Æ-:£—Îè£Óokªf|kÄzY÷4è} F#[EÏiÄdå¨hôÎLƃëYꈈ.G Ýdz~–{Ë —NŸéݳ<š<§ Æ&"b0~Õœy‘Ïï–.º/*:k²ñ¦±cwM2Jv²Ïõñª›I•»»ÔO÷¨Ÿã-æQäï_|äèpÚ¥™×îf\ïH§5Ñ2[hm?xnÚAËè¤Ñºµzh´>míÖ\!ZOFú«=´ŽŒ eF¦‚vMF»¦¸šÙ’I¿w5ã«=ѽžÔB/j­§{+Õ¹söô¾YÓZ½fÈHf4쌎PѤ‘Q× Ÿß! tÜ¥ôZSÜ „Öêé%ͯ»ºò<ÜÄ®.uînõ3fÖzÎâ;9_[±²*åô£OÎߣÑî]¹rëòåö‹[ž“¦üŸi›VÇSŸvjüw:šGºµ°ÛÒ.6§¥)Ò.I/^’]JW¦göŸ¿8œ4¼8P8Ý•ïé¡ôpn9­ƒêÑL&wqäÚN½¦?.¡e&-˼®‚|^j>ºè8*uB+Úebšî`_ao/°¶ª¤ØŠÜ\%Ô5Ó¨Evi¡aÍç/|™zª÷ÒÅ»Îu}úIçÙ3ª³g•?®?h}qTçÎ(Ïm8wV†9¡1íRwJjßÇ)OV¯Vº8S=.N w7¹›k½“c»›ÈÕ©œhv^O/¡¥®náÏKÍG÷@]ÏÓCËŒ # ZZ纹‰k)vG'96°¥”º¸åÙ9|º;ºûÜ'Ÿ}t¼ëÌ©îS·=Õq*¥55U•šú£ú#ªßîT3æTª [èôÉÖÓ)ª3)§SN¥6ž9Óž|´=åô“nG–‡{5v®¥8ðìø¾««ØÑá¦M¡¥yB[Zž ù¼¤|t4ÐeDB¡þVýX3bšµ]>vF´¥TÛÙÉ]]UNÎ2+›2;‡g׫{bzN¦ =ÒvìHӉį“Ç[NU?ö³Ž7k5>¯ydUqüD=æÄ±Fl¡’[0'“•'“›O$7`7$$¶ûèÁÖ°^çNΊǒR`ãÄÆöïà$²™Zi;•7•œc wpœ^Ù<ˆÅê…|^F>: è¬åïFèýW ÷O4Yü¾Ìyü>ùáøFl•C»¢cºƒ7u8»åL¥°¬í ­ì™DëlKÛ©ÔÒªÊÕ¹Á†Ì³"1ôõÐFCýßòµ÷Ïè tÓ«  ´\_?n J±$‘ÈDË"¹”H.'™s-4*Èì©V¹ž3Š7µïÜѱ{WC|lã¾˜Úø8éÞ¨ú={d?«þy?óÿSDíQ<ý=ÑuQ{k÷D×`5&V¶m§$"²9*úîæÐ»v”l ‹+K6É¢”dQþL¶yÍþÍ‹qSÒÚƒÐÆys!Ÿ˜ƒº GØ ýÐ8œ)ƒlÅ%š—ÈE‹2¢y™9IÂTbažoežíhŸýájÕ¶°Î;”‘‘’=»Å»vWïØ!Þ±£nÇöúÕHGT·É·ooÒ’oßQ±S±«RcgÕö(Éæpqh„2r÷àÊ•­Ö– ’Y¶©ÈœÄ!’øD¬š—}Oóæ%6–%cÑÇcQÞd+äóóÑaÐ@…E\GèmÃ(„’,±s-© O`ãHxB1†`VB0+&𱉦AÄ_z{ImXhGÄÖ†M‚ðpÁæÍÜ-[ªB·ˆB·T¬>*Q ­ Ý,ÕÀ[D![+C¸O… ×m…4†o»ãçWI4ËÄè|>Á¬Œ€¯ÀJ´¯ÀÆ`¯@ °ím*L&_‹ö"´*88òy!ùè6h ƒ6éù`¼á~Ó4<>ï•)yÆø|c3– ®ƒ3eãL ñ¦ùx\.wÝø•ó¾³KC7w­—­¯ æ­[W´‘$ø5„¿FuІZ l$XÌ]\Y·‰».˜¿zMåÚ ÅÆM=ÎN¹8“tã,l«Ú=k÷Ÿo‚gap¸|Œ.„¿†Pô„ñ¡Û Ï ÉG·ýÿÿìÝÙs[Õðß9çn’µØ’‰c !‹ Y½%!!v6OÒ8{LJÚ™2C ÐR–¡ -…@HŒwI–®®d-Þ÷%q\èÚéô­/}ëÑsŽlÇ!v%ð"ÿf>ó›+}uÎïé{Μ+á!„B™¦¾ñ†ªWi¶óºþÞ‚¼ ÃÉr$Ù1GNÔéNpnWÒíJd»bÙn+7'”ãª/\f>ößÕÕ?=ûí©SÃ'OÔÔŒÕÔ\KÙñtLœ>óP3qºæÚéçFN?7tê,7rê¹kÕ'®Ÿ<óÏ#ÕÿZ˜ïËÎæ7ìÍIÊ1ó¤sfGÙ–¨îŸ…Ãn帿ñ¸ßTè¾Æ¦ï°?÷ÙŸŒ‡ „Beš§éÇÎeÙ?±ÙêY1§«ËpD §iËŠrYö6Îa:ìf¶³Õ›ã[”׸¿ò/öŸ<ùmõ±‘ê#ǦçèÕtŒ=z]86~ôøèÑãÃÕ'†$~qýpõŸªý£¤dÌ]çrµ¸œ¦ÛÉ̇µ9L›#8)Ëâsq9bºRo×>ÕØ/z¤rïØŸûìOÆÃB!„2MÞ‚ã6ã€_¸]—)«ST˰wè6K·EµY6#ÂÙ Ën˜†Þœãòå¸V¯ŠWVNì?0~è'×öí믪þ1VU]•øÅðÁCC ðzàÐpÕáñý'öUÝXº<’娳ͺ0ô°Í°l6Óf Øì>]è6“Ï…Çt6:l—^×µç]®ÃØŸûìOÆÃB!„2 À^•¾lÓ?Ìq7FÀ4¢ê¦ªe5u-ÌšihA…6;²üngcNvmEÅßÊ·:ô×]»++†++,ü棕c¼VTWìäöìÞ³wtïþ‰g÷~»»âFާÁ0êT¥ÒJüºfêzP×}ºÑ¬ÚšT^åtmå³Ð•+ªò¾®½ Pñù7°?÷ÓŸŒ‡ „Be”s/†<îóçsÜ_)¬ A7’Lñi–ÕGÀ?ÅÇH Àןù,¿ °¥xl÷îoÊʇwíyfçÀÎý;¶÷qü‚¿ÜõÌ।¤gçΑ={®>ûìXyyï¶’îm%½¥eCûþ}ýÆ´öÀW”6ñt ÐBÁOÁGH#¡_«^ÅtøZ5bP 𮡾átœ+.¾Ó)ìÏû3à!„BeÃÚ *<ðºMýŠD€&UOÅš#àúñËŒ{à’ËÕ´¢°sËÖ‰»þ\^6R^:PVÒ_ZÜW²­—WŽ¿ü¡””•—— —••”— ––Ž–nŸØ¸yl鲤ÝQÏÇP˘ÑVžb©à'¤™z‘n§.SS- S¸ÀèK«{ ûsÏý™p€B¡Œ¢±ÃçøH!—åÖµŸª€€Èµ<‚OÃ)”(‰´…GBkN_áªòíßmÝ<²es?·ySߦ½ÜƧ{¸ÔõlºÓ²më ¿ùÆý›6 lÝ:Z¼íÚÖâë[¶~ó`AÄ)~¼ö² ¸T RfòK!DÅ€Å&· ¸<æò°ÞJhDWã üàm€<Þבÿbî­?ó.B!”9Ìб«ú—*iàI1ÄS ¸¸%à¶Î¸A[ݪHH½×tuÝÚÁõëz7<Õ÷ôú~^ùõº'»×>ÑõÔÚž9t¥…ß–ßsí“=ÖmÞtmã†kEEÃ+Vô¶f*NæÔòt 4 ¨e0‹B˜ÈMn™n'.€¥ª …‰Ø¤ÿঞ{ç×cØŸ{èÏ< „BeŽ·/ 8õú{*\dТ©¡a€f™›¿pEöñ×OÁ‚OÕ"šaõ35èv[…Ë»V¯l|u×ÚÇ{×=Ñ÷dQ¿^³ªã‰5ݳ+êLKÑšŽ¢5]ñÜ<¼vÝØÊ•‹&œŽVÆÄ8E"§¦„™‘S0)DyÆ•#÷mˆŸB˜±#aMmÖÔOÞ ô•§ØŸ{èÏ< „BeŽÃU—\ú«Tœôø=ϵ*‹ ‹³à¬e΀ aqZ5j³'U­ ÀP›—k,j]º8¶ryrõÊîÕ+;W­è,\–x¬°ë±ÂŽÙ*—¼ûº|Y|ÅòÄÊ« {}´+oAÌfðÏ­c<×ÒVÊLmeºÈò€S F!t[À5ÆxÕ4¿n\bÊo ûyùŽ?`î¡?ó.B!”96¬û• /\ø\#<à†@óm˜#à†¥‘# ‹ŠïÃá‘Q<]z%Ëv9×ã+È7—<tqlññ‡ ,~½ä‘¶ÙjÛ’Å‘»¯üV<ÄktQžérùu­‰Ò&€ù<«)vµ‰55<1B ©S.òñÖæ›—ðPÞªªU»¤¨ï¼¶ºèMìÏ=ôgžÀB!„2ÇÒ%ç~ðn–Òâ2’âLˆb1ƒÄzùÓ϶†Èdp!RÓ’ªÚDÒm“‡ã/|i×›<9áü¼x~~…˜x–—O\¤TÜ‚‡^ÃþÜCæ \ „B(s,È=Ãàe *P§°Bâ”ÆÅV± ‚ä¦èmxF¼Yù;2Y)´2Ò˜øa,›ü¹Ù\O»×›Èõ$¼ÞX®7æÍæz£²F¼¹áY«Çkz=¯<+çxB¼fgGTT¨¥R‹‘0#ŽŠmìȬc# ÐE cr`Ä'.å5¤hí2à†T”Z€Þ0ŒÓ¦9ŽýI·?ó.B!”9r½“—AŒ IRÒ!O€¤bb@DÉ6~Á ¦Ò„®& -aÓãNGÒéˆK1§3:ź3‡#Ìee™“ìQ…¶ñáq )TlcÇçO’@ϸ2ˆd´å×?#àFfjâëq>"ð–aÔüW±?éögžÀB!„2‡×súÖ€ÛAI'@&7‰Ó"kòÐ)(¡KòŒ««qM‰iJTS-M5¥ÐóÎT%”"¶¢©¥8Ç =%uˆeŽñÌ ¸aq¸EdÜV –¢vË ¶ñ{Î ¸ ƒØŸtû3Oà!„B™Ã“sjFÀ*ÐI Ïí2&iÚ‰¬TFO™D“*Mpü¶©)âh IâŒ|'z;…¶M_§±H©ííYî\ã¡ÐKÏEžØ¡AÉÒ¦(}ÀS8j´àcïð€{år7ö'Ýþ̸@!„PæðxNNÜ&¾²›çB¹°CÆÜ4Èå”®©óåüÍvJ“”Æ¥6Ê¢“øµÜM¿£]ÜôKyáöwî8žÎ©€›ϼRS mÀS²2ÐÃÿ†'i6|"îÙ/¿hÇþ¤ÛŸy!„Ê^ï‰[.…ƒý0™S;îºvQèçôy²ì”)¹#Xíd¬]Jü%ía¤‘ïU…*´Ÿ×éwä{)é–·{úsåG´Ï5}LÌ¢Pžq£@Ût)lTN°[!q6OÜ‹Ÿ'°?éögžÀB!„2Gnîqç(¼/nBQr„TTíšÚ±þ¿•§Õ!Ž9©ˆœŠ¹3¶½;fè’÷ç¾Wù}d®’¹vpúýÉŒ ½ÓŸ;ãþ³GÜ>ñY$!~ÙŠWÂÿ…èq€a€^qÿfÀ­™5àbîÜŸyâÿÿìÝÛoT×ðoí}Μ,'M¬æ­Š¨Û‡¤j^S)QREU[%IÓRSj ‰!¤ŠRçRAÕ\J/QZ(ä„@@{Œ=žÇÆ7ŒM1IúÒ§þÝ{Ÿ9ƒí|ÆFªuæ“~ZÏxŽ÷¬§oo­3怈ˆˆ’ãö–ŸjiWè´3î•€›úàrªKŠçâU“&Ï }R9#?똘{ÎÕЙ9>óêµZ »îíÝÕç+çÜ6y£Ûiœë¯§GW2ú)—nO¹ëd=5ôÛ¤[ ¸»;ÓéŸïÝ{‚ý©µ?u‚"""JŽÖ¯m~ìhj8ì«Ýw˜xšS(¸&öÄ«=îØø¼ËŽáƒìé™oa´½a­Šµ±é6«+ý ä©ÍúÓþ¨–A—ŒÍ‡Ýüxîö–'ͳ?µö§Np@DDDÉqÿ¿Öê  CãÚ~µå9Á€B)ð‡]H퉂é¢5¥Ûþ9wìü:÷ä{QÕw=bOÜ+çôÑÌßÍk ÝˆË Á»Z›€»õ+wnîêdjíOà€ˆˆˆ’cÓæCAÐ&ؼ¥¥«ÁïW6ùÊܤ×޻ĩVn1}תy—tCËü²}KÜõúrž­vV^¤[ìà~6Ú–€‚FOàŸÐØçÊ{úîo¾pæÌ(ûSkê7DDD”üËðx:xØãëS9Á€Ky§oa0½n­•I¢Y[cÊΉыW±S:yyå2®Xæù0ÍGKI6ð?¼ ½ªíÞû^b–П:Á % ð}ßßž ØÿG+Yesm •8˜s17f½±ü|¹(°Æ—‹¿±Ñ¶à¡ lÒµÞR9Þvu ã÷úÞ x øñ÷~ðû³´þÔnˆˆˆ(QV5­¶4føÞ1àt ‡Ê@Q )Ôbà†jºÔr)5J¾­m§ö‚ ,q‡Ü«ÒY­ßvTúG6ý‰ýYZê7DDD”(ßùî^¥Ÿ R{<}8™±··Ý % cn•€Û?ßõ®}WÉ%ΘjY ŠQÀ-i—q•ežŒÂ^-ßÔp^ë÷€‘zòÖ/¯íwgÙŸ¥õ§p@DDD‰òrgÃêMžîô½?Ç‚TÑÝ$:j2%\ÅÂTZZ˜;çrþ÷yö ^d$¶rô§ãÒsÒm¸Øãí0àæššz=ï БYÝ~ç×Ûßû[‰ýYZê7DDD”4*õ0ð+à?8æé>wè”qWîKcT/Ä<ÈE7‰^p1qÜÕáh>|uÐýBX5\£8׬TvÌÝÞí;º•}Úë÷ü‚ôþtæ…”¿öÛu||j„ýYr"""Jš»îy Þ: ÃO¿œÖ2¡ä2¤Ý€„‡ÄcÀEÁ%ÁDx±ÀNƬ‚²k±Óí“Ô‹Pe¨Qˆ åC:ȉþ;ðÐvKó£¿\¿›ýYN"""Jšm/‡÷x*³ò.ä_O—ì¶É¸&Ôº)÷ \m/F·N­¬¼€[ GÛݧ(Ûh+c¶ê²—Ê*õWØo÷ÿakëú]»Ž³?ËéOâq@DDD ´ªùgAcðFcc·q±)Ö ±ŒºÈXž“_À;Üp½úêèJ¨fUÊfÜêÂÆlº­|¢‚¨ÓÚôo{àÁG>ȱ?ËìO²q@DDD ô­û~¬^J§>²“Àtd öÇqK¤8~MøLUøÌÿ»*ŒiŒkû`Ü-~ªBÆ´.ˆt)µxzõªŸ<Ñö{ögùýI6nˆˆˆ(v½YÖÀ”ênLM*̳À?œ—t'&ÚJ|¬_1Õ¬JcJaZÙ•Gë—áLf@«ÃnÀ}Ckkû«¯f–ߟd〈ˆˆ’é÷¼lÞö¥«Á+j ?‹Ì*sçd\uÁeÜððxÆ™ŠÎ’WB £íŒY¶ªdôi{ì-ù”> ìžonnä‘ÎŽÇoaê7DDD”LÏo?§õÆ[š÷ûNjŒ¹\ÜÏME%ã.¸Óî |6ʸÓ+£N‡Ñ6Œæ.éNjôôYà Щdãš5Ïl{î ûs³ú“`ÜQbµ´<Û^7)0í—|w¤­m´½\mnü·‰"ECÂTurøÜ\Ì.¯ŒzÙÝÒ:¥ÕU_Ìâ/†2AN«£Àn`Ë—nÛ¸öÑ݇õ±?7±?IÅ %Ö;{.y~›R[×ïhjL›ŒXÒ˜ññOÁï_p jÂ\mî%Øøø…sÕ%Ë++£^Q2kVëéY_͸ÿ{Õ›Nôd¿`§§Û¾º¦}Ëæ}ìÏÍíORýÿÿìÝkp”Õðÿ¹¼·Ý\ u:Õ/Î8¶ÓAg:S‘ª-TŒD ¨­‘„[€¶"T®V„Z¹SZÊý’P Ü$„Íî&ÙìfɹcÛsÎf1xûÒaóÌüæÝ7gÏnžOÿçÌÙ³ÔB!$•uìX<áØùÀ›À`»#Š=Q½W$èð^<æGôòv"àrpËŒÄ"wI¹JY ½Ú}܇v ¾Þ¶^(åàV­rºþdÄܹk¨>ÿ÷ú¤$j!„’Ê,*Îlу‹_*ã.fØdó]Q"(wd•Š`Ç!×nÈÜ’¦ÃìÈ?|l[g»˘ÙÜâùûÜwÿ3#_žEõ¹õIIÔB!$Å 2èìøò]ß<ÏYÍ̱÷>Qn¡JYŽã'!Š!Cƒ8 28Î4§Í·]z¾7©>©‡B!„¤¾ï?0DeA ßï_–æ{Ͳq9PÉdì4Ä1Èâ&pÕ'äâ¤Ù„óãí°œÀ` /£÷#]‡ÿáµÿõpªO³B !„BRßÂåû³ÚªŒ;lffÚVà}svd¹D\ œ«D+OÂ: ë8d DDˆ³2Ñdp^ê¸%Ì>ì_ 6å¥ ¹ÿ‡/Ž=gã¶íTŸ›ZŸC !„Bš…‚Âé-_PW²7,¬O“G\`(Ó—… Ju´U¬RXe!ð¯Êš5R~£Ð ¾9³ê1•Fyrp éËo¤”zöI)÷ïó€BðAß¾7·wΤ·ÞYMõ¹õI%ÔB!¤¹øi÷‰`=-‘Lû­½¢ág­Ê¸Œ ç,ÐI× êo”êøÛ€#˜–Z…DD¢J"fÄ9b† †pR0)ÐÈõ›jd C-CL?fg;•”v¬j[}$*Õ›•Iìs°ÁåïX¢ñœÖížì™=êµ ¨>·¬>)ƒB!„4#Ý»k™Qà³f¶±;CÇÙ 9Ö&„ÁƒpCpÃf›{¸1þ9p¹ ¸<pªŒkHº_»§ª0#Uº­gˆ›ñÆN‰#öÃ*×aó´TâˆÍóÆûÁíÛ÷îÔõÙÂWgmݹ“ês+듨 „BHóÒ¹óxó…×ß3Vg¥Éð<7b¹qð*½ÈðÕBŸ“1gV½Ôˆ¼É«Î¬@,©êF‘ŸÆÑ3› {}’D´-‡~—ÓBì ä[¥ÞÙR ð\»ví6|̤ÙE»ß§úÜúú¤j!„Òìüø¡B _ºû;Ž9ÀRÉÞ“ü8á^%˨ã^j“ÎÕê&XX%X9xÈ(3FHÐþÙÙ¬ZÏÆ+5=­ÊµÕµu‰|¬Ïà¥>§Øsw ¹q•nGY¬›6ýîòRÁÄ76n¿‰kÛTŸÔF !„Bš£Ÿ=ö:C?`¸dÓm±\b+°[à׉9R¥Ìà\Ra’.‹&ƒiȆcöÄkU£7ªþzQˆr-ñ*zë8Îs\To$÷DH¥[×)_LSŸ쉶wõìôèÐQãf¬+ÚFõ¹½õ¹£Q@!„f*;{N›6yÀ¯ >kY¦·Sb¯…“>QÉôÎjÏ)æšõiÕ›aT6Õ!5Ô ±\}}Åúk®É¾zõòJ=«NÜsuÕ‚>ë¨Í7oca`Ùw}ëñGº 3yúÚm›©>M¡>w.j!„Ò|Î_ס}.ŒJsr¬¶dÈcž>n2VV¯áS5V^§‰#¨0"&¿*1#nÄ’ÌŸÔxn^ÈâŒÅ$¢6 KœpåOnþŒžmÑzнßУWÞäiÓ©>Mª>w(j!„Ò¬­\~ £ÞòîðñfÙXœ&T¸Ü"Å)Æ+0e,Vc®Jº—°ë.˜¼«3.3¹V×™U½¤†A¥ä:ýXßÑI׌‰7̦2´º#ÂBœ±Å Gl›g¿ëȹÀHà)f¯<8ìɧF¾:cËÎ-TŸ¦VŸ;5„B!]sú.èëà7éö`ŠÀB`£´‹= ã'Ì÷_Ìŀj[^®@oF¿¨°kæéùÄ®·ÂëÍ*hذ~Qâ2Ãs§–¡†óZ[ÔÚÖó’ó¯ñ܈ÏWâºûß,dl0êxýÛvÈyð¡Ü¼3Þ^º–êÓ”ësg¡€B!D[´ жõ ;Ó ¼¼ ¾Æv‹lg—%÷IY,x P&ÙY‰s‚]’ü3)þ-ÅTƽ,pAàS©¯—$®\‘¸*pÕÂ5õ@6üµN²Z›×(5Q›Ÿq­Ã–UÄÄRàÀ+ÀóLhÑòéïÞ7¨Gö˜±“æ¯Z·ã¶‡ê“J¨ „BùÜÐç–[f ³¬qÀ`ªNºP7×þžÏ)¥@%×?U[¯ã,¿êŠÏ,\´pÞÑ×ˎɵ®Y:ûêýñõê=^ëʳ>õY~t¡fÛ,2çØäs+Ïñôeô¾ûž§;uy1÷…éo/ÚxÛ BõI=ÔB!„|ÑÏÿ½?} ä`°<.ó› ¼.ù’–™;Z·8˜•~,Í=eá”ÙúòIâ·±lD-ê æ nÔ¨«­ï¨ûA‡‘8|ìþ)±Ib×çØ¨Éó„쟖٫uÛ_üèá¡ýž™8uú_×oÚ{Ûë@õIIÔB!„|µÜ᫲Zõº¹îବq‚O €ÙÀ_€¿ l°Ä×Úå9ûüÞA‹í±°ß8hác㺺â#Wîsä¿lY$øzÆVË€y¦J=[.C_Ÿï—ß¹§o§.Ï÷ÉyeÚÌåÿX¿û¶ÿïTŸö_ÿÿìÝyL“gðßû¾-mAðÚÜ q™F3Ï º©³xÍLåœÈJ¡€ÊDðbjÄ j â¦NGt™:uNçæ1EE·9o±¥7©è@ñYëbâ_‹×V¥ß䓦yÛ?ú|Ó7¿çÛ·É‹ðoò>?ܽÇtû6—(¬©W¦ˆŸÅÑ<ž–ŠÅ_x¸¯—É6pÜ:û†Uà7 Üm¸­"Ú&pÛ>nÛÙrÜRwÑ?[䎟´·Úx½eTÇŽBäI)©K¿Z¿Ûé‹E>®à‰(wúû©šùªÄ¢¢©öM*ÇeŠ%sˆf¥?×Îñg>—ãr=Îw“Ì'q¦ýÍD±DÑ$‰qóšèÕ"ªS§ñÇ&§M_^¼z×Þ}G¾:äã:PžNaѵ¸¸ï XØ%«M@JïID£yÑØG¢3ÖM)õ óná×nâ;ï& [Ÿ\’™½qíº½{öqúZ Bx.›·]©þnAîÆìœ’ô uRÒ2…bIBBžýIJjþììµ r7,_±sÃׇöî+sú§E>€àBP\ € Ap!(.À… ü Ô?¬(>r|ð¢ Þs:wP´‰ ðŸØyj¿àô¡C³2fl^VpÀéŸù<9Ì/äóÊAø©Õ'Ç_í÷æ$¢ˆFÈÜ¢%’‰DÑÅñŽÛãM&²¿4ž(Æ~£h¢0žDá¼Ú¼Eœ À ³lù½z¥ ±磻jé¹ÐƒæÊ(GFÙÞâì7šÍíØnq¯nAA+ƒûçZñþàUBŠÊ×ô´6¨ÿšÞA%Õ:¶ Xåë›'Ð\¢Ž>“ˆ% ï-Stï:^Îq§¯ù€ëÀüB> À 0Eñe›€)Dr©dr+ŸYDÉDÓšp‹ý›­î¶'fÌEì9e܉œÌ²-kNŸfg/°sWØ…rvYëðÇ5Ç‘“e¬@mÍ™§‰Wœ;ö؈áGúöÙÐf­—G^ ﲈRxJ ÷j­JÚéôU#hÜ0¿Oc…ð\2f~Ë‹Fr4E*ùTâfÿŽfH…œ·Û– xxܘRUüÅùY›7Ü/+eUVv¯ŽÕÖ2c%3V1ËmVSÏî<`µ÷Ù­¿˜©šéÌìî=v·ŽY*Ù©S¬dÍ­i¥±öG†ÐoO[ÿO÷…2i¶@©ÿEÓú5…2a»Ó@>Ðø`~!ŸÆ à]î8ƒ(ÌÃ=…^®òpÏ:Zz$)éLQqÕùóL£a6»}‡UZY…þÞpßbm0YëÌ5õÕ·ªï²ûK6f¶6èÌLV^Á´ZV]ã8[ôzöÃ>[Á²K¡á"¢ÎŽõk;|›.&Ç9 äHa? üZÇ«Õçžò€Æó ù¸€g1lØb %Š9®v¥úûmïÙóø°ËÂ#K“ÓέÛd-»ÈL6v«žé«ë®jMWo*ô6se½ÅÜ`ÐÝ3êï õ&}½ÉXg2Ü1nt·ôúªJó£±V§­ÑjlzmÙȪ-Žê|ñËS×DD :ù[PŸ­[®ñ–-á)MDŸ&—ç:=ä¯:Ì/äã"PžNþÊ_Ú·WEHÄ)bÊòñ(èÞuÿ˜Q—BäÇF~thVöÕï±r#ÓT²?oš¯›åm¹Ys½Bsåºîêu‹F[g11ƒ¶AwóžöÆ]ÍZÍ ›¦¼ªBS­ÓVé**õ:«]…ƪ½Yi?hÐÙŒFöûe¦¯bÇJÙ´Œ2yÈ®1£O†ŽºÐ·×O­šKùR!(¼™Ï¸Ââ3Èç%Ï^N˜_ÈÇ¥ü ÿÿìÝ P“gð—*èZH„p_å©+‹µÕ¶»µZm·ÛK-¢€ˆÔâÑ ¸hµ`¥%AL8ÂDŽ!„#„SE®jë1Ú5û%ÕZ­µÙ޶éøÌüæ™÷ ß—?ß7Ï<Ã`ø?|¼å4Ò[md¼¡ÈiF¶ÌåŠwßî}EqT8÷,õ†\¦êíSIeªÖökÝ}׺ú&ºúÆ˜Þ Eïw åuEÏ­ž»nÞs]Mùý¯ê¹ÞÙu£@uyTÕÙ¥ÊÌZ÷sY@ñšUí+—wúz5MÎ@(Êdúž)úßZu òÑÙ|è&è_ϳm¹{odô¾ñôE“lKýÛ—v­|¥wY@]|¬ˆš;ÐÜ ’ŠUmRUw7v¥ÞŠFeßÞsU&ÿ^&¿.“ßи~oûÛU.¿Ú«¼Ò&½ ·µÝ‰Uy´k!!ÂE~%o¿5àß9×…çDª@;±à©†á‹„|t0º úäó ‚@+³oL}¡§¦8;1ÞüGŸÿ‹üe‚•+š‚6¶VW¨¸5ÿ·¨dmªVÉà;A˘X2._¾K4* EBáwjØâÇ­U$•··Š‡øßÊ;U’6Õ×§noØÐö÷¥¼¾¦|%°sÙÒ6W»³Dܤþœ¬Õ¶6A>:•Ýý òy6ÁðèÅÆÓWMýà9ý­S “=ÜË^l_(~uIóýëy*±HÕP‡[{S(¸Ó"¸QWw¹®~P$žhä_и¤1ÜØ8ÖØ8¡-F´Åæó.´I®´J®ÖqGkê¾ç5©8µªüsªuk…¯..¾àË{퉹˜h–ŠÐÆçÐj“Yk ]È€n‚þù<Ë`xœ<š!l¦46Þ©?逯wó’EX]ýV÷Ò€ÒUk™e,Uççü­††¸Ü›UÕ#,Î0¿ùjcóX5GYËTãÕr/Ör‡këGkëÇ5uD½ÕN}ýpMõPcÝ(¿a¬Ž;VSÿíyÞ힊]§úò„jùËU }Ëü×/YÄ[èÍZìÙ>eŸ> 5ŠP -òùó › A>Ï8ÇÈ8¡7Œ ¢ŸCûÈnÜ|ºÞY}k¡À×·båÌÿœ.¬¼J/ªbM°ÙWØœoYì1NÍHMÝevÍPEuë|¿Æ ‹s»1Xìì ꊭ9µÄaŸgT– •—õ«·µ£•ìñrÖõJŽª¼Rۻğ°´î¥Å +–É_ðnôö`é©ÿm^ˆéó-‡|þÄ|è&è_Ï3€_5Ód匙L×C{^ìX¼@é=·ËÃYðr@»Ÿ_ñ¿Þ¯ª¬U•׌•²+Y# Æ@aÑ›3Ž]ÜôÂz¡¼š=Ä,ëÑP2Ëú˜¥CÌÒ‹Læ%5õz@kCUåã%…‹ý%Ì~fya©»ëŠ+¯Ð‹o3JT¯oñõa`7@ ¿ÌÑší¿@îåVg2íBáÆ†›gÌxZ¿ ƒ|üAÿ‚| æé9Yÿm„>04Hô"×úûõ,ñ»àCîöóió[PóR@ñ©œòÎP]4FÛš¼°p°¸dˆ–ß™Gm§3ÅL%£¨›^Ø…­é %ÑG§Òéèç.©+½_ýˆ–èƒEçFéùÃêC”W •VöuQh”¼¢RÕ¡Cc~ x²ü¼E‹—ø-öRøûJJ02ˆÕÓ[7s֛ϜÝý òw`x¤——§à ‘mœ>-ÙűˆìÎóœÓºÐGñ‚Ü“\?c÷žÑ¯³¯åä]È=Û•}ZHÍï¦æ+©ù î)Ô_¢õQiTÚ •zA]Õë>­ Ðò.«Qi4%-_N-bò äjO.mâLž*,LéH¢úz¶x¹wÌséñÛëåÑæ9‡k0) ¡ ƒ)ë.Š€|þ°|è&è_ø ‹ŽÉ›>ã“I“¢¦§8ÙŸóõnžO»»´ÌõhYè#œãQºdIÙ¾ýãY''rO_Ê9£È¦´Qr;(9]÷=°UPrz(”^~ ePS{Õj‰ÒŸ“}Qí›þŠ"'G–“+¡œQNK¾ÉíÈ¥^þ&çæŽ˜Or‰7¹ÉÓ½“ìܳ`î ×œNïy"‚»‡Zo±%dÀÁù¬“3‹äÀ²$Û81±ówpâÙÌ®µÍ™M,0ÐÛ3Y/ˆh¾žÁ€|žF>tô/ÈúûC`¸kõÛGzço†»¦"ÙÓlŠ­lÊñls ¾m«½½„dÏmC'Ï?¥LLT&'ÊâøÉ -û“Z“öJ?“>ŠäQb¢01QpPíÇ» ö&s“¸IŸ °%ï–¥$t¤`u·tßÞÖÄ=âÄ={÷m îqt¡’ìKlJ‰vT¢ä̲¶áX[ÖÛÛò-qÌéFG ô¢¦Nù·wäóÄó › A>Ðß €{Aè­œñ|´úŒ`škkϰq(±"U™[²ñæuB‘ȳ¶âXYóö) SÄÅv'ííü4š»gWSòI|œ(>Nü(¢»vµÄïjÖàkj‹öââ›ãxì… ;E ;[1»cÅ ;ÅŸ%H±£ìÝ£Œ‰íÝø‰ÂÙ­`6‰amWbeOÇ[ç[Ú–ã–Võ®Î­6DŽn¬Ÿ¤‡6êÿžÅ…|üAÿ‚| ¿?âçþ§Ÿ.xqén„VëëÇ?‡R-‰¥b1Þ²O¬À«æl µj¢s¶Õ9ÏyeÖwGnSljMˆ“îŒmJˆ~ݲc‡è±Zôø'ÿ’$z‡äî÷‰iŽþ´iGL#VcãD[#aíÑ1—6_²#å[XXY2 ‹ª{ª±“WŸ¿y™ÉóÙí@hâ…IÏÌ€n‚þù@$ÔLpkþF$Þdh…M½å8b)΢o^iNP³ ”[˜Y™ç;Úç¿÷®|kHOä6YD„`Çv~Ôö†mÛøÛ¶5o oѪÞ'Ôªn‡‡·iˆÃ·5‡ErâjÕ"ëã›BùÁa²ˆí#k×vZ[Òfù„Rs O¨ÁcÕ¼òGêwa^ncY> }1 E›ÎÜù<Á|è&è_ô÷G‚`YHØ„^70ŒF(q„JSÓ„PlŠ+ÃàÌÊqfex3&G·ÀÑð¦'__Ù¬ÛÒôI]hhݦMìÍ›ëƒ7ó‚77hWï ækUƒ›ƒ7 Õ°Åf^Жڠö]¡Ü7p×IC·^ô÷¯Å›åb70δgV‰3­6Å•kÞƒ½ŽioS=szæ$ô)Bë6n̆|žH>tô/Èúû¯ùÿÿìûo”eÇÏó¼×™Î} µ*÷¡*–[[ Òrk`)wJ­ ht7Yu×õ׸ë*ŠP{Ÿ¶sïÜz¿·´Ô˺¸f³¿m²ñ·ý/ö¼ï´B[¦hœdNòÉÉ;“æç99ß|óÍ3o‡ÀÎ9ç?¡¨oÚu.WÌlÙ\qÛ¼¨ÝÙ8NG‡Ëw9Ãó^›¹zS~ï…óÿ­ªü¶ªrüìÙá3gúªž­ªK†ëÉðeÕ3ßhàEÕXå١ʳÈ™sCgÎŽ?}­¢êûgÏý›vÚ›ì6.U_s·¾þ¸ÝEœÎ82Ï[àò¼jP.,Yü õçgéA‘šQÈß§#Ý@mý I)“ åíù™“)˜aŠ™la“=d¶F«%fµDm–°ÍpÙ½˜ s–ùª*ÿS^>ñLå×'O8Ñ_Q1ZQ1–§Ç“aâÔé¯4*&NUŒ:3|êÌàÉJdøä™±òã×Oœþ×áò/ÈrÛl(¿ÓÓ׌J›m!³- Ukwa2ì–€?:¬¯‰|o}ÃwÔŸûìA‘šQÈßg ÝÀþ–•£ç3Œ µ¦Œ°ÙÒ©šBªÙgÈ!Æ6Äd ™Œ>›¹Õiw/̬ßWú÷ýûÆOœøºüèpùáþcGG’ãȵd?räºÆÑñ#ÇFŽ*?>¨ƒ×•Y~ôûÂÂQ«­Æbi²˜}V3.—2˜|“g’ŒîÅb +b­QþH~/òÃ¥{Þ¥þÜg‚ ˆÔ„ü‹úCþ>é2ç3¨g~gµ\áB(Tc»b(FV ƒDŒjÀ¨úT¥ÑnqÛ­u«VFJK'öí?ø›±½{ûÊʆ~IFÊÊ®éàÅЃƒöcÝp¨ìÐø¾{Ën,]ŽÁ½Æ 6*J‹ªø jÀ`ð -£[ÑhQ >Ü ÊXæõ&À—¹Êb9Dý¹ÏþA© ùõ‡ü}Ò=ì‘øóå=»µQU½nàAIñIŠG¯>Eö#ªìSeÈMÍVs½ÝV]RòâmÃ~»s×@iÉPiéÀ/Þ¼d¤´dkIéPÉžd÷ž¡Ý{Föì›xzÏ×»JnØuªZ#‰uœ7qÖ¬È>Eñ(Š[Q%Cƒ„UߎÀ[qŠxUßQäJ>ùôõç~úCA¤&ä_Ôò÷™àW_Á¯Èùs^‡õÀ»õsQ¨¨SÔ˜ …¹5êÕÍ y ·Àš¾øØÇYÙ-› FwíújkñÐÎÃOíèß±½oû¶^/ðåΧ~. »wìÞ½ûÚÓO÷l)ìÚRØS´upï®ËïŸ7¿‰ Ÿ|ÎyN?@‡fnÆêÿ„jÀªm·Ð* ^ªÞR¥W̦ó3‚QfîA‘š‘¿“¿ÏLZ€õk.JPð²Aú AR¢L L#€f5ë¸ pÙbiX‘Ó±ióÄößo..êßZØWTÐ[¸¥+‚/. ú· oÚZ4XX4XP8PT4R´m"ãèÒe1£©×P-n̸8å\£™±FÆjµéŸŸ,8Ô|Àá¢ÀŸ[ùÈëÔŸ9÷‡ ‚HMÈ¿ÈßÉßg&­€,Âø+Âû"»¢GÛf.Z´¹ÇéÁ ´&à¬#&çM8XŒW›ÌýÅÛ¾Û¼qxÓÆ>dã†Þ ù=Hþ“ÝHâúnt%Å–Íxóüü¾ ú7o)Ø2¶¹àú¦Í_=4k?nwE@==\ðá”sðrmÁZÖ€2@1·2T¤ˆÈ[þðÀY‡ó%ðÔŸ¹õ‡ ‚HMÈ¿ÈßÉßg&}€ÏûƒÃFé¢IùLbu8I^œíâ6´Þ"èQX’Z´&Vët†Wç][»f`ÝÚžõOô>¹®+^¯}¼kÍcO¬éž†Î¤ÀÛâ=×<Þ½~ÝàÆ cùëÇòò†V¬èU \;¹«ÆéÞ"bº ü0æú™‚õéŸ@@’¢¢àaZˆàA:ÿæF©?sèA‘š‘¿“¿ÏJú€7.ö›•sfåm . Ð$KÆýú¬4þDš64yø´§dÀ-ÉAY o$ÕÈYÞ¹*7þèªÎ5ö¬}¬÷ñ¼n¼^½²ý±Õ]w'¯#)òV·ç­î|4u5´fíhnnÿÂQ³©U´ujŠå-‚èÄ ¾LÀ!Ô€¾r7ðz Ö ·à„°Àü²Ô(K¼Âø ÇOµPæÐ‚ "5!ÿ"'Ÿ•ô ‡Ê.[”¹vôœ{I‚à×¾+&4M+ðkdÐ*J!ƒ1&Émˆ1€fº|Ù [—. ç.­ÊíZ•Û±rEGβè#9ä´ß­"±{¯Ë—EV,æ®èX™Ó½dIgæü°AÅÏ­pîy+|8úúôõ¢Â"„9xï€x«,7+êeAü~[¼ý¯ÔŸ9ô‡ ‚HMÈ¿ÈßÉßg%}Àúµ¯JðÀE€ODð à¹xÝ4ðëisÆ„ö¼<Ž”öôÉÕ Ã—Ãå[üpdÉ¢ð¢‡ÂeðzñÃmw«m‹ï½â­~kha¦ÏbiVäÎ0øêÏ»ø´ÔËSËÓVÈ!*B4q ¦?þÒø£жU’Z$ù²(½ðÒª¼×¨?sèA‘š‘¿“¿ÏJú€¥‹/< ðV†ØdQcÚ™‘T Zý?FÝ|ösdb°´!“å˜$Å<šÚô/Ï]øÌ¨48ìþ¬ÌHVV$+³-33”½¯Û²¶Ý^ƒÙYÁ¬÷Z³‚,/ÈŒÌs *~V ÂY‹AMäoO"õNet\R„CLG;Ó¦Ÿßn!¬=ëƒd—8×ýàKÔŸ9ô‡ ‚HMÈ¿ÈßÉßg%}À|×ižçðž5"ó‹,ÂyD‹’ú ° ÝÎÐßÑ'ÏáUà^YÐ~8àÿËw:£.GÔé »œa§+är†ôtºüw­§Ïé`E-Ù^¬6[Pâ‘$˜“:µ˜¼ëÚDt2hŸ\skàX½¢×à(V¼ ðŠªžòùÆ©?Éö‡ ‚HMÈ¿ÈßÉßg%}€Ë9)jp¤Dã¬]?!JŒQ€6jmx!@XâQEŠªrÔ D̦˜ÙÑ ›Í¡)3c2ù‘Œ ß$ÆÈÛpyˆÑ\‹¹‘iÖcÐÐgÝ«>  ùEÁ'kÏ¿ÏàuU­hi¾FýI¶?ADjBþEþNþ>+霎S·  ³€L†È$mq(µÅ1•…j@‘"²–Å,dɧãÂ73’èM EUÀtŽËCˆ'HrM³ž[à׿4 ´b¸¥.}ƒmxÏ[P_7@ýI¶?ADjBþEþNþ>+éö“· $Bg8q}Db< âL¯\M}Rc˜ƒ¼mâÄJ;ºâ^í˜L't'˜to^'¹tñ÷.˜n=z8à^ô=îÑ `¸Å^€v@•òÌk>`ð& àê•.êO²ý!‚ Rò/òwò÷YIãà81%€:Aû¿Q]87 ÍM».ƒ$Ðg‚ΩïŸá›qÎcœGtÚ¸š¯õ´}'ïDn¾Ôï£qç;3®§cJ1í™îÓ`m€*ºñoPi2¯øP@ågŸÆ©?Éö‡ ‚HMÈ¿ÈßÉßg%}€ÓyüvàÐ ôÁä·ßsíäЇ0èeÚxáäuè*jO ´À;!®ÕÀ—¼[`½ëÿIù€Èû°Þ|G¿sFs]]7?Wÿˆøtë WÐvg, 5Ö) #ú»D‘yãM\ú$JýI¶?ADjBþEþNþ>+ÿÿÿìkoE…ÏÌìzí¤R(B€à+H @€*w¨m)é…«(´¥ ¡€ZÄEU)¥Ü´Ð‹½F¤‰ÓıçÒ$mCR(ðøÌÌî:ŽIìu‚ÔE>Ò£WŽ¯Ç¯ÎÑ«£™Mj7,^ü„ÂZ‰-Ö‡#55¾”ÛÂD[±j5wióh:} ù6(ŠÅÇŠh³××t–T}«û.«ûtáùÀh/|nÑõgZ1À óYâ°ùϺ ým°ph7õ¦ °|F°?åûC!$žp~q¾s¾W¤vÀ%KW¢Y¢Åœ ºaul•t"ZÕj;©‘èA†n·hœ°Õ§­ˆ_Š^ª3Ø·wžr°qæ/aÎ6»u³¯§S>jÕÔ^GÇë~ Ç8!0À6ÍÉä“;vbªí!„xÂùÅùÎù^‘Ú MW®ž65Ôíuåa{ϸ–oF"ghÅtF«6Vž´Úò¤ÿEçtJ¥_¶ˆ´aÔŸV‡Û ŽYËé5ô$Ý%ú­sô—Ý ¼¼|É’5ûöeÙŸjûC!$žp~q¾s¾W¤vÀÍ·¼¡är`ƒÂçÊüé+{%òž;dEÜ ·bM‡êï)ò@ ééµ8W¤`³¨ë&‘9>¼‚þܬÂ@¿Ý;$ð™RÚ/]vùó­­ýìOµý!„O8¿8ß9ß+R»`Ýó{{§H^ø6ˆB`€žéÌnó®¼UdDªY úBä•õ€4èç‡F`®–m¨;©Ô7ÀkH¬¹èÒ•[>hgæÖB!ñ„ó‹óó½<5Þlé©[¸ÎQ-®ópÀKôÁlhÍÁŠ¥ªÍ—êrZÎÍœwK5ê_d82ƒáGGE©ß_Lüõ ihèrœÝÀ†ÔÂæË¯jþæû<û3·þB‰'œ_œïœïå©é ‘‰{g€·\ºím"ãæ œ´7•Ë.ý ÞDrÊÊhÌÖ¡ð¨œÿj¿ý¿Vd¨J¢\³@¿4ÇàÌÝ0áÙ¸~»rM·rz÷g/¹3™z5á.½íö ‡³?sî!„xÂùÅùÎù^†ZW_¿Î2Ýä·Àq%NKq"Õ3…ì…ðCä(pVàWÓ~Pö7¹`NÎ Ç˜í¶—9ý¦qEkÓ§Œtþ 9/ Š< OYøárÒ2fÍ8T_ú“zÙ2ðð„‰Å"›PG€À+Í÷Ýײÿ`Ôý/ö‡BÈÿÎ/ö‡ó}F ¯l<¡ÔêEÛO%Ž(ŒZÝûøKW(1À„ ÊçCLÄ£NøÒ÷­kpF‰~Gµ»)V_qÅsë_ÞÍþüWý!„O8¿ØÎ÷aX²ä9ÏÛ(ñ®VIÒÍ»6ò*#ýß?ëÿÖòâ¬cP#ÐUž…8ü¥ø]`Rà\<ê9{Ë˸’¸B/þ”À@ÊË(¹Ø¼pñâÕKضgO7ûóö‡BH<áüb8ßÿÍ?ÿÿìÝyŒUÕðïYîòÞ›ˆ¶š&¥4MŒm4iR•Vª-DˆŽP§lX R6q€¶n•¡¢ÔÈnIU(û2FTlafÞ:óæ½fAv´=ç¼yà ®À…ù%Ÿ¼¼¹sßÉ7¿_N~¹÷¾K@£Â™{¥5˜óÑÀôNv\UCÛJ,Ê}2Saà»tÕ{¡Ë«Ü(5•wЯ9SCù~)Y¼Ä<ã×þ·dsÆK1ø‡Ýòò›Mù|·ùBñ&Z¿(Zß/DÀ9Ý»Oîsì ÀËÀ`³#Š}"}.)ìðˆ.Õે`Ó\5@ÈH Á¥y•RÍåj.±Än†÷_m[ó/rè 7äöú嘹sWP>ßy>„B¼‰Ö/ʇÖ÷óÐpÎü…ÅÙmúpñ;@õÀ"†u6ÿÈ¥A˜#«Ty•@ì2š b Ô;Ì{j‚ÿ¯mítœÍR,eæä—/0ছûä,ÊçräC!Ä›hý¢|h}? -ä › ôtü\ÿ«>g93_‹ë1 UªÐ9‚Œ€(†Ü ¹âx,Ìä(÷ŒÃæn˜ÀG>ÿ>ßZà%sÿ€®7öÏðä²­£|.S>„B¼‰Ö/ʇÖ÷æh8ßOn¦jE ÁÀÒ ·ØaÆÊPÉfì0Ä>ÈbÏ6€ú¹8`NÒ}àø¶XÎ2ài`ˆ?«ÿ½Fýõ¹o{ó;åC!äZDëåCšÐp¾o|ܶ£êá`3³36ï›ï–ŠIÔĸªxyÖ^X%¥!ˆg!᜗9n)³w[ÁW‚ÍÆù2†Ýü³ÇÇŽŸ½vÓfÊç²æC!Ä›hý¢|H.bbÁ–Ìv£UH6ÇÂê ¹ÇåA†n(Ó¥¯Xe°Bð‹Õ""ÍÄZŠ´péšÖûT±ôÎÁ´ ÿÚ¡Ìgr;ð6ð*Pž÷ýn#úçN{åõå”ÏȇBˆ7ÑúEù.îW½§‚õµD¾ypô¢€µC4>ö"ÄepŽAÝ ¾°¾ãD·G#ŽpZTjq‰*‰¤QÑäˆ3T0DÓÂiÁfš6ª=kê’ú=+gìP P*xÔ±ªmõ/±P©v°YHâCk\þº% Ïmßùþ¾9ãž+œOù\±|!„x­_”ùœ€KèÝ{2pO»¬‰~kðÛ²t¹‡Ímïq †5—ÁE›ãçèà¦xºªŒ8kì„óš¡ù¡*ÌžªújÌþAÆ©¯àªº7¢æÇ2‰=6ÖK̘p†véÒ¿G¯G ž™µqëVÊçJæC!Ä›hý¢| —Ò³çsCÌ™ËÛfîÉ }nÜrkÀ«ôŒˆð×Aß#Ÿ7š×´…S-‘~Õ5 $ÓªZŠ·ü1ÙŒ>²)ô¦ƒ¤J?ýW ±W°O$ß(õ™¯‰vî<ä®»GMšöRѶ÷)Ÿ+Ÿ!„o¢õ‹òiåhø¿¸­˜éþ™c6°D²w%ßež2•—pÜã@]Ú Zm««‹GŒ4"z½Û¥iĪõÑx¥¦«ê¾š£Ž£>Õ?ú;zE™ß)ö¹Û„\øªþqÔ¡ÃÀÛï|bâÔ9k7_ÆÙ—ò!„r-¢õ‹òiÍhør¿¾çE†À(ÉfØâ ‰À6ƒ®“t¤ªÂZàhZ½a:%Ò…17Ë›kæ´ )åDKÕ_,ÓRŸÒ]QÏqŒã„úC5>QÕï:Eà‹Ôÿ v_ÇN}{Ü5|ÜS…«Š6Q>W7B!ÞDëåÓjÑð•ääÌîÐ!ø=ð´ßZšíÛ*±Ã¿¨dúÌ”*úc´™_yBŸ,Sµ«‹8Ò(5Î6M´_ئ7ôÔÇ+õqXuºŽ Ô T;û­½6_¼LF‚åtúÞ½wÜ=xÒô+7­§|¼!„o¢õ‹òihøªÆOXÕµË —á,àxØ%÷ùô×Q%ÁêÁ4|ª±æÀë5Qk$!âFÜÔ·’4jŒdšù•ÚŸ›ò”Æ’ ›E%ö»r§O®þŒiÓ>¯Û÷é—?ý…”§ò!„âM´~Q>­ _ÛoEoé®/‰sø³l,ʪø6Hqˆñ ÆãŒ'««5Í :ád#Öä¸éÝÌÔ½Þ_×´úH-Ss3«×ïõÝ fŸšÆ£©S[DTˆr[ìwäNÁ6ùì·9 <Èî÷Ó[GÞÿÀø‚g 7lÝ@ùx-B!ÞDëåÓÚÐðµå>8_àAÈ´ŸžX¬•v±/PÊø~sLT ©@µ-ϧ¡/V;¡ß°³æÇc©d\_*§Of¡ñ‚¶§Ž›-u µœ×Ù¢Î¶Ž›³x­Ïûý¥®û±àk€ŒÍ&Ãß Ž]so½mDþ˜Â×–¬¤|¼œ!„o¢õ‹òi=hø&ÎvlŸäd;jô|x|…íÙÎ{–üPÊbÁKdG$Ž vRòϤø\Šÿ1¨8%p\àS©_OJœ8-qFàŒ…³êlüm½du6¯U8j6/w­Ý–UÄÄàoÀŸ€Ç˜ܦÝC?º)¯OΤÉÓæ½µjËU‡ò!„r¢õ‹òi%høæ†?ºèÙ.k¤e=¥FaàyÝ PWþ®ß)ve@%ײkÐåÎϸâ3 ',sôë)ÇÔ½ƒ³–î }ýœDƒ…¯så¿Lø­Š€»PGÛ,4÷¹OàV¾âÏêãêqçã#FÏxmáÚ«åC!ä:@ëåsÝ£àÛúͽ d –ÏåƦ/J¾¸]ö–öm>i›¹/Ã=dégh4ô³3lÄ-á é Æ¨U¯¶Þ¢¶‡V.Qüؼ#±Nb×÷¹«ƒç 9(#»_ûŽ¿ýùíÃ><õùÿ\½nÇUÏò!„r=¡õ‹ò¹ŽýÿÿìÝyL“gðß{” ÛÜ€ É2QŒfžè<&ž3qrHQœÀJ¡€rˆ"ˆÊ”Ð:QÀMT<£‹Gœ: Æy¡‚ËŒsš9‘Ê â@ðY‹1ñOãp í7ùä iÒç›çÉ/ß¼M^€î¡Š:ìØWI4]& st\-ð©D+‰r‰ ˆtB"œ—I.Ê¥Wmå7$Üe ]ïrCB·º”¯2á¦L¼*Klijœãí%ʓз¢é¿©8R*sRNœ¢ö_˜™½ïØñKf_;òK…ù…|, @wÊúîÂÈQËǀȷ·}’ȯâh-O›$’ïm»åò"ŽÛeÜпOàö‹tPàŠtHàu] ¦í^H¦Gîm$zq„M•×ô(>ÿ÷ú+Ý݃§yGÅÄnúq÷ ³/ù€•ÀüB>à­PGuuÖôqÒHÄ¢0ã&æ¸$‰t Ñj¢xâÓŒL7ËøtŽKy]g#]G’$㇉BˆIdc¿È¾ŸrÈ…³fDÇ-Ïݱóةӗ̾:äÖ ó ùX€·k{ÞƒÐÐ#ŸMÊô–ìâÓËa1Ñ—¼8ÿ%å+æÛÈdv¾}ý-úø“è9¾ã “Röì:uòd‰Ùׂ|^ÀüB>= Àÿªxÿ¥­ÚãëÓ÷¤¤Æ'h£¢6«T™YÆ?bb³W§¬O/ÊÝr´hïùS§ËÌþm‘ÀëÀüB>= €A°"(VÀŠ X+‚ðÿÉÑ^üJ•7kÎzï©=Ç®:Xãæâæì14l¼WüŒÉ ‰Å›sΘý{"€×‡ù…|z€·H«½¶páNç}N4[n(•." (”7=o ‘ñ­…DAÆ9 $òåyAô㟾ýB½§mËÎ}höU €Wa~!Ÿž ûÅ/+î¡q´ 2=ôŽ‚b¤“]B_û޶ñrAÍQ¨È«Q#4‚)"yA-p‘Ä©²åI¬ÈÅð|ŒÇÑr"µñx¸¸BvÀìëB>`Í0¿Å@è6›s3&–hºqßËHÓßnƒ-¥É)UN)’”÷û¤¹Ê3"ÇÓs«×„l¯)[&NÝ6iÚŽÉÞù¦xNÈëY8ÔC;xÈönÛœœ²J#Jå詸(R p¹jäðukS/›}¥È¬æò±<(Ý`©ê·¥DÞ2é’wWE-ëÅe¸öÙé5âdм›ªruè•Ô¤²ý{šnÜ`·î°ò?Ù‡ì^…ÉïL¯\+c9ÚºÔµÂUåóçÿ:{VɧãN¸¹ØÛfõsÈ(™(†§"?û^š¨£f_5òˆù…|, À’°â'^œÃÑR™t¥ÔƸGdBêG §O¾°`^©&üîºäÇÅEe¥¬¾Ž=kcOž°ªZVUÏjZXS;k}Ξt°ÆXu«4°§ÏØÓ6VSË®_g…ù‰q¥!Á?ø›4þä@×B;Ź,E Ø®_Ñ xW¥Ž8löXÌ/äcÙPÞÐö¼{Ã<‰|m1Ôu»ÊV‘íåyÎ×§Ôϧ$*êfÞŽúÛ·Ù£G¬¹™µ´²Ú:öX÷\§ï¨©ë¬®k34µ7´t6`0¿5@x3gfœQˆhºÛëê|xôèË3¿(ó (Ž+ßµ¯®ì.«nfíL×Ðv¿¢úþßúǺfCm{¡S_ù¬J×Q¥o¯ÖµWWµUë[õú}e£NW_kh­ªzRYÑTñ¨YWÑf¨b 5¦ê|÷/–¥mò,ñS^ øÍsÜ™ýóä™<ʼnôµ@¾ÞÞéfÏù@O‡ù…|¬Ä¿ÿÿìÝ TSgÚðô³*UÂ*ÂŽFYDÔâÈ tt¾Î¸·™v¦êX[E6"‚ZP\Z?´.Xi@I–°“È’@ daIH $Av\ªö«3Þ¹IµVDZ̜ÚfŽÏ9¿óœ÷½$ÜËŸ{ÏsžÃ`ø÷¤g6H!´eªq„1Ú?kZ†/¹rÃ:Yèjî[¿g'$)ÊÙXï ¦Ť}ÃÊáÁÞMï°Z©Uw+ûʵæÿG†°ÍßûûhT÷Õª»jÕuï¸V}³_3Þ¯½Ñ?†ÓªÇ4}£øÁþ;ƒƒX‡»1ŽqùXT¬huhá†õÍ×I–.®µœyÞtRŠéä„6[ÌúÃÙóÈÇÀó`˜ A>¯þ ||m43ß‹PÔt³L’#34Xñîæ¾ÿ]SιJ½/•`ª^¬]‚µuÞíî½+ï—÷Ž*pªq…êŽByOÑómÏ#ß ô/ÈçUÀDyùí™löžùŒ}Å+ƒ:CVÊ×¾©Z\Ÿ/¤æª[±vÖÑŽuwãwê·ሤëæc·%Ò¯%Ò{é}½{·?^¥ÒÛ*å­Žö~`°£ãP„åÑîîÚ%XX²yƒ:8H¶ÀëJ¬@¿°ÓL×/;ù`> ô/ÈçÀ„Ì&¬3™öG„þl>-ÕÍ•±îw½AoðV…ð×®iÞ±½­ºãÔþ]ÔŠI:°6ñC>ÿ¿uT$ˆ†Ž„cá¸@pG_|·@ G¤cm¢ÁÆFM#ï¦T†‰;°//=ض­ã×+¹¿ÿ­òÍÙª•NWmæžBº¿“µÑÑá/AåÀ0Aÿ‚|^M0üz±Ì|ƳiïO2Þ3Õô°·WÙêÎU!¢ß¬á­f¾÷—¦.&b 9ußø[ù÷ëë‡ê4BÑx¯_o@o°©i´©i\_ OoÇíïßjß®çŒÔÖÍmÆØuXþ5ìí-‚ß„òCV –pû¦ØŸ\l3' ¡í“ÐF‹Ù› CÈ€a‚þù¼Ê`x‘<š¡ |¦47ßg<ùX€_ËŠe]xݸ¡{epéú-̲¬‚ý}ýÛÆÆ¿q8ßTU×°y-·›ZF«ÙÊ:®F‡£­ãܨã Ö5ŒÔ5Œéë°n;1 ƒµÕÚ¦ú^ãh=g´¶áæuîƒZ.ƪǾ8‡…®®ZP´¼aÅ2åþìS£Ý¯ÏÜP-_ùü‚ù0Lп ŸW /bfŒÐ[f&1“в'g©¿üß.ñçT¬}‹ùç +oÓKµU5ã,Ö-ûf k”];\[?ĪÕVT÷Ô\ïÓÓÔ°ûñ£†5Œ¿@Wñ5ûƱYƒ×k†+Ë´åe}ºmÝH%k¬¼æ^%+¯ÄââU+‚˜Á+ëµ¼qÍ*éR¿&?ï#Ý¿ÍÛõúk‘…B>¿`> ô/ÈçÀ¿4ËbíÌY6™n„¿Ñµ|±ÒoÜÛ¿:¸30°øïUUÖaåµ£¥,MeÍ0ƒ¡.,R³ØcøÍM/ì¢J«YZfYž’YÖË,Õ2Ko0™:ºµz´Uåc%…7Š}%Ì>fy_a©êŠ+oÑ‹0J°¶¶ø3ð $HâbÏ Z,õõ¬·˜~¡psÓfÎ|Y? ƒ|ü7‚þùžÏÇ7jŠñf„Þ75Iö%×ö¬ì÷'wúw.®ýUpñ¥œ¿å]¦2ä4FÇš´°PS\¢¥åËò¨t†¢˜©duÓ åøšÎPÒ½tº†Nï§_ÐUzŸîÈÑ5E×FèùƒºS”WiK+{ ŠäZ%O]TŠ81¸¤`±OM Ÿ0x™fE€v¹¯"( ¡$3“x#£·gÍ^ùüÌù0Lп ð€çZšjIˆBhûŒé‡Ý]ŠÈ^\ŸùmKüKý¥>ä†E Ž|™}7'¯?÷ª<û²€šßMÍWRózÝOSè>Dë¥ÒÔTš†Jí×UݺwÂÔ´¼!ª†FSÒò¥Ô‚v\^”BíÉ¥_ÉÔ.Dj€O«¯W×B÷ž€*_ïŸù“É)í0™úö’e‘ÏÏ–Ãý òßàY1qy3fþuòäèéæ©®Î×üZ‘E^î­ ¼[—ø æ{—®XQväèXÖÅñÜË9WÙ”Jn%GþÄS[%§‡BQéõQ(}UéN¥/'û†ÎW}9ENŽ$'WL¹,¤\•Û•Kú*ç›Ø8µ¹ÄÜìã%#»õ,^ ñ/ó[($Ì¡àÏ0B[ͧoŠŒ¹ ùü ù0Lп ð=žr1»y¶Å&„Þ72J¶±ºâáÁööäy¸·xy¶.\Ôìã[ëêvyÓ–†´S·¾8;D¡ ]ºÔûå—Ý.t=%Kòƒ­\OñÈùï·¡{‹J£<ëBgV–8ë¢àÂEáÅlIv®öì…±äÃc¡!œµ>Þo7Ù¢ù ²w'y¾ÈÝ…å8ï²ñ”8„Ö›M_Ÿ{E ù¼Ô|&è_ø!žB&ïAh Bѳfg“œ«ëííꈎ\O>yaÓ|r©)kç®Î³çî§g¨/^8wFyþ‹žÓ™ÒÓ§%ÏÖ'd?é™LÉ™ÓmgN qgϵg]T¥¥k>O»ûî»w×2²·ØÝUìå)òôhuuiòòäz¸VYÎ9kd‰Ð:ÏÝÏKÍ€a‚þù€‚à‰Ä$¶ZonijzÔÖþš§'×Å­™èÄwqá Gb…»g¡éüÞ8Õ™/î|v\™™¡Êø\~:C‘‘&KO—¦§?SŸ!ýÏetâ2Ò¥ø‰N”J“f¦µŸJoËHoÏÌìN=ÚvêîŽ*ÃÛ«¿ï‰$¶³k-‘TëáÁs!]wr(±µÊBè#|Þ½;òyIù0Lп èïÏ€à ˹[M?61N˜c™eïT„ßCŽÄF''‘‡‡ÔÕMhçPéD*póø*6¾ïdÚðÑ#òcG:N¤´Ÿ<Þuâ¨äø±:Þ©×þ´Î‰Uññ­¸ÇÚñ}–Ú…;™*9™Úy"µ ArJ×±ÏÆ?Þ¥&¹]uu«!’jl‰Å®LüúI®\‡yuŽóØól LŒN1Úacµ•ÁPC>/#† úäýý0<²qó)„ÞùÓýÓLOi¤b;‡rKk–•5ÏÁ±ÍÙYLtæÌs “]ŠV&'+'K“x‡“Z¦´¥'Úþ<âÇ„ÉÉ‚ädþcïþxå:ÌINá¤|ÊÇOtø€$5©+¯ÚjK>(J>ØuèöÃ=.îT¢s‰©ÔƉjC¢ÝjìØö¶ ÎŽ<Û¹Ìf§MŒ¢§Mý“¿_äó“çÀ0Aÿ‚| ¿ÿ3a´væk1&èSÂ빎ΠR‰±ÊÊ–eiUO 4ÚØpííØvv×üüK ñÝ)‡dŸÄpîo>|Pœ˜ LL=ð‘ý­‰û[ôxúÚ:q ‰- I\þƤ}¤}m¸ñ¢¤}¢O“Úñ³:¨Œ‹Wmÿ«Âͳ`‘aïTbçL·´Ï·u,ŸK¨°µkðpks°aÛèæÆ)Fh›©ñògq!ÿ A>Ðߟó}ÿůÀ¼±òB'¡4[›R‚M±¥m±¥M…¥MÁŠe­SmcÍœgwÍgaÙ¶­ÝQнÑmI íû⛓ŸÄ´ÆÆ _¨õi/~ñ?ÇÄŠ}ž¸–˜OšcãšðŸ Üŋ쌉øpç€1ßÚºÀΖI°® XW=V_¼îú­Ê,^ËF(¡mË–¤@>?a> ô/ÈúûsÁ c1÷ýïˆ$ZÌ¦ÙØáSoù\›Ò¹Ö•–V•VkB¹µU‘U¾‹sþß•îÙÕ!‰ŒäÇîåEïmŒˆàED´D„·N¨>!˜PÝ# ïÐ…G´„Eq¢ët¢Âcøîæí “DîÞ²EfoK#ÌÉ·&”Zj, µ–xµªüŽî«°*w°-ŸŒ>ŸŒb^Ÿõ1äóæÀ0Aÿ‚| ¿?×?ÿÿìÝùOUwðs¿w}ðÞÂC)ºƒUÚjµ¸‚¨Õ ¸q(¢ ÕN2Í´µíL§ËtšÎtºY¥ìx;o;Y¤µíØé4ó[“I™Ì1ç^ÀÚQÀ§6}É;É'ß\^Èå{OÎÉÉÉ— 4ìxî‚ `¤üàO8þÚçõÛìë¼N›½ÙS{í©=i©‘4{0ÝîM³5ì)úò¹êï/œûç™ÓcçÏUUEÏž¯>;Q}öó»[§U_¿«µú«êª*¼8;qæÜè™ç¢SÎ_+;u­âÌwçŸÿO^ÞhZj°ÝÖaOí·Ûmö^í"Án,Y0h6Öñð2ÀáÊÊfŠÏ‰!„øDý‹âCý}&4ìX–yšcÇdå5³¥Þf Lá[GJjÈlíBVKÄjé²Y:lÖ€ÝêJ1ÔlÈé«®úwEù×åã••Ãeeý§F**Æbq-ŸW<û¥ /*ÆÊ+£å•ƒ¨ìt´¬räèÉÑÒŠoOþ!+3`57›SܸUmÏ=Úþ;̶²Z;Pª5<ÏæxI'W/Zø,ÅçćBH|¢þEñ¡þ>“Dênˆr±¤«–å7ìiN½Þ—¬ëSz³ß` !“1l2†RŒ“×fvᙹÄ]Qþ}IÉijå×;6PZ:RZ:ƒ“㱘8qò UéĉұeÃ'Ê†Ž—£áãec%G¯;ùÝÁ’ÍKw¤¤`x¬æ°¶g¬ä€!ÅoHñª«)€O¡Oòš­°˜^Øî†Æo(>÷B!ñ‰úŇúû,}Ø»ïÏ’| *9é=®NŸ0#ŠÞ¯ܺd?JNjGú$¿>Ébh³šóÓö~µwÏø±c×K—8røjlÆbüСkªÃ㇎\=t$ZrtHƒ×”|^røÛÜÜSJ­ÑØl4¸MÜ0nÛ¯Ó»uzç”d/>‹Q…º$é}‰ÿ­À½Eñ¹ÏøB‰OÔ¿(>Ôßg‘è@šýˆN©øÉx™ñµ‚èU’:eWNrª«Î«S|(Iñ&)nEn2fSýŠåÁ‰={Ç÷ÿzl÷îþââèÏéjqñ¨/¢ûöíÛ?€ëÞýÑâã{öMì.¾±x)îµ:¥I–[Ù£S¼:[§kÕ%9dU«¬sã³`K¬A¯» ð‚,U(>÷B!ñ‰úŇúû,}(ÙYü¶ÙÔ¤(.0Ÿ(»EÙ©­nYò Er+’S`Múä“¡ÁœRSPð÷ü­Ãû÷½cç`aA´°pðç‚7/¸ZX0‚kAa´ hí*Šî*ºZ´g♢ë; n˜-õŠR+ õŒ53®E–ܲì”e‡¬4‰ºFWíqxÖ†O! WDáMY:PðáÇ7(>÷B!ñ‰úŇúûl ð‹ïàTuÚe1UT›MŸ |-@½¬„y1œ¸&mupÐ2ÍÁsÍŸ|Üé­6ìÜùÅ–üèŽÃOoؾ­ÛÖ>„øåާ”ÜÜžíÛ‡wí}晑üüÞM¹Ý›r{ó¶ íÞ÷59©öfŽÿàSÆ1ûš´0pp\Ç>¾pU¡Mâ]<Ô¼®ˆ/ôU›7Ïv Fñ™=>„Bâõ/êïÔßg—ÐÀÚUE¨xA'~Š Ð(Ê!NðÎP-<×¢ÕÀ€KFcã²Ì® '¶íø2Ëp~ÞÀ–Üþ¼Í}¹›zqEøåƒ’»y`K^4KtKÞPnÞÐæÜÁ¼¼«y['rÖ,^NÒ×á~jxÞ3.f9Sµp\ÇÕ©Ù?] Ü’èeÐð.ƒ‹<;³üÑW(>÷B!ñ‰úõwêï³Kè@âàø+À;wYm[˜èhUó³‡H˜,€¶IŒkÅ“±fL,ŽÕè ŽÌåù[¿Ù¸~xÃú~´~]ߺœ^”óT𼾓î˜lÚ8ˆ7ÏÉé_·n`ãÆ«›7mÜ|mÃÆ/ÊðÔnwY+€&8ïÆ,gàbê†Õ!X+,,æ6Žùd1(°V€¿¼ Pi±^ðøþKñ¹·øB‰OÔ¿¨¿SŸ]ân×L/êåOD®3É…Y¢^ü¤Ún)'h£°(¶ªL\ÕX™=ºzÕàšÕ½kŸì{jM?®x½ú‰îUGž\Õ3ƒHLð¶xÏUOô¬]3´~ÝXÎÚ±ììè²e}Š®‰©'w5˜ýÀZœny/8æz8mÖ²ª¼¢x'§ñoœãŪ×~?Bñ¹‡øB‰OÔ¿¨¿SŸSâ¯^0ȧ ò"|ÄC³$z9æhÒr¥éÿ @­ µ<Üê[2à%Ÿ¤xµð¢Ódòf.¬ÈêxlEdÕc½«ï{"»¯W.ï||e÷ewÅ${egöÊÈcÙXWÑU«G²²æÏ ôm<¯îS­XÖÊ ^ði€°k@Û¹XƒŠkÁÃóžóHb“$¾ð"ÇÎ=ÑJñ¹‡øB‰OÔ¿¨¿SŸSâŠ/åóL= ú æ½Èû€÷¨¿+Æ7ÏXàQÈ Mýº¤°(µã@ŒhšÍ1¿mñ‚@ÖÒðЬîY]Ë—ue. =šy4³óN+ ßýºtIpÙÒPÖ²®å™=‹EÒì‚?·–ǼgmŒwcêkÙïÓvˆ ÀÀu[¸p•¤Y¹Ä äøçó·ý•âsñ!„Ÿ¨Q§þ>§ÄÖ®~I„3>ÀÅsX.Z€ÕÏP85Ï8Þ¯¾/)¥¾}r%YwÙfqd¤»>\´ °àW_exñzá#íwZÛ.ðÝýŠ·zäa\ýóÓÜFc‹,52Öˆƒ¯ö¾‹[z9ïôöÔ2 š<Ó^iú±8,Ú6Ql¥K‚ø&À…Ù/S|î!>„Bâõ/êïÔß甸Àâ…Õ§^OšJX=3¼¼‚ T§ýŨ›ï¾à9™Xj’IRX;œ*µÚµ_žûà“$¹Ñbö¤§ÓÓƒéiíiiþŒùxÝž1¿ý§«/#Ý—þ÷n×tßCóóÒ‚©¯NÁŸU‹תS&çoçäÔ;=£ã–‚ ÂõLÍ~v³ðê»>ø€ÜGŒ©ñðŠÏ=ćBH|¢þEýúûœw°ÛNòp–ÁÛÔ œGà‚ŒÕQRKîGþÛ`ý¸â'Zæ9´ñÌ%ñê?ÎÐiÿŽÎfé°ZC6KÈj ج«Ío³úµÕgµyî¸Z¬n«Å‹+Ö’ÙâÂ5%Å'2§À¼"óòœ'uÄÔ1×wǽqâ ÂAçÔÆ8‡Z W— uhàx§ Ô¼𢢜p»Ç)>±Æ‡BH|¢þEýúûœw°Y§ €‡ZL) 3®S;!šL£€šjíxÁC@d!Y )RH' ú°AÔ ÿ4ïìôzJNvOIò ¬·‡xMbꘜa?az°´\wi©ÐrKøÞ-©¯Ï¿ÃÁ+ŠRÚÚ2Jñ‰5>„Bâõ/êïÔß甸€Õrâ§Ðɸ.€0L ‘151)ÕÅ4•ø0Ö€,%! ~IôJ¢[ãšæž(¸&©£*óâtŽÛCªÛ?™u?]ÓV߉an×XEÂ@~VšÄÞÓ  ü“;(>±Æ‡BH|¢þEýúûœþÿÿìëoUÆŸsÎÌ^ZhêøÑRý F¿j¢Q£F¼+‰b¹y‹("£…`ЈoAÅ ¤BéEzÙÒÝî¶K[Û‚µhˆþ-žsff»]ÛÝÙÖ„1û$¿¼ÙÎvgϼyž¼y2gÚÚ —]¶j¶´hR@/|w„®]½a䥕×i]Ôá ZÉN¥Ú-mý£<¥D}%Õ‘)GöêZ8bÏÜ­£¹5À/…ïµ_Ñ>ßzz”¹Šv!ŽCj´B¶Ct9*m/ðGœˆÉÃ|¼¯ý©¶?„B¢ çç;ç{Ej7\~ùS %vY´9Fj: j<)w‰¶bÕjî׿ÑôyòlP‹;Šè²ç×ô•T}«û~«ûTá¸ït¾·èüs­Ç Ç|—h3ÿùBW¡?¢ –NÝf£ÞŒVÏiö§|!„DÎ/ÎwÎ÷ŠÔn¸bÙ“J4K´˜=p¾2À¬Ž­’zÂU­¶Ó‰ágèn‹¶A­]Eœ*zw¦Ì`?Þ[8îç`ãÌSAÎ6wëæ_OŸò=ÜnÕßnÏ£ãõ06Nð ðžÀöDâéýûO°?Õö‡BH4áüâ|ç|¯H퀦«×ÏÛꎸ²Í>3®å›‘ÈÙZ1}ájŸ•§­¶¼©Ñ7›Ré—­B­Gõ§”ïá.ˆk9½†tÂWbØ:G_ìà]à•+–møñÇ,ûSm!„DÎ/ÎwÎ÷ŠÔn¸õ¶7•\ lUøL™?}¥#ã D>îŽZ÷­XSúÓE(!5»'ãŠlv=Â$r?ÇgÐß›U¶·ÀN|ª”6ÀËW-¡µu˜ý©¶?„B¢ çç;ç{Ej7lzá»x|À6àC%ZëÜ´49ãJm€ D¿¹¦2•˜©úS¢²;,ú—ÍG®G`@"ã˜jöÒ Ñ+ÌÆ¾,Œôó@N‡ã¸{Bá7Þ"Í×ÝðZW×8ûSm!„DÎ/ÎwÎ÷ŠÔnøü«³À£‰ø[À>Wý\ËèlU’µ ” wÞZ-Z©)+뤊lV¹ s/ë +­„AÏg€!}i1‘Š»? ì…Ú¹æ¦[v°? è!„hÂùÅùÎù^‘Ú æâqŸë¾žŒ4ÿ¯N¤¤Ñ}¾\2Ö!ky²³É‚O&üz„‘~ÎAN'˜@,üø;jë`Òíw€`#ðø½îfÖB!Ñ„ó‹óó½‚G.ú ."KV/Ö'ºÎQ 3®ÎHŒè˜(4"W ƒe©êT‹EbH!ïššSfWŸ&'0"0fCðà’DJ©ÃÀv`L<¶nÓìÏÂúC!$šp~q¾s¾—§¦ÀÝ÷ì—ê¥xlŸ£t"<™4¿ Ù'Eò³A|¤g3¿̧òV‘!©f1 WÖÒ  ŒÃœ-ÛPwZ©¯7Ûpé•kw½ßÍþ,¬?„B¢ çç;ç{yj:¼Õ’®[ºÉQ-®ó%p4‚¹a4®5+V”ª6_ªËY!87wÞ-Õ¨w’±ÐŒ_U¤~o0ñ×3@¦¡¡ßq[“K›—_Óüõ·yögaý!„M8¿8ß9ßËSÓ@#c÷Ïo»ñ£Ž°‰L™=pÒ>T.û!ô‹LðɯVF“¶Ž[å¼w‡í/xµ"£U朆¥Ùgž† öÆ Û•k”“vÜãñÄDòµ˜»òŽ;·¶µ±? î!„hÂùÅùÎù^†Z×Þ¸Î*ÝÄa S‰³Rü‘‡JÏ !¼9ü&ð»ÀY/({7¹`vÎE˜ím/³ûM'xÈ!ÈÈqmÚ3*žê{`°æ’Ƈž]ûû³˜þB‰&œ_ìç{j=lyãœGcÉíŸBt¸êð» ¸ÚZôö.˜}‘  ¥ÿ[`€ï®Vô 0äm}³W1b¤/&LU#N,%å70ý÷‘¦¦µ{öcÓB!Ñ„ó‹ýá|/C­͒Ƨâõ[Ýõõ½ö˜Q¹½É5n%5R¤oÏgxÔ ïŽG¡êUIãÂÂ&Œúý+Ê Ù©Ì†¿-À÷ݾ퇟2ìÏ"ûC!$šp~±?œïóÁp×Í·¼¬v$bÇ”‚ÁÓS0?N„§¤É¼#¼#»JL(L*óbÒ.~ÊGL(•¢UÊýÀæ¥KžX½æögñý!„M8¿ØÎ÷ù`¸kÏ^zW:ŒÉÞúØ9‰óÀàOËyë„s¥Š÷åU`22U¯JaJbZš•ë£Éä ’Gì¸uMMÍ;waßB!Ñ„ó‹ýá|ŸÃõ7¾ ¼ |äŠÖ:gHéüpAy@þj=à…Ëó–© kF¡zÒ?¯—-}O›X,²1u8¼ÚØØüÀ-? {ÿ‹ý!„ò„ó‹ýá|Ÿë¯÷(µþ’Æ}À''&¬î=ü­+|”`Úå ¦£Q§=é{ÖµN8§Ä°£ºC@‹ëW¬x~Ë+‡ØŸÿª?„B¢ çûÃù>'ÿÿÿìÝyp”åðïs¼×nH!ÃU§3¥tœql§ƒþU *­ÔÎ@5Âh¤B5ÊaÀZŽr‰:kË!(J9Æñ€‚Ü)Ç(‚Š#H€%ÙÍî&›lBäFÛçyv7$€x”ãÅüf>óÎîæÝ7;ßùýæ™ß¼ï»K@ZNÎHÇÇ1]U‰kí°ÌÈ+téB‚IU^Œíeü3ˆO¡¶|/X)P¦0d(a(õǶÔÜòR,xÈbêÃïbØé9Û_Ì ~Ð鱿Ÿ±dÉÊç2æC!ÄŸhý¢|h}¿ i³fï“ÖÎGÓ»æì ºª†v”X3”{2Saà»uÕû Ë«Ü™Ê;èíAÎÔP^*Å!‹—˜ßÅøkÿ[²y ¤ò“žùOÌ¥|.o>„Bü‰Ö/ʇÖ÷ ÑpN¯^“€{{"ð2°ØìˆbOD Ï%U8<ª‡K5øê!Ø4W 1RCpÈ'[)Õ\®¦áKìax_ð÷lk¡à…R>Þ©S^ß_™?%åsÙó!„âO´~Q>´¾Ÿ‡€s..nß¡?T,aXgó] ÄY­Ê ¬b·ÑÜQÓ!ÿ0Wì© þ3ÛÚå8›¥XÆÌÉ//8èæ[þ8vÜÊçJäC!ÄŸhý¢|h}? ­ä› ôqÝÀ«ž³‚™¯Å ˆ¸…jUèaÆ@CîÜq< VÁæ(÷Ãæn˜]ÀÇ^àCÏ[ ¼hîñÔãÆ¹ƒÆ½ùÖ:Êç åC!ÄŸhý¢|h}o‰€óýìÖaªVÔ .Ër‹€f¬ŒUŒ†ØYìÛPŸ‹æ$Ý‡Ž·ÅrÞž†²ÞÑwÔßžÿo~§|!„\hý¢|H3ηhù'7tQ=0lvû¬À滥âuq®*^€µV d"å,"|ƒó2Ç 1{7°|Ø`¼—5ì–_<9vÂܵ›6S>W4B!þDëåCšÑp“ ·´ë8Zõ€dó,¼—%÷º<ÌÑ À¢eºô« V2 ~±ZD´…xkÑV.]ÓzŸ*#žÙ9œqá?R;”yö)w﯅àù?ê9b`Þ´W^_Aù\…|!„ø­_”I¡àâ~ÓïY°–(0?½$hí韽ˆpY'œ#@Xw‚W¡ï8Ñí‘ÆQ‘“Z¥DB¢Z"iÔq$9 • ±ŒŠŒp Í/ª=ë’ú1+gìP <æXµ¶úH¬¨R;Ø,"ñ‘ƒ5.Ý…Œçuîv߀ÜñÏÏZHù\µ|!„ø­_”ù’€Kè×o pOÇìIkð/Û³u¹W˜ÛÞ@ ¼nnÌ\k‰Ÿ£€›à™`¨6,Ý ç5CËCUš=Uõ71Ô™ýÃŒ6R_ÁSuoÄÌÓ2‰½6ÖK,˜tïÞ}`ï¾>7gãÖ­”ÏÕ̇Bˆ?ÑúEù.¥OŸ©æ†˜?³VÜÐnov0ì¹ Ë­¯ÖC0¢"Ð}|JÂhYÓzNµDf«kHfT·–hý4Ù‚>²)ô惤J?ý_ ±O°O%ß(õ™¯Ivë6ô®»GMžöbÑö(Ÿ«Ÿ!„¢õ‹òiãhø¿¼½ÜÎý+Ç\`©dÛ$ßm~;b*¯Æq G€Zõ"X5XX¬ªûZŽŽÆTÿèïèe§Øs· ¹†qUýã-öpNÎà_ÝùÔ¤gç­Ý|g_ʇBÈõˆÖ/ʧ-£àëýöž2 FI6ÓË%6ÛºNÒ‘ª 룆éV“)ܨ¹YÞ\3§…M)×´VûÕj âZê]º+9ŽqœPÿH¢ÎQUý®Sþð‚úœ`÷vé: ÷]ÃÇ?=kuÑ&ÊçÚæC!ÄŸhý¢|Ú,¾‘Üܹ99ÀcÀ3kY{o«ÄN ¢Šé3Sªè]Ðf~å5úd™ª]]ÄÑ´Ô8Û<Ñ~e˜ÞÐGPo¯ÒÇaµ™8*Ð(Pë "`í³ùzà` 0,·ëwÇÝC&OŸ¹jÓzÊÇùBñ'Z¿(Ÿ¶‰€ojÂÄÕ=ºò€ñYÎ"Ž· Ùr¿§¿Ž* ÖÖ¤ásµÔÞ¨‰z# ‘€¨4¦¾•¤Qg$3ÌŸÔþܼ‘§Ô1–”¨±YL¢Ô•»<¹x <Ò¡s~Ï›†ô¿¿`ú 3)_åC!ÄŸhý¢|Ú ¾…·ß‰ÝÚK_çð©æØX’%Tñmâ㕌'¯a¬¬Þ4ƒê„“i¬ÙqÓº˜©{½¿®iõ–z¦æfÖ¨ëWt'˜}êÒGS=¦^1!ÊmQêÈ]‚mòìw9 <lÿÏoyß Ÿ›µaëÊÇoùBñ'Z¿(Ÿ¶†€o-ïÁ…:øS;{0C`°VÚÅ^0Äx©¹?&¦†T Ö–g€ÓÐ«ÐØYóôXê×—Êé“YH_ÐvBâÃqóJC=ç ¶h°­ãæ-Ç,^﹉@ 亟¾XÄØ\`20ÜñîÒ#ï¶ÛGŒ™õÚÒU”Ÿó!„âO´~Q>m ßÅâ…á.óÜöŽ=Ÿ^_i»E¶ó¾%?’²Xð‘ìˆÄQÁNJþ…_Jñ_Õ§Ž |.õö¤ÄiÓgÎX8«Èô_%k°y½ÂQ/Pcór×ÚcYEL,þüx‚É!:>ôÓ›óûçNž2mÁ;«·\óp(B!×)Z¿(Ÿ6‚€ïnø£o}:f´¬§Õ( ü]wÔ‹+ßpŠ=@PÅõOÙ5érçg\ñ……Ž9z{Ê1uïଥ{C_?'Ñd¡Éã ®<5«2(*\¨£m›ûÜ'r«À  d¼ñÇõ¾óÉ£g¾¶xí5„ò!„ò=@ëåó½÷?ÿÿìÝyLTWðïm³± ‚µ¶BÀ¤©(FS¶‚{E–ÄÊ&²(V ÃÀ" Š "uCYt¬¨`+*¸E„XµŒuDMµ±±.( *¸Ôõö=Œ‰šŠ0s’_^È2™{òn¾œ 䢼¯o¦äÚØÍ"1š¸8^L縢Õ"_æäpÔ¥[£ÝE[ÍI9Cûråì ÝV+šÔÔ¬¦»îÉW•rG¾ÿ·šûK¤KDõD'‰ŽˆT-R¯üŸ»üæq‚aëàÒÓoø¨ïÃ"³W®)¯¬>eöXÌ/äcÁP:‡>~£sÑD&ÚÑq‘Àg- *"*!Ú)ÐI8ª‘ŽkÕ§m´uwR¢³ê$:סA¾j„zxZ-Ö¨ÄÃ_Éq»‰¶K´RTÞMÏQˆN7Õ£OÈèq† i« vì¯z§Ù×…|Àša~!‹Ðiò‹~:4‰h¢üÜkÈØÃv™ ek)KK™Ræ'ݳ=û¬:¨ÐÛ{ÏÈŸqkG_?fÂÆ±¾›GŽ+ñ¹y˜wi/Sß~<Ü×;9å ”M”ÅÑjqQœ@1Zýà9K²Nš}¥È¬æò±<(`Žþ'W÷9D¾õì%͵ãV¸ußä3¨*lZ½>ò¼!êTVzCŶ¶º:vî;ÿ'»t]¹¡¸xU¹s¦šZ³–\ÑŸþ}Êäšá_pw-±·Ésq((ƒ(‘§X¢@{»Pcü>³¯ù€eÃüB>– ཤÎÿ…ý8š£Q/P«äg4U#d}îQ:qì±Ój1ädÜ,/{ÑPËîµ²çOÙ£GìÎ]vçkyÈÚž±Ç¯Ø£ìÁ?¬é>»ÕÌž¾¾xã½ Øõ묽=|Ìî¶²›¯o¿hi}ÙÔú´¹íÙý‡/ï?amòKí¬¹õå­æWM-ìÚMvã»ß¦ì–ÆFvø`{aþeÿÀCA!ç¦N==dÈ^§n+HÙŽôò6èÝ+Ædº`ö4XÌ/äc þÿÿìÝ PSçðôY—VM„²¨ÅÊCiµí«ŠZÛ¾nj­­Zë‚Q\Q±>ÜQ1 $ˆ BØIdIØB „@«JÕV[ﻡÚVk-íÔšŽgæ7g¾ï’pïü¹wΜÉL€àÏX°àÀpƒ„>¡û´kÓdëLŸÊo–­ànÜ*þé A>Ï þ˜„¤ "ñ3„–4üÒí7*Ñ‹T¸dQsð|Λo±""eù,¬M‹){1I{·¼[ÛÖ£jëVÊÕʹF&ïQª¾ëéÂ:U?hÚ覆•Š›JÅ€²­_­¼¦QõkÔ½š>œZÙ§jïÅvj´Z¬AŠuôc.¶y›`~pÖ’Å5!‹Ä3g”š=e<,Úxx(BË&Œ{÷Ä)ä£çùÐOп Ÿç ÀÇŸ_@!&¦[Ú<Ú$‰hÇ”½³¬ýÙ[6²/QnKĘ¢ ‰±úÆ›-m7¥mýÒ¶^NÑ/S Èä·d­wZïûö[:òo~Së­féív%ÖÕƒ5K±Ó§Õo¯`Ì Ì^º¸qap³¯W•Ɉ$„¶L³{¤áê%‹ÏA>z›ýý òyÞÀ0TîÞ_ 7yßtÌv„B ¶ô¹As¥ _UÌ ,ßΧ¤)k+1‘ka--øz‡Çï7]{à†XòXrK,¹=èÖƒíïW‰ä†B~½A¤áñ´ wù,zsÝ:Þ,ÿœeK”ÍS]8N„„ð [;ÊxãìY!=Ì€~‚þù<‡`’ñ拌F½‡Ð‡¦£bè‹þÓðrõ¼ îÂ5kV×`ìÒu˜¸«Þãr¸u½aOÐu¿‡Çïãñûy¼|ñãv•Ïï‘4öÕ ´••ªÊêk’fLØ€=wwÕª†Ïå¼õºüÕ æys\í/YN<‚tß“bgûä£WùÐOп Ÿç ¿ƒ–Ýl:fɨ†~1Ò8ÆÃ=o~Pã¼ Ák ªç2Þÿ¨ª‚ƒ øXeÅ=vÙ·<î½:îíòò®ò _Ð_U­Ô9H[UÕ[UÕ?_tUµ¶š£i^¯Þ(g÷”–éÁXeXÆeìíå¼×‚¹Asy3}9¯¿*ô!e[¾Ðêa(dÂø¥>ä@?Aÿ‚|žg0Sššn7~À×»vά&¼†,i™˜»x9#¯+`Ýc]½SYù=›ýmQqw K[]{£ª¶·˜%/ã¨tØê2vG[[VÑSVÑ7X»uÛ¡©¨Ð–««Ê{ª+{ËÙ½¥×®rî–r0f9vü$<¿ÈÏ7/`vÅœY?ï’Ù>¬1#÷¢õ/Ž]P5Cù<Ã|è'è_Ïs€'11 DèM£ÐahÉ=ÓGº"䎟××·`ᛌÿÔfޠ媋Jú™ÌëLÖµf/«´»´¼‹Yª.(n-¹Ú>HUÂÒàF ³®âkVDZ˜Ú«%Ý…yêü¼vݶ¬§Ù—_r«…åbaáŠ9ŒÀ¹å¯Ì®\0O2Ó»ÊÛ£Ä@÷oóÖ½øÂ&„‚!Ÿg˜ýý òyÎÁð›ÆMX8v܇F#6 =/7Íž!÷ž*õpæÎlô÷Ï~÷ý¢Â2,¿´7—©*,é¦Ó•YW”LV~sÓ²šhY’b¦š‘×:HÎÈkc䪹 F§Žn­2uQ~_NVÇz{£‘ßž•+ÇŸºìÂë´ì»ôìã•u¾>tü ;Ú0fH¼ÜÊ'Œ>†ÐFSãÏÆŽ}ZŸ…A>þ‰ A>€ÇóôÚ<ÂpBEy‘Êü[çøk|H-þ> þ3J_ Ì>—ú}úån ]J¥7\¤J²²TÙ9jjFs:¥‘F—e3äô+-´,)¾¦Ñå4z¦¢Ñ4´ËºJk×"šêÊåZ†63SwŠü"una[æ)™ÚDNW^ÉÅââzýý2gx–ø{óg©æøªg{É|EEš…¼=nü"Èço΀~‚þù€{0<ÖüàX3óÍ­3:ÆÅñ Éã9¥ÞÏG6ÓGâIª˜>¾kwÏÙ”›©éš´KÒ” ù‚ð|ZS¥ë|ê·Û”ž¤oR§{3ɹuÆT•×”fïi|ó—Èø3ŒÐJÓÑK7…^€|þ†|è'è_ø 9“R3~ÂR„>00ˆ²œtÑÕ•åáVíêRëîV7mz§W©“ó…¥Ë+â\?~¢‹Lî:w®íìÙ–Ó§›’,þÅV:Hvß©VŸ¶C¡{‹bþFiòéÆädaòÞé3ü3)â”4õ‰Ó}Q1}ÁAì©®¥žbçæéSd$FÒ‹#ÓnòÃa-6½8í¢òyªùÐOп ðK0<„Dú¡åm7>…èPìàPnc]F°ã¸¹rIÓª¦rí‰Ék×5ž8y;!QyætçÉcòSÇ[&IŽ?ZÖüבK;Zì(wâ¤(ùŒ">AõuüÍwÞ»8å‘<„.NBw7›k“c•»ÇÕ©È쥛Zäê¶òyªùÐOп ðK0ülg$Ë-65Þdl¼ßÊæ²›Çѹ†`Ïutà ;B‹[–=ñÔÖ0űã‡Ê“‰_K&Êã›$ ÔGHþ¼ÄF\b‚?Ñ‘ÃÍGâ%Iñ¢# õ‰ ¢¤¤–Øý-ñGn®Y£p$Ò=Ü+ñûž@d98•ˆ¥®®ÕŽÄ«ö¶9V“’ú Ÿƒ×¯Ï€|žR>ôô/Èúû#`ø™ÙĕƆŸF¼d–lc¿‡ì•ööWW‰“3ßڶО˜éìz~[xûáøîýû¤ö5ÄE‹lŠÛ/>xà‰6=¬qhUx0®w@„ŸèPlîp¬øplc\l=þ‚¨è¦‡ú?_§$:_rr.!K¬Ù¶N üú‰NÛÉev“Y“-3 v0Xc9i%®„|žF>ôô/Èúû#`¸/dÙ„VüËxÇ(ã8‚Õ–˜mm›ofÁœdQmkWïà $8°'ÛÒHÓ/mÞ"Š’ÇDI"#ªc"ëöG×GïFí=Žð~T/*ŠûOçǃ¿_¹{bØQÑìè½\üD1»Ä±‘M±xÝ%Ú·§>j· jwÓž=êO×¶:ºP9¶Ä\K{Š%‘Jp.±±eÙXU8ØU[MdŒ19jd°eÔÈÿúxo€|þò|è'è_ô÷_ƒàA Ǿj„öš¿˜fç@·%æXŠ&Y1Í&•››WZZrl¬YÖÖ—½}r6lE„·Dïiþ*”½{GMÌnáÎþÎÁãðïÛQ·sGí êÁZ7t;k#"98ü‘Ûù‘Ûëq»Â‘Û{#EøYöì–‡…+V"svËœL ÛØçX;ÐÌl2¬ìò'šXYW¸:×ÛZ²¬Íi¦†Ñh•±áŸùZ\ÈÀ?ô/ÈúûcþîÏü ôÁËsw!bh¸sŠ·²Ì5·Ì6³Ê6³,0³,2ŸÄ´Ð)¶´`L¶¾ì9-oÕÊ–Í_ʶn©Œm¯‰ÜÉû*´nÛ6þÕ=ìÉ/þ5aè6áýßVúUͶ°*¼†Gð¿ØÌݰ©14¬óÓµö„ ‹Lk+†¹E¹EÑÅøÅë®RÞ„RچЪY~ÑÏ_˜ýý òþþXÿÿÿìÝùSU÷ðs¿w}ðÞÂ{€$qŒ’D£qQ£pa´â.*¢à‚MLLÒ¦YšfÚ¦ÙŒöíí<Þc_²ˆ1“4m:I§“_:þ=÷¢Ñ4¢fòf83ŸùÎ…ßï™sæÌ™/hPYíûµwD~mµx'=‚So»}R«=¡Óß§JˆkOˆo|$Þ—4Ý·kÇßýç©“ß>ÿüõ3/\=ý•“'¯žûó£EßùË¡ƒÇŽ †,::t¤ÿÐÑðMÇ.ï=p9ÿÐ7ÇŽÿ;=½ß[‡l·5Úc;í¶n›½];B Â#Øí-Ó'w›¥<¼ °­  ŠâóPâC!$2Qÿ¢øP «“’rl§¬¼f¶”Ùl!ƒ)ckŒ‰ š­ÍÈji±Zšm–F›5`·ºb /è(*üWþ¾ëùû z÷îíÌ?ЗŸ?0—ÇãJþþÏUø?°¯ ¼¯ í=Þ[зcO^þ×~Ÿ’°š«Ì1nܪ¶ç6mÿf[Y­(Öг9^ÒÉES§ì§ø<”øB‰LÔ¿(>ÔßG2Ñ€Òò¢œ#éŠdù »Ã©×û¢õ!}L@oöLAd2†LÆ`Œ1còÚÌ.œ “§»ó÷}—›;´ßÕ]»Â;wvååõåå ŒÃžÁñÚ½ç3UÞÐî¼Ý{{wïíÙµõîÚ;»ãòÎ=ßlÉý[\BuL €Çji{ÆJbü†¯ºšx }”×l¬øÅô²ÀÖ•W|IñyÀøB‰LÔ¿(>ÔßG1Ñ€ /ÉÛ ££þ Ó•ê£c‹¢÷+·.Ú¢£ê‘>ʯrÇê¬æêxGùú¬kÖîÜy5w[oî–®íÛ.ÏÖþñܺõ²jÛàÖí—¶nçîèÑàÃå͹Wr·}–ÖgŠ)1«Œ·É€Æmûuz·Nï¼)Ú‹g1ê²P%½'ñ§¶%+û-ŠÏƇBHd¢þEñ¡þ>Љ>8ìÛuJÀ “ñ<ãKÑ«D5É:¯åTWW§øP”âRÜŠ\i6V›Me³f6de ­ß0¸éWëÖuæä„N—rrú5øÞ¸©gã¦.\7l çl\¿qh]Îi3pp/Ñ)•²\«ÈâÕéÜ:]­.ªZVÕÊ:7žËXbåzÝy€Ó²”o4n¦ø<`|!„D&ê_êè@¶Èëä·Í¦JEqTó‰²[”Úê–%R$·"9V©®1ÊÍ133¿ÈXÑ»iÓõÕkº³2ÃYYÝ?üðÌKY™}¸ff…3³»ÑÚìðÚìKÙ뇞˾º&ó†ÙR¦(%¢PÆXãjdÉ-ËNY®–•JQW!⪇gux Y¸ oÊÒ1€Ì>ºAñyøB‰LÔ¿(>ÔßGK€_|¿ Âƒ.‹© ÈlúDàKÊd%Ä‹ફÔÖjjn©æ¹*€OÞîý„ÄÚÅËúÖ¬ùlyFxõêÞgWu­ZÙ¹rEÂürõ³ÝKZZÛªU½k×ö?÷\_FFûÒ´Ö¥iíéË{ÖmüjÞ‚®X{Çð c˜ýU jTs\9Ç>þ"àªP'ñ..¼®ˆg úÂeËF»£øŒB!‘‰úõwêÐÀü9gEÈ8­?Á¨å 'xG(€ž«ÑjàÀ9£±")¹yñ’¡•«?ÏXÞ›‘Þµ<­3}YGÚÒv\~ù°¤-ëZžÎX^žÞ“–Þ³,­;=ýRúŠ¡‹ú¦MEéKq?y¾g\Ìr¦ªá¸JŽ+U³ÿV0pK¢—A9À» ÎòìÐÌÇ_¡øÜw|!„D&ê_Ôß©¿nB¿Ç_Þ¸óÚh[ÃD@­š÷˜=8DÂpÔ c\-Ž˜ŒUabqì¢ÞP<³+cÅ—Kõ.^Ô‰-ìX¸ -x¦ ?ßMë¸,]Ò¾`AçÂ…]K–\Z¶t`ɲˋ—|6)ÑgPÿ¹Ýy­Ê™àd¼³œ‹©V‡`­° °˜ë8æ“ÅÕüàU€‹µØãûÅçþâC!$2Qÿ¢þNý}twp»¾ç`K”xV/,re˜I.ÌõáGPwG8A…E±V½`âJ­ÖÀìÔþ¹sºçÍmŸÿtÇ3ó:qÅç¹OµÎy²åé9m#hüXüÌ9OµÍŸ×³háÀ‚ù©©á¤¤EWÉÔ›»‹˜ýÀjœny/8æz8mÖ²ÿfxE1(ðNNâß8‹…¯ýºâsñ!„™¨Q§þ>¦‰;¼z¶Ë 4Èoˆð!U’è嘠RË•Êÿ+µ6Ôòp«oÉ@µ(ù$Å ¬†&“7yFˬ”Æ'fµÌy¢}î“O¥¶áóì™MOÎn½»ÔæqIÝ”:»å‰T¬«ðœ¹}))]ñqAƒ¾ŽçÕ}ªËjyÁà >í8û±´W+Wq5Àá<<à9$VJâ{g8vdÇîZŠÏ}ćBHd¢þEýúû˜&î°9çœQ>ÆÔ› ?bÞ‹¼xú»b|Õˆõ‚ êѯ‹ ‰R=Ä8€:lîÄøºi“)3B³RZg¥4ÏLjNž|<¹åñ䦻­(tïëŒé I3‚)IÍ3“Û¦NmqØ:n yÏêïÆÔײߧí @€ë'àÀU’jdå/ü–ãg¬üÅç>âC!$2Qÿ¢þNý}Lw˜?÷%œø@Ïa¸@ªV6Bx4>àÔ<ãx¿ú¾<¦”úöÉ…hÝy›¥:1Á=屆©““ <šèÅç)Õßm­Ÿ2Ùwï+~Ôcàêw¸ÆYª`¬_í}·:õrÞ[ÛSwÈ (@pøL{ý¥òvpX´u¢X+JçñM€âY©/S|î#>„B"õ/êïÔßÇ4q€iSм-T•zg$xy¨Tû‹Q?¼û‚säpb©I&I!QlpªÔJ¨×~yîC€£ä ‹Ù“àhHHhHpÔ;þÄx|®OŒ¯ÿñêKLð%LòÞëšà›ˆs4ÄZ¼:V b\­Nž¿ÃSï­·ÔÀ ¤QoÁÔìg?! ¾ëƒä>dL-€ÄGŠ)>÷B!‘‰úõwêïcš¸€Ý¶‡‡Ã Þ Dà<×ÀXƒ:Jj‰ÂÝæÿ Ì¡Û+~GË<'ƒ:ž¹$^ýÇ:íßÑÙ,VkÐf Z­›5`µùmV¿¶ú¬6Ï]W‹ÕmµxqÅZ2[\¸ÆÄøDæ˜Wd^žóऎ˜:æúîº7‚´pÐtsc\µZ W— 5jàx§ \x àŒ¢ìv»)>ã!„ÈDý‹ú;õ÷1MÜÀf½Y<”`J \ˆqMÚ Ñp¨©V<D”Å "urƒA2è4ƒÁ‹wtz½EG»oŠò ¬·‡xcê˜Û0Â~B´a h¹îÒR  æŽð ¼[R_Ÿ‡ƒW%¯¶¦Ÿâ3ÞøB‰LÔ¿¨¿SÓĬ–Ý?.€&Æ5„àæ9 æ"&¥š ˜¦ÂÅIH‚_½’èÖ¸nqN\ÃÔQ•yq:Çí!‡ _r°Ÿ; À£^~©5P‡Ã½ ¶j¬Çϼ³Ê˺)>ã!„ÈDý‹ú;õ÷1MÜÀbÞuGøhfæG£–"!6œ¶2-5µL áŒðc‡o¬Ô«+æÒ¨×dÚwü?…“îÏ×\šáñ÷.0Ò~´3À³h7zÌ©ñâp/M€UÊü+x—ƒ×°.œo¥øŒ7>„B"õ/êïÔßÇô?ÿÿìëoWÆŸsÎÌ^ìÄ ½©Q?>¢_A**ˆ"ŠÚª@¹4’L“ªPQÒ´ªŠµJ[ nn„6‰œØY{_Öñ®wííÚNê& Šÿ…÷œ™Y¯7ñî¬ý!ƒö‘~zµ;öΞyõþ2ëž©ªÀq P\ÏÆ°Ÿª:EƤÅ`62@Õ8h‹_TX‚=[¹§ë²1'€zêŽ{÷~sŒýÙ\!„$Î/ÎwÎ÷ættx¹¿Øµ}¿gú}ïoÀ™tjö†Ñ’hN¬hTmµQ—ëBpåÖy·Q£ÁIc3}u\LúƒÀÆßÀ¥žž)Ïû3p »½ï¾ÏöøG•ýÙ\!„$Î/ÎwÎ÷ætttêàgÀ+~úŒg¦Ýc"«vœv•ë)(yQŠ"ùÐÉhÅÕ…h«\ðÓ9÷ AmÉB›Ä9g9m·ÁÙ§a¢½qsnå´ñŠž>9–É>ŸòÿÚ× çÙŸM÷‡BH2áüâ|ç|oB§€ÏÝ¿ÞN‰ƒ~æ$0jÔU­þ U…)®¡g ‚¹ |¤ð±ÂÕ (7¹`wÎ-&IÌî¶—Ýý& zzz JL{ŤKÊü 8 ìþÔŽoÿtÏìÏVúC!$™p~±?œïMèôðÜ gá=‘Ê‚zjÄ7×€mÀˆèÝ]0÷¢@¤ÿQd€ùà®Vò 0l}sW1o¥¯–m5ó^ª õßaÿúïw{{÷9r–ýÙJ!„$Î/ö‡ó½ „m;žLw^ëîžp·À¬ÊÝM®%'©ù:}¸ Ø VûéRª¬J[Ô¶lÕ^QEéQc7ü=|çÁ¯|ÿt‰ýÙb!„$Î/ö‡ó}#úò¿v/fRç‚„àë«°oW,*PÒÊÁ‘Á‘Û]5– VŒ}±â¿¢–©(5¨õðôöm?صûwìÏÖûC!$™p~±?œïÁðБ·%õ>H>žÒÝ©k7€O€ÿ8n8'\kT|(¯+‰©²þUƒUëÚ®å6Àíííí{õÕSìÏÖûC!$™p~±?œïÁ`ùÂý¯ÏðÕ`—7k¬tþñ‰¶6¨ó€þÐy —7«QÖLB ¤C–­C_·±X•Sæp øõŽ}>ÚúlÜû_ì!„ÿG8¿ØÎ÷[ò?ÿÿìÝ{pTÕðïïœs» ÏB†W;ý#ý£ÓÇv:è_µb¥•Ú¨FM©Xäa°"ò*FèT[iGãTEAÞ)à(+’K²ÉnÈc’€<k{ÎÙÝDm/“ßÌgîìnîÞì|ç÷›3¿¹÷îò`<1e‹”£{t_ ¼)ñ/[÷É(×[¤z C”ØAùhºJ‚±-I–~²um'´[ÉÍÀR @Ðèììñ_Êù\­|cŒ¯_œ¯ï—Å@JVÖxÏ›"0WW‰ïìqìÈ+Mé"Ý3º¼ˆ’øòCè­8*Ê5ÂB)¡,Û2{ËK±‡ô‡ßGØòÞ–b 0ÈÿF¯ÑÃ~9oåÊœÏU̇1ÆX0ñúÅùðú~)R,<¤œQB<Ì훵7Ã×5´G¢ÔA”PRÕ°±ß4€Ô p¦¼*¬ˆ­¼#Áؤ‡ò2%:¢Ôþ.Æ?}÷ME‹ Ó”õì¼üG 9Ÿ«›cŒ±`âõ‹óáõýR<\4pà àϼl¶{²8$+aÎ%Uy"f†K=øš!Ø6€Ð Pi%‡àH@¶Jé¹\OÃ¥Ž<@xGŠ·\g¹J=Ò«WîàŸNZ²ä ÎçªçÃc,˜xýâ|x}‹–¿\Ü­ûP! èXIØäŠ÷}‘ˆJT{ªN—¨r¿ÕÚ1Û‘à°Wìé þ#×ÙçyÛ•\MöäW(cÄM7ÿfò”EœÏµÈ‡1ÆX0ñúÅùðúÞíäY òÂÓýð‹!o-ٯŠËjuºÐ¢$CC€*< U¢qÌÞ ³x?Þ mž³÷øð­á9#¦¼òMœÏ5ʇ1ÆX0ñúÅùðúÞ}ÿ–1ºVôœ‘±:Ó/öÚ±²¨¨":YUØПPÈÃö$Ýn/´Ãñ^ž w~Çà zæÿ½ùóaŒ1v#âõ‹óa­xèhÅšzôÑ=0´°[æVà]ûÝRÕ ÕBW¼: çœR¨d%dLP¥ !Ê=?Bî~`'Ä:Ð2`j(sÌÍ?üÝäi…·mç|®i>Œ1Æ‚‰×/·µâà2fìèÒó1ÝŠ;x+SôE”Pi€bå¦ô5§N%T ârµˆXÕíÅÚ¹rM›}j¬êôÎÑ´Kÿ‘Þ¡<äVjð:ð"P‘÷íìqÃsç,}i-çsòaŒ1L¼~q>,‰€ËûÙ§@Ùo8ze†³W¦~ö¢R¨F颦BUæŽÓ)UiqeW¨U¨SHX ZÂqB<­*-ÚFë‹zÏ&B3!aSÑÑ$ "EÜs\ý‘¨¨Ñ;¸T©ðž‡ ¾xÉ‘$r{÷»wXÎÔg,ç|®[>Œ1Æ‚‰×/·}ÆÀ 2 ¸»g×agðW»ºšr¯²·½×qˆ*ø1øq{\¼-q‘ia@¤€PgÕRª:4CÛC·{êê?Ih´ûG‰ŽYɯà뺷âöi¹ÂA›–IÌÎðéßøíƒ.xzÑÖ;9Ÿë™cŒ±`âõ‹óa<\É A³í 1O %Ööèr°kF4ä×:~#D‚“áf˜{ä“j­¶5mFádK¤·¦¦DZ]{µíŸ&Ú0G¶…ÞzdéWÃü—cR’ô¡[•9ó5Câ·ýú=tç]fÎy®h×»œÏõχ1ÆX0ñúÅùtr<|ÝVŒìâÿQ X¥èm%öÛßÇ®´•Wïùg€æ´@ƒ~TªUCĬJ+jÅÌf·+;‘B æh¢Æ0‡Õuß Ð,Ð’ìó½²<ì‡ü]Rm ¡«ªCfeüñO&ÎxjñÆí×pöå|cŒÝˆxýâ|:3¾ØÏïþ a$0AÑ|W®QØ ì’8â{ Oé*lN¥µX¶¨>]¸1{³¼½fΈÚR®o¯áóÕCVÉw™®h8-pVÿ#…ÆŒéê÷½"ˆ¿ÏêÏ º§Oßa·ß9vê¬/ÚÆù|½ù0Æ &^¿8ŸN‹€/%'§0++ <vVw íTØëàpXÖ93¥‹þô%m`çWQoN–éÚ5EKI޳­íç6€í sýösjH7À)‰‰Uaç+6KYÀxPNßoþ⎻FÍœ;ݶ͜OòaŒ1L¼~q>_Ö´éëôäS3½¯[ºª’ù:ª¨tÒÀǵu¢ÅMV²ò¸Ukë[KXV"ÍþIï/ìER#QB¡Þ¥¸B™¯ö…Ô&ày`ðp÷ÞyÙß5ô¾ü¹ÏÎç|•cŒ±`âõ‹óé„xø ^}-~Ë@sIœ'f{Xäbe¦ÔÅ·EÉ£$Ž“¨%QOÔj²Í ;á\ µ:cûÁôÙº7û›šÖoi"=7S‹yl^1`÷iLM÷˜~EÆ¥¬pe™§öIÚr_÷Ô`2pF·û~pëø{ïŸVðô‚-;·p>Aˇ1ÆX0ñúÅùt6<|e¹,—xÀÃã]ÜyÀ<‰ÀFå‡2"$Êìý1q=¤ ®ºœ‡¹Xí¬y@ŸÚ§§“'È„¹TΜÌBê‚¶³ ŸÎØWš MB4»²ÙuÎØ·œvDSȯ ‡#¾ÿ€D…ÀL`¬z°Ï€Ü[o—?iÁßV­ã|‚œcŒ±`âõ‹óé×½HõÞP¿?ÇS—@]ZöžÄßÑñ7tÂ5=wU"ål‰¶:~ç^Ä QŸ¢3Äø%ŒÈ6YW×mmuz È\Ö/äãòPžÕ»S*ôž)ħcaù"†)'Zų Þ^‡}û´=/xH—uíoÔ½34ô‹¨º!ÒM‘n;ÜUŽuD¿*2ßót‘èÑ ¢C<µñÔĪ¿sWNnáød¯hßþQ#ÇÌIL-[±º±¥í¤Ós@>àJ°~!†Ð3LY{>ñD%)Ýh,áXÑ¢¢z¢]í¸Ã’pL+žÒkÛæ„@gÚ:ïС%îœÄŸù£þsŽma˜=D;ˆ6 ´‚WÏfb(^§{/0(~l„9vzáʪûZŽ;}îÈ\Ö/äã’PzRåê#ÃÞÌSn¢è>†"ž]ÈÐb–V ÂGzÝ6­¶a¶(4Çîä˜&žvsÌnžöpÌÇq7§^îvR·Ü[Fôä*T+¯º_ì‹ý⃃“'Dfåä®Úºm¿Ó'‹|ÀM`ýB>.à¹0[šýXûz[>“(]¹ˆ¦H•å[¦P?,c+¦âé±\#–“P¤ü3Q*Q‰‰à ƒoü AI“'eÏ˫ٴy_ÛãNŸò÷„õ ù¸€çkÃÆËiiŸŒ _òz±_@ާW Ñû,÷Tü?Äi´Ó$h/ŸØA3Þx;;*zYF¶½¨t{ý–¶ÖÖ£NŸ òxëòéÕPþWMÇ×Õ¶,©Ø^j³çÔfe­1™VffV*ääV•”Ö/©h¨YÛܰãpÛ§¿[äðo`ýB>½ €Ap#(nÀ ¸7‚ðÿ©®=6Ë´qrÔ’ÈñËBG,<Ðà—àŸ28}TXþ¤IÅ…kª:ý}"†ðÕÖžNJÚ<à•¢wˆ¦h5 ¢8ƒ(£4VÝo&‘òRQ¢2ÈPQ4ËÆr| Ë}àã›9a}UͧÏù¸€ž—?·qHˆÕ葨nzGÉ:ÞâíQàc˜oÔçk93Ci|¦q‘u£#êCG×µ©8hC`ÀzoïJŽÊˆl }(òK‰,exiMÆ”/¶púL‘@ï…Ðf›>ö ˜M)‰3_0.$Ê&šëÉ,÷ï»9lhkâÔs¦ÔNsÚI[QGÓö®övùüE¹ó;ùâùÒª —Õ‘ÓruíÛâ2Lqq_M™|tä[ûüê úJ_¯jŽŠ‰rXÊ$Š1x&X³š>käС<“‚ùŸ²|C³%q¨QžA $ÎöZ }â¸#Ó§žµf|S^üScÃ㎳òÝ;ò£‡rw·|ý¶|ý®|ëW¹ëù·¿äîÇòýßå÷äk7åäå[·å3gd{ÝýÂygS“?›s(|Tk ¿ÝC·T+•r”ëø–|âKýMæÌ½NOùô.ÿÿìÝyP“wð_Tõõ*‚7åQ‹•EiµíVE<Úíe­µUkÕZ׋ª€¨X<±Ú€’ &CäH ¹€„„@.BB@P¬X}÷ Õíêô Zqç™ùÌ3¿ß›¼óË|ÿzžÌ; Љ“òÉ~ÛZjo÷ê{ÅÞ.iö,ÖÒH^TdÙ† ü“§:ÄbL­Æº»±[=X»Óêè[0™ï·™ï»z;oÝ#uá/ucFó}ñA› kÖb ÖÙeé†õzìê•îäDYdTñ²•‚E‹ª/qYzÜuô)Þæ:¾ôIjªø™§ù ù Ø|úË7ðóÁ¶ïÚ ßÐV¢3cnh}ø\ùÂWUóÂÊwoP3Ô7*±Z!VW‹56âh/_`’4t>Ò%‘Þ’H{$Ò;}zm»J¥]*åͺZŸo¨«»'b™´ÛëÖñg…äE-Q‡…ʦxq=ˆWÂ?ØZ{›³g‚|`> ý2jü"kûwzßÎ>ÞÓƒ±èÍ¡/WÏ ç-\p}ÍjñÕ+§ô¾°“Ôabѯ›WÓ.™ù¶‡&¾ÀÌtðùÝøâÇm?ª@`’Ö›ÅBCe¥¦²ºS*ÃDuØ·gï}ôQÝßçrßz]ùj¸lÞÜ:o׋c"Ëï`Fº8ù ¨|~=Wf7|­ý{ƒ¬>jçç[0?¼~^¸ðµÕs˜ï~PUÁÅ„¬²â§ì{>ïA ïNyy[y…F 쨪Öõiíc¨ªj¯ªêèƒ/ŒýUm¨æêêD7Å¢®rŽ©´ü÷:Æ.ò.aË—ñ_‹à…ÏåÏ æ¾þª(ˆœë0&¡ÕƒPäèQK!ŸÀ@À¯É¤  E(ÒÎn‡ÕàƒÁ7æÌjÀkä’Æ¹aù‹—1 XØööµÞÊÊ8œï‹¯YlCõ®ªíWÙÊ2®Æ‚£-ãèË8†² SY…¹¯-Ûþ©¨0”^ÕV•›ª+ÛË9í¥׸÷J¹XI9vü$1¿xFpAèìŠ9³¸3Y³ƒØÃ‡î·Bë_±¡pZ–òy†ù @0ü[»0„Þ´µÞ:í'ûpfÉWDöÎâ_Yø&óß' 9E]ô|m1«£¤äf »“UÒÎ.5––·•”j¯\mb]ké£a±uxãË*1âo°T|ÍÖ÷»Äpe,*дX¶e¦¢s!«§ˆaÛ¶«æ„2Ãæ–¿2»rÁ<éÌÀª@?Áò·¸ë^|aBÏ3Ì`‚à½pÄÈ÷­‡l$ ½a/7Ìž® œ"÷óäÍ« É}ûÝâ¢2¬°´=¿DSÄ22êœËê¶o^é9 ôéÕ-³ ©’YÐÌÌ×2óõLf«…e­î7mq¡9/G™Ñ’Çla¶ää+ñ®:·è&=÷#ûpUMpopÃC%îN%¡Ó¥>壇Ch£Í§#F<­g] €ç ?Ï?`ó«(„Þ³±Ž —…†4Í Ñ‘C‚êB¦—¾–{6ý‡ÌKF*CNcÔ] Isr4¹yZZ–,“ZOg(r™JÆåFzŽ_ÓJ:£™N×Ðé:ú¥VK¥·X®ô]sù’‰žeÈζQX¬Í/jξ,§Ð(™êËùXBB{ÈŒìéþ¬@AØ,Íœ`íìEhp-BѶÖÛ „å#G-‚|þâ|,~Æüˆøqã7#´zø°8/÷Ëd_®ÿdñŒ ÅÌ ©?¹bÚTÆ×{Lßž»ž©Ë¸(?wžOÍj¤f)©YŠ>SX^¢5Sij*MC¥ê,Õ²nî75-³Í‚ª¡Ñ”´,)5»—™-¥P›2h2± ”îDj°M€oÃT¯¦à)ª¿:ÿÉëÁ±­±º|ƬMÏ_–À@À“¶nË>âãÁƒ· ³‹÷p»xcYèëU3ůfF²_þœ9û˜ÓÎtdœoM¿ 8G©£d4PÒå?yl« ¤7Q(ª>-Ц¯ª,û‰Ò’~Noñ]K:E‘ž.IÏQÎ (çEße4dPÛ¾Kÿþ«mjr^ ùº¿¯ŒìÙ4}Š&`²,pª`ü Þ£#´ÊnØÒM[ÏC>A> 9sîú¨ÑKz@ˆq˜pÁÛ›íçSííuÃ×§fê´ëþ¥žç—.«H#8sNr.C{â´9&ÎΙâ]êï'ñó”M›¬ ûÕ“' ½ÜK\&·² ¡Å¶Ãg\B>O5€€ÇÉŸ#´ ¡-#G#¹]us+wr,#ºp}¼yä©U“Éù®¤´µëêOœ¼“”¬>sºõä1å©ãM©)ÒÔTÉ“õ'²?ôXŠäXªøXªwâdmÚUb’æ›ÄÛ+WJ¼< È~"/‘¯ÐÇ»ÆÃ½ÊׇëíQO5€€ŸìŽfÐb;›M66&:]òñáº{^'ºòÜ=„øÂ…xÅË'Ç•têËmªcÇ»R¦$«’¿‘§&+’eIIÒ¤¤'ê¤\r=.9IŠtôˆìh¢4%±öh’89©6%¥1þ@câÑÛkÖ¨ÜI ?ßJ¼¯%’Øn¥DR©·wµ;éš«sÞÄ i}ŠÐâõë³ Ÿ§”Às€ŸŒ»ÊÆê3k«cÆ¥9¹^Æ{Db¥««ÐÛ[êá)pt.r%e{z÷Õö–#‰Æûå÷×%ÄÖ9Ôp@rèà¯:Tß§öqõý«¢C 5¸„ƒµøA‡ãpGâ%GâëâÅøbbîølšäyÑÓE$±&s=˜øç'yp'•¹LbOrȶ&ìBXã0aƒ¡†|žF>ÏŠŒ:ŠÐŠ¿Ùì²·I ºÑœI¹ŽÎ…ã^*™ðRµ³‹ØÍMDtãLr¦“§]ܼE£Œ‹‘F﬎‹®9+ŽÝ+ŠÙWûsDbbø11¼Gø?^üíÊÛlj‰åÄîãáÅ}-‰nˆÇë×µû÷Šcöcö4ìÝ«ýdm“»•è–çLÊwp¥:hDO–“3Ûib…›KõıÌá¶©Ö„-öCÿ¸òùÓóx^Àð(ÂÂ/lµFûÆ¿˜áâÆp&å9‹'L,7¡|üøJ®“#ÛÑñR`PÞ† ŠÛc÷Êþµ•³g×õ¸=¢Ý;»w Žà¡]5»wÝèSÝWkúoçî;£¹8üÆè‚èbÜ×Û…Ñ;„û¢kñSöîQnÛ®Zý±ÂÓ'{‘áäšçèFç”5Ñ¥pìø++¼=ÅÎlÇñt;«XúÈÆêüì=äðÿá?ÿÿìÝùsS×ðóî[ek—,ɲ »mNba·16›‚ÙWc°YÌŽÐ$MBÓNÛ4!Žwy‘ô$Ë’÷ /˜BÒ¤Ói:üÒtúOô¾g ùAã3ó™3×Ïó½ç§ï½sŸ„Eê‚wÞäù· |×âˆk´Ç7ÚãÚíqŽØ°SÑçl=*ðjJ뮜=üÃñcß¼sæÛ·N_{çí[§NÜ,,¼ýX7ôø?þ¥;' ï =çäõ§®ž¼Bëé3·½Qpä»'ÊËÿiü8ŸÓY7*¾Ùálw8;ïꢓWæÛj1Tìš;ë,öç9ö!„B(‚à@a±íTß}Ûb–ãF…í±m¶¸›³ÃÛëP8mÎØ†Q±¾„ ¾Íÿvpÿ?þþÈ‘…ǯ;~ùð᫇_?|èæÕ{n=Q=øõ¡CU}}èðõ‚£— Žõ*Žö:q#ïÀÕü‚ïÿïºu!^vÄøœŽ–XÇ»£ÇNklÇ e±mcâÛXøˆ…VÓ>ìÏsìB!„PÁ Àâýn€‚tàwñ4×::¬¶f‹£Ñjk¥l1m¶˜V{L³ÝVï´ÉvkÙŠe×öçÿP°ï›=»ûèËË ïÝÛŸ¿w ïå'«wå_}¢š=?ï–‚öìÙ×»gxÈKÛw]ÊÙóíƒÿNKëµÇÔЀn³6Øb:lÖ.«­M]B3E—`³5OÓeÒ—°p `}nn%öç¹ô!„B(²à`qBân†l¥ß˜Ì¥VkHg­ Ƙ ÉÒDYÌÍs“ÕÜ`µl·QW4{F{~Þ¿rvÜÈÙÑŸ›Û½}{Gήžœœ¾á¸4—sv^SÐANߎÜðŽÜ.jûîðöÜž[{·åÜÙµûǤĀÅTi2zèTÕ9·ªóo0Yƒ”ÅÒ@ÅXBk-ÀI˜?nìNìÏséB!„Pd递²[¼˜%hòEñ=›½V«õEkCZc@kòë AÊ ôA£>`4ÈV“Û¤/IœàÉÙñCvöÀÎW7ooÚÔ¹m[϶m}ðµ8¶l½¢Ø6°e[ß–íÝ[¶_ؼƒêÞ¼½/{ã¥M[¿]›ýÃé2iÀõZL!uÎ4©tF¿Î(+Õ «ÐFÉ&}5À;fÃ)Ž,/+¿ýyÆþ „BEœ‘¾X¹ê÷‚¸ /:êM‰6: Ó7KZ¿¤óh¢ýTtT¥òk£@¾ÉðÇ”ŠRˆåÀ¸€©P«‹ª»\,S ðÀÇÀ|쌯ž=¯gÉ’+óÓËw¿¾¨sÑÂŽ… Ú): ?.~½ëyIMm]´¨{éÒÞ7ÞèIOo››Ú27µ-mþ…嫾ž6£3ÆVɰŸ|AH9M·•ª¸¦Œ!_[´*Ë¡K¨X7 EïJ|¡N›7oÞãn¹`ß„B¡H4¢7ÓSNópLÃA"@9/N~DÀ­b™*5ã~ pN¯/OHlš=g`áâkéó»ÓÓ:ç§v¤ÍkOÛF+E|^RçuÎO §ÏÏO»šva^jWZÚÅ´3fõŒŸŠÒ–Ðù±¬‹%54ÅEÃT0L‰’nï\— ”üÀi–ì™ôâ[ØŸ§îB!„P$Ñ]ÏÁ‡s^=º®"¼ Zɵ4‚K¥ "L5¡1‘TÒàÈ"­Î•8©3}Áí9³ºgÏê fÍlŸ9£šñZ+58~˜–a™;§‹>|ÆŒŽ™3;ç̹8onßœy—fϹïÓ)_^{^ ¸e„«%¬‡¦Xn¢LX9äV.¹4¬×0Ä'òõ©ø À€\³¥ÀëûöçéúƒB!‰FîÀãþ‘µQüi­ø9Ï”Фè¦)P<pkî ¸µ uó|µr„)±XS’{§¦tM›Ú6ýÕöצuÐJÇS_iIy¹ùÕ”ÖGhúXúÌ”WZ§O»0kfߌé}ÉÉá„„vISA”›9E4Ý©æx™°2^2/£r«év(àÈ<äØZF9¤? °åó~óvöç)úƒB!¡FîàÌéN¸['¾Çç,T ¼Ì/@…š+þ/à*ÙW‰¿å-Xpñ‚Od U,_k0ȉ›''5¼4¹9奶©/·¿’ÜJÇS&5¾<¥åá’›†%yJcò”æ—’in§LíIJêŒuuÚ–Uæ©$rRÍr^–ó©KððÓŒ«ÎܤLÁTC—àeÙËx¾Bà?(dȾ[ª±?OÑ„B¡5r7k²ÎéÅD¹éñ'škyÖ¬W¹ ÎV>2à‚W¹5ï×D…x¡   ÈnõÄÇÖŒHššœÔ29©iRBSâ„à‹‰Í/&6>¬R¡'¯'Ô'L &%4MJl7®Ùn h$ú‹YškI a=4ÚªéÖ§ÎÜî_\­‚P%JçXî· {0}៱?OÑ„B¡5r7Ó§žäaÀi€O8p³ ¸nª€”>"àzU>`”ɰ~åóphdTÞ.ý2ZsÞjvÅ;=cG×óBà…x™ŽÇŽ®{X­;Æ÷ä•>jô(Zý±v^_% å„”Tªï³z”SmF¾;=e†‚o¹¨¯·VÜ ¸ å5<_Í ç8þ}€‚Éɧ°?OÑ„B¡5r7ãÇæìx7š«ÔK!åN'³ ˆ%ê'Bþün«› ŽJˆ„Ï7Ô*”¤[§^Žÿàó(±Ülò:íõNg½Ó^g·ûãcé¸.>¶îÁê‹wúœqò“V§/ÎpØëc̲F¢ÿ«˜"LµF<_¯<Õ¾{O§TO ¤Rn¹(é–üpéÊ»¼ţ„(7~Töç)úƒB!¡FîÀfÝÊÂ^g9(æ/ÇÔR¯«A¹Çÿ 4#Þ«ô7j²¬%P÷À*_Œ¥Q¿nÖjn°X‚VsÐb X-‹ÕoµøÕê³X½­f‹Çb–i¥YÙdvÓj4úxRË™'2ËxYÆGåÛ÷й1d ™Æ¡‰1.%àZݜР\/ÇÖr\À…’´ÅãéÇþ ·?!„Bjän¬–¡€ËB1Œ"L£zd0&(Q²ŽXð$(òAIjÄz6¤ÓÖ«:ÿ.ùñ´Z/íåçHÅBpQޱë1Ÿ­4ãªYÖ­F[p«î ¸>ŽõÊÇã|ÈÀ[’´­ºªû3Üþ „BE¨‘»°˜·<p Ó‚¡Câa%kÒЩPC6D3®È× \@àü/ ¼Gå¾Ëóx<ç¤E™cêéô( ^byÄ|î¸^år‹’qk€‘9¾E]`}æý·¬´ û3Üþ „BE¨ÿÿÿìÝïo[ÕðïyνþÑ´”ÚˉLo7 Ä&˜Ø4Mlcc”mm×ZÄ6 ‘•‚ª-TLí6&uÊ6¨ t-­œ&qâ4‰ÆNì¸NHÒ`Óþ™s®¯ã¸Mb'/Ö«û•>:º¾Ž¯Ï}^}ÏÑsø.vßùÓ¦€›ñ0*Ê俬‹€ÃÒ¬r£¸èé’è°/C†¹lБb[Sä‚cÛ`Ü™ÌÍ<hM,N°½}‹€»Þ|ãs/®cGÎ;— DDDDãÀîgÀû¾¶¿ 9fr!l.q1·nG9 ûËÍɬȰȠ3 :SgŽÝnú꫊ήKwëæ3Îg4 ¸Ãö™WùØR0)Ù›®˜¿1I:!g€?»€»ÿ­þ,ëÓi}ˆˆˆˆ"*¾ €»îÚ³6àšPX&QÏ©#m9Á¤¡0¡l|4ÉrÔ¥ä‘ °jÕ:ë Yæ¥\ÑjB«|ËèIÁ“I36θ+‹sw¬ñ½î+²ëÍGcBÛ»È*ub2n’…ÊyºènpÌSƒ 9Û¸;5ÄútZ"""¢ˆŠïàÑ8$8îîg£ä¬ ªæÂëMG“V§L86òADbnÓ¶÷H“œ»¾‘oÍu\®r¹¶Ð8_ϸo|oÓõo5p'ìw©!ûŸ­Ì¨ÌGL€.WqÛˆ¿p÷Þ2à²>ׇˆˆˆ(¢â»¸çÞŸhuPÐg{Üë·LÃåT—'ÚMš¼j¦U}|Ü11wÂ\“+Mﮎ°ë>>Ù8_ßç¶ÉûJ¸n»qÖŸO^×3zÖ¥Û¬»NÁ“9 h“n=àžT8šJý¬¿õé´>DDDDß@ÏýÏ?Žtï8çËûMOK‚²;0‰0ßÞ˜wÛÆW]v  7ɯÕm7Úš²é¶ ë=5â"µ™C1å/j5ç’±¹Ù·?¿½çÞç/\˜e}:­QDÅwðÈ£¯iÙ ôj¼«íO[N(̪IÞ…Ô|L7 aº-6eÜ…µcóÎ÷¦1ºÝù(»ã^ß§¯`¾wVc^aε¸ *¼£µ ¸¿ùò}/f2s¬O§õ!"""Ѝø.¿øQ2¹OáðW­2;ü¢ØxÍpKPS¶Ý¥Ñ*mfzu4ŸR“ñv™?¶iw> Ó‚’gGÛ+¯Ô¤²û³°Ñ¶ ”5òIPã-?Ù'Þ _ùê˹Ü"ëÓi}ˆˆˆˆ"*¾ €¼x*•<œòõ@W¢¤0ãRà¬3ÝL×;e’hÁÅÖ6šbô棲]:³fÅe\e™óeàP1·–P…¤? ð&ôȾ¯=ü*ë³…úET|öæñßÿ]:yÚþ?ZU›k«¨ÇÁ’‹¹mŽ›]«Öö•ÚŸ²Ñ¶ì¡,6éÚ oUßÞžwãLÚŸò½ó@pøñ·¿÷ë³µúEQ¬;»÷¿êJŸö½‹ÀhR_Ô€Š2T¹3êèRÛ%¨hT};–µíÚ7Ê 5…·É=³3UÐú,p8 ©8üOÖgkõ!"""Š¢X/¾õD¿è_'§<}NÛÇ[+îIЪ bn;ê·¸Öú×~ªêg›:™ *aÀ­j—qÅ2ça¯6Û½ãªÖg€Wx~÷—öÿÓ8ë³µúEQ¬ÇúŠ;vötŸï½\L&*î!ÑE“)áÂ(ZSiµ5w®Ùä.ßz?»5ƒYh[-üêvé¦tLv{;¸¥îî)Ïû;ЛÞuð¾žù°Êúl­>DDDDQë€!‰ï¿~ï'/zzÚ=ºb{ÜÅýhŒLA™ƒRøè'.&.»q>l…ÞsŒ›šïP;×l˜ÛænŸv {ßçÜÌií=ÿr2õv*ýrÂò›õeXŸ-ׇˆˆˆ(râ¾xð¡Cðö½~ê,0ªÕuQÿ†ªBWÉ T°I¼|ªð™Âõ`#Û¯Q´pðø‰7+À“@/p:!“]‰‚/€ÿÿq¾pI÷Fk¢­ÇdžåÛf4ó_ÑX|.væáüÕ|:=£åœkp?ÐÓsðõ×ϱ>Û¯Q´üÿÿìÝ{pTÕðïyÜ{w7‚Å ¯vúý«3Žv:è_µb¥•ZGª£*Ö‚<¨ò#t*ŽS†V´¡T¨-•‚ò¦€£<ª±BBH›ì†l² I°@_ôœ³» No:ß™ÏÜÙ½9÷îß_ßß™sOØX·Ü¶˜,ñÄú˜Þ§l4<žS#mÌí’qe™Ë¸™Éã*§"7—†c&ÚV™Ç–ÙŒ^i§½Å»¾Ú¬¦Œ¿ÿþ’ßÿáj×·°>DDDDÿ7ØXÓgmWjBß‚e@©ÄF…¿¹\› ¸uæˆlƽ(àVº‰ðš\Æ­ DZ2m3ÑÜ%ÝÃJì×j°(‘bÂ!Sž~j%ës­êCDDDÔƒ°È*,œ³$™ñxnJ[Ùh{ ¨-ÈK›ø(D¹A}s”åÕ@!pL J :Çj÷Jk…’µž0_&p0¼£ä:`1Pü…~F~ñš5{XŸkX"""¢ž‚ @ÖÒeG´7NÊiÀ¢…ó"&#P¨ò8Õp ò ¸ÊÜ#°ññ„Së’å±pIQcžV«OV¹ÿ{õ—ˆ¿Q‹s´÷•!ã‹\Êú\Ûúõl.:tð`àÏ~lvª"ªêa׊42a'e¹ÞÎ\in½“™ä® ÉQë:ØÙî*OxWÉ·}o•’%Z?Ù¯_ÑðoÏxùå?³>×¼>DDDD=€ Vý¶¢OÁRý0wÀV_¾Qµ q…Æ@7›øQuÈ9p.àÖ†‡[‘øÈ÷Ê‚`·Vk…[ÜÍsË­?œ9k9ës=êCDDDÔ#°èfüÄeÀ° 67{%lnÛû˜jôÐl‚¬D\È£PЇ¡+¡j ã q‰¡qܽíZ¼íF·/¹=|Æ þÒèQcf½ñÇ­¬ÏuªQø±¸Øm·O4Y˜›—·6?² 8è¦&‰!ŽCUBW„6àš'”ê¨[„³?ˆîñ‚7€gÇc½Gß=|êÏ_ø_7·a}ˆˆˆˆz46[½îƒ¾ýMƱ¬Oþà=·wd£F›B£4‰V…w^t-T=TBŠzRÖ‘ZáöBn‚x˜ÍŸxë×2sNé–»YŸëZ"""¢cp óJöôºišÉ¸Z¬ððv¾.ȸ@½ ¸"Ug£­áÕÁ«‡N@^*k"ÑEcw‰n®œYí˜&§178žóÉ2ê¢þQ­o¯%ã¿…c‘ h“2Ûs:—tEK.˜&Üf8nM¼wQµ¥»ÖËkj´2WÙÔÛ)qFâœù!¶¨J˜t vAþxÑ<'ăýŒ¼ëžI³ºô­];YŸÏ·>DDDD¡ÂઌUZXX LžykûD÷jôp4¦š„]ybBí™OÄ\7?-[ìb“MmHMde¦«ÏÏX_6àºìkï`.o²÷­¹€û±B§Bk€†˜wÄ—Û€•À3ÀˆQ¾ø½»ï7Ñ’M;·±>a¨Qx°¸Zsæ¾5xÐd ˜¬–Xlï­+£v»É4D'Äi ·DW§!;-ÕRP'”˯FÚisÒ9îOf¼tÊŒ6!Ò-¾HjTGtYTo~ Ìž(¸yü¯Ž{àáâE/.a}BU"""¢`ð¬ÿSòö¡vÉ{ XîcM¾2ár»V5Bž2%d‹mí.욤û,qÞY—wmÆ.×Úñ6³šKÚLJî´Ÿí›tݘ¶ìÝL†6gTR©¾ªt™;£þ›~˜ <’×çá¯Ý1å¡Gæ”<¿tûÞí¬OØêCDDDl>³¢GW)<à©^þb`±Âj`‹ö+¢yµBV»÷_“B¤V_ÿøìbôsöƒøûz&³FÚ¥ðv± ² ÖÏiüSà¬;Ó!Ð.e‡¯:|כּäŒ'Û£‘T,V‰| äf`µ¥À|`R}¬ÿà¢;îœ\DDDDŸ¯ÿÿÿìÝyLWðïÌ{³³»\‚`mZ1hÒÄ3šÚh+Ô£TÔhmÚŠZ (¨ Ë. ˆ¨TQ© X/°ˆ·6˜*ÄhK«± 1šT£Õ6mcSµô²¥3X“þm‘]ä›|ò²y»™ìûæmòûm&óØ<ŽŠ­ßt™ŒÐgÀz¨UëQ‹~\“§¥âºÆÕŽÍϱÉV5—î“`÷ŸÚ=vXdšÃ½jKEµÇa>DDDDÞ ÀÿõÆØB¿Èd(.Uf+Ê"`¥T+ƒjC:Ôú]ðµ^Òp©ùÖ—¯žeÁºé†ŽŸtüÜì–1ZÌcþº®\•¸œNŸJÔHìVÍçØw 9Ù7 :¤ó¸ÁCgÆ%,_µë`Í)çÀ|ˆˆˆˆÚ6-Ѻ?08eµ&æ 5x(Ê€=‡4QkÕŽÛôÓ>¶:M9©á«fuÎ5«7F«8k•§uyÌ" õ ¢ìv5,—æÕ bìö·ºuéœøÞÜkv8xÂãkg>DDDDm€–T´êó/ee.ÝÁ?[ªó,T±RÓ>ô±o³Ù*e«Q° u§PvKìÊ^‰}BÙ×<îf9[óHÝ¥ÀÃy®ù—¶yÔîÄg;Åôì9ydTjzÆÊŠm‡<¾XæCDDDÔ±x"œ®ª®]܃ܚL’"UQ²5} dA-0˜7è…ŠRøh\dÑAË6> $±Ðã,þSüCbzõŠ3:mvfɦÍjŸðøê˜QÛÅàÉÚ°ñJRÒÇC‡¯èÓ7'4,Ý/ x[•“‰ùIÛ»Vßè€à‰]ºOyñ•´qÑKg¤•gçm/ÛZS]}Ìãka>DDDDO6­j×îëJ..Üž—_ž5§45uµÃ±"%¥Èx‘ž±&7¯lqaeÉڪʵ5‡ë=þm™ÑÓ‡ Q;€ˆˆˆˆ¨a@DDDDÔŽ° """"jGص#lˆˆˆˆˆÚ6­§¸ôø4ÇÆ1ãGX>hAïî°Ðİ®“ûôN~5"kôèœ9sw­.>âñïÉ|¨-âþa>̇ù0ïÄ|¼€'¨´ôL|üæ.Ï'¯cm–X]ŸÄ $©æñ·Sã­x ΘT D«êD!'¨b|pHRÔÈõkJ®y|̇¼÷óa>̇ùx'æãýØ´¼¬Y»úõqúÆ™‡Úb²]º‚|çûÏ ôɲ §‚$©:…tkÂ-¤K.U8…â‚â´[35-C*骚n³dNãçÑó…yŽä=_ó!oÀýÃ|˜óa>Þ‰ù´!lZÌê’ÏÌFûÞ w'ß%>(°!߆¼-﹎=»/Ø¿8<|]Ä5‘k‡X?|ä¦×¢¶ ‰, ²ePxyï>¥=zmè¶>(¨H ÈWð.—.6Ç€~‹æŸôøJ™µ>îæÃ|˜óñŅ-bЦ;> ›DYõ©ÏÎÒ€Y~ʲ®7Gô¯Ž{ç¬#±Á™t*?»~÷öƺº¦s›.7]¼Öté;Ó…+æÌ™ú¦âÒ›ù ¿áh˜4é˱cŽ ~ùPXh™¿OQH@±@®"˜àïëN­òøª™µîæÃ|˜óñŅíúÿÿìÝyP“wÀñ"ÈáZmm=!n4Ê!¢W¥«»ÝU«ÝÞum­Z×{{y,**­€ Ö”1 "W I¸’B¹ÈÉ% xüö ­ÛµÓZÚ­U²ÏÌw~ó¾&Ìgž÷gÂ(,ÿS;þ‘=løË6hÈGØ3ºÃÁv·éÌKá×^]Îûð=I̧êôÔ»Bn7ã;·qOÖ™°®oâ®~Ü{÷ÜÅ·°¾k ¸ïî»&|ã>“Ò¹sïí7 VE³¼˜Kšzf¤S¬£Ã.[´yà¯è^›ðüºõd>qð_0?à>à>Ogà3Ôƒàgvü„tšÿN„V8;ý |\åì”0o.{E/:ªdãFþ‰“íµµX©ÄÝÝøf/6™±Z{_Ûv×h¾§7ß6tõwܼ×ч»ˆ/ucƒùžÆp_oÄ-j¬RáŽ.ËÓ¢Õâ«Wºã£¢ W®,]ZtiìèCÈò ¬·AëˆÇ`ò„÷’“kŸ¸ø@¿l0?à>à>à3}†J°üœ/>dk…ÐÛÃ-Ÿvmž:938¸bñŸ„Ñ«x›¶Õœ½`J°¾wöcmÇm™J/kmSk» ¦~£á^›æŽN{W×Ö¯×öëu·õm½mm7Û4Zm»ÉЫÓõhT]*e·VuÛ ÃFËê,QàÏ“»Vþµ$zuåªUusgNx.åǸahÛpô¾-Z±hÑþ'n>Ð/Ìø€ø€ø EŸ!,?­„¤22yB+GØýÝ}:Æ91R°|icä"îËá|²K–ÏÁ-:¬4aq«AnеU-¥\­l’kdr£RuÛ¨Çmª{šÖ;*EŸRÑ£Tt+[ÚÕʪ]£6i5f"µÒ¬j5/¶iºu:\/ÅÚvÌåá-;„‹"³–/»µT4gVñøÑ'†ís°ÝŽPô¸1¯?ÉŸ§Üzt0?à>à>à3}†\°ü„Þþà<²‰rtچЖ‘ŽIdWVd¸lutëŸçlÝT~‘Ö'aE ®áÚ†ž¦–iK»´Å$#R´ËÝ2y¯¬¹¿ù›n=¨×’üæÖÜÛ(íkUb½7Jñ©SêWV±†ç¬XÖ°$²1$°ÒqxB[ÇÚ3ÂnÍòegÁç©õÌø€ø€ø EŸ¡,ƒÍ/èC[Ç×F}ŒÐv’ sAXCÄé’— ÃK?ûH@KSÞ¨ÀuB\_‡›šˆIíç Œ"IǃºDâ›"q¯HÜ7PïƒÛ?Åâ.…¼³¾NÃçëêëï„8Þ³~=nèåèåÊð°ÆéÞ\OÒ„ˆ_ì}g‡MóæŸ§Ðzt0?à>à>à3}†h° ª±Ï/µwþ+Bo:9Çzy2—þ¹%ìŪ…¼%‹¯¯]S{õ ./¾'¬Æ¢z\[sŸÇëæU›„5f¾PÿM#_`æ ÚùünKÄÅ×·ƒ8£¸Á\+ÔUT¨*ª:ĸ¦Ÿ9{çÝwë¿€û—?Ê_Šh\¸ ÞÇíâÄçŽ"Ë¿“åêòøÐ£ƒùððŸ¡è3tƒàGbä4:ZìèüÆ0»G8ì÷÷Ë[Ѱ0Bø‡ÅUóÃY¯¿UYÆÅB®(»_^r‹Ï»_Íë+-Õ—–©ÂöÊ*Í@mé*+M••í†ÁV¥«âjêk:kkºJËÅ¥7¹×1§g\¯¬äÿ!’±€?'„ûÇ—j‚)9ŸGhÍ05nì ðy| Gó>à>à>CÑg¨ À£J§  #vJ'§íl…ݘ?WBœQË›„ç.[ÉÊcã+œûœkýwËËo^5°9ºª]•7LW9ò®ÊR¹º¤\[R®+)3–”™Nƒåvp••銯ª+KU¦ÒrSqYÇ5îb..*Å_žÀ‘‹ g‡ä…Í+›?—;;ˆ=/˜3jÄ;´á·£7 AÏPÏô`~À|À|ÀÇú|¬ X•£S8B/;Úo†P|ËçKWEõÏæ…„\Yò2ë_'tY]Œ\u!»½¨¨³ˆÓÁ.2qРťú¢bõ•«Íìk­©Ø ñ`°‹ Ä7XN⚣dœ"Ý5¶¡ OŸ×j¹-1™óÙ½œ_€w~¤˜Æ _Pú»y‹ŠçUù³m,ÿmÞúß>³¡Hðy‚>Ìø€ø€øXŸ À6fÜ’ÑcÞ´¾Éí Q2o–à>àc}>V,ßÓ¢ÈØñÏoAhͨ‘û½=²)~Ü€iµ³ƒes‚Å”²™3˜»÷ÏœëIMפ]”ž;ϧe4Ñ2ä´ Ù@M'³|‰ÞB£+it¦±œ–ë–A§¤§ë-ÑTtºœž!¦eÖ¥gŠ©´æ4zû…t¼q£ÜƒD ¨ô“Ìðn™®ô¯˜Vno»¡µö#^™=w3øüj>Ìø€ø€øXŸ5 ÀwÛ¾3}Ôè¿ÙÚnéëé~)$èÆLŠÐÏ»zºõì`þ4ÿÜùóó4§œnO;ß–zAvŽZOM“PS¥ßöЭŒšÚL¥*j¥RU§Âòâ £¶¦žÓZúª5•*KM¥¦ÕPÏ ¨çk¾J“¤Ñô_¥ÞÚ±S@¹D¹à×Hñjž5]8­1h†àùg©Ä3ŒÐ;N#WlÞ~|~æ|À|À|¬ÏÇÊ‚à¡NŸ»>vÜ „Þ°±‰™øÂŽ¿o•÷ ?ßê3¯{z_±²,þhç—ÇõTªþìÙ–3gšN’ë €‡¢P>Dh%B[ÇŒ=Gv¿êî^:er É•ëëą̃œFÉu#§¼¿¾áø‰¾„DåéSm'ŽÉO~Ùœœ$NN}÷ü¶Æ_.ñ±$ѱäÚcÉ¢ã'êRN+âT_Ä÷¬^-òöÌ£ø×x{Öøù }}ª==*ý|¹>ž…ãŸ=nc³¡¥>¾Àç±ú@0?à>à>àc}>Ö,ßöÙ.Ž Zæä°ÙÁáà¤)—|}¹^×In<O!qáJºâí›åF>¹m§âØ—ÝŸ–'%*¿&'ÊãÄ ß9¿“øç—Ø@”˜ &Þèè‘Æ£ñâ¤øº£ µ‰ uIIM±›âö¬]«ð 3ýý*ˆ¹'‘9îžÅ$r±O•ùš›ËåI/¤ ´ŽØƒ7lÈŸÇäÁüÀó>à>àc}>V,ß6þ¹wì>°·ûäÙñ)Sܲ‰r%U¸¹ }|Äž^‚É.näL/Ÿ¯v|Ôz$Þpð€ôÐú¸}uGKâŠzd‡ª{¸†Á5‡ãª‰âÕoôy¬„èH¬èHlC\l-ñ 1û$‡>oÿ`½’ìuÑÓ‹M"³'‘r\« €oŠŠ>ŠÐªß8|êìGr§»s&»äŸPô„*×Zw÷’{ùTeæÅ-[å11òý1â]ŸTíßU}p_í¾½51ÿ¬û¾j$ˆ‰áÇÄðÄ·ôõ‹?~òöî/ÙW¾ïŸ<âöïÅî’Äçîº{kcöcöHöîU¿÷~³‡7ä~Ù…œ;Ñ6‘L'y±§¸p¦L*sw­šôk”c²½ÍVç¯mŸ_Ü‚ùç |À|ÀÇú|¬µÿÿìùSTWÇÏ»oí¦÷nz£qW0JÆDFÀ­4Aãn\Š(‰Æd¦f&“̓";½@ÓÍ"«¬îû$S©8“Ê/“©ù'澇f™¨%j~˜îSõ©S ^ßû©óýáÔë×ÀLšAŸ+À1»¥rø¨À°Ñ±#Ú®ÍÑc·_Œ‰éÛëŸüjcNν‚üïŽýö`nß{‡¯|ðÞí#7Üz7ïsøú‘ÃW.+õú“SpäjAa?…þcá¡›…‡îPÞÍ¿Uxèֱ»ôU޾÷Ïùßgn¹?®vèˆÀ‘±£êlC|®á-V{«+¶÷…ø;Ãb:cíujþ8›%þi>ý ÏöúA?èý ŸÿG?á 2‰sÞxƒçøØsÎÓ`s5ØbZm1ívGÈ)ÓãlëeBóæŒïöí¹÷Îþ;…wå_);û6nîËØzwç®%%uÛ¢+i€­–zkt›ÕÒa±¶(Gh¢Ð#X­M£†uu§Y8°*3³ý<?öæ ý ôƒ~ÂÏOxƒÀü1q[²F”Mg,– V4Xê Ñ£¹‘b65™MS½Åì·š« ÚSÓ§´fg}Ÿ±éZƦÞÌÌÎÛ26wedô †¾Áp1ãí+2t‘ѳ)3´)³ƒ²qKhcf×êõÝ2noÞòC|œßl,5Üt«Êž›•ý×-ŠÙ\O‰6í–*€*1{Äð·ÑÏsñƒ`ÿ`¾ÐúA?è'üü„7‘>œ.¾Á‹ËU¶(µÚª4_”&¨1ø5Æ­>@Ñë‚z]À óô^‹±šNq£Ü›î¥§÷¿½éòÚµ¡5kÚ7lèÚ°¡g¬ï ýëÖ_’ÙпnCϺë6ž_»‰Ò¹vcOúê¾5ëï¾™þµÝYf0ÐxÌÆ ²gšd¿ÖP£5xåª÷ÓShÔ^£® Ð¤?È‘EÅgo¢Ÿgôƒ`ÿ`¾ÐúA?è'üü„=‘>,YúA\¥þ“JuZå×êš$M¤u«¢j(QêZŠF]£Q» ÚJ³±Ìa+^œzuÉâÞ5k.§¯êL³ý­UÇÊîÁлreŸÌªÞ•o]XùV(}õyºè[‘~1}ÕíÄÄ.½¡H§+ÕiÝz-Ý0ÝvJãViªîå¥gÑiü"wZ-|$°û8òfjÚûèçý Ø?˜/ôƒ~Ðú ??aO¤6ë[*)`·^w’°Eï•Ô ¢Ê+ª«äªòª$E-yÕ’[KŒº2£þ̸±u©©ý‹—ô.£gÑ¢¶eËB¿'–-ëV ‹ÐÒåç—.o§uÉòв½‹—ö/Zvcäh:¸©¤Q¬DJòªTn•ªB¥.e*D•›ž…ÆX ÅÕI€ý¢¡Ó­@?ÏèÁþÁ|¡ôƒ~ÐOøù {"}HãÉ6•xܨ/‘¤j€2 >^tób•RÝ¢à¡H‚[ª8R¢‰*×k‹†S))דçt._~mþ‚ŽÔ”PjjÇï½xÊ…Ô”.ZSRC)i”…i¡…iÒ÷¿žvyAÊ £éŒ$ñÜBJ S. nQ¬Å2Q*áUgyZ•ã°¤’žBä¾ä¹c¢° å“Ïn Ÿgñƒ`ÿ`¾ÐúA?è'üü„==dm©6é³²ú/8¶àŒ(YÞL0%J-c üe,S ðÀÇÀ|ìtULŸÕµ`Á¥ÙÉ¡ùó;_›×>onÛÜ9­º ?έãy‘˜Ø=B¥ÀV³p à]‰ÏÓj²fÍzÜ]0ôóx?æ ó…~ÐúA?áç'ˆè`ò„|2ö«ø/hœåÅÃy€r–)W2ð%À î옸Æé3úçο’<»39©}vb[Ò¬ÖÄ™-´RèÏ‹ÄYí³“BɳC³“Î'&Ÿ•Ø‘”t!iNÿ”i]#GÕšÓt?§X¶ŒÎ¸´Ë‰L9Ô0Ìi¹û€€[ཊþH Ÿ%[Ǿpý<µó…ùB?èý Ÿðó Dô °+èøËÁ‡sRmË ï¨ûžv"a •¦‚Ž˜„”ÒÆbÈ)¶,nl{òœ›3¦uNŸÖF™6µuê”Ê”W›)ë‡qnPÌœÑA/>eJÛÔ©í3f\˜5³gƬ¾é3.Ÿ|ZùËíN*(&\aÝ´Ë TyÃò¬€Æ€†¹’!>‘¯ãHÀ_ 2Mæïßèçéü ˜/ÌúA?èý„ŸŸH rwõ ¼©æó5âç7ᥦW&4?‚¦AA/K¯9áåæÉ“ÎO›Ú3erOBBh̘VIUBä;w§h÷©àètËzð c®‡Q†`¥ûïÀËóŽ­bä!þ8Àv–Ï:|¤ ý<…ó…ùB?èý Ÿðó!DîPß®·hÅ£<|ÊB©À{â(Qz¥ä gCއ[~JÊxÁ'H^ å,_¥×{ãF7‹¯q\Ó„[&¾ÔúrB3]ÛðÒøs'¡qP$ŒoHßôbÍUhÂÄ®øøv‡= ÕT²¬¼O9±¤‚å<,çSŽ@'àšeçe@Še˜r`è<,ëgÀ—üGy Ù¾z]úy ?æ ó…~ÐúA?áç'BˆÜ`Ų:q'‘ïý™ö=Ïú€õÈïcKðÈ7È ’ãkTê /ÔÒ˜ 6‹Ûå¨9Ì?:8.þܸøÆ±cãF^ˆkz!®áa•|ò:zTÝ˜Ñø1cãšGŒh²Yý*‰¾nKûžTÖM[_é~Ÿ²C?~Õ¿ €ˆŸVA(¥,÷ÃîJžûôó~Ìæ ý ôƒ~ÂÏO„¹Àä‰xØ ð Õ,CP B93€GÁŒÜg [#?/O[J~úäË(ÕI‹©ÌåtZ7b˜Øÿ——®‡­}X­>Ì÷ä•^jh,­5›[§+…³„œ¥ƒ¯ò¼‹[žzïƒíÉ;$à 0pLyü¥äç04´•<_Á '8þ@脃èç)ü ˜/ÌúA?èý„ŸŸ!r€‘ó6¼ŕꤠ|ψó²m ÓÊ'Fýôì #Kn2Aò|=@•Œœ„ZåÍsŸ|®ÏšŒ§­Îé¬sÚjm¶—ƒ®k]ŽÚ_WŸËésÆxŸ´:}1v¿ÝVmòª$úZEÂT¨¤ù»j`ê}0£Ó-Õ*ÈwÁäî'?€Á/?ëCÈ|JˆWlúy ?æ ó…~ÐúA?áç'BˆÜÀjYÏÂ6Ç9(âÇÔR'’J£0?Sóhý\éo”Ϋ"PÉ’j•¿8C¥|ÅTo6,¦€Ùì·˜ýfKÅ\£TŸÙâyh5™Ýf“—Vš%£©šVƒÁÇ“*ŽxyâeÔ)Ds}Ýšh¸¿1¦L¡µšê•x8¶ŠãN¼'IëÜî^ô3X?æ ó…~ÐúA?áç'BˆÜÀb¾ŠhKqL0 Ê¢6 ·Z-]°àçI@ä’P‰uZMP«©Sðkµ5ð>ÆC‰ŠrßG]ÑZº= ˆ<æÖ=b?Aši”^¯VZŸ üðq¬[ŸÿC’´¡¢¼ý Ö‚ùÂ|¡ôƒ~ÐOøù‰þ ÿÿìûoWÅϽwfw'V›´?¢þø$ø¤¢‚BˆGy4P’PB“ª€¨ÒE`EE /)¸m 4Qx4N¬ul¯½Žëx×^{cÛ¡)âÏáû½³³^;±½cÿkçHGW³cïìÎÑêèÞ±Ó[|n}†­† L$¨Å”jP±iÆ I²á@&¸™ ò™°/^÷êu}k…Ao$­ª¶OÚ¹LOäPˆ-rm2ŸæÜÐÅ/ÍÀ{RîƒpÔß`¿\³9W.—È')Šùb¾È‡|ȇ|ÚOJ”ÞpðÑ4 `ÄñGÁ[dÈ&PÁøÑzkz§IÉe£+]º²½^ºLæÏäï—4ÝÆq´ÈåÕß`³ùXŒYȽø={Í«OÊ}ŒÔÚ|ƾ \08'xçÒ(ù$åC1_ÌùùOûñI‰R\~?Àe§7jT|õͰAùÆ©ï?““k‡¬ðê·._—û¶}¿œ-Š/ýuT÷ŸÙr>#q†ô™{]eú!) ¦€[ò;’´Œ½üÞàø›=òIʇb¾˜/ò!ò!Ÿöã“¥·:td}Ä4%`u·<-&DãFí%Îñ)Ž íìˆs¯A•¼´·œwfrÃØR`'dlœñW“jî0Úø\ÿ…Íæã0îô. ÆÜ„• äa 0ÅÀ•ý Žf c¯6ð狃䓔Å|1_äC>äC>íÇ'%Joxì±gNZœ÷ ÔjRE‘•‹q£Ýv7OIxD“Q„¢4Õâá&ýõE“F¹Ž÷ý”÷}©q¾žŒ5>·éúš`\?Ë ê¾ÑÈ[$`Uà60¦õÖpô Ÿ­ùPÌóE>äC>äÓ~|R¢ô€ÇŸøž3',ºu\=`ÞÇÞIã­â¶Û"‹iSïÐc^ƒq?F*6éVÓOׯFüÛ'çë=X“y+îÙºZ·ù|&]=Ãïþ‚¿ŽÔëy ¬I¨à‚ÁÙ\žòIʇb¾˜/ò!ò!Ÿöã“¥·þÈO€gºöý+´ƒþ™q±oÅ¢êÄ1“­“¾VÞöÞŠJ÷ir½6Z˱¡–æcÔý%WÏpfØGNæPÎ…ËÎÌûäÈ;üøÅãO¼ÐÛ;K>IùPÌóE>äC>äÓ~|R¢ô€Ï<ý+g§Þqú§¯¤2ÎXÔ²á¢7ñdlÜmÇRìþrS6¨´~ojÆÛª³Vçc´‘×{||ùÜY‡Eƒy¿6`ð¶s€ŸøÉ—òùyòIʇb¾˜/ò!ò!Ÿöã“¥·œzéŸÙì1ƒ3ÀŸœÉï ËV-r'´€ Ì”.‡µ2ª*Ûizm”w™ رV%¿¬oiu>Ó•@GÝKgÌ„Ñ}³Pë×€ª”ãl8àðf˜í¶Á‹ÿÄ+Åâ2ù$åC1_ÌùùOûñI‰Ò[þzù.ðL.{¸ºþÎLE°wɬ×ôFãn:&•8µämÝ¢JM1Û~4ºŠ7`Öú •œ¯w€9¹µŒ)eÃ~ƒ?Â=ö©§^#Ÿð¡˜/æ‹|ȇ|ȧýø¤Dé-zóøJþ²#{Iÿ_)Yõ} u»T| Z·ÖìzUbC·®Jëó1jýj€ªÕ$h!6õú»èÇ™Žp* ®ÝÀIà;_þÚëä³3>óÅ|‘ùù´Ÿ4(Õ`×à§—Âà0’uw,¤&‘©&ÑÌ–Jt©ÝÊbΡêXuº«OT5X0Xò%xf®äÜUà,ð¼Í}ûùS#Ÿñ¡˜/æ‹|ȇ|ȧýø¤A©._üRu?Ëf.NáP‡>þ2矩™(­¨€òzm}WÍ;²E%™ æâԜπUÉù%ƒeèÕf»öÝvî ð*2/üÐñó¿#Ÿñ¡˜/æ‹|ȇ|ȧýø¤A©.çºËûœ \w¼ ÜÈfæ  FËâ9x³b£kk}¹®W`÷ú{›]d©e-Äݪ\“û£ @ëo€JW×Tü8ÝqàÄ“=qå5òÙŠùb¾È‡|ȇ|ÚO”ê ²™¯?~fonÚ?&rO÷ÀYÿP¹‚‘ƒJüÉ¿½Vý¸o•‹~:ï!·ÕbBµr͆æ­nƒÓ§aâ½qó~æ¢i”ƒðf6÷V®ã•LøõÏ}þô`a‰|v̇b¾˜/ò!ò!ŸöãÓöJ{øØ'O"8"u0Ì]Fœ¹kÍÿ`jpå5Ù˜¨D®ï|`p7*ÊÑ"tçÜÒ‘4f¿ì¥»ß¤ÁÃÎÁ.À.ÃHhï¸lŸ÷€óÀ±GùÆŽ_ ŸÝð¡èæ‹|ȇ|Èg/ˆßöðò«}žÉtœ…yf8tÿ>Ђ+ÓûU0P‹ Ö?ÀB´ªµ÷0m}ów± Ö7+:º… S²öïпþû­Ã‡¿ñFùì†Eÿ0_äC>äC>{Aü~O¤´ÑþGžÍvž^ïìœðK`êr¿Èµì-µÐäï(wãDÔ?]Þ £ÌÊj[Q÷×ï¨jìˆÓ /ß|ú³g®]¯Ï.ùPôóE>äC>äóÐG~¿' À>ýÔo€#Àk¹ÌM ä %ø¿±îA_®ªLä¤Õ5EgŠÎ<ìÑbÅaÕéÁªŸü½ºÌŠsUcòÖö/ØÿÝ£Çþ@>»çCÑ?ÌùùÏCùýžHÿÿÿìkpTåÆŸ÷röìÙ3¶ÓÔ/Î8Úé`?µ+­Ô:RE‡¡ÅÒ JVÐbNѱå"TÐΈ…‚¶TŠÊV¹”ÆB¹6Ù]rÙVÛ}ßwwC‚aä²9>3¿y'Ù¼{öÌožg2ÿ9{v9 _ø[3õŽÌürDn/ˆ”KTµ@£Ê5¡üüÄgãÕÉ¡¼YÍùW(THTJ{æ¹óƒàJ®qo€›pË-%ó篡ŸÏï‡0?ìýÐýÐO¬üÿ~p°ÜvÇ<`°Èëcz¯²Ñ9ž£VÚté€,s(w“e•#3(çÉš‰~•9m™íp¥‹ÅûµXL/**¹ÿþÒ7þ|©×¿è‡°_ìýÐý\ï•~®µŸÃÀ2}æ6¥&ö/Z,“بðo—ûLêÍŠlÎ+@¥”ks¨Ìµ2ýLu]ʕاÕV`%P*ÅÄ!C&?ùË•ôs¥üæ‡ý¢ú¡ú¹Þ+ÿ¿_²Oöý™ LJ¢Þ~Ï&©\ÙèêŠ Ò&^BòÔ‡0«<Q ÔŽ T TçÇZíny©P²ÎæäËþ{J®ž¦|iÀÄ‘?z~õêÝôsýæ‡ý¢ú¡ú ŸŸ°Â Ëâ%Gµ7^ÊiÀ‚Å ¢&Cûª<ÄN:—0ÈöÊà(l¼N8ê\òŽåÇzL 3”WkUëÉ*÷½F6j±\`¶Vã¿6¤dÊÏ—ÑÏ•õC˜ö‹~è‡~è'|~ €s :xÐÌ^6»|U¨ØkI¾L˜„ÙÁ×Á®Ò Á‘‚ëòdÕÚÌåf®òT¹ÀûJ¾ñV)YªõcŒþ½§V¬øý\q?„ùa¿è‡~è‡~Âç'”p8Ǫ?Vô+z@ª¦«¶DäÁ¨ªSˆ+¤|ÝbâQuØÑY€„+@]þàÞ±g&øC¯Ì÷wiµV¸‹_AÁ˜Ûnÿ錙Kéçjø!ÌûE?ôC?ô>?¡„@7J&-†ù±9ÑØ+¿A¸Å©”‡t‰¸5PÐåЕPµqˆF¸Ä‰¼á¸»¦ 8ÄöÁfà%wÿ˜›¿2zÔ˜™oþe ý\%?„ùa¿è‡~è‡~Âç'|p8Ÿ;îœd²b†à‚‚µ…ÑÀ7V¦€&‰F!ŽCUBWämÌJUã.ÒíóƒÝžÿ&ð,ðh¬ï軇OýÍ Ÿ÷æwú!ÌûE?ôC?ôóEó28œÏëëþÕÿ&ÓÇ!–ô+Ü|à>[*¥Ñ®’&ñºÞQxUÐuP P )TÞ e½­‘ÃÀÈ·!^f…“nÿÆ/fÌ^¶yÇ.ú¹ª~óC?ôC?ôC?áó28\€¹¥»ûÜ0Ít@‹åÞ-ÔG¢2.Ð` Põ6ú¯^tòBYD¢ ©î$ºÑs¦íž&G*·9žãÓ/d6Ô‘­÷o¯¥%_òÄè±Ï­|mý\?„ù¡ú¡ú¡Ÿðù .Ì÷Ġé©)î‹£WxTök/¤nWþ) n›4Ú;Nl=²H4æHjËIf´£]"-Ñ,pR ™£1G¼ š§Î¤íÏℵ€:%“¾×1§$Z&³!"4þécST¾æ©R!ÇÞ8è¡‘£f½°xý\3?„ù¡ú¡ú¡Ÿðù .ʈÏ÷ÝÐwnÌ[ ü!‚½}mÜÝmïÍ@²Ñ¢I÷6¸dWä9l¤+€Ì@ ÅÑ,²M8¯ ]uÒí4é?+ÐîöÇ…8îÈ|oÒäÞ‘t¿Ök‰`«Æ« ó üÇ}×ð ¥ —nß³‡~®¥ÂüÐýÐýÐOøü„=1lØÑ_K,þ¤Å{ZvßÝà’×êG?Îä8´™!Z š R Gƒ#îHØ v[ÏœÊ"ÚìÑd“ÅÖä¾MâŒDG¦?ö3zU}̯¢{•Þ$¤Iÿ,Oü¤¸xÜw¾ûäÜùË7ﺊ³/ýæ‡~è‡~è‡~¾h~z;>›Ü÷;qÀT-EÔ:íÀ^…cQ?ík“ÂÓÀG9:® ¢5Ü„»YÞ½gÎwQníNÛÅi…JY2ϲ­èøXâ¿æ…4Ú•0éú;!×/šó„xð¦#ïºçñY¿ZüÎÎôs}ýæ‡~è‡~è‡~Âç§WÃà’5jYqñ`"ðlÌ[Û/Ø£qÀCML5 {eÊ„þãOÕÀͯ²Õ^,3Ùµ!NdÉŒ³íE àºa`žÞd#ÚrøH¡C¡ÍGcÌ;‘[•À3ÀdˆQ¿üûïÿô‚EoïØJ?ùà‡ô óC?ôC?ôC?½ÑOï…À¥2{Î;7~ Ì*ô_—Xlë«+ûqTiˆˆ³üÇ"ºr²Ã¢N;ÒPÍP'Í.߆´£Ý‘ÎáþdöK÷D™¡]ˆ´FkD$5ª£º,Ð[€ßOŠn,rëøž²àÅEô“W~HÏ0?ôC?ôC?ôÓýôR8\ëÿš¼s¨}Kœ/çùXÁêBe·M«Z!O Ù,d«í§]Lþ—Etò‰ëƒí€p¹·ûm¦ÍSN 37‹û³}Ä6ÁíiÏÍtÌ<¢’Jˆ¨j_—)±#ˆ¼åëÀ à‘‚~ý›“zdvéÂÅÛöl£Ÿ|óCz†ù¡ú¡ú¡ŸÞè§7òÿÿìÝ{L•uÇñÏïò\ÎAœ-µ©[›·f˦+ÌK–æ4[MÔEÌ@B4R!Tм–7PñnMKeNËÊ93§é\µrV®•³ dy×êyNµõW[œçŒÏöÚ³ãAÎxÞû>|wÎÙÃà?—R£b!·•Y”)¬öjó´/ꌟ…¾ó³¤?˜úpî‡Õ®¸ÄÍÐ?/ýù™t?*ç¾™…¿>ÐvEãšÀåÐ3 õR6˜ªÁ4.‡~å’!ë}öy¿ÿŒmSr°NˆåÀl`ªåKk×~\ßþ`~ùšo±—ûпãü°û°û°O$ö‰,\nÇúš¯Ú%> ŒŠµœÕ3X¹Ó´˜Ö!CÕú´’g€¯µøIã%®jyK«ß´ú]À¹®)\VøU»Ç«×®kÜP¸aà¦ó@ÿõÓŸµh0e½C¢^á‚)¿´S†q@¨Àb`%ôÄÖñ©]ïyö‰Q³çÌ[õÆÛÇ}èâü°û°û°O$ö‰ \nßÔɵÀ ø˜i†1×Y……î•çÉJ¾ï·N§€³ÀwÒ½•ÝEwÜå [Ý2pÅÀ%Ë=^³Bsoá¦á^îçç4.¸è“ ¶þɯ/øo£Ô9ΫíÖ‡¾ç^( •îݱKêÀÁÓ9K׬ßö ìCˆóÃ>ìÃ>ìÃ>‘Ø'"pø¿QÕ*:"(u¡ó%ZÖÆÇLl}<®Õ'Ñö†{íÏCÜ{g˜8o¹.XøÞÂ!õÎÑtŸqž?g‰/5>NG€w4ê4¶J÷{î΋•N‹ŽMNl7òÁSÇO*Y¸tËîºÃÞ}¨)p~؇}؇}¼‰}"€ÆÈ~#.!x̶3ãâæ*Y ¼Tkm { uÐ6ù¬£Q¾ã†8bàXÈq‡œt޶:a룖þÀÔ”Ü-Ä`°ÒÀBí¾Z@ Åï²s—”ƒ³ÆŒ›µ¨bó®Ý‡Ã~îìCMóÃ>ìÃ>ìãM졸4¦ÅKßë}¾sÉ­c µœ-0Ob‰a¼åßàóÕ Qã ´’›•ت±]‰í;”Ø:nWî¸Wýå^ðç%4Ë]yÝ[ñ¹£mJ·niC‡dçæ-Y¿aOØO–}¨™q~؇}؇}¼‰}"€&‘ÜyW‡œ6ñ9†žd:C,D¡a½Ì Kî›e²TˆÒ¿óMk>ŒBç?“€TXã͘‰1‰)Ý»O>lúŒüÊU«wÕí;ö³c /Îû°û°7±O¤àд^_y6#ã̓õ¼gNÇN¹­bÓ§¤û·”kúž¶£“cÆtè2ñ¾¦L.›2½º°hãÚšº½{?û¹°y ç‡}؇}ØÇ›ØÇã¸4«-[¿Zµ{A鯢âê‚™UÙÙåÀ¢iÓ;ró*æ­]PZ[¹|gí¦ƒuûN†ý¯eŠ,œöaöaob¯á@DDDDÔ‚p """"jA¸µ \ˆˆˆˆˆZ.DDDDD-""""¢„ @óYVuhr`åð‘ †zfBÌóqQ>•%¡e–Ò9†ÊQ:h¨ TYJ!²üv¾aäi‘+e®©fäYÎåÑíîç™ÛÂ~^ìC^Àùaöaöñ&ö‰ \Myå»}úä9so#§môËQ(ñ¡Ø‡¢X£èÎ6%ݺ¼ÒçÞeII¯öë_Ñoðò®4tÕÃCÖô¼6©ÿš¾IÕ=zVuíþzçN+âã+”Å/Yúe ¨0%ÖèÝkþ¼â#a?Sö¡æÇùaöaöñ&ö‰DÿÿìÝyP“wÀñ"h­G­¶¶* 7h”C@-VÁjëVEgÕ²ò5_–ìÚÁ£$¶–•a.—×a¾ åÆªë¯Üàá¨îȾZU¾hëýÙù“ýè¶£NìxØ«Qæè{„¾éƒV#6ð•ׯ£½ð?5ø@Ï'˜ððŸ—3ðé½Áð?µíoé}úÎ1C+¬ú}ÛÏ’˜ÑmV滜íÎÌ ¼þÑ|öú¯jv¯HJ¸Çcã&¾{··cµ«›°îníÂpû=Ürkš±R‹;ïâÎ;X§Ç7oâ3q-Û·°—-Í^ƘþN¦Ýè3l­­vš£Ý‹î“7G¬Z³:õ… €ôì‚ùððy9ŸÞ,²'…ã<¶#´ ¿Í7¨ûãªþ6‘S§0„²ÃBó×­ãœ<ÕTQe2ÜÖ†ou`½+TT÷t†ûÃmkWó­û͸•øRÖî+µ4:,U`¹7·Ÿ• _»ÚQ–³p wîÜRoïKC@Æg`ZE<o¿ùULLÅ ×èéó>à>à>½Ñ§· ÀŸiÖ¬æf¡-ëkü´kãè·S}|Šg}À [ÌÞ°¥üì¯kÚpKV5ßÉ5¢†F…ªM«ïÒiï7*ïªU÷Ô]U—F}GÓØÑØx«QÙ¢R5éµju»RÞ*—µ©äw´jܬ3®Î5|8¦uáÇùaKJ/®œâ—óæëq¯ZꃶôE_›£ÁÁ{_¸ ø@O+˜ðððé>½(XþX‘Ñ…«ZØÏâ ôýàþQ^¤ìùskC‚Ys>d~·St…‰¥j,ÓcAƒV¬UKur©V&VÈêÄJ‘X'“ßÑip£ü¾²á®\Ò)“´Ë$m2i“BÖ¬”7)z•Ò@¤ä zâÅFe›Z«„XÕ„Yl¼i/8$mþ¼¡sù“'å tʪÏ+ó­… üщSðyÉ} 'ó>à>à>½Ñ§× ÀhÙêóÈ,ÔÚf B›XG;ØÒCEKÂ>˜•±yCÑEJ§€%R\ÉÇÕíuÒv¡´I(Õ‹ˆ$M"I›HÜ!ªïªÿ¹Û¿ÔaL|ë7«ï¨v6ȰF‡k…86V±h1}F`Æ‚yÕ³Cj}½J¬ûF#´yèÀûY¬˜?ï,ø¼´>ГƒùððŸÞèÓƒ §¹{¯7·þÔfà·mµC›P4]8{¦dF`Á;¸”DÙÍb\ÉÃU•¸®Ž˜Ô.Wǯiþ¥V¾à_ÐÁtv×ñËíïŸA«DÜRU©äpÔUUw¹<œ”ܾf gŠÿå°ù²À€Úñ.,'»«¿Ø×ý­6Lr|^BèÉÁü€ø€ø€Ooôé¥ÁУ†Œ˜kÙÿc„>³éîìD›ûWiÀ;¥3‚سgÝX¹¢âÚU\”wŸW†ùU¸¢ü›ÝÆ.ÓóÊ žæç¸:×Àá6q8mƈ‹ßöàäru‚jCO]\,/.mÔâò*|æìÝ/¾¨úËtÖ‡ï‹gÕΘ^åjqäëG‘ñßÉ µó9ø¼T>ГƒùððŸÞèÓ{ƒàw¢fÔÚ œeÝi‹õý¬öz¸gUÏâ½7«tZ ýÓÏK Y˜ÇÅÅ…ŠòosØÊØš‚B9—×TRªì®±;uI‰¾¤¤©;âBÛÓJÕ¥,eUyKEykA‘.¯àëfæã”KxÑBÎ{!ì éœÉ¾¬÷g–û2F‹@hE:tÈðy| 'ó>à>à>½Ñ§· À“JJæ!@ì”66ßZ˜ðõ¾9mJ q†Î¯›˜9o!=‹¯20¯wß+*ºsMË`ªKo¶–ÜÔ_cŠóYrcEŠü"U~‘:¿P—_hè>µÆÛžUX¨Î»¦()Еë Šôy…Í×YwóX8·?‰C‚sü|³¦N›ÂòófLõaì·Ï­}mÐZ„‚’Säàó} ˜ððð1=€'emˆÐkË­}Ð>’[ÑdáâÐ.?¶¯ïÕÙsèÿ<©NËn¥f*rM¹¹-¹ÌfF®ž™§Í+Ðäæ)®^«g\oèNÎ`*‰ƒ‘«%¾Áx×LUc檯3´ÙYŠ+Y ÆÛ|]v®á £#›‰¯dãí;$ÓèÓ ÞZ¾’§ÏÌ•g3´4š,-]–Ë4ÃMM«¡¦ ®å*èYõ݉éYRz¦‚ž©¢Ó¯e=N‘sÅp9M•Nk¸Lo _iHËO]Fv 5ã.í2^¶¼ÌׇF<A|ÇQ¹“^nCChƒÕªAƒžÕgaàÁüÀó>à>àóÿæcÁðëyzmêk†ÐR+ËÝ^¤üÿúiþJR¿O•ÿ¤¼w3Î&ÜKº¤¥Ð„É´ª É‚´4yÆeErJm¥šJeÐÅ´ô:jš¸¦ÒÄTš”J•S©Jê¥FãIm0¾ÒèòôK:jŠ:5ÕøWr™ÙÒÔt!9¹†œ$KÏćéýýR'y2ü½¹SäÓ|S½D¾•í´¶Üaf¶hð¹àóœ} ˜ððð1=“ €_)8$|øˆM­8`¯‹c:Éå9®ÂÏG4ÙGàI*œ8¶ëGÝ™øö„$eâEaüy%¥Ž’"¦¤ˆº«{4‘ñKÉRJ²Œ’,§P”ÆÓx-íq²ä$1Š<9Yœœ" ¤V%¥ È”úÄä¦ IxÝ:±£Å׳Ì˽f‚K½ïx‰—G•ç¸"Kó=­´ì·ÈoÊFðyn>Ìø€ø€ø˜ž) ÀãmÝž4pÐ—ææ›Ø„;½äë}s"‰çîR6Þ£Ìχ3Î#sÚ´¬}û q§›Ï7&\Å“«È‰5äáù‘êÉdIw d²¼û”_ìa䆄x•±s dQB?!±œ|žK>_~.±&‘¢9—p{Ûv™'é²7醧{-ɹ~Òx¹×¸Zï ÜÃÈÄ3ŒÐr› 6n=>ÏÁ‚ùððÓó1±`x¤Óñ7† ]€ÐR3³Ý#߸àêÊôp+uu¹éîV6aâ O¯<'çó Fm9~BC&kΞ•ž9S[óHqüÿºv'ú¹SõÆþsÛ“Œ?"éŽøAa\lu\\yÜiNìiîéx~|¢âD¬a÷^CHPÑx×u¼>&ZÃü|XíÓKp,š,¦âX —èÄÉʸӒˆHùOíK–ð]œ²Hå.Nåîn<7×2'Çw7–«SÎða'ÌÌ6"4×Õm-øà>àcz>&Ù¿ÿÿìùSgÇŸ~»{ºæža.ä2JMŒ7ˆÉšÐhi‚÷DA#j4 ˆ¢&[»›Íæ2FEnæ€án‘Ãà×&Ù­˜lmÕÖîÖþûv#›ÍÆdEÝvæ©úÔSïLAÏû~êùþðTÓ ÷y=ã#€õjñX¨øëèwdlkDd§Åî·ÙG#£îÄÄÜŽŽžÙøììúƒ‡¾+)ùîtÉ×E…£§‹nü²ôNiñí’SwÄí n–”Œ•”\Ÿ`LbüÍÿ^¯Ÿ.).=u~Ðé_½Wô‡÷h=q÷Ýâ;%'o•œüCqñ_²s¾›îŠŽi‹ŒmŸæ uG'ôM‰ìŸâЉu˜}å§ æP¨°ù…9¹èç‰ûA°0_èý ôx~&D0é:mžNYM5Q1M‘±mÑ=6‡ßb´Z¯„‡L‰èˆðÎy¡-7÷^aÁ7¥Å<’7|òØÕÓ'o/¼y¼ðÖƒ¸yŸc7Ž»&3*×Oáñk…E#ú‹EGo½C9Qp«èè­SEwé§ŸüîpÁŸ²vÞK˜Ñ05ºiÊ´¶ˆ˜FË#ªÓlírD =•p'2¼?ÂÚ—2°Cäåßâ¢äqÀþA?èý ôóÿè'PÁ@"ié €×yþ8áíÖðV‹£ÕÞe ï±Úüv‰Þp»oj„÷¹Y;2¿9xàÞ;‡îÞ=ZpµèøØ‘¼ùù7–?äçøÇÜÎË¿}ÿ:‡¯å¹šø Z oî;x=÷í/óÿ-;çoÓ¢=v{C„ÃgµwYí=ôÒÍKû·uµù;Í/E?OЂýƒùB?èý ŸÀóÀà a4¿)?#rÜhp‡GЩ·ÓÞn¶w[lÝ6«„ÝÚi·µDØ =‚Ù싉ìÕkγp`]VVúy"~ìÌúA?èýžŸÀ€eqñ;²Qé L¦fµ¶YgjÑ…5ém£Ág4´™ -&£×l¬Ó©Ï.˜Û•“ý§Ìí×3·eeõoÛÖ¹c 3sp2 O†+™o^• ‹ÌÁíYþíY½”m;ýÛ²6l¹¼5óöŽNˆ÷õz“nUÞs‡¼ÿ½©‰b4¶PÂŒÍVS-Àa¥õ&úy"~ìÌúA?èýžŸÀ&Ø€óec¼°J¡Ì„b³¥V¥ò„ªšU:¯J_¯Ö6Q´šf­¦I§ñê´n“¾ŽNñ1ÎÌí÷22FÞÜ>ºi“ãÆž­[¶nœ[†&ÃÈæ-_HlÙ¼upó¶þÍÛú6m§ôoÚ6˜±axã–»od|iµWêt4.£¾YÞ3M²W­«WëÜRÕzé)T!n½¦ È =‘åeo¢ŸÇôƒ`ÿ`¾ÐúA?è'ðü<Á>¼¶ò=…° ;4äWJåyU¨W­ñ‰ªzQíT†ÖSBC(ªzUˆS§®1ê+m–²i×^[1´qãhƺþŒ7zÖ¯»49Ö^ž Ck×K¬Z»þÒÚõþŒ }2t1¼&ãJƺÛIIZÝ9¦B£vjÕtÃtÛõJ•S©ª½O¨›žE£ò ÜùÅû ö GÞHK/A?éÁþÁ|¡ôƒ~ÐOàù x‚}°˜×+Å,€ýZÍžãx·Ò*(ÝBH­T•n¥è¡„ˆîÑ) åzM¥^{aÆôÆ´´‘¯ ­~}pùòîU«üÿK.­ZuY†.ü+W÷­\ÝCëk«ý«Ö ­X9²|ÕØ´X:¸ŸSŠå‚P- .¥èV*Jeµ2¤R¨”Nzc)S)Ï™Íôó˜~ìÌúA?èýžŸ€'Ø€tžìV ¥zm¹(ÖTñð‚“jåê.ЍpŠŠZŽ”«B«´ê2½îljꔥý«W__öroZª?-­÷½xꥴÔZSÓü©é½”WÓý¯¦_J_1òJúèË©czÃQ<Çs© L• p B­ T b9¯¼ÈÓ*‡%5ô÷Ï{R÷Ñúy?öæ ý ôƒ~ÏOÀÔ@öÎ:ƒ6 G¯ý”cÏ\Äf–÷S L¹\+¨š ’e*>ø˜ìŽê‹^~ù‹%)þeËúñRÏK/v¿¸´‹Bôå²_ô>)’’:^z©ÿÕW/¿òÊ@JJ碤öEIÉKú–¯¼õüÜž0sÃ~ð)!i÷T¨"PÉ0e ùس@«tz„[ÇÂY€"Ÿ¯Ve/^üswÁÐÏÏûA0_˜/ôƒ~Ðú øD£¹ß¶`áȋˮ¦,éOIîY’Ô¼¸+iQ'­úòI‘´¸gI²?e‰Ir_Rrßâ¤ÞääKÉKGæÎ˜Ó¢:O÷p–e+éŒK»œHT1L9Ü—º"œ ÞM  à— X²kúSGÑÏ#ûA0_˜/ôƒ~Ðú €~Á‚ùÂ|¡ôƒ~ÐOàù ‚w(,èQ ;ÕB1²P¡àÝ q”˽Rþ²!ÅÃ)=%•¼Â£Ý@ªX¾V«uÇÇúf$´<=Ã7ëéÎÙÏt=›ØA×3§·>3³ýÁ$¶MŠÄ™­‰3}O'Ò\ùgÍHHè±Y›Ôª–•ö)%–T³œ‹å<òè\O3 ï¼H™S =‚‹e½,ãRðå þ}€|†ìÙ°¹ý<‚ó…ùB?èý ŸÀó$ï°fÕ'a/‘îýšö=Ïz€uI+ÆVüdÀ%Ý ƒޝW†4óŠ:ÓÔbr:l5Ó"½ ±Í3Úg$´Mk‹iz*Þ÷T|ëƒ*¥ùáklLc\lSB\ÛôøŽèhŸÅìUŠôsϱ´ïI a´õåî÷È;¤ðrà%P÷£8xiU(ªñ–;ɰûR^ü úy?æ ó…~ÐúA?ç'HÞ`ÎìÃ<ì(øu,CPŠ* ~".0RŸ1l½ô¼$D €#"ý<‚ó…ùB?èý ŸÀó$ï`6maa7RÎqŒ‹c i”FI¹Q˜ï©ÿ´‡¾¯ô¹ój Ô°¤NÁJ_œ¡”¿ŽÎdh1›L†&£Ñk2z¦z“±^®£ÉõÀj0:7­4KzC­:‡'µqóÄÍ2.:©Sˆ4æz¸7šð1ÐzcL¥Bk§h‘àâØZŽ; P/Š›Î!ô3Y?æ ó…~ÐúA?ç'Hø'ÿÿìßoWÅϽw~¬ªMÒŠGÔ‡ÀHðʨ „!Ä‚h $¡„&¨€¨ÒPEÈŠ ¤¶)´‰i㬽¿¼þ¹Žwíµ7¶q¥ß{gg³vb{ÇyÀÚ9ÒÑÕxvwöÎGçÈ:ºwìô€#‡›0xG,å©‚V%·BÙ(`­6.¾Î‡~>ä{ÂÜ@a ?ç4105¶»úûGE}}#Mõf==.Óä#i[ss;̧ 0-p^vÖ—Ül À?<3ØÇç§ðj&sü½›Kä“”Å|1_äC>äC>ÝÇ'%Jo8|è¹­(i5 `=”O$X/Š)­AŦ)HB?x— ü±ÀqŽ5²»|o8’­ªzLÚ¹LOdPŒ-rí0ŸöŒÚÅ/›÷¥Ü{þ”»Áq¹f{®_«OR>óÅ|‘ùùtŸ”(½àÐã?h @ÖäV⢳HA'PQ¹Q;k:§¤‹ä²ÑŠ•]ºÒÃNv™ÌÉ>(iº­ãh‘Ë)ª¿ ÀNóјÑ{q+zú–Ó˜”{Ï›J”êl ß.)\¼}uŠ|’ò¡˜/æ‹|ȇ|ȧûø¤D).‡¾àš±7jJ|ë›’‹A¹Æ©ï?““E­ ZçœÆµÉ6%Ç®m?(£Ë¢Öî:VžÙu>“q ö™=b¥Æ!)ò€iy$-Ð×?¸œ|ãJ‘|’ò¡˜/æ‹|ȇ|ȧûø¤Dé-‡Û1M˜CÓÇ¥ŽÇ²ÆœHaVY{‰ó&]ŠJ‘¡ž4¦è”·’õ´Q³FÍo=]ñôœŒ­3îÊ3RÍ]¦Zßë¾¢¸Ó| f½‹¢RÐ’,tªì™ª»Á)Oå}£€?_ΓOR>óÅ|‘ùùtŸ”(½àÈ‘g Nk\tÈ{ÖjRE‘•Ëq£Ýs7/HxD óQ„¢´ÕâR›Êîú¢ùm£\Çù~Áù¾Ò:ßÌfZßÛvý‡ÍÇ`Ö~—ÊÛÿ|!£’HÀêÀm`ÆnÔ»€ã ùì·b¾˜/ò!ò!Ÿîã“¥·<ñä÷Œ:¥1d÷À5Pá|ìœ4ÛÙ(n»-ÒXTÍ=ã$1˜uc¤r›¦Û^½?¶Âà>>×:ßìÁ6™Óq϶«u;ÏgÞ43\tî/ºëH½^ª6 Í\R8ŸÉœ5xÛØ?}%•qI£úëÎÄó±q÷+±û«mئÊÖq¶­ï©VÌ:²¼Ùãã+È÷.¬+¬º%°œÂ[ÆH~ñѧ^ÌfWÉ')Šùb¾È‡|ȇ|ºOJ”ÞpæÅ›axBáð'£²½~U[‹Üñµ µ`—Ã:­j{iñþ(ŸRsÐ3JÞl?Òé|5jží^:¥æ”ÝØ· kýP—rú9ƒ7üpH{?ýä§^.—7É')Šùb¾È‡|ȇ|ºOJ”Þð×k÷€g2áà²oÆû‚š4`ç’e§ÅíÆÝqL*qjÅÙºCUÚb¶÷¨ì*Þ²‡eí2 ¬ä|¸¬È­ªúã „9}â3Ÿý5ùìƒÅ|1_äC>äC>ÝÇ'%Jo°7¯úþ¯z«öÿթж¾o i—š‹A‡ãîZÞªZlèÎUë|>ÊZ¿î¡®ml!VÍú»îÆ¥Á÷nCÀià»_ùúkä³?>óÅ|‘ùùtŸ4(Õ ð𳾞«¾7 L†æŽÆšÔD%Rõ$ZÚU‰.õ¨ÒX1høv¬»«OTWXSØp%x©?S1æpx^g¾óü™wÈg|(æ‹ù"ò!òé>>iPª À—¾|E›Ÿ‡ÁeÏH#,ôØÇ_VÜ“" Å 5Pݪ`?ÕpŽìPI&ƒ•8 ã2 ­äü†Â&ìÕ–{osxÁ ‡>ròâïgÈg|(æ‹ù"ò!òé>>iPª À…¡jïÀÏ ùÞ»Àh¬À.mŠçàÌŠí®ml÷å–\ˆÝ›ŸmWt‘޵u§2mî&[£Ô<ï/ÀÙžSO}üÔõ¿7Èg|(æ‹ù"ò!òé>>iPª €H_~ üÆG=³èùݧÝCåzJjñC$ÿt6ú—×ã­rÑ««î Ѹ§Öª“k¶´ªí68û4L¼7nÕÍ\´h¼ªçO„™73=/þ7¾ðųùâùì›Å|1_äC>äC>Ýǧë•öð‰OŸ†wLê Ÿ¹LuO«ÿB5`ª÷¥— ¢yø@áC…{QQ޹`wÎmIcvË^v÷›4xèè5èM( íÖ”y¸œxü±oþèä%òy>ýÃ|‘ùùñ÷{"¥½¼ôʼg‚žóPoA•|óoàC[p%bz· æqÄúÄX‹Vµ^V¢­oî.Ö¬õÕ];š5/¨hý7Ø¿þûí£GO¾þúù< Šþa¾È‡|ȇ|‚øû=‘Ò^Dý=ö^ëë›sK`Öån‘kÓYj­ÍßQîň6¨µ^Ý<£ÌJÛ ´&v׺¿yGu¥'Ýð÷ð­§?îÖH|‘Eÿ0_äC>äC>ÿ÷‘¿ßéÿÿìkpTåÆŸ÷röìn‹Ûéê—Î8:Ó±:c+Ö´RëH•ÂŒ 5–hEa ZÒ©:´Ü«hgÄ‚P[FŠÊEH+—”"!„„\›l–\6‚µýÚ÷}w7$Ã%›ã3ó›w²›³gÏüæyfç?gÏYß¹wð80/z(S0Cpu†*؇‘JRÅyRÏôz¦¿W‰Ã ÊþQá¾*8¬Ô^!6J¹˜6(wÂ…‹éçÚýæ‡ý¢ú¡úé÷•ŸïW€‚—~o¦Þ±€‚_ É9¡J‰ ¨uÔ¸&T^˜øt¼z¨ÈšÕ•B•Dµ´Gž9~q0ù§’ëÜà&ßqGÑÂ…ëèçÚýæ‡ý¢ú¡úÉ‚•ŸïWËwÏfK<±1ª÷)ꥭA¯ÈC®•n²¬q¤å,YSѯ1‡-Ó®¶c±ø8¤6«€YyyE?\ú—¿^éù/ú!ìûE?ôC?ý½ÒÏÍö`8XfÍþP©)Có–+%6+v¹O Ñ¬Hwà‚T»A¹>ÓêìX«SÑOU×5¡R‰ýZmV¥RL5jú3¿^M?×Ëa~Ø/ú¡ú¡Ÿþ^ùù~pH“Ÿ?Ý÷gK,2) {<›¤Je£_4äå$M¼„8*dÔ'0«< qh4Ô ÔÏŽõ¸»ä¥JÉO˜ƒ?$Pñ?Rrð2Pü•aSÆþäåµkwÓÏuôC˜ö‹~è‡~è'x~‚ €4K—Ó^¡”3EÃóËsÂ&Cj<ÄNFt.aGl”)À1Øxt4¸äÕeÇZ'…ÊkUïÉ÷»ÿ‡6k±J`®V…ßUTüË•ôs}ýæ‡ý¢ú¡ú žŸ Âà<÷ÜS<ê‡æ¯[€]¾ªŠ¨&ØsI;Œ›„ÙÁ×Á®Ò É‘‚²dÕÚÌåf®ñT¥ÀÇJ~òÖ(YªõSÆM,øÁ³¯½öwú¹î~óÃ~ÑýÐýÏO ápž5®’÷ˆT?LÖ l ɃaÕ SHøºÝÄ ¢ꈣ§qW€†ìÁ}cÏLð!ïïïÒj½p'¿"9î¼ëçÏÍ^N?7Âa~Ø/ú¡ú¡Ÿàù $úP4u0ÚÎ G_ø›„»-nT%<´› KÄ„¬…ª‚®„®†ª‡ŒA4 Ä$Nf 'ÜÕ0‡€ƒ‘èþHd+°Â]ã?áö¯7aö;ÛF?7Èa~Ø/ú¡ú¡Ÿàù .äîoO5Y1CpNÎúÜpPîÆÊÐ*Ñ,Ä ¨j説-€9B©jÝIºý~d·ç¿,žŒÁŒß½r­¿Óa~Ø/ú¡ú¡Ÿ/›Ÿ€ÁàBÞÚðï¡·™< ±lHî`¯»·TB£K!!Mâu-¼cðj  š âR4©¬AÊF?Ü BG€=ïA¼̉äN½ë[¿znîÊ­;wÑÏ õC˜ú¡ú¡ú žŸ€Áà"””îtËLÓ-Vyø W ˘@“-€ˆC5Úè¼FxMÐqÈ‹eñ^$úïÃå3m·iu$2Ç2|þÌ‘P­Ö€w×RÈ¢¯š6~â‹«ßÜD?7Áa~è‡~è‡~è'x~‚€‹óÃ1 !ÆzªØýpôÚ¯\¥ö¢Iê.åŸb¶ ‘f{ʼn­G‰æ -ÚrJ£M£]#éè’HJ´ œhÉМ!Ö‹ž'Í–gÎ $íßâ¤õ)€%[|¯3dIt­fƒhÒø—-aù¦§J…œxëˆÇÆŽ›óÊÒ5ôsÓüæ‡~è‡~è‡~‚ç'0p¸$cƼÑr‡¶g¾J~1bÄ“<8ãùW”íÛK?7ßa~è‡~è‡~è'x~€/àÞï–“…+±x[‹´<â~»É%¯Ãÿ8›á4Ðiž„h‡h…H@ÆMŽ˜#n7°›]žÓiD§Ý›lµØÝšÜwJœ•èNõÇÞ£W5FýªHxŸÒ[„4éŸã‰'òó'}ïûÏ”,\µu× œ}é‡0?ôC?ôC?ôóeó3ÐáðÅüè¡?Lfh±$¤6hìö)Ô…ý¤¯M ÏŸfèv¸&ˆŽLpãîby÷9KÌE¹£/—¦*aI½Ê¶¢[â3‰ÿ™7Ò芨¸IØ/ƒ\,6Ç ñèmÃÇÞ÷ÀÓs~³ôý²ôÓ¿~óC?ôC?ôC?Áó3 ápEŒ·2?¿˜,ˆzë‡Döh”{¨ªVaÏL™Ðö¹¸ùUvØ“e&»6Äñ4©q¶g¢½d\7ìÌË[í~Dg¦Ÿ*t+túhŽzÇBr;°x˜1nøW|ÿƒ…Ï/ZòÞÎíô“ ~Èåa~è‡~è‡~èg ú¸p¸RæÎ{ÿö‘Ó€‰Àœ\ÿ-‰À‡ƒuuÄÞŽ* Ñ q΂ÿXDoÎAv[ÔGª ꔣÍåÛtt9’Ü¿ÌöÒ½P¦è"©Ñ-ÇÃúPDoþ< LλµhÔ7 ùiñ¢ÅKè'«üËÃüÐýÐýÐÏ@ô3@ù?ÿÿìÝYlTUÇñßYî23]h¥ÁhŸ„ȃ+ѸDŨT`Y" ---Ä -kcÃ.ˆ,¥´,RHÑÒ¦S„$Bˆ! „ ©Â”²Ô{.ÅøDÂRf&óK>¹™ÞN'oÎyøgîär¸ U›N=÷¬¹$ΑÅ>µ±&Iy‹¯^«£BžòŒBœ…ˆø›ÁÛ —[‰ÿ4ûûÁìá¯{ó|³¦½?‰onçÍcsÆìÿ9g[_ÍÛcÞuJ©¶:âèï•Ø°7;z 0èJÍz²[Î;ý?šúÉüúõìk}èÖ¸~؇}؇}Ø'ûÄ#·m@¸L!ì  Ù.JVµÚ>òˆÿý˜SÞ üaëà*ÌÅj—ÌqÍÿñâȤ¹TÎ|˜…Ö Ú.i\höÏ4 D¤l²U“m5ûrÑ’‘€{&<æºû”Ü ¬b0 åwxx@·³sÇÍ_QùûÄrº5®öaöaö‰Ç>ñ…À(/û¥CÆp OªãžcÏ!«mw»íì²ô^­+y øU‹s*qYËëZý­Õ?Þ¸¢Ð¬ð—6ÇËW®j´(´X¸æ=Э¿=¯E“-#‰ˆB£-O¸Ö!ËÚ.T%0˜ŒzH»ôwþfŸI“§/ßôuCÔã°Ý%®öaöaö‰Ç>q„Àõ~Ð3=%Ç²Š¼Q˜ev¼“ÕJ~t‡€ãÀoÒÜÊî‚Yî²ÅU×-\²pÑ1Ç+Ž¿î\³ÌÞ0×Ïi\°p! ›\}.¨ƒÖé:éÂ{µm@¹ÿ=÷Biå:¡¡Á”w;eìÑ+?{̼åµQÂ>tqý°û°û°O<ö‰ îÖ¯—„’‡B„È•ºPˆÀ\-+ÒS2ÚíOKþ1É=j™{hÿì3÷ΰqÆ1üîà¬/âmsÆ;Ò'4~{€o4ê46Hó=wïÅs•œ”š•Ñ¡÷ ÝG 6mÖ¼õ5ußE½ûP[àúaöaö‰Mì×8ÜÙy›ÒÚ‡W\wdZZ‘’S€…ÀJàK…­–jp­]go(°ß{,ìóí·ðƒï wtÕWïuôN[oW²Fˆ*`-°ÌÂ,m^-[  ¾õXf¸G¯Ñ}Lœ½`Ý–šÝQïìCmë‡}؇}Ø'6±Oœâp/Í™·ãégÆyÛÈj—R¨å$és-kI(¸&¨¢Ì[ÐJ®SbƒÆF%6jT)Qå7*³ÜWÁÜr¯¸±…&š‘×ÜŠ¯ïC†;wüòKycç–¯Ùõ7Ë>tŸqý°û°ûÄ&ö‰;ÚÄèÜêG:Žy }Œ¥s€‘Þ"¢Ðr¦EÀÈióa™,¢äæq†íÌ€Uè= „3ÈN’’îÒå½×^Í?náò/¶ÔÕïŽú»cŠ.®öaöaŸØÄ>ñ‚@ÛZºìøˆ›»÷œýD×É-HN ¼-u¿›ÂÿÓÏôw“²RÛ÷í˜9ä©çó{g•~¿ª°¸reY]míΨ¿ö¡XÃõÃ>ìÃ>ì›Ø'Æq¸¯ÖoØýÙâš™%•ÅSVMøpq^ÞüììÙ99s¼c¯œYR±pQuÅÚ†ºúƒQÿoÙ‡â ×û°û°OlbŸXÀˆˆˆˆ(p """"J ˆˆˆˆˆ""""¢Â€ˆˆˆˆ(p """"J ˆˆˆˆˆ""""¢Â€ˆˆˆˆ(ü ÿÿì× € ÿ¯’à FFFFFFFFFFFFFFFFFFFÿÿì× € ÿ¯’à FFFFFFFFFFFFFFFFFFFÿÿì× € ÿ¯’à FFFFFFFFFFFFFFFFFFFÿÿì× € ÿ¯’à FFFFFFFFFFFFFFFFFÿÿÆ”›³#ÇIEND®B`‚golly-2.7-src/gui-ios/Golly/StatePickerController.m0000644000175000017500000000527612536111364017334 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "prefs.h" // for showicons #import "PatternViewController.h" // for UpdateEditBar, UpdatePattern #import "StatePickerController.h" // ----------------------------------------------------------------------------- @implementation StatePickerController - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"StatePicker"; } return self; } // ----------------------------------------------------------------------------- - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // release any cached data, images, etc that aren't in use } // ----------------------------------------------------------------------------- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // return YES for supported orientations return YES; } // ----------------------------------------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; } // ----------------------------------------------------------------------------- - (void)viewDidUnload { [super viewDidUnload]; // release all outlets spView = nil; iconsSwitch = nil; } // ----------------------------------------------------------------------------- - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [iconsSwitch setOn:showicons animated:NO]; } // ----------------------------------------------------------------------------- - (IBAction)toggleIcons:(id)sender { showicons = !showicons; [spView setNeedsDisplay]; UpdateEditBar(); UpdatePattern(); } // ----------------------------------------------------------------------------- @end golly-2.7-src/gui-ios/Golly/main.m0000644000175000017500000000217512536111364013771 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import #import "GollyAppDelegate.h" int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, NSStringFromClass([GollyAppDelegate class])); } } golly-2.7-src/gui-ios/Golly/StatePickerView.h0000644000175000017500000000175412536111364016113 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ @interface StatePickerView : UIView @end golly-2.7-src/gui-ios/Golly/triangle-right.png0000644000175000017500000000027112536111364016310 00000000000000‰PNG  IHDRHûg!tEXtSoftwareGraphicConverter (Intel)w‡úSIDATxœbøO%À¡Nœ8AƒÀ€ãP ¢Ä8,‘gNƒH5Ž€AÄG”A@5ƒð›E_Q!Œ¨kTHGTHÙTÈkTËý”ÿÿŸ§+\]^KËIEND®B`‚golly-2.7-src/gui-ios/Golly/PatternViewController.h0000644000175000017500000000627512536111364017361 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import #import "PatternView.h" #import "StatusView.h" #import "StateView.h" // This is the view controller for the Pattern tab. @interface PatternViewController : UIViewController { IBOutlet PatternView *pattView; IBOutlet StatusView *statView; IBOutlet UIButton *startStopButton; IBOutlet UIButton *restoreButton; IBOutlet UIBarButtonItem *resetButton; IBOutlet UIBarButtonItem *undoButton; IBOutlet UIBarButtonItem *redoButton; IBOutlet UIBarButtonItem *actionButton; IBOutlet UIBarButtonItem *infoButton; IBOutlet UISegmentedControl *stepControl; IBOutlet UISegmentedControl *scaleControl; IBOutlet UISegmentedControl *modeControl; IBOutlet UILabel *stateLabel; IBOutlet StateView *stateView; IBOutlet UIToolbar *topBar; IBOutlet UIToolbar *editBar; IBOutlet UIToolbar *bottomBar; IBOutlet UIView *progressView; IBOutlet UILabel *progressTitle; IBOutlet UILabel *progressMessage; IBOutlet UIProgressView *progressBar; IBOutlet UIButton *cancelButton; NSTimer *genTimer; } - (IBAction)doReset:(id)sender; - (IBAction)doStartStop:(id)sender; - (IBAction)doNext:(id)sender; - (IBAction)doStep:(id)sender; - (IBAction)doFit:(id)sender; - (IBAction)doChangeStep:(id)sender; - (IBAction)doChangeScale:(id)sender; - (IBAction)doChangeMode:(id)sender; - (IBAction)doUndo:(id)sender; - (IBAction)doRedo:(id)sender; - (IBAction)doMiddle:(id)sender; - (IBAction)doSelectAll:(id)sender; - (IBAction)doAction:(id)sender; - (IBAction)doPaste:(id)sender; - (IBAction)doRule:(id)sender; - (IBAction)doNew:(id)sender; - (IBAction)doInfo:(id)sender; - (IBAction)doSave:(id)sender; - (IBAction)doCancel:(id)sender; - (IBAction)toggleFullScreen:(id)sender; - (void)updateDrawingState; - (void)updateButtons; - (void)toggleStartStopButton; - (void)stopIfGenerating; - (void)startGenTimer; - (void)stopGenTimer; - (void)doGeneration:(NSTimer*)theTimer; @end // other modules need these routines: void UpdatePattern(); void UpdateStatus(); void UpdateEditBar(); void CloseStatePicker(); void PauseGenTimer(); void RestartGenTimer(); void PauseGenerating(); void ResumeGenerating(); void StopIfGenerating(); void BeginProgress(const char* title); bool AbortProgress(double fraction_done, const char* message); void EndProgress(); golly-2.7-src/gui-ios/Golly/Default-Portrait~ipad.png0000644000175000017500000013100212536111364017607 00000000000000‰PNG  IHDRì}eL !tEXtSoftwareGraphicConverter (Intel)w‡ú±œIDATxœì}lÛšž²›ÙMI°‚ A€d³A,‚}Ù`ó²d³/¯Üw«ïµ¯-_[¶Õ{±Š%«[½R…j¤¨Þ)‰E¬¢DªKVïÕײ-[–}-Ù¾ù†ãåò‰Ã!%Ú’¬ÇÁùÌΜó9ÿÎwfF²““áøä“O¤RéîîîŽÃq8Çá8‡ãpçî€ÈÔùõ¯íd:6961ý Q-*ohlž›_´q6™›¯­­Õëõ=ÚÛÛ;88xóæÍiÿQ%êÄ@$AU§ÓUTT¬¬®ÙØM¥Rsý†kn~q]c{k‡°½³û$Ñ.Z¿ærKmmðQíï×'&&ö÷ë¶¶<{¶ûâÅË—/8#P(U§ÎÁ*óvÓŒ&Æ#k_ý©‹žˆŽ÷âùgm-¹Ü©s°¿ Ñ qÄ€:Ý%€|±‘âôlwÏí<™\=4zd|ê•Kåª.Ÿ’À!,¯¬²Ùì©©©/^œ¶¼9ÚÂ333 ?3;gKOýƒÓ2­­\Ñi­§fæÝ>7T“’’±³yòdgoïÅÙD\yê>^†YŒ/FÙ–;|èè87žÿ‘ºÜùî‚u–;#Åéé³çæhiíèÓ L|Pôé[ZÛ) ˜b}}“ÃáLOOïïž9Îqpp099Y[[»¶¾aµ³^¾ìªúƶÎÓ»ªÎËÇÿÜPÍÉÉYYYÝÝ}~f!‘ÈNÃGÍã‹Q¶_'†ˆŽóáù¯Ëï.ØPgd °'Rœvžîš£µ×?0¢û @hˆ’€)„B‘V«…Œ8]cÏéÖ××'‰¬vÖÇ?¸²®¥¶©ãt`rn¨–•±n?¶zóO]ÝâSçðQ3Äøb”O†'çÃóipÆ]î|wÁ–€:#K€=‘âôdg×míü~ýH¿~ôc Q0baq¹¡¡aooï´5Œ½º€Ž ;ôýõ ­¬m©ªk=]€˜œªUïv†ez78IœLtœÏÿ¨]î|wÁj@%àØ‘âôpû‰9ššÛU½zK‰{Ä2Õ!£R£ƒQ¡î75âTbVÒhˆ’€---«««¶È‹çÏ^¾>ÓŸH£#ÍÍÍôýõò ,åÔž€É{¡ZXÂa–Už.U6›óàûí³ŒÖvî©søØb”éÝà$q¼@.bU³«§<ÿ£v¹óÝ«eÏj?‡·ŸúræôýÃÇæ¨oj•«û,A«RjúM-=*­H"Wüv1©B©¤ìÕÑT…†( QSSóôéSUÑS8õ7¢?ú3®ÓŸqÿÞçÒ?n[.#³âGn]QüÄW•nZƒ—öç0zöþìíÛ·¦ö;ƒ—M¯º¦ü‹¨AgÙf²v^=¢¬È›Œ°DõÙ³gè}ݼü™eU–[PvÃÕ󖻃É"-~¡Þ4—˜#:>%)=×j10±‡*œét;Â?(Ô/(,%ƒq$¶Ã*U‹½¹õ½%LNÏÎÌÎÓ84·´Ñ8u’Vž:0Êônp’ “}ÃÍë2r™˜¦ãaò¡=ÿìxב\îl²=RlÇÊêÆâÒêúÆÖÉ“·P¶¬V@èãÌOZÒ³ ‘†·çä—þv\°áQq‡ªò 'ÛŠŒ¹‡Ë³óKÞ×á´õà‘9jë[¤Š^KÐô BñO%r K&Sja7Å=jA· êGÝ7@S¢$`›Í¦ÿ{?I£éã ô?;ÿ€L7. ë†ú/ÉÓCøïÜß7^>üHm´n+LkþVþß(/o].Ùþa‹2 ¸h‰*:Âb±èû q“WTn %ìjÔóêÕ«¸Ä4Ò²´¼òdg‡æs46·²8ÕV‹‰=TÓs ËØËËÄÓ;(ËÙ¹ù¬œ¼œ‚RÛ Ø«TKJYkë[æhléð ¼ýéW—>»ðm@H„¨[£¶o–RVå%u M–²(I¸‡ÒÂã‹HKUmSoß5M¦—³ªmÿ¡ªæævwŸ#!í!¾‡)ãÔ¾¯5Âicó¡9À¯[¦²È‰\M¦»¤JžP,éQèÔèp £P,‡òF…ºŸ¦*4DIÀ(õóòõ‹Ÿp²C°Fܸý7¯úƒÓ_tÿäÎ>z¤¢‡¾ƒñ¢üOÉÓ¡G*sý$ޏ™  ‚ÉÈ©!@¹Õù¹ôaùLúÞìÿmUÊ_uÿ[3ÆÈÓÅÝ)Âè}¯»zeå—ZBaiYL®LJgÀ²¸´ „Df^IHDô wŸ[¾·ïÄÂ’œ™çáèŽtT\ ÒQqÉþÁÐa:ý`HD MC˜ØC•Á,Ȭ®mpb‘D¾¿ðêÕ~v~é!1‰éÐæ.®Ø „¥å0a ‹Šw÷ˆNHuó@VlR=O[¨—®¬®æL£~A¡"±´'¸ðíµ ß~‡Íe_?!€°™_òáP]Ó@i·DYŸ}961Åþ¦Q[yE_PzÏ,9*C÷§¦q¹›—_Yy¥KË«6rà D¸¼ƒ'°§#ez78IÐGG^q9¢øû‡Û½ýƒFä±[ÛyŬÊÈØ¤>¼üC2ÅïÝómñ®cÀÕÓÏÛ?‰¢6)€ìôÌC.g?[#CÛÑÜÆ½—šX»áîmžk5vè£ÆìQƒ§o §ª¶¼²æn\"N³r ¥Pi*kê¦fæì¼™Ç€Õ€²eµÚßßߨÜJÏ%æö¡áQòoÙ”WÕ—°«àíØ&ÃŽIS=V®¤´äª{ûaLÍ.ô¸}ÃÍ;(4j~aq÷ùsÅ2â!E«Šrí8F¤8­m|oŽŠêz¡Xa rU_·*G!è–wtvCôÀô¨ú`áwõtð»%=Ò(SjiªBC”Œ @Pÿƒ÷Ÿ¼Ú&-+Ïg£Óï bPì¦ú¯]ó׬„Wüü?ÂË!Ô²Tl´´.—Í™¾,ûBúŸ`¬[`Ðð4@ôý½vÃ==§È0E¢’½/@ .1 â×Êžì q;"¶Û¹ýèÑæÖìqZZ^ ¿Qª{ïÄ$•²gfçù"©n`5ì<}*‘)iÀĪM­h¨¾¡ÙÓ'(42®µC€ ±„]cJ >9;#‹±¼¼úôé³~Ý@@p.ìà 10ò‹––W—RÓ³ï¥1ì¤Ê,.Y\^;n'±è–WÖ®¬m®®ov º…źÁQMŸžxÄ®D™É鹄äôË×o9_wKJÍšš™÷ -*-GnQiUo?ÒAa‘©™¹Dµ‚.lQ{¸±ûÓ°`kˆb9]&W[eHéc”ˆ»— }¥…•Øhlåòó™e“ÓVc‡>jŒ€¾A ñ÷ÒÖ6¶Ö6Ì-.CrEÅÝ3DP“HØÀÐÒÂnOß Wïv®÷SUgɈòÑñ˜¸0Ž¢îÛƒèHeËjµ°¸„ŸIi¹‰©¹˜ö±`ë`E-<Š˜ç™¬Ô¬ÂÔŒìä±rUV×!W¥éÃåQñƒÃ?K{Prw÷9Œ(PX¡\;Ž)N+kÌÁ®¬ëõX‚T®v+xBYK‡r§‹^._ÒÒ!ì’ªŒF(!šªÐ%#èôÊO;ÿúãKéŸ0§¢õÛ=”ßA[@Š-.ìÐ@»ûOÊÿÇHË·:ht,.ªŸšVrTDßß+×]“3 ,!Ç0o*ÕÚGŸè†"ãRà^@Èjiã¼meie ‰ºÆG'&‘ÎÍg>~ŒR;¹Å u,¾Èï’Ñ4€‰=T ˪޼yóúõëÁ¡Vy¥oàmOߨM $¥eCÉÛØÄÔÁÁÁÜüBLb¼ ÷±ù‘Ø@$$gÚIµ °x~aåG¿øæÊ—Ã"c9UõCÃㆧ٫j“Q «e"c‰­XHxTàí$bSQÀÙÅÕ' ¹äίº¶IÛ?„DQI¹JÝ]rÓÝ“ïW—¾ƒø@1ìäû³Ë7W®£Qs&‹UAi·D²”U‰†nyúbq¢ls ½ââ…ÄW—®êFQ8>)Í…ÅlÔ¶¹ù=ä)Š1 K(iÐ0$126‰Ëݽ±…­#u¨×ð2{nx ÔVP”™@w •ŠJ9]âSÐtdLJFF'(TÚÃ3ÌÑ·Ãï”h®Â=¿tÕ§¡w¢-qÀ(Ó»ÁI‚>:2óJàÛ«kklN‰Ì\&³¬FA—¤©­óÁƒï‘††HÍf¾wÏ·ê]b©·úË‹Wáùp-$0R!D`7ƒ ™ÅÄ3ž„¤ô˜ø$$àE0ºzúB^ QhxÖ§:v8Pºœ%¶£cS¨ %61­\r¾195GÏÐÜÇેBŸ„ŽGtÀu¡0ŒLP-®ê×[ú¨1âþä,j€>Ëb0³s ýCÂ!€xü.dAW!K£Õ£Sô4ânÜW—œaÌÉcRgç– û Ú’!oyÁŽÞÙDG (W«ƒƒ×ÌRNJfNåJ ~–°«»%r$ò‹Ë£Ò^½ÚÇB€•ë•áù.ÁåÚ~â!胇ÛäfÆ.± i“M¹v#Rœ—7ÌQV^ÝÁ—XB·LÍõ@ýt eHÿ¤j¨A·ÜÔØ%QÑT…†( A/€pˆ7šþÿŸ_cýEç?‚L™Þ6-cI…é¿=~ø&Ò¡ú¯‘†Å˜K  ¿ýѧ’ÿüoÁ?Ãé×=ÿuåù¬=ˆ¾¿ß^½™Ê°„ ¡Æ¤rî3I©Yó ‹Ð6ñ)¹PÊ›[[Î×\¯º¸ÁcÖÖ7P>3¯ôÅ‹—ä߬kê +.ÑÓ´BLì¡ €$é»?>’+ÕáÑI¦HoŽˆŠ½rÍUlö™¹Eð~$*k[P@$&‚¤±¥ÃNªùùÌ™ÙÅCÀ4ÑÑ)tqó&ß»c¦Æb ;Ö`œ—q°üÔÏ]ò8vW(34<‘œŽYx|bSŒ‡O`JFNc %e=ªÌì|b¶êÕaúHÏb Ú2ròɉiii š3ŠJX”vK$—–×0EÆ%¦..­R6šb@ æìŠj¤Ùœšôì<ÓO ÿà0²!¬U8Í-(¦¤AÃV£C5cQiú«k±ŠèôÃX?0S£dK{'!%RÀMÕÛ/IÐGž ‹|67¿üÝ w,Tó Ë€óuW7/\…¹ûË‹Wººekk›–8`”éÝà$AiÙÌC3ƒL¡É7¼ã Å(ЯDÚþ ¥ô|«Þ%÷DCœ‡ô^±Tô-Œ p;EÍí ÃSDŒãž~AHÖl,ºÇJ—³Ä¶¢ª§Í­ÜÕµÍv® &>YÝ«£ghîc]†.f²i7ƒ22éQ¨Û:ø÷§­Æ}Ô16>u¨é¯/_ã‹ÄÈb”àTÝÛßÁ vÑÍÆ–vÃ=,¢4’}Á(à¶c^%^Ï•ÙDG (W+ÌV9ùç°…¥Httv+‚„xÃ¥PõFÆ¥b<53c^çGƒBZØ%E:;¿”rí8F¤8Í/®™Ûß6^—%€%W æ %H˜B$Q»å‡ŒB±œ¦*bŸMEÀ«ˆ¸5û;¢õºÄ·/eÿ™”A+›/–(ÐóƒgäGÓÚï»qÚ½Þ€4,{»dRý_á¿üDüï%þwäÇFPB‹»“¦õUÑ÷÷â—ØälKHË!æMIéµõÍÙ¹y€@©¹‡zýú5ÊDßËlj%ži¡XhT"Y ñ ÎÀM+$ÀĪaÑÎ.îÁwâ J+DùÃíG ‘žS`J`hdìíšÆ6x?‘ñ©(O„P·Tn'UF^Áäô¼9°ÜbZ׎TÖÔcrÄL!è’ö({‰Ç9¥å‚.™aî(% gæ;×n©¢¾© ‰š†È òª:oÿì¼Bl¦¦"cMd­|RvôõRr QPXb)‹’$ì@˜ë‘ l4%=‰‰ÉÉÕHgçÍ/®¬¬n˜bielEn}9ùEÇ`è ›àÀÐ;}ºA#c÷Ç&¦±W¾èìªß\¾öÕ¥«(‰Í®o`(Éó»u­0‚°a ãá’Ï.üV_p“Qs·§oàìü Œ2½œ$è£#93Ž=3;ÏdU“HÏ-f0‰¹Ž'èF>ñ‰¨ýAjÉóé½KÐ-%sE Àÿ‘Võꆫ_¹~‹ð(…&ðö +—xw“”ã-_Oß $ò ß]rìp°är”l±äZ_¡& ,,/¯¬OÏ.Ð0¤ô±™¹¥C¡LÍ,íºyßšiÌÌ-¢!ã)MìÐGã÷QôÜúæáJ×nz" º YJM_ƒùîQÐô<ùl5›Á¤46&(SÄ'¥ÙDG (W+…Z;:6!K‡GÇ[:øÄŠ\ÂvR&+¿Ó;©Ù†K 4<%"¿jç ȪˆÿM|w A—öLF1åÚqŒHqš_5GQiEs»È]òv^7\iS´r»xB™©…/ê¡© Q0‚^mÿ°Õ÷P<öXk´Ì<ù+Á?=ôêŠRqW8Æ_ ûsÞßÇOò”·úîCãC¯Àží?!VÆx€i=G@ôýýúÛkw2,!9ƒ˜7±Cš]Ùð£Aè<~ü§/^¾Äâ—”‘’…&,2F/ÿPòYúÛ·oïÆ%EŧÃýÑׯ‹ºGÓ&öP­ªm†êº—’éáâ•‘M<ÿì’ÈM ôö9Ó²ò’ÒÁawýÃâ’²Ég¤ ɾÁwò ‰7<ØNª9Œ‚‰É¹C¨mhóòÁŒ<9½€‰•|YL&× Á,)W6vÑñÉdù°Èr_«ÓO†nßñ •ô¨¿¸è쓈2Éi„ìÈ”Æÿð³mz1ãkû‡Ì9‘›Ç¤´["‰,Lî$7ÊF“ ¨S(Aº†V¤ËØUìʺ°ÈXSdd¿»3=Š^R$•!‰~ÃÓ²ˆèxð$qêÝBÈ®¬ÅjÕèËKWQr`hlxì>dfvÛ2¨"ýàxs;!€šZ¸()éá`òŸŽÃˆ¹Û?8œ†€Q¦wƒ“}t$¦ÓÅðȘ©ûZb^âw!M   °˜áùV½‹/"P§eò O °Æ#íåŒ@‚àçë ¶Ir}…‘”ÆK”êþc‡¥ËYb[ÛЂß2"±œÅ©Ñê†éšû˜¬G}(4~”lÚÕ €,ñ¤‰ú¨1bhxÂtª»?ã|Ýht|:'¿˜¼ÿuYÓ΢ùÈ9‹QHi„ !Á((1vgc) l\­êÛ÷ö^ÌÍ/t ÄÍm<ó˜lRÊdäµwv!ù >t*Ò= ujVá[ˆ'™Ü; ü¦‡ÿ“g»»¨“/KF6“rí8F¤8MÍ,™£ ¸¼¡…o ä×?dº×ÓwHailá·wŠF._BS¢$`½}Ükø*ù¬í-–×o_)ýÃï…ÕÐ ÏÞŸÁøó®}Qþ§$~&úW°xiN)€p¤ŒyÃâ­ýö úþbW|'.Í@2“§S3s8}òdiìõ‘f'§eíì< ‹mçr»[¦ÆJ… î}GÒÕËþ±Üß ¥Zg5vè£Æý ñ³ Ôajf^`èO _ê +ûÝó- Ê¿Œææ I20‚¥7 ÏÅÍ J(=;ïâ•ëµ­6Ñ‘ÊÆÕ*ƒQB.%åÄ·ÏHä–ñE¤”)L5¼ÆnþüñÅ´L®Âå‹Ë«ÏŸï1KX"1ñ¬ÆNñº&%«€rí8F¤8ÝŸZ4G^!»®©Ó¸|iS›ÐxÚÚÑ ÐÁ—Ö6ò`©oæ·rßÛ;%4U¡!JF°Ùl=qðfÿŠâ'Ð?áþž›æ¯ã‡o^ýò×àw^=¢@_n’|teF£t£…| ô臔¨p*Ê\HI¡;ôýýâkçðèKHÎ þ¾‘ªWGžæ°Þ¾ýñÙ³]2kdìþþ>ñ¹ÏÖƒ‡é9ÅyEœ7oÞ®¬m W©ÑÁ.+Ö ŒìïïONÏÑ4€‰=TúfîÂâ ùgœÖÖ7y i7% éQí<}ö£áÕ5uÀïÇéèø$ùÇQ°ÀÓ·b Õ¬¬¼‘ÑéCŸ˜ÅŒI*oÿŠªº‰ûób‰Ê°B³QF¡ê#§঻¯J£#¯MÍ fÕêºf¤½ ¿‚ÙéÉÉf1ûê ÷O oñ›[¹DaÃŒ¯ÒèÍ9‘––Ci·DY)é9¾ýîvD4e£I©„º›„µáó ß±PÕÌìÒòʆ)æVɆ$RÃ$žË<*C­AEÆ™UjÉꆻOHD41Ë{ÇÆgîÆÝ»pùN‘[QU’Ð=ØšÖ¤衸ÄTdâÔÃ'°W;ˆW®s7 £Lï' úèHH!ÞYŠA³Ü°`(‘®ihúŒxŸñÞ=ߪwqù„*aW¡Ln^±A=kHWÇ@ Qƒœ%,>ù¢ó Øa$ä…O ñ™\{ìp t9KlGÇfró‹È ED´ó„VšûØøÄÜ¡ÐP3Ù4!€ny™Ä&¦Oe”}Vc‡>jŒÐéGMßXA¾Ü‰IÐŒ"+›QDÞáTÕ]¹vëÊõ[†«²s™–Œ¡„ü à^Jæøø¬At¤€²}µÚ{ñ“ytbf§xðÃ,­êQŸ:d2J‘ 5L®Xð²FVeÃ?¼"—³åÕõ½½0JåÄûŒÜbʵã‘òÿÿÿìùS[×Çß_ÐßûÏôhÚ:™¤ŒÛ&µ™IÆY<^(61‚Ø7 A@ì’XÄŽØA¬ZÄ"Ђ1%MÛ´v;v2mÓ¯$—jÐÓ“ôï==Íg˜Çå¾{¾çžstãÚòF‚[Ó;¡±éž±ðýðDèwzºz†B#Ú¾‘‘)Œ ŽNq,C¬NÐh4¯^½âh)¾}}tךúhP¼/7ÃçD6@_UðÛ??ý÷þÿW_ÿ럡÷”éüµ¬ Pèmð?›øÉ_ßü‰GGà·¿ï~™}ï+ÞÜ+,/®PÆœ–s_ñåÃ2î9P’©y……¥µþ÷^ÜÉW„>[ü©«Ü¥ùÅUp'1¥–WÖÚ6¶#ÙÜöx|ÏvÜ^‡sÇx/†ƒ—ûé³Ûn_èÚ·ÿ¯¨lv.ðièF÷Þ>æàv\ãF\o8ß~iÇíÈÙâðøBÜ»~L°;vX5„P”TDû«H°»·ïõ=éÀjÏzxîsmínn﹃?Ñç° "wvý<x‡Û÷¼OO­ UöMŸÿÀã}Ü¥À&`tbWýûÏ·‚îàvÌÜÝóc‡q½ëy {î?m,fÂYneî4’3rç”ùÜÙ…Wÿ^#sNÒ\ j¸©…Hí?=Ä8Q ¾àEø-üÊ!ZÊE«…ÀO]ÝÞU“IâÚÚ‹©5Ç8ðýÏñ·¥xÂÛdæ®îª +œÁ¨‘Ðú;Á킉'ÆÕþAƒÅ¨ý@à;¦ÚžÖAÜ…MÀVØ[ðO!ñQB•”$Q ¨~ ¨>5x· DQYÏqש³ƒG¥0vçn$ÕuMº¡hôLëúFO öô0>ÒÙ=Ü74Ù?<ű ± 8A¯×Çì-^þðÝÎßlYF?s²X8w¸ýýÕû™·r‹¤”ˆ"u1ø>ù»¥I”ZZV½nÝŒ†ض8&XíÛ€cë- Í/,*ãžSä)£EŠÊàl¸Ë’ˆÞ £«b—ͽE–è7FQæN!¦Ï˜ù e×YnI´¸SŽÕ4Fpf'¤GŽ%Ë,¯X3~w%ã·W>¿x;jæ‡Y‹Ë묃aÛ¾•hXÉYPÒ9­xW c±ïDRQÓØªˆÚmßXä¸V?Ö¦ Á§º~ÇR0Ä*à£qqyeEìÖ%98w¸ýýå{7î<”P"ŠTuGÏôœñö—EI”ª(­Z[wJ™‚‡Šä.¨{¤j^^۬¤ƒ(s§SÈ2Èü”N9!]0Yœ¦õNm_Ye]K‡Îbs™­.ÖÁdYŒYPÒ9­xW c¶nERVÝ îÔG£¥+ê—†Xœàpn麻Oý›ÒT|À8âpnsûûλ×sH(‘TEIÕªÉ!eò!Õ"ÊÜi $ÂT‡ 2?¥SNÞ.Ä,(é¼+…Y5»")­¨onëmnë;o`ˆUÀ ŽMÏøø„Íf»9ë. ãÎM·¿?¿pñ‹ìü/² Dç e#µ¨¸|iÕ.erï=]Cª+D”¹Ó@H„©d~J§œ¼]ˆYPÒ9xW ³´ºII…²¡EרÚ}®ÀDI¹’U@8ï~ggçÁÁØ= ÿÇÑÑQkkëžÇÓÙ ï_úôfÞç·óÅ~ñÞ%ÙH-xX2·`2.[%KNn¾èRZ!â‹(Ǭ/Á :ä‘ù©›ròv!ž‚’Èp–Jaæ­‘T×5Õ6t¨šuçJ]CGÍ£fVᬭ»Üî]µZ6BìN†Ï­Ä?~hZߌéì‡W>¹zíög·î‹K֧ٿϺ&©…E¥C£³s ë’%;çžèRZ!â‹(Ǭ/Á :ä‘ù©›ròv!ž‚’Èp–JaX6<.©T=jìR6iÎ ,£†¹x‚aw¸_¼ü_0«Í–B¿©ÜÞÞîñxÑýÄã©¶gè×™W?¹ž‹¦U,`t½Ã²‘:42U«lžœY|7¶sã•+ùøE>Ý_qªxq²Ÿ8‰wG_øÍb4ìwû¼nŸ÷4Ÿn6ÉRæø<›z½MÆFz3»ïþNYMòÏÁUu;ÔØ©ôVœ²È§Ì%í©¿3(9LË?–Ýæà3“ü`Â`0 7ó&HS2ਸ਼¥R'`¯kT…Dd79lÍZKã\R›Çá•®’§§úo|¼Ñ$m×½÷¯ ÀØ @o6  —»¸Ï±c2™-–?XéÜLã>—Óã ‰.içƒÉî‹&佤AîÈëôE/Ï‚VËä*³'ý5Ë—A.á·[”ãi¯ôX[œ@ ²ë°˜Mò%Ç/Ó÷ÇüR ´ßüaäñS*ì’çiuí¦ÏB>É©ÎgÁ¸·ˆú‰&g¯£6嘽9š&—ß>]²Åò¹¨š9=’ó +ÞÖ(}—&Eøì'èÍ4~<Öl¹[£û~-¤¼¶‰= µ!¬A¹Zzií“5’’åËgl¥çùÞ]M¿ÍGS~Ñ#2Í)u> ºù]Óª•›aïf8Ï?ša|™Üúj\øÍòKÇ~_ùÅ4Âù2èÍÔ-îMŽ[\¡îë}ÿv=ýÛÐbIÔ¿+K&ÖPa4ßIæíµšöšg-Ò>s+ģwÕác\ êß•Ps¨Ç‡qŸäø¥ Ÿ7ØÜ·3bÛù]õmT½ˆˆÅ!¹ùÖmÍ>ŠÉÇ2¾;T^;ÿüDü+ @o6Úk4ó‡a¯û›¼ f2iîúëÈv­D@%dž5ǵèéXD‹—äpÎùO_ƒÞº?ÈŒ“ež$ÝMvœäªæQ' @A5:R{ÛÊW& åÃg#šñ.@(›¿\˜rÕî} ;Å¢ñïp0 GºŸ(¼ OO¾Ü¸XÜÿH\ïv·‚Ý^”ºŸÖ]1Ó˜[å¦Qâ¢%Ø3NèÈÒ^F«g:• ‰œçƒû4Äx— ”Í‚ÂÇ¿ Y“}º0’«ï}~èû ífuAw4Þ%è#ec:µ,T÷ µQ›®éQ¾àüð(sfÎÊfïžcZÆ»}  ļ–»¯º£ËÎÿÒõß0Þ%è#ecü}ã]€>P6Æß÷È1Þ%è#ecü}ã]€>°X‡¬CÖ!뀀u@À: `°X‡¬CÖ!뀀u@À: `°ÎÿÿìùWY›ÇýËfÎü<ÓowÏ›EM:‰k\¢ÁFã.î+n "(®€à‚Ê"»+²¸ î5.Ù÷tzºóÎW™Ã鉤$Ž·Îçpn=uë>ßzî¥ê[˜ÓM @ „ 1@@ .Ä@¸pd’ld#ÙÈF6²]°-àå«·@ Š€W¯ß@ \(ˆ"pá ˆ@ Â…ƒü @ b€Á¿¹ìåíÜ/@ðÄ‚C p ¨ Ђ}I,îkåw45óηŸÈ Pâþ%£ìSköwTj-!10èÚýã—ÂO?ÿŠO ˆa1¸¯Íþ©'ú‡ê,kKðY6å_^Ø~”R©µwi÷®ýçOÿø ‹Kñ§Ÿ}û÷ÿˆŠŽöq.]º|îNTÎ]‰ƒÛQQñññ™Y:ý(Ų xñòK´ºQÜߤ2•Æ 3Lœ=úÑI|";4@ ô|KªïÈ>f§¶Žt=5=«¼ ͦB=‹ƒO ˆa18Æõ©Ù?ÝD{£PgV[‚/ãm䡼šº†+A¦—”W1꘵ÌFPÓÀòRÓ2Íë·°XgÎ mí¾ ’Z¡ufœeÅ(0™-:¾½£#%%•ÓÌûÖÊtm€l KBnÌhÂõج³öóÙ¡J::öÅeꯙÈþ.ÍþŽJ­ ‹¬®eu zÅ}ýRÅbX ~+4B£3øÚì×D{µPÞ®-ÁÇñe¤Rko†„U2êÚ;…"q¿¸oPÒ?ÐðJ+k>~üäãèô†s×p¢ÂOŸ~ç®ÄÉÛ·ïö÷¦¦Œùùù£c.gÀó¯#êéUªtÓ–9óŒÍ€…JÛ#éw©Ö7e»©Ùß¹KK,)gÄRq¿ÌK`ðâòê„{I¾9ûnNôÊ{µ%ø8Þ6@žh‹§%–Vt %BÉ€R\VýáÃGG£ÕŸ»?UøêÕkNO§¸\œÏž¿:Ž@(›0M›ç|‡±‰iPìR­ÏÊvG³¿—ÐÌïH¤^¥™ßs‡vƳ?:>ý'úl å¥Ú|o O´EÇÆs¸ü.¡Ä7¡W¼{÷ÞÇQŸ»ÿU¸µµ]YYårq<}y¡¨w|Ò¯‚HtƳ?>iRkÇ&¦,?d¢Ï¦P^ª-ÁÇñ¶òDÛø^[W[—È7É¡—¼~óÎÇ‘+”ç®Á>{þ²©‰ãrqì¼8ް§lÒ<6iñ%ÌPåR­Ë>Y³¿s÷ÞƒÖŽ~§Ø« ñì›,¶ £U©ÕM{>ÑgS(/Õ–àãxÛy¢-ŽvËï„òM2s ^½zãã ËÏ]ƒÿ*|ùòuK ßåâ ØÝ{vœna/nú¾T¹Të˲OÔìïÄÑ’¸|Á€Dg<ûS¦Y01eU¨ôjÝ„‡}f…òFm >Ž· 'ÚbãiM¼6ŸåaFÞóç/}œéйkðk…<^‹ËŰ³ûô8Ý=ä¯U.Õú²ì5û;±ñ÷ؼŽ3‰<Ÿý!åWÈF´Î£#šQìÉÕR™ L-ƦÌr•N>¢ód¢Ï¬PÞ¨-ÁÇñ¶òD[Tl<³‰ç³r¾|ù²´¼Âá¶–3X'ÖÖ ‡ËˆÄî÷ÿ®Ú^L††•¡¡aÎÿ½ heí1â³s‹ü¶NµÖ@qn· G Ÿ:uÿÀpLL¬Î0áfo OÊ]UË¢¦ŽÅùûúñâ%¯…ŸœúèÄ='>!eçɾû¬­?þùRƒ_¯ßOIïõ">6aD„ÕÄuy–V?öÏÀߺ„’ïÊ夳[HÝAÐÓ/~¹œôP¦P«g“ƒn&ˬû٥à Ü^©‚ÝÜf™EO¬•ÍÇ;r[Ú)’¨r©ÖMÙ}R%²Œ¨4é¹2óªõöÅ%èÄ¡.AœÐâò:7œM{§Á¡aÅÊêÚúæö:D.Ø¡AˆÄ ·ž@öúÆc³ÙÚÄ¥’}¢fçzHdayÙôòÍÇ[x³šé•,(«EK»Œ†fx 4eJêqÈ£Ù?B¡Î]ø`™RçžÈ \ëÉDS .EÀÒºoµ¸w» •ŽqôËÐþÁ³ £ùóçÏÛ;Oй­SptT;;oG£C J¤G/͸¯eÓ˶¶wþøãYÛâë7oþøãèÅ•Ööb™±_¿~Ïþø»´šÚ†©wlħÍóyùˆÓh ݱÉ2åʘ¡jF]\\<â’¾Av÷¶ë×\^ݺ?ùêÕ«¹¹ôÔ‡éè{„q**¹yô¯pf/))GO™\í¦Zo O*|#$¯¸‚š’ÊäÂóÂÁ㑊šµöðoå?}úýógFûÉîÞÇŸ&§Í»{{ˆ—VÖའ¸Šn‘ <Œr Ë666÷÷NÌ B#o¹}qì¤Ô ÇníÑ_”šyí:ÃL6Áô¬<´eçáÑÛ?¬ÒèÑ€™€«82LüÍm÷“r8-GMæÙÿ¾zýŸ¿¥¤góø]ëüΓýõmÃèÔ/—ƒÃ£âPœKA7ã’ѹþH0|¼Ë£QŽÆÄ'&¥>B#—^Ãqû íªæòÊÆé:0[æ0NyUí¥ 0ŽSF v«kYøT©õ£Ô!Ñy¥¸œàaó6Ø/áá/g¢^œN/*ûõÊ5]*§¦®žårq,­<>«©Uܯø’~…maQowFfçlSÓf4†å*‹2ÚŠÚ=½ÃýC ö¥þ!5‚x¹…EI¿LÜ;ˆ†J;†à L‹7WµFO‘@•KµnÊ÷Ë‘qq ~kÆ /Ç&“¥žÅíé“ýáõ:9%¯ÎhO¶vô˜-3SF³Cì‘Å:‹¶F«‡Tǵ@<‰<ÑìïßÏ+fP[XŽ»’~tœ–ôhoÿàý‡©tıT¯¬e×=ãñ5£‰<›ýCdJ=pîöôʃi핎H”ï †•ú#·äÑâ¤.TaYŠ×rðôÙ›·oÑþ믿êÙüzv+¾üwhI´Ä”§ÏžÃÍ ³uÖöåË¿AÜ>jY\ñÄYh0ê›ÐôI¯ßŠÌ/,=¬í ÌÃÚ^L†eªÄûIð7ÚÙ%B\®Ð`íñ s+¿S«›0Ñ Šod7#ŽÎaa‡UUkG|˜öÈl±™­¶ððˆÀÀ ™¹Å¨¨è«Ç¶ÅåMGêâ’2œ5$qSª· 'e ¼v3›^BMair§MÎnÈÿ:|Ab«4Z4àrè%•¹…e"I_.½0$,R¥>ü ¹‰ÛÚÑ-B£±‰«7Œîîí¿ÿ>éaÆŸþ‰{ΉyÁÐ(<×ÝǶ°„G2á¡·ï\»Ž6œÇÄ”ÉñG.f#×ñ˜OËÌÝÞÙ›_ÈÊ+ìô(G´‡¿¥eâßJ¼óWRf#‡âèÊêfŸtzÿžæ '¿ñòÊZìŽáJ+hÃ¥Õ5°ÑŸ4¹´¤‡P¾W²½Ëå[Û»çæazò Ëpú°¨i™¸X—Ê©S×Ö6¸\œÿ ÿÿìÙSY–Æõ'ÕË<ôKGLGtOO—«lì2ÆxÅ66ØÆl^0 v$6’;fÚ!±ˆMl´¡ ±™Å¸ªgºªjÚÝ].Ûó%9AÔ€HÉ–©à*~á8yîÍs>Ý{3ó¤”Â÷òËÃÔÔ½«õGÓ½gÙ‹R€ÞlïV£Z4[aãˆu¹= åï@ÁáQõêÍÛôŒ‰îÜÛ¯‡S©ÑŒ¢<òtJUpJZìŽn ITùT l¹Z‡Œ fëôœyÆdu¸¼Ø”+{ÑDFûLí¼zÝ;0‚VÜÌÑûNÏÌ¡‚2åQ’òC<ú L£9Üùöòœbô÷_“S8U­¬®Á®×Á¯2À.¯®«Ü»`÷ 1ÇA¢àfŸUØßT÷c³_7†"ø¨ÎZ=ZýFö;ÑÌUPJ=&õ÷¿¿ÙØÜ^]9•3§®Š}.NŽÓ½~‘¤Yª`Snš7?ËÌ+«”ääñœ.qÚ?ŽXØ= -ìÞþAØrÕÀü¢ ÅM!¯²RØ S¨÷œÚ±‰Y5µMâºÖ"~å’ùh¶3'…*Ÿj–­EÆñ‰)zSÝ7ŒÍÑq#l@“ÆéÆ–®–vYN>¿¢J‚+¢gyE©êƒf(Ç‘i¶Pò¬6‡Íî(ä Dµ/šZQMΣ9܉¼t-+¿ì(Ò3òw^í8¥N§3sKô#°K’ a TÆ q7û}º1°¿Ù«5¨ûF:k´†¥®[®õÙïD3Tn±àõ÷€ÃòúxläiV!ä/oß™”úìÞƒ:ôW`(Êᤠ ”'Üæ¶ª Ôê‹J«Ÿs‹î'¥gæò‚ÛSnOïÞ½'–Ôï{’“SéÚe@g€QV^ §¤¶vi™`ÑâÄ 6<ðÓ ºóóÌlÓ‚Ìšls&œBV¸9yii°Ÿ«˜W‚½úµCª uÌH^ˆŠyÆ-`&·¨¹fæL7î$\»“”šþ믿º<Ëhû@}´Y»¨”ª“NWAIEó‹6ص-ðo¼Üô,/ÿúî¿¢úo?ü`[ZÂîÜB¾ß¼Õ¿Ë³8¶%7®¸©OŸonïnní®­oãú ÿÈØ^TÛd[òœº\\"€sÁâhzÑ908ª£öz’ù$ƒ ÊJZ%”0´võ¨’ÒöŠ€ TBýº!ê+Q-4À0Œ­v nû…âz8Óó>[ŸfæFÇÞ¤ÃvËTí]rܽ(…4³& U D2EoTìõÄGi ÍmÍT„ñ¹û ù›o¯ØôìèVÀ‰VêÝI•ÔÇøU ><>•3§®¬û\œœ%çêaªkšºdý Xl®eïêØ¸Ç<*¡•Õõ©™EøûPU¸»e}°5}zØ2¥§ œ»¥2%‡Ãé³GÑkÏúÆÖ¤q¦¬B¨R÷!‚q/PåSmÀ²ûzl|j߃ºg|rª½[ƒ·¢šzˆ±Xí f;Z­v'l±¤A¥îÇ›E çÔì¢weM®Ô” „Æ©™õMuÿH0šÃo¢¯fä–ENu^sy¼•5M4?ÿü?oÞ¼I~ÂÕê†ÑÄ«—UQ¿¨ût q7ûXu`S¡dè¬ÐP­ÝšæV™ßÈ~'šy ² ©/ ÝïÿØä üOpËÃ+{ÿáÃÛ·oÓž8\˸9ææÝ”Ãæp¡ç‚ņž™Üüü’êþó_ßÿõ¿2²ò”ê¾7oþÑ)Ó9¶§ £éÒ¥KÑÑÑ\n^Ë‹”8QQQ·oß±-yéš&-ýÉàð„¸¦v¤§¾ø»÷`ãV»£üÁîrE/ £7nbßm]MÍípÞKHD””´¸¸[@aDg/*¦ ÜC¨6ÔP0#q1úqf3Ùù|äzõjW¦P釆üñ§÷ï?tHh¢Ì-*…]UCýV@©ÖÄÅ'lmoî×Á?8L}ŸþãO?ÁÆIûzWVý&¥Ù[üÞÀ1[Ô“¼Ÿðí}É%’4ÂNIϸtõf²7¿¸ N¥f``У½Kfœž;wñRbRšÝ±xÒrA5C«al 1¯ÄÅW‹P.ÜNxˆ\XÍæÅØä,NLÝòÞ}Ï¢uéõé´rt‚º´—UÕUŠ©?282É Q0³OC?¯³¿I/ZfšÚdôzr¢™*+Ÿ*€Ö_nð—W7üøÓÏhúï¿ý°¶Ný-%¾@"ªkÝyõú=õú°ûúûjI zvöhèž™ye-í2,fúf¶:2røAŽíéD®ì¿}'~ÿ{«‡ áŸ7»hÆóì ã*¶Sªp8W±×’cåñÞ³SÝ=*:ŽOåÌTT}.N΂Å}˜ŠªÚJ¿´K5rµ®µKHg©RÛÖ}°'öE\‡‰U>Õ~¬ì£ßŽZªÐÙ‡{vöôøÆýjw".ƤgHüìË5zðQ«È.~'ú“êqVaa©ð°?§H8³ Ê÷mìõÛÍ`ÆöÔbZtÆf4ÔßJ˜û­5ÐäôâÔ¬•ÞDa4·à8°ïÌœm¸°gpÄ8l˜ÂŽ¡Ðê(m_GD&?ÉúŒp KÒ2r>W4\D-6÷G±¹µ»º¾uÀiw,Ãï^^‡½ä\A‡Y“ÙåY]^y¹çñ¢Õå^ƒ;jØN÷jà‹yeÌ =Ëkö%ÏÚÆ¶Û³Fû=ËëØD³º¾Mgôxבݶ´ì³Õj÷¬­o[mN³ei}cwûtð—;ŒB:8R/{7`ol¾‚ Ra,9¼°WÖ6îŒÛÊÚKz¬hV×¶ŒØaåÌ”–Wù\œ™‡)HšÛlª|ªe³l¿šÃ³ßĤfHüìËT: ªm z—à'úØ*cK`9¡.€‚Ñv&âbRúsÖòUDä‚Ù ,V÷¢ÅõYBå”ÒmøÊh¶ºö:Üj¶º;™ßK€ ý¿‹ õJ€™ß×oá—|.NÎŒié0ürqC«Œm@•Oµl–íWs¸óõùèä§yÇ?ûÝ í§üDÛ@…bl ,'ÔP0Ú¾<{áAê3Öò—³‘s K,''¯øÄ5„µÂb~…ÏÅÉ1ÎXS\*ªk–² ¨ò©–ͲýjwÎDD'=É=(øÙï”õ}ÁOô± T(Æ–ÀrB]£í/_ŸOL~ÊZþ|æÂ¬ÉÎr²²óO\CX+,æUø\œœ‰)ËaŠøÕµ]µÝ¬ª|ªe³l¿šÃ/ÏE=Lç>LÏ 5gÎE±yöýNô± T(Æ–ÀrB]£í?ÎDÜ{ô˜µüéˈ©Y+ËÉÈÌ=q a­° ¨ÔçâäŒN,¦_%ªï7t²è)àUùTËZÙhwÎ}s)1%ëA7¤ ÅWç/±vö™èã¨-儺 FÛWßÜyz7)üñ?ÏMN›YΓ î‰k_…£¦œ<žÏÅÉ;L©@R!jÖ¶³¨¹¬²Ö§ZÖÊDs¸såF|\BÚýÔìr+1ýzÜ=ÖÎ~ }<¢±%°œP@Áh‹¹wõvbüÃ4vò‡?Ÿ=ñúÕ/éO2O\Cø*T÷äåó|.NŽ~dö0 ÍPa‰¨RÜZ%icP=JͰOµì” æp§­Sw7)#1%+D 8R´w©Ø9ûNô1 TèÆ–ÀrB]£­µC~>*6.!ù΃4ò‡?}e7±œ”ôŒ×¦ õÃÆ*QƒB¥ó¹89ýzãa†¦Z¤|QiUc¹°E ~qR ;4@ ô@•Oµl“ýQšÃAÃl¯ââå[q éñI )YŸDXG $bÛìÔD‡t B=¶–ê(mX]ùÅåQ±Wo'ÆÝ{tû~*«ø÷?žÑ̰œäÔg'®Á¯BL48q%ûh'ê¡jq“¤¾õ¨S§w`Â'ºái™R_^]_T"ÊçU?|!þEvh€è9J*{dšæpgdÜÔÞ¥J|ô8æZ|dLÜçá2õ/"l[— )X5ûŸ6Ñ!¨ã[›¹âWòöV¾â¨Ë×ÏG]¾ðm, ÿƒçß~÷{\#¤¦ù·?7ÿ/þÑ2.]¾ ÈT(’´€Ï.àÓ¨5–WÖ– ÄJžáÇQõEïÞeÈ0;<:wR ;}uaÐÉ6ÙŸ 9ÜÑêc“‹Ós¶Ùù¥Ï",‚³sö?a¢C4PÇ3¶Öê(x…ìYùáÈôœýÄ5„Â@Nq¹z„@ áTÁ‘*†@ Nœ.™ž@ áTÁiïÖ@ œ*8-½@ § ò @ „Sç‹P¾Î;ÒøIII!jý$>‰šã“ã—Ä'ñÃ7~¸¿x‘ˆéî ”Ä'ñÙŸ¿$>‰¾ñÃýøý‚@̯p_ $>‰Ïæøäø%ñIüðîÇï¤b~…û%ñI|6Ç'Ç/‰Oâ‡oüp?~¿ ó+Ü(‰Oâ³9>9~I|?|ã‡ûñ‹×ÿÿÿìØÁ @Á–쿺» |»0)`^ ˆ -õ‚òù—}ûåó»~}¿ã´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷çÿÿìØÑ BQ DAKJ)ö_VAÌÁÙ† oÂ{<Ëy€_?AD>ŒýŠtSßïø´çÛïçóÿÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷ûÎ ÿÿìØ± Ä ±ŒäѲõ™ÀµO ÀÊ@[êÊç_öõ—ÏïúõþŽОúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿_žWDDDäŸ2>@{ê Ï¿ìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýýòÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯï÷É ÿÿìØÁ @Á–쿺» |»0)`^ ˆ -õ‚òù—}ûåó»~}¿ã´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷çÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ @Á–쿺» |»0)`^ ˆ -õ‚òù—}ûåó»~}¿ã´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷çÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØ± Ä ±ŒäѲõ™ÀµO ÀÊ@[êÊç_öõ—ÏïúõþŽОúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿_žWDDDäŸ2>@{ê Ï¿ìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýýòÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ @Á–쿺» |»0)`^ ˆ -õ‚òù—}ûåó»~}¿ã´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷çÿÿìØÑ BQ DAKJ)ö_VAÌÁÙ† oÂ{<Ëy€_?AD>ŒýŠtSßïø´çÛïçóÿÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷; =õ‚òù—}ûåó»~}¿ãÚS/(ŸÙ·_>¿ë×÷ûÎ ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯï÷É ÿÿìØÁ @Á–쿺» |»0)`^ ˆ -õ‚òù—}ûåó»~}¿ã´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷çÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿìØ± Ä ±ŒäѲõ™ÀµO ÀÊ@[êÊç_öõ—ÏïúõþŽОúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿cí©(ŸÙ×_>¿ë×û;Оúòù—}ýåó»~½¿_žWDDDäŸ2>@{ê Ï¿ìë/ŸßõëýhOý@ùü˾þòù]¿Þß1€öԔϿìë/ŸßõëýýòÿÿìØÁ @Á–쿺» |»0)`^ ˆ -õ‚òù—}ûåó»~}¿ã´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷çÿÿìØÁ‰Q DÁ I¡lþÑx"ÐÁ`¬‡«(¦Äwm©”Ï¿ìÛ/Ÿßõëû/@{êåó/ûöËçwýú~Ÿüý—óü€o‚ˆ¼û馾ßñ´çÓßÏçÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯïw@{êåó/ûöËçwýú~Ç´§^P>ÿ²o¿|~ׯï÷É ÿÿì›ùS[W–Çù‹æ‡®êª®®ž©Lwº2=qœÎ8؉Ûí³ïc6³ $±6;ÚÅ"!öÄ*b“Ä.V;±Íjú+¿*Êc=„Ê&<9¾·>¥:ï¾ût¿>uôÕyOæ×m€È ƒ 2È ƒ 2\p¸E‘AdAd|bÃmkûg@ „O Ò@øä @ „OÒ@øäpÛÜzN ðIA @ Ÿ¤"ðÉá¨Ò6µ_¾òã…‹?g.þýÿðŠ­!2OáÁšÿêëo>®š7LŠÅ²â’Ò|Ñãs¦ °¯Ø ƒñTœŠ¦©ÃÃ?òÂwÞÿù¿·Î“ÿúò^±/v‡Æó@`-Îû·Íg´ð³r._¹z?"š0ÿœäŠðŠ­!2 à$ÂYÁlÍg >¢šoií@ÿ¡PÖk›Û[ۻϙ¶Ž¼bk€ ˆagd* ^±5@Æõ›wš[Û¯ÂoÆkžâ£¨yýødiYUskgßÀÈà~hÄÀØ £´¬Ò0ad<-´¨›:.þ+:„Ý_2—R¹’Z½~þ`_ì _]‹Ò¶t1ž#¸ˆÅ¹Tÿà¶¾±m@0‹Í«+ÅòzÆŒ670è­TáL 5ï<Õ5R¶µpT7¬gÈPk[j$rÆÓBËMßG>‰ê„§KÉëÌ > wüãÏ \Êâ\ÄKÝÖÖ·ìñò •”WJ”.‚¨¤ÌË'€V*p&šwžÊ*Ig÷@¿nÔEèì3žZ¾õH}gŒ+µºáy“ßÞe1ž#¸šÅ¹‚—º­Z7íñ ).«)­’¹I´R „3Ô¼óTUK»zt=}C.Ä@ãi¡å’—à¡h>ªxÅ€èa<'Fp5‹s/u[YݰÇ?(´¸´¦¤Lì"@ $ÑJ%ÎRóÎSU#ïìÑuö º :Hb<-´\òÉ /X -¹‹ÐÃxNŒàjç ^ê¶´¼foÀ½Â’J—’h¥g©y穨’¶uö»ÄxZhùÚ3/D¸è:@ã9!0‚ Zã^ê¶°dµÇÛ/(ïq©KI´R „3Ô¼ó”UÔ4·÷œ!šæŽ|Hb<-´\¸+ôÏž?oî”oÆ™•ô0ž#œ³Å EO2sDŒ»¨c/u›_\µç®w€ ¿Ä1ܬü[î^w<|y‚jÆ?(ÔÓ'ðÔ ßH¢•J œ §Ö|Vn þwO¿€ûéü¼“ÖGD'`Y:?÷·WóOË«µ­]Î –×=ˆŒäž´@¢¨y”—X«nvò=i$ÆÓBË·…ž\³~Œj»àUü½Á%Ÿ¼¯¼Ÿ\{Ôçxý=Œç„ÀŽ-Ž'ݺëý0=ÚÅ^~Á¾÷Nr96/'84ÂË7è~D4^Æ&þJ]Á‡{©›É²lښ̜BÇ䊞íîîÆÆ³¨“Ù²µ½}ê…ï$ÑJ%΄Sk>;¯èè­±³³c˜˜Œ‰K>i½¶¹ Ëò—þöj¾øIeƒ¶Ýê5-Ʀ– q]X\nlétò=i$ÆÓBËç7rn³M'q-a,Y¨™4m¼>:zýúh̸–*¿ÉšrpÉ=Œç„ÀŽ-.'¿äµÝÈÎ+¦]¼jµ...ärñIiƒCÃ{{û8µ±±)‘)bR¥Æà½ÔmμdÏ wo?Ï1ÇßM-m‰©<ÌÌ™Ìh€°3sï…GÝòð½ãé÷ÓƒÌDÄ$zøÆ%§#öòñ ø Á£d&£âRNÝ @­TáL8µæ¹ªÝj]kïêëèî7NÏâpn΄Sa¡’Yéوã'±ùš¦V,È)(Ádt|*nAnº{û…±2μ+×üã’ò:M‹3Ô6hÑ&Â%§rx™Ù¹Y‚˜¸D7K,¯—Š¥r,(¯¬‘©ÔÊúÆt^vdLÈÈ(ëµNî ‰ñ´ÐòÙµìk)³'áËDßc´<ãJV…*ëÎÞá«ÝƒÛ,N}Úô—[¢ÿþ—ð¼*¿¼šhüëâ¿ùÔP~é/ÃáÕ¤©âô_x–vM€Ã<ìu°ô0ž#8¶¸La¡ÍßÖÖ»zuÇà›n‰¯j~^bZ&b|•#^]µ.,.!xÛåŽ1™-{{{šæv©ªaqy ª$ êÔýÈ8w/r?ŠrB4ˆÑ'P]½UÚ·À7(48ô!æo{øúßObg¾Ÿ—ºÍÌ-Øsý–GjFŽc2slß/^¾DŸÏÂÌìœykkÁOá1R¹r}ccyeµ²ZŒC‰¼vjz&SŸÀâéõÝàpRŸ/ÈÇd•Xqê^’h¥g©5ÏÉÌCÁëÇ ‰©™ *ŽõìÙóýýœ’)êPÉü<ÄUb9bž @ÝØŒõÙ¹%¥§qxfó<Ö÷ö †„;Sð®\ó¢¢§Êú&§¨k4&›Z7¨µÕ5Òª)>þ emnA±ZÛ:4<н}:U};#K&WŒêîÑ$9»K}$1žZþôcÖ•„™“H)3ÛŠ¤´ã/wJ/5r*-ªÞmÿ,ó·QÃIÂÆiËæêÆKu§ñN”ô:kvlÚªl1|ÿhòrütEíð蔓ߕ·õÏn>Û™\ñ‹ãBÛèa<'Fplqܬ|”âÈèXhD,El[˜_ 7{ZVüâŠj)â4@ ‹Ž]îí·:88˜3™Ñš‡Ef Dƒ#RE=æD%?]\\rEmXD,&‡FF•ªúj± ŸzZ«´o'0Ù?0XßШPÖ­Z×:»zâ’ÒÞÏKݦfæí¹zÃ=‰å˜Œ7ùjëèÞØÜ‚šˆØäÙ9 œª‘ÈqjvÎb², («¬yR.F –*“Ù™Ôs£ø” ±Li{zVTvê^’h¥g©5OÕá6ÈÓ'0•Íšٲ€Sí=ˆÓ³ò«[ó…… š&<(‘•Ž›„ÍÍ­QýÄþþþôÌlt|ÚG]óy…OdªFg«Ôㆠäq¿nÙ³Ì/M͘&&0µÖŽ^ÝÐ ŽŒK•jUm=Ö8mšž1§fd Uµ´ÎÉ ‰ñ´Ðò‡+Y—b§O“k:8<Ú?xÝ>0›œ«ýÚ[ôÙJÛ<Ç`³ÐåYçÚ«ÝýË&‡§¶__zÐóuxÿ//÷›ï÷O›×wö›†žY·vw÷¯Ç´8Ø@ã9!0‚c‹cgæ¢äæDK(Ø\¨¸ “REÞüæSÛЈxeeu~aÁ±Ë½ýV ‹Ë˜´Xæq·›pÃÝ;6‘ƒùÜ‚"ê!“y~Ao¿“ÛÛÏ^¼|i{šnž§µJûvW­¯o Ízþó/óoöBö~^ê69e¶ç‡k·ãRxŽIã ±±¶¥½FV‡ 1…33;·¹µõ(™»±¹¹¼²òÏëî×nÞÅ?oaq)!•OgOß@N~ÑúÆæÎÎ?§-Þö³ç§nDI´R „3áÔšOJË:úÿãÙóçá‘ñ8…Û¦q…ˆ)GàfÔ5hm]?š sõº»æÍ ››óQ×<î Årµ3Hä úñ‰M3bÜ&Ž£YA¬îíÓ!Ðh[°ÁÓ ‚¾þAêÂ~Ýð˜~¼´BêäFÄxZhùýwü‹‘S`U,¯níSuøúHÑlø"¤Ç‹;Ç-¾àYøÏã%ëóݽ¬äK—°&”×íÃêB)YöãèÖôýñ2Ï;¶qtÜñvÐÃxNŒàØâXé‚wü­©µ3¯ð©íÉ…¬ ø9¶ßÈTuÄËh€æ»ÜÛoÅÏ-¢šj˜Ì–ÈGɘǭº–Ô ›OöëFtCcÐ!`²¼Z~lžo[eZ†À¾Àʵõ/^²2lFŠfhÕºö~^ê6>1gÏå«7c’ÒÃʰ嫱¹ 1:>ܺ[”Â}'øça͸aÒj]«–ÈqÏ75=[Q-Y[[ï:u# H¢•J œ §Ö||*ÅŒO~¦EÝÔ6g²à°FªÀ©ÖÛR2' 1î(G 6O88<úÎ'âi¥ä£®ùláã*I3ÔHkõã¸$â¾~]gw/5`@7„½ )Õ¤òZj\Yo;TªÜ’O -¿û–ÿ·Æ“øÌ§ù÷W þìßq7Ã$TYç­¯PIŸûÔIµúŸ_î½xµ¿»wˆÅ—fpøD9&¬<8xý}üt\‘ñÒÒè¶l ‡ñœÁ±Å%±ù¨ãÔŒ à E*W˜[hûS§j‰ÍåÒù¶GDŠZ5bØ e~áØîàrÇïó0.õŸ7=<ü9UR•qzîÍs# N¡SA@- ‹ D@õ4Ô¤½U–VIiÛ‰µõõ9“™ºÊl™ßÚÞ~?/uŸ±ç»®GÆ¥9&)Í–/¶±¨¸‚R¶¹¹…ׯ^Y,ó±‰iqÉ¿ Ð°ˆXL*j5Go~A@›Z:FÇô8DßwêFD+•@8N­ùؤô#Ûoäzêú/A£c㈛[;£Î=|ï56µ¼y”ƒ[%¸¯êêé·œÌÄT^HX¤PXlbúG]ó|¨¼Zå UbÕ˜ÞP[߈¸·O×ÞÑMÍw )ƒêÕMXPQ­’©´† £\QÇá 9\am½‡…ÆÉ ‰ñ´Ðòßð?5žD´hfĸâ«øÃ-ÕŸ<[RÔ(•ǵó9â ÙËÁ=ºñ%4@Ôú>ÃæäÜ:fzô8üIh²­—_‰ºÚø¥gÑÅÐ.Ûèa<'Fplqñ,Û ÞÐðèÛ“Â[TVQíx?1…ƒX®ªÇüòò  Ç.w|IbzfV"SÞòð¸÷ð®OЫW¯VV¬8¥7LþòË ˜¤_ȃT/· “è]¦¦g¨ki­’¶X[[Ÿ™£®²ýùùÖöûyé¿ÿÿìœýSSWÇï?Qu\[·°µJíÎÎì»3îtgw+µjÁ:¢£T×mqkÕ.¶XÐexL €$yUT0 Á" yÕ(ˆ(B°R@»VÝ}’;˰››jàšïw>“9÷äÏ7ÏÕÒÚ&þ€þûƒqêTñœÇ#柌…É”±–ï“öÝ»?í.“%I«8…is>ô¹ê0vMÎŒç#¢Uûâm=*Q%·yÂÊyeBÊñSgfˆÜ3¥ÄO]E–˜‡E’%k5¿ó?ׄ˜¦Îü~o‡wx§#k ¯°Îw÷9“ü0 ` —8º”‡DÆýÔUA¡Q åëyyœ&:>ÉîB‰Rù’í„­Z*\¾zÓï ¾û‚e\A–$­àóŽsX•|,«€+Èó°Hâ¶ZûÛ=~ ?Ìc˜Àa‰c^K…úË7¬ñZ¿ùË‘\A–$­àóŽŸ”~"+Èó°Hòú*íovøü0 `‡%Žy-jê›­Yûáæ½û#¸‚,IZÀ) ç':N›z,—+Èó°H²ØSûöN#?æ1Là°Ä1¯¥Bum“5kÖmò ÷<Èk×m’´ €S@Î;NTLbJ†.%#‡Èó°Hòª§ÆãSƒÇ§FNxÕSË<&€ –8æµT¨ªÖ[³nÖ=¡ÿø*œÈÌë·HZÀ) çG“ MËNJ?Å dF¦H`I~µ:ñÍOÚ—î0ñ9q/‘yLx+q<ÔR¡¼ªÑšmïôÛýÕçûÂ8aÇžÀ¿ùí’´ €S@Î;Nœ*Y©=¦IÉâ•öØau ó°HòޝÊmëÕ7ü:yÀ}ëµ?mS3 `o%އZ*”U6XsòTÁF_¿ÏöSëIJAf²t…’Vp ÈyÇ)(*—ÇjÕI'’O2‡l™3EÌÃ"Iêɲ׼ ܶ·»ÒÅòðšw~Zöyæ1LàªÄqRK…’²kÎ_h)”>íðÛ¸soðî€P&ÐÖd€l²$i§€œwœsåu陹²m\BF¼&S•tœ ´5 d†,1‹­¼ åü«藾ͯoïpû¸sö¡}iwòð¥LÇmR™†“ÇU-ŠÏUKRùíejšö|ä»}'5P³Ì¦­;è‘¶&'u…dÆ–OœÛœßø‘ßÊùo*êòΔÅ'¦EÅj)gYŒ†ik2@6È ó€ØÏ«´ìŠ5»N,õÉ[èU4«x—Ðã›>y«wHͪà<©ÀLøÄñ×?…g/Ú¢´¬æâ¥«u×®Ü`mMȆ“8ä¼ã[Ú ò UL ­ÅÖ‡y(8Ï«9”T`¦a^â¸J{!ÿëJ—BÈ-(p)]^€K!d唸Bfv1€K;@p9‚ ‚ —Ó_ ‚ ‚\L¯!‚ ‚\LÂÛd[Ë—/_±b…§§çûÿÕªŸ‹èEÑK£È:ÆA Ë!ȶ¨E`ݨ̬Ä‚ r5 oAm­\¹ò½Ÿµè²Ž1Ä‹<<<–-[¶Ô¢eÑ kSs[SC:Uˆ-ăÐAöĺ?™ ±Ž1Ä…èz¼dÉ’E‹ÍŸ?Þ¼y .\¼x1Íà:ýb¢¸Q£ãææF!]°`Á+SD‡4éîîN' ¼Cýÿÿì[LÙÇÝ—¼%¡6ææ× wL ¶„\6MH°bB.‰€´ÙnÕ$ É*+m–í®¶R»R¥Jmµ«l›îJ»Ò>ì¦Òn«VJ›ªêC Q ÉkÿÌ#ãa 8S¾ŸFGg>Ÿ™ùæÏgŸÿŒaPå„<û·¼5&b‚œœ‡Ã188xçι¹¹±±±ÖÖVx ÌÓìv±A מ={ÒÒÒ`%«««{zz&''!é»+`A»ÝŽpHâ !‚ˆ2d€ˆPÔÕÕñö'Ê‚ä­ñ«Âæ› hF —Ëuûöíw˜5›Í™™™¤çaÕ¨×뫪ª&&&Þ‘pïÞ=Ö °Ùlƒ*–à‚Júí,AˆÔÖÖÖý_ƒä­ñ«’••¥Õj5`AÞym ˜_WNçÌÌÌݦ§§s…oÇ8&¹U€’(˜•ãããÕjõ­[·fffn –›°)Ÿ`:Æ´´4æ _<¥ÝnŸ˜˜ÅD>‰k¦[è%}>ߌ€´&âKAcM&“øS ˆ( Ê"y˜Q쿪ªÊét~ò¿úòé/¿X^~ÿè"ˆ+}t–oÃ'==}Z`jjеb'tÓ9ïÜcxõêÕË—/ x v‡ Á¤¤$¿ß¨‚¼“u ‘Ãá˜^A,¹ÁÁA¼µZ-œ7t†Âeee½½½ÒZµZ­T™D4QÉÝ''À\ˆr0÷ƒÄßüýÅûZøùƒ…÷,üúoÏ=Ò ðÖ8|0gߘœœd­Ø OÀŒÅ¾Ú¶ˆ anNMMEîÇív)â+E ôzýøøøÍ˜tÝÝÝx Îæ§LI;::}}}F£q›×$MT!ÒÄåráªÑf³}ô×ço:÷þü[÷çñ—%DÇ«Š½Z0@¼5LØ7VÀÌ¡Ñh¾¿0ó=ï“à N_ðâÅ‹:N«Õž={öÆjÆÆÆ¶¹Pë}ð†½!¡°°Ž¯BC¬ŽŽŽ¢hÙ&ÙÙÙˆLLL'©‰¨¡J#y*++]J‚ý————””|øÝÒß-½ÿíòòÞ·Kˆ ®ôÑY¼5“ÉtM``` 99ùÚæÁxŸOpúׯ_‡¬…Œ^¯WªÒ©S§¶¹Pë}ÚÛÛE%EaÍõz}SSSPÉ!.•ÃHj"j¨R B§ÓY©$Ø?3@{„¿"A‹>"eee¸¦t®F‰xk>˜B~"ÐÜÜ\QQñ¦VY+vÞ”{à}<Á\ëóùäWKKKá/·¹V¡8ÃÃÃR%>¼{÷î„„ö*`2¢…7’d?éLD •‘ ä‘ZÈ‚ýÃY­V³ÙœŸŸŸ——‡} ;g¿Yœ}¸xûáâÔ׋˜à•Hûä­qøàÂú 8¹'N¼±y°Þ'ÁÛèèhh•0‰Yr Þ)Ç"b)†Æãñ@@ †˜555T“_T‚‡ÙåÀþa€ìv;.²÷îÝ[\\ŒÖb±`¾¹ùÍâùþÓ|÷ßu“ÿjþÝ1##žvÈ[ãðÑétããã~¿ÓIggçxH®\¹ÂZ±ƒ ±Þ'ÁŸêêê‘‘‘ÐêT F£bÌ@±®Bhˆ÷urr²Z­v¹\kÖ$ZªI"j¨ô!óŠ‚C”••av± X­Vf†Z>YȾú(ëGöüøÑë¿ÇG§è"{tÞ‡OJJÊØØXCCt[‹ÑÑQÖŠÀøñãÇÙtNdgg766 0}zzz8€’T c0yc 'Ý‚@)Õ˜”––­V‹YÇãñÈÕ$ZìŠ÷ÙÛU AÈÏQ¦0öÕ`.ÇÄSTTôúÇ 9?{œsíqîµÇ?øxÁl6ÃE<ì·Æá“””422‚S8räÈÈf¸téZœ>ï3ˆuœNgtÍÍÍ ‰‰‰°A¼³‹!PЬ¨X»&999¸¼Ë Q“h±+ÞgClTÉ!O Ô‘0tüþÓ¶|º¼ ÂnEüp¼5L¸˜Öh4çÎZaxx˜µbgh-°!6ç}±$ª¯¯RÒëõÆ €"¢««kÍJ¥‹‹‹»páBˆš>ŸT%¢†*‘ äÁ›-¢X׃}ÿÅþ(,===55-ú………‹E‰|xk> ‡*..þáæ9xð »“A„*;v,H½žžT¦Z­& kª®7Ö-KÔ3IJD UAÈ;²®eÙØaIIIÃgϰœøìYãçË œÍÉÏŸ±¥IXòóó›Vúl‚1R"Þ‡V«…ûÙ¿ÿ…ÍÍy§¿eÐétn·;HÀ®®®¼¼¼¸¸¸øøxü xçȼ=!KÕ(‚KÞçAl#TZ‚f¥4r`o˜w1g7}±´÷Ý',sOš¿\*((@[2÷„-èçææE0Ÿ°‘͇¥Ä[ãðÁÔ _ØÚÚÚ×××ÛÛÛ'À:½ñ@ÚÚÚØ´Ml””¿ß/UÒf³íÚµK£ÑžPÀëõ®Y{è˜Íf @+W“¶´´ŒD4QD233#øŸç2…ÿ”ššÚòÕóÒç­Ârê«çz½­5 ‚kî ˆÉdbÿE(‚ù°”xküJTVVvwwwuu±Vìt ÈűïÄ·˜›}>_’ ¶¶–wj±Þ¡rµ'Ž‘«I€w=Çä ‚ Vq„HX™Ö¯_Ø?zÊô“““×Z““'OúýþÎÎNÖ†@–ÿ ±y²³³E%­V+Œ{QQV+**x§+ÔÔÔ° ªIH§ZpÍš,--å;ADJ £ÑØöç—KRRÒºlEHŠOBGGkÅŽt ﬷0‹…iø½Ðw»Ý¼óŠ!\.×fk›ðΚ b5 ÝÒét‰‰‰ì×ÐØ_½¢1-(‚‘Ow€ˆ¡²²ÒãñÄÇÇÃýìܹÓ#À;©Ø†šx½^ϰÛí¼ó%‚ Ðï„gç³GQ±‡êŠ«Ò{4>¶Â¶d€îìØ±ãèÑ£§OŸ®¯¯GÛÞÞîp8x'sÆÆÆÆö`®sxgJ±J öt“É„H“[ aO"DÄð@uuummmgΜA«¼3ŠQpéR^^ÞÐÐp&¬"¸ü‚ ˆ˜E Ñ!¾Ø&O&‹ AAR”0@¯Bd“É"D±]ùÿÿìkHÓkǽì8'fs33ËÀ.¦›³LZ5¤b´„4ºßoP”]@mQ¡ÍfIš³ò²Ñ‚‚ÈR¯£¨ˆ|Ñ›®Dù.°·eœó9{pìL‹cšsg¿!Ïÿñù»çÿõ¿ý>Ïÿ?›ü~ÆïpŽ1… ‚ Áˆ ‚ ‚qˆ ‚ ‚qˆ ‚ ‚q S€òòòJû1›Í#e-#Hø PJJJaaaAAÁøñãC=—°!---???>>~H»ÈgTýG´Zmff&_ÕfFF†^¯8Ìh4þóAÜ‚ c™a ÐÊ•+ÿꧯ¯ïòåËÇØl¶®®.‡ÃA»££Ãår ç‡J˜ ÕjmooÿÓGKK ¢ê…N§“¸.^¼ØÖÖV\\}Jÿû÷ïñ¤¾¾¾ÞÞÞƒ._¾¼³³“öÇm6[NN.]ºÔÝÝŸŸÿîÝ»›7oÒóüùó 6Dš‘e¦¨¨Hm:6§L™²eË–]»vUTTTWW«gHOOß¹sgccã¡C‡ =.—kÓ¦MµµµÇŽ Çcÿe,‹×ë1cFtt4NC>(cP>•••$I8%%%­­­ôÏ™3gíÚµê³Ni¨«A§NZ¶l=©©©œÕ ëÖ­c/½^?uêTJûÙ³gù·&•ååå%øPWZZНŸ8qÂl6Gõ V«%4ž¿|-//çõôAºsçµçÕ«WH¨­­ ×Ak>~üxíÚ5^"CåfuŽÙܸqcöìÙ÷îÝc¯%K–<{öìÁƒô0ûaí>sæLÚ=*++{ñâ##M€ìv;e&11QmªksçÎ¥Š755Q³W­ZÕÞÞ>nܸýû÷ì„ œNçÌHj»$ß éqŒ*x pR•i¨›†Aùdee‘'5Sܸq£F£ñßÛ³gñrú/z¤ÓéøEž½{÷²£ÑhÄÝ>Œ­X±O õA6J€áÙ=þü3gΤ¥¥‘ ¹qÞ*Šg@UU’¿\al1"tÿþ}´†uBC'…Â]z{{;;;ÞËÉÉùöíÛ‡ØDz^¾|©¨ººZýXÚG¥qûöm¾iTTTDå`òA›%™Ô‡žÂÂB4¨¾¾¾¦¦æäÉ“O”O€,X@cëÖ­ª'BÀiP’)((À{ZZZ’““ƒòôX ‘0 ÎF†¡MøÃáˆê¿&‡Y,·ÛM›s•ºÒ#J€fÍšõ‡uˆÜÎ;GžÈâéÓ§‰7P€ðuv,..æwê#Aègoùéééinn6™LŸ>}ò «ílŸ]¿~ÆãÇ;::0¡#GŽP~”±¶V?6ýÙ‘*@TqJ/Kg&OD”–ºº: <åÙãñèõúÅ‹{½^†Qf¶oßN]a>oÞ¼(ŸY­Ö¨È ¥K—RbÍf3„µ´¶¶TP>J€²}fIªëׯú·©«h~¢‡aÓ§O§¡ˆïLMMu:Ê–"ŠìÁÞ´hÑ¢††bŸ6mÉ#FD¼III+ï4alÁkÖpôbPºuëÖçÏŸ»»»_¿~ÝÕÕ•››ûöíÛïß¿S®^½úõëWVÏø2D'Xˆÿ>âCñ¯ÀÌëëëÕ]†ÚÚÚŒŒ :©¸,²q Ü%%%jª¬¬TG±¤Ñh6oÞÜØØHn·[ý…WP>Ôfd311‘³I²Ùl? ôôô}ûö!£åååô †… òäÏo'ÿ4/{0ÒjµäC˜d‚šGõ¿H OdÄÔårEà3AÆ4)))ÃÑ‹ë°nì1™Lª‘ãÃ?ìwþôb}üäGåûàQVV†ôÐøÑC þ|J€,Ëþ[&A„ÑE¼4Ìs;pPák?ƒ¢(Ô³ˆ °Çsá¯×k·ÛC=0Ã/@¡žˆ ‚æ°ÈÖét¡žEÄa45M¨g–$%%It‚ ‚ ‚0zü ÿÿä\×â¤G‹AIEND®B`‚golly-2.7-src/gui-ios/Golly/PatternView.h0000644000175000017500000000222312536111364015302 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ // This is the view used to display a pattern (within the Pattern tab). @interface PatternView : UIView - (void)doPasteAction; - (void)doSelectionAction; - (void)refreshPattern; @end golly-2.7-src/gui-ios/Golly/help.png0000644000175000017500000000102412536111364014315 00000000000000‰PNG  IHDR;0®¢ÛIDATH‰å—ÑMÃ0†ÿ«úÐ @ê“­<„ (P&€ Èt2BÙ HÉå©RÙ L@yìC{<àVk»ŠÄIQ¤øþûî|'Ë!Á!¬sê!ÁG±ŽÌ| ` г–g "Ê•RÏ1ñh_ pä€ùlFDÃ} ·š™Œ[@ '"EUU!'oÅ:ltY®µ¾q-8+þ&( ™ùÞµ°S±ééØéLTÈìþ•eyÖét2|ŸK—ÚWÅ#Oöc¥ÔÅr¹œ3ó›y. I’­õ€Ü£Íì ° ÔóˆïÖs'v’Ýn÷Î%‘´,Ë3/ž­­õëV u+IöûýwŸžˆ†!pꮇd2™‘7Á¸Û÷ÚŒ™e±XÌ·üCX×õm@·2"Úô¸®ë[ñ æŽEŸÕË•RÏÌ|JD¹ˆ¤mÄ_®xµZªªº0m ug±Â$I^ÌVŸDJ¦!p 6ƒ …ˆ4bÛ`çQé =HÆ?÷‚µÖOˆÛîÖš8p¶ˆ sâ¹ÁƜǞ#ÁÍ;Â2ûÃØËCQÌ4oÞû ®ÛÈߺ€ä_%ŠÈÈxÙÛ ¶ø½ëíOÙÿû…ùïÞÖaæÿ6IEND®B`‚golly-2.7-src/gui-ios/Golly/OpenViewController.m0000644000175000017500000004447312536111364016654 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include // for std::string #include // for std::list #include // for std::set #include // for std::count #include "prefs.h" // for userdir, recentpatterns, SavePrefs, etc #include "utils.h" // for Warning, RemoveFile, FixURLPath, MoveFile, etc #include "file.h" // for OpenFile #import "InfoViewController.h" // for ShowTextFile #import "OpenViewController.h" @implementation OpenViewController // ----------------------------------------------------------------------------- static NSString *options[] = // data for optionTable { @"Supplied", @"Recent", @"Saved", @"Downloaded" }; const int NUM_OPTIONS = sizeof(options) / sizeof(options[0]); static int curroption; // current index in optionTable static CGPoint curroffset[NUM_OPTIONS]; // current offset in scroll view for each option const char* HTML_HEADER = ""; const char* HTML_FOOTER = ""; const char* HTML_INDENT = "      "; static std::set opendirs; // set of open directories in Supplied patterns // ----------------------------------------------------------------------------- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"Open"; self.tabBarItem.image = [UIImage imageNamed:@"open.png"]; } return self; } // ----------------------------------------------------------------------------- - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } // ----------------------------------------------------------------------------- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // return YES for supported orientations return YES; } // ----------------------------------------------------------------------------- static void AppendHtmlData(std::string& htmldata, const std::string& dir, const std::string& prefix, const std::string& title, bool candelete) { NSFileManager *fm = [NSFileManager defaultManager]; NSString *pattdir = [NSString stringWithCString:dir.c_str() encoding:NSUTF8StringEncoding]; NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath:pattdir]; NSString *path; int closedlevel = 0; htmldata = HTML_HEADER; htmldata += title; htmldata += "

"; while (path = [dirEnum nextObject]) { // path is relative to given dir (eg. "Life/Bounded-Grids/agar-p3.rle" if patternsdir) std::string pstr = [path cStringUsingEncoding:NSUTF8StringEncoding]; // indent level is number of separators in path int indents = std::count(pstr.begin(), pstr.end(), '/'); if (indents <= closedlevel) { NSString *fullpath = [pattdir stringByAppendingPathComponent:path]; BOOL isDir; if ([fm fileExistsAtPath:fullpath isDirectory:&isDir] && isDir) { // path is to a directory std::string imgname; if (opendirs.find(pstr) == opendirs.end()) { closedlevel = indents; imgname = "triangle-right.png"; } else { closedlevel = indents+1; imgname = "triangle-down.png"; } for (int i = 0; i < indents; i++) htmldata += HTML_INDENT; htmldata += ""; size_t lastsep = pstr.rfind('/'); if (lastsep == std::string::npos) { htmldata += pstr; } else { htmldata += pstr.substr(lastsep+1); } htmldata += "
"; } else { // path is to a file for (int i = 0; i < indents; i++) htmldata += HTML_INDENT; if (candelete) { // allow user to delete file htmldata += "DELETE   "; // allow user to edit file htmldata += "EDIT   "; } else { // allow user to read file (a supplied pattern) htmldata += "READ   "; } htmldata += ""; size_t lastsep = pstr.rfind('/'); if (lastsep == std::string::npos) { htmldata += pstr; } else { htmldata += pstr.substr(lastsep+1); } htmldata += "
"; } } } htmldata += HTML_FOOTER; } // ----------------------------------------------------------------------------- - (void)showSuppliedPatterns { std::string htmldata; AppendHtmlData(htmldata, patternsdir, "Patterns/", "Supplied patterns:", false); [htmlView loadHTMLString:[NSString stringWithCString:htmldata.c_str() encoding:NSUTF8StringEncoding] // the following base URL is needed for img links to work baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]]; } // ----------------------------------------------------------------------------- - (void)showSavedPatterns { std::string htmldata; AppendHtmlData(htmldata, savedir, "Documents/Saved/", "Saved patterns:", true); [htmlView loadHTMLString:[NSString stringWithCString:htmldata.c_str() encoding:NSUTF8StringEncoding] baseURL:nil]; } // ----------------------------------------------------------------------------- - (void)showDownloadedPatterns { std::string htmldata; AppendHtmlData(htmldata, downloaddir, "Documents/Downloads/", "Downloaded patterns:", true); [htmlView loadHTMLString:[NSString stringWithCString:htmldata.c_str() encoding:NSUTF8StringEncoding] baseURL:nil]; } // ----------------------------------------------------------------------------- - (void)showRecentPatterns { std::string htmldata = HTML_HEADER; if (recentpatterns.empty()) { htmldata += "There are no recent patterns."; } else { htmldata += "Recently opened patterns:

"; std::list::iterator next = recentpatterns.begin(); while (next != recentpatterns.end()) { std::string path = *next; if (path.find("Patterns/") == 0 || FileExists(userdir + path)) { htmldata += ""; // nicer not to show Patterns/ or Documents/ size_t firstsep = path.find('/'); if (firstsep != std::string::npos) { path.erase(0, firstsep+1); } htmldata += path; htmldata += "
"; } next++; } } htmldata += HTML_FOOTER; [htmlView loadHTMLString:[NSString stringWithCString:htmldata.c_str() encoding:NSUTF8StringEncoding] baseURL:nil]; } // ----------------------------------------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; htmlView.delegate = self; // init all offsets to top left for (int i=0; i 0) { // recent/saved/downloaded patterns might have changed switch (curroption) { case 1: [self showRecentPatterns]; break; case 2: [self showSavedPatterns]; break; case 3: [self showDownloadedPatterns]; break; default: Warning("Bug detected in viewWillAppear!"); } } } // ----------------------------------------------------------------------------- - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; // no need for this as we're only displaying html data in strings // [htmlView stopLoading]; if (curroption > 0) { // save current location of recent/saved/downloaded view curroffset[curroption] = htmlView.scrollView.contentOffset; } } // ----------------------------------------------------------------------------- // UITableViewDelegate and UITableViewDataSource methods: - (NSInteger)numberOfSectionsInTableView:(UITableView *)TableView { return 1; } // ----------------------------------------------------------------------------- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)component { return NUM_OPTIONS; } // ----------------------------------------------------------------------------- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // check for a reusable cell first and use that if it exists UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"]; // if there is no reusable cell of this type, create a new one if (!cell) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"]; [[cell textLabel] setText:options[[indexPath row]]]; return cell; } // ----------------------------------------------------------------------------- - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // save current location curroffset[curroption] = htmlView.scrollView.contentOffset; // display selected set of files curroption = [indexPath row]; switch (curroption) { case 0: [self showSuppliedPatterns]; break; case 1: [self showRecentPatterns]; break; case 2: [self showSavedPatterns]; break; case 3: [self showDownloadedPatterns]; break; default: Warning("Bug: unexpected row!"); } } // ----------------------------------------------------------------------------- // UIWebViewDelegate methods: - (void)webViewDidStartLoad:(UIWebView *)webView { // show the activity indicator in the status bar [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; } // ----------------------------------------------------------------------------- - (void)webViewDidFinishLoad:(UIWebView *)webView { // hide the activity indicator in the status bar [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // restore old offset here htmlView.scrollView.contentOffset = curroffset[curroption]; } // ----------------------------------------------------------------------------- - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { // hide the activity indicator in the status bar and display error message [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // we can safely ignore -999 errors if (error.code == NSURLErrorCancelled) return; Warning([error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding]); } // ----------------------------------------------------------------------------- - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if (navigationType == UIWebViewNavigationTypeLinkClicked) { NSURL *url = [request URL]; NSString *link = [url absoluteString]; // link should have special prefix if ([link hasPrefix:@"open:"]) { // open specified file std::string path = [[link substringFromIndex:5] cStringUsingEncoding:NSUTF8StringEncoding]; FixURLPath(path); OpenFile(path.c_str()); SavePrefs(); return NO; } if ([link hasPrefix:@"toggledir:"]) { // open/close directory std::string path = [[link substringFromIndex:10] cStringUsingEncoding:NSUTF8StringEncoding]; FixURLPath(path); if (opendirs.find(path) == opendirs.end()) { // add directory path to opendirs opendirs.insert(path); } else { // remove directory path from opendirs opendirs.erase(path); } if (curroption == 0) { // save current location and update supplied patterns curroffset[0] = htmlView.scrollView.contentOffset; [self showSuppliedPatterns]; } else { Warning("Bug: expected supplied patterns!"); } return NO; } if ([link hasPrefix:@"delete:"]) { std::string path = [[link substringFromIndex:7] cStringUsingEncoding:NSUTF8StringEncoding]; FixURLPath(path); std::string question = "Do you really want to delete " + path + "?"; if (YesNo(question.c_str())) { // delete specified file path = userdir + path; RemoveFile(path); // save current location curroffset[curroption] = htmlView.scrollView.contentOffset; switch (curroption) { // can't delete supplied or recent patterns case 2: [self showSavedPatterns]; break; case 3: [self showDownloadedPatterns]; break; default: Warning("Bug: can't delete these files!"); } } return NO; } if ([link hasPrefix:@"edit:"]) { std::string path = [[link substringFromIndex:5] cStringUsingEncoding:NSUTF8StringEncoding]; FixURLPath(path); // convert path to a full path if necessary std::string fullpath = path; if (path[0] != '/') { if (fullpath.find("Patterns/") == 0 || fullpath.find("Rules/") == 0) { // Patterns and Rules directories are inside supplieddir fullpath = supplieddir + fullpath; } else { fullpath = userdir + fullpath; } } ShowTextFile(fullpath.c_str()); return NO; } } return YES; } @end // ============================================================================= void MoveSharedFiles() { // check for files in the Documents folder (created by iTunes file sharing) // and move any .rule/tree/table files into Documents/Rules/, // otherwise assume they are pattern files and move them into Documents/Saved/ std::string docdir = userdir + "Documents/"; NSFileManager *fm = [NSFileManager defaultManager]; NSString *dirpath = [NSString stringWithCString:docdir.c_str() encoding:NSUTF8StringEncoding]; NSArray* contents = [fm contentsOfDirectoryAtPath:dirpath error:nil]; for (NSString* item in contents) { NSString *fullpath = [dirpath stringByAppendingPathComponent:item]; BOOL isDir; if ([fm fileExistsAtPath:fullpath isDirectory:&isDir] && isDir) { // ignore path to subdirectory } else { // path is to a file std::string filename = [item cStringUsingEncoding:NSUTF8StringEncoding]; if (filename[0] == '.' || EndsWith(filename,".colors") || EndsWith(filename,".icons")) { // ignore hidden file or .colors/icons file } else if (IsRuleFile(filename)) { // move .rule/tree/table file into Documents/Rules/ std::string oldpath = docdir + filename; std::string newpath = userrules + filename; MoveFile(oldpath, newpath); } else { // assume this is a pattern file amd move it into Documents/Saved/ std::string oldpath = docdir + filename; std::string newpath = savedir + filename; MoveFile(oldpath, newpath); } } } } golly-2.7-src/gui-ios/Golly/StateView.m0000644000175000017500000002172012536111364014755 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "prefs.h" // for showicons #include "layer.h" // for currlayer #include "algos.h" // for gBitmapPtr #include "status.h" // for ClearMessage #import "PatternViewController.h" // for UpdateEditBar #import "StatePickerController.h" #import "StateView.h" @implementation StateView // ----------------------------------------------------------------------------- - (id)initWithCoder:(NSCoder *)c { self = [super initWithCoder:c]; if (self) { [self setMultipleTouchEnabled:YES]; // add gesture recognizer to this view UITapGestureRecognizer *tap1Gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)]; tap1Gesture.numberOfTapsRequired = 1; tap1Gesture.numberOfTouchesRequired = 1; tap1Gesture.delegate = self; [self addGestureRecognizer:tap1Gesture]; } return self; } // ----------------------------------------------------------------------------- void DrawOneIcon(CGContextRef context, int x, int y, gBitmapPtr icon, unsigned char deadr, unsigned char deadg, unsigned char deadb, unsigned char liver, unsigned char liveg, unsigned char liveb) { // allocate memory to copy icon's RGBA data int wd = icon->wd; int ht = icon->ht; int iconbytes = wd * ht * 4; unsigned char* pxldata = (unsigned char*) malloc(iconbytes); if (pxldata == NULL) return; memcpy(pxldata, icon->pxldata, iconbytes); bool multicolor = currlayer->multicoloricons; // pxldata now contains the icon bitmap in RGBA pixel format, // so convert black pixels to given dead cell color and non-black pixels // to given live cell color (but not if icon is multi-colored) int byte = 0; for (int i = 0; i < wd*ht; i++) { unsigned char r = pxldata[byte]; unsigned char g = pxldata[byte+1]; unsigned char b = pxldata[byte+2]; if (r || g || b) { // non-black pixel if (multicolor) { // use non-black pixel in multi-colored icon if (swapcolors) { pxldata[byte] = 255 - r; pxldata[byte+1] = 255 - g; pxldata[byte+2] = 255 - b; } } else { // grayscale icon if (r == 255) { // replace white pixel with live cell color pxldata[byte] = liver; pxldata[byte+1] = liveg; pxldata[byte+2] = liveb; } else { // replace gray pixel with appropriate shade between // live and dead cell colors float frac = (float)r / 255.0; pxldata[byte] = (int)(deadr + frac * (liver - deadr) + 0.5); pxldata[byte+1] = (int)(deadg + frac * (liveg - deadg) + 0.5); pxldata[byte+2] = (int)(deadb + frac * (liveb - deadb) + 0.5); } } } else { // replace black pixel with dead cell color pxldata[byte] = deadr; pxldata[byte+1] = deadg; pxldata[byte+2] = deadb; } pxldata[byte+3] = 255; // ensure alpha channel is opaque byte += 4; } // create new icon image using modified pixel data and display it upside down CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGContextSaveGState(context); CGContextTranslateCTM(context, x, y); CGContextScaleCTM(context, 1, -1); CGContextRef ctx = CGBitmapContextCreate(pxldata, wd, ht, 8, wd * 4, colorspace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGImageRef newicon = CGBitmapContextCreateImage(ctx); CGContextRelease(ctx); CGColorSpaceRelease(colorspace); // draw the image (use 0,0 and -ve height because of above translation and scale by 1,-1) CGContextDrawImage(context, CGRectMake(0,0,wd,-ht), newicon); // clean up free(pxldata); CGImageRelease(newicon); CGContextRestoreGState(context); } // ----------------------------------------------------------------------------- - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); int state = currlayer->drawingstate; gBitmapPtr* iconmaps = currlayer->icons31x31; // leave a 1 pixel border (color is set in xib) CGRect box = CGRectMake(1, 1, self.bounds.size.width-2, self.bounds.size.height-2); if (showicons && iconmaps && iconmaps[state]) { // fill box with background color then draw icon CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGFloat components[4]; components[0] = currlayer->cellr[0] / 255.0; components[1] = currlayer->cellg[0] / 255.0; components[2] = currlayer->cellb[0] / 255.0; components[3] = 1.0; // alpha CGColorRef colorref = CGColorCreate(colorspace, components); CGColorSpaceRelease(colorspace); CGContextSetFillColorWithColor(context, colorref); CGContextFillRect(context, box); CGColorRelease(colorref); DrawOneIcon(context, 1, 1, iconmaps[state], currlayer->cellr[0], currlayer->cellg[0], currlayer->cellb[0], currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state]); } else { // fill box with color of current drawing state CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGFloat components[4]; components[0] = currlayer->cellr[state] / 255.0; components[1] = currlayer->cellg[state] / 255.0; components[2] = currlayer->cellb[state] / 255.0; components[3] = 1.0; // alpha CGColorRef colorref = CGColorCreate(colorspace, components); CGColorSpaceRelease(colorspace); CGContextSetFillColorWithColor(context, colorref); CGContextFillRect(context, box); CGColorRelease(colorref); } } // ----------------------------------------------------------------------------- - (void)singleTap:(UITapGestureRecognizer *)gestureRecognizer { if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) { ClearMessage(); int numstates = currlayer->algo->NumCellStates(); if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { // create a popover controller for picking the new drawing state StatePickerController *statePicker = [[StatePickerController alloc] initWithNibName:nil bundle:nil]; statePopover = [[UIPopoverController alloc] initWithContentViewController:statePicker]; statePopover.delegate = self; // set popover size depending on number of states int wd = numstates <= 16 ? numstates * 32 : 16 * 32; int ht = (numstates + 15) / 16 * 32; // add border of 10 pixels (must match border in xib), // and add 1 extra pixel because we draw boxes around each cell wd += 21; ht += 21; // allow for switch button and label if (wd < 196) wd = 196; ht += 40; statePopover.popoverContentSize = CGSizeMake(wd, ht); [statePopover presentPopoverFromRect:self.bounds inView:self permittedArrowDirections:UIPopoverArrowDirectionUp animated:NO]; statePicker = nil; } } } // ----------------------------------------------------------------------------- - (void)dismissStatePopover { [statePopover dismissPopoverAnimated:NO]; statePopover = nil; } // ----------------------------------------------------------------------------- - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController { statePopover = nil; } // ----------------------------------------------------------------------------- @end golly-2.7-src/gui-ios/Golly/InfoViewController.xib0000644000175000017500000003222012536111364017157 00000000000000 1280 10K549 1938 1038.36 461.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 933 IBUIBarButtonItem IBUIToolbar IBUITextView IBUIView IBProxyObject com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 292 274 {768, 960} 1 MSAxIDEAA YES YES IBIPadFramework NO 4 blah blah 2 IBCocoaTouchFramework 1 14 Helvetica 14 16 266 {{0, 960}, {768, 44}} NO NO IBIPadFramework IBIPadFramework 5 Cancel IBIPadFramework 1 IBIPadFramework 5 Save IBIPadFramework 1 1 MC4xODI0NzczNzYyIDAuNDc4NzY5MDk4NCAxAA {{0, 20}, {768, 1004}} 3 MQA 2 NO 2 IBIPadFramework view 3 fileView 9 saveButton 14 doCancel: 6 delegate 8 doSave: 13 0 -1 File's Owner -2 2 4 5 7 10 11 12 InfoViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 15 InfoViewController UIViewController id id doCancel: id doSave: id UITextView UIBarButtonItem fileView UITextView saveButton UIBarButtonItem IBProjectSource ./Classes/InfoViewController.h 0 IBIPadFramework YES 3 933 golly-2.7-src/gui-ios/Golly/Golly-Info.plist0000644000175000017500000000305212536111364015716 00000000000000 CFBundleDevelopmentRegion en CFBundleDisplayName ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFiles Icon.png CFBundleIcons CFBundlePrimaryIcon CFBundleIconFiles Icon.png UIPrerenderedIcon CFBundleIdentifier com.trevorrow.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 1.2 CFBundleSignature ???? CFBundleVersion 1.2 LSRequiresIPhoneOS UIFileSharingEnabled UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight golly-2.7-src/gui-ios/Golly/SaveViewController.xib0000644000175000017500000004763612536111364017203 00000000000000 1280 10K549 1938 1038.36 461.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 933 IBProxyObject IBUIBarButtonItem IBUILabel IBUIToolbar IBUITextField IBUITableView IBUIView com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 292 292 292 {{179, 83}, {183, 21}} NO YES 7 NO IBIPadFramework Save current pattern as: 1 MCAwIDAAA 1 10 1 1 17 Helvetica 17 16 292 {{40, 112}, {460, 31}} NO YES IBIPadFramework 0 3 Enter a file name 3 MAA 2 1 YES 17 9 IBCocoaTouchFramework 1 2 18 Helvetica-Bold 18 16 292 {{106, 175}, {328, 21}} NO YES 7 NO IBIPadFramework File type: 1 10 1 292 {{106, 204}, {328, 160}} 3 MQA YES IBIPadFramework YES NO 1 0 YES 40 22 22 266 {540, 44} NO NO IBIPadFramework IBIPadFramework 1 1 IBIPadFramework 5 IBIPadFramework 1 3 {540, 556} 3 MC42NjY2NjY2NjY3AA IBIPadFramework {{0, 20}, {768, 1004}} NO 2 IBIPadFramework view 3 nameText 15 typeTable 16 topLabel 20 botLabel 21 doCancel: 13 doSave: 14 delegate 19 dataSource 17 delegate 18 0 -1 File's Owner -2 2 4 9 10 11 12 5 8 7 6 SaveViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 21 SaveViewController UIViewController id id doCancel: id doSave: id UILabel UITextField UILabel UITableView botLabel UILabel nameText UITextField topLabel UILabel typeTable UITableView IBProjectSource ./Classes/SaveViewController.h 0 IBIPadFramework YES 3 933 golly-2.7-src/gui-ios/Golly/Default-Landscape~ipad.png0000644000175000017500000012274412536111364017712 00000000000000‰PNG  IHDRìò)R!tEXtSoftwareGraphicConverter (Intel)w‡ú¥~IDATxœìùS[×ÇÕö§þý©Óßš_;¤igú[;$vbgâŽí$Mbj³Û`ÇÄ@‚ñ³¯’ˆ}Ç VKBB`ÈŒ͎ˆÝ~‰¦‚¤'¡íIʹóùé¼÷îýžwï;ç\/˜Ãù±=z´³³Ó`0ü—5jÔ¨Q£F5j~ÔPä£Ô?räÇÔ“66_AAáÇ|ž°Wý¿õÖÛ¬K!‚ ‚ ÂÝ6¶Þ|ó-΃-¬K!‚ ‚  øçÌ?[`]AAAÅ?ǰ±EAAÄÏÚAAÄϦ ÀèØD}CS±¸¬PPäB>Ñ!ºEçŽ)žžÑ÷¨Ôµµubq©@ à{Yƒ$ƒ<ˆ„TÇ|”É‘Ñ1'O}päcžáè»Çñ‰1.F÷K©J¥êZbbXXX`PPðùó (8ØKxÿý¬k°©ÐÛæ³‰9Å̲I ‚8€k³Ã;ÇÞsUä÷ª8ÆrY×༠>ôÀK(ž/\ø¦XÝ(•êqYsK›T®Tôh\‚R¥Å':D·èC*šÌÎÍKZ[+**”JåÔÔÔìììâââ‚—5H‚0ȃHH…`È>”›¹¹ù'O}xùj½Ô̬\®gÈÎãá#b\Œ ~&U(,Š‹»\"ËdòÞ¾þGƒ¿x Å%bˆ²†Çd0h€Bo{h˜GÌ&æ3‹ùuSC„¸<;ääó]ù½*ŽYƒ9)x85XĦ`”+µ0ÊšýF|í0»r?È¢ÕÕÕz½ÞžòzcwýÅ^ýO„áHUU³¿!aQ±7%.‘š/Èá±+•Ï<{¾èÍÔÔ5°®Á×b–™—Aàù²c‰,—'Êãÿ¬"¿O‡\ÿv9¡8¼È`cµ³^Îqà†9e•5R…Ú*]¿\©ÙoyØ­’tHe?½¬S¦ÄVAÞ£eè Y`¢¤¤dmm¡ªFÑŸ=ÿwÉo^oà¼Þð‹ã¯ÕNs§¾8û¡ì sþ-ÿóþBTÿ„ñ|Ï?^½zµßþYßûïúDþ—ø¾ºžÖâÔêö’ÅžAÆÐkR×××᳿!9\‘5Ò²¸çΟ ºžÃ3Z£bƒC#n1çÚ7Sî¤Ù¼ Jœ‘ ¾¼q/,*6úÒ•ˆèØð踛wÓ%À~lJåñøOçŸ[chdltl‚áPU]Ë|ë"m*dÌ2ó2 Â<{¾ÄœÒsø!¸›–ƒ2%éúm\€4áîÈï=ÑõP!×;ÕÊû™ÑÏM=ÖÏÎÍ{^ßt¼ó5XŽuþ~÷åÎÿ»’¿Ýö;ï~iü:ef w˜ýýô\ÈW™ÖÈ.ûé’ÊSî¤Ã2õxÜËÈ¿xåZ@Ð…³Áa—>K„寽Œà Qá1—qŸtÇñI7"b®`¢Õõ]¼’À0€g¤¦çp1#ú's Íí’éÎÎîööÎýÌ‚’ï`ozæ6Ãq·Ss`‰‹ÿ"(4òÚ—·C#q*1å.³N{¤æåÌèg€˜‚0+iï¬kl>qú“§?Skö6È@æ·¸â’r‹vk"qêø¿>HL¾éüÐè­PX¯3sò«ÐÈwÃ#¸=0$œ[Xdâñ´ÞN ÍÜ^ߨìŒ#˜eæe@„˜{Μ2ò ‘Åž/,öhúLdäòkêóxEWSÔZÒGHÄÅ»éy ýœq(òÛ]àÜùðЈäæó'#óë¼Z“Bû©ªm¸~ë.rM@P¨ùY›¹ƒ9k˜Gçâ"qaQÉçIÉøúUZNɺ•E%¥Ã£ãN>L`N(6¹±ZÛÙÙ™{:'m¯¶é4hüYö…¢²|¾«=5› ;Š”:¨ÜRn§â¬¢Gã­ûÙ¡‘—C£cã'&§ 0¶wíý&u.Od±vràMùÿÿì]iLëzFU[Umu+µU«öOU©RoÕJýsÕªºÕ­zÛ«[éÞÛsîIr’œ@N $ÂûÀ€16‹Ù÷}ÇÛ`c³Ù°ÙÙ!ÉɾŸì}f&õua<&†¡c=Bï¼ó}ßû|3ß¼ËÌØ¸­m|·Õõ #¨µCÝ*dùY·ºCÒ¤ W;´«·CÚ­ìí§”=}ƒ CÁ-˜ dÛH¾ÿYü»^Þ¥4+O-QFÀþûHâÑìœî'›º#ÿiçŸ`Wâ¸þþ{çC³©hY*°iZ— )sö/ }¥ú[(ë <í æùž9{!=+ßà"1ȳçÏA >) âg…<„p-<®]$¹{…éíÆæVl•ÕbÝôé"b“ó‹Jç,V©\¥Å=Röô1Àd'T›Z%0TßÐì{9(42¾µC‡XXZcO !…—‘)X^^}ôèñ°~äjp8:vˆ;-óVANþÒòÊââ'w#M°CªÂ‚ÂÅåµMIˆ¤³¬²veíæêúM‰¬KW 7šú‡ Ä€ÒJ´™žOLI?åéíáy>™“93g›ð Í/*ÃÞüârÈÚaÈAa‘.ŸVÖåw%í£ão˜§f¡))¯F3±¬ûR@ˆÁhÚÊ(¯¨¡Õ;" V§½Îçä—Ð-,­„Ñ6‘ôòÕk°+“+hÇ £¦+Áa¾W‚a([X䨙#†ÌS3è›´¾qÛèkê›/úžñöMJÕè©Æ`ûíÙ 78Ã#cƒúQ0DwÄûNEź„9zúøzû^’Ǹ—•#Ì-( NpÄg™y°`Áb°º~›9:ðs‰×tMæ „ ñ7¸¹ùeðü Íím"ÙÇÄ{¿Ó3s\A!Ã8ž.y~§ÞµO7|½¢º!<*ÞÇ/ ¾©­©UtáÒÕË×tƒz2.X“Ó2‘ÿÁ¹qù9ˆ P"½††WPBÞ´w9к\Gl±K­ „›MHIïQëœ2¤õ±´ˆ¿ÁA~J™¨MÙ*’æ‹'§gÆæ¨a Œp#mmãÖÚÆmËÂJލødi  5C–tvûúyù\jÉp Ë«ê)Ñ><&çQÞÝ»ý ²ý€ât‘SÙÚÂâþ&§ñ“8|¤=H؈<°¢+ŠÈs„%œÌyòJ$ÖhWXN›;¹p¥¸­¬ÝÞŠÒÊ:‰¼×TêÁÎn¸³§¥CŽt›ÿ‹‘TÙÒÑÙ¥ÒÚ”¨†‚!Z60È×,ù}äßGT?ÎÄîöÒ~ØQ ¹%‚5À“W~,ýÈê[ ê h¼´?¶äc æùº{ú¤ps!‹ô›}ºÁ{÷FF#ãS±¼P`WK›ˆ\m+K+kê[ 4MNCæçïßG«‡ünšÛßÝ‘võ0Àd'TóŠ«Þ¾}ûæÍãèxIY¥à5_ÿèí $§ñPÉ€›yræõë×óօؤ ¬~4@½‹ü=Q@¿NLáîjn^uaeFŒ¦¯Ž»9áW^U?:6A>Í\ÕõëጠK*Ñ&2ޏr=*ðZ8„¸$xxù\¾‚½ÔêÚ¦ÁáQù…eZÝ0òòs.Ãù=ù-’o4Ëäçbïq¯ãîž0º• PRRA«wD²¨¤†¼}ýœh§À¨»—OpX„£'OëGLhœœf¼‚RŒvóæw(ÏÐLWHKƒ!…qó4º_¸ÿKqh€|™êR@0V ªDP´ŸÄtP*䕟ððŠOJ…éÈØD´ŒŒIÔhsÉg¾ðÑ×®G“•Xzᘟ<í…ÍЈGp–™— ,öË«·˜£7»¾}um­´¼Š—/WB)ëR6µInßþ2rhOÈ0އKžß©wU¨Ôp5GNœ†ç‡k…Ou5„A¡‘è(, îñ'&§Ç&$C€…ÒÇ×é5„<ò !ý¨Ëá€Öå:bk2Ï`(¤èqI©°rÒãìôÌ<3í>¾zShÌÓë·7n~× ÛÆâװaŒŠDZƒ9jØ095‡PŸd „<~^@Èubiv¡®À®þAÃÔ´'3 Ž?zÒʬl!­Ò2¿„²EK J o?è1»ùí‘í§‹Ü–­½~ýFXTžÊÍÆ¦º¯ K«»•j9e±‰i/_¾B"„Ìí%ù|]Ð}pØ@dJwîRÅ0 (»=ÂRÚÜÉ…+Åmqyc+ŠËª;¤JGèîÑIå½Èþ%=•Ù¿¬[m¯ìRj†‚!Z60ø(6šþUú‡¶×xþEò{HÓgŽÙ·qT„ŽCŸ0vr¨ákÈÐØöRÀÊÿì åßÿ&û#l~Ýû+O-;)˜çûÍés‰#dˆjD¥Öâ8CHædZ‘Û'¤òQ)Þ¼uËãŒÏi¯óX1këhÏÍ.zþüõ?Ôêš:¨A—Œc V(€ÉN¨ I­Ý÷ä×Ô}ºë1Éö¨Õç~ÆGA–¶\~>V?„ÊÚ4+ˆ‹¤±¥c‡Tsr„s–ÅM€›ètz¿D½wOdzä Ø,(.Gø!³ÿhê@ÿ P´›LLI‡ž˜œƒ‹¹x905#«±E„–=½Z./‡ðVz¸ôLdŒ–‘•C9¦¥¥5ÝÊÈ/,¡Õ;"¹´¼ŸÄY\Z¥5šJ æ¥ÕKËkÒyÙö¯ZÁa”!Ä*lòs hi00¤€h´idÄmÿpum#¢ˆÞ0†øO–-í¢”JL7íÀ°L®ÄŲ.ê yëò·g/ PY–¸­ó~èß}ä„{WwÏÚÚMGp–™— ,ö KëÌÑ!'Ü{4ý9ä{AÒN Œ©S.y~§ÞU®è%“æb8OÊ{+TšÕõ[Þ/Ã;¡H"oln‡ƒê ïÊ#"@éíëï{%B.™³"ét9к\Gl+ªê°ÙÜ*Z]»Ù.’Å&¤èôÌ m>þ–ò±]ä”72}ž,lLz5º¶éäÔ¬ÓØÁ5l0‘÷ìñõ©3R¹»¹…ØÔ wˆd`Ólli'a>­’š Î;ò âõ¤üâÙí‘í§‹Ü–­!Zwˆ;KÊk™¶çc æùžp÷ŠKá9BZá7•½}×ÖoZæ­Qpø› ½yómbnp›Z‰gh•D B¼‚?2Ê`…˜ì„êÕ°¯ Áñ¹Er¥úÎÝ{ ‘ž•kO`tܼ‰vMcV?„ÈðrˆK¨[¥Þ!UAvîô¬u+àþàâ ÆñÊšz8Gx Y—ª·o€¸_T&ëê!}GÕ˜›EܹéViê›Ú Ô4´  («ª»ÂËÎ;îî93»›´É‘µvH©´{hØHËBn^¡£]´$¡G_Öhj:Âäôô¨uyÙùÖÅ••Õ {,­¬SVÔdÙ“•“ïC€º 1¤7R7O™'g“ÓOxxêñSgŽž<–SÓÿÀPŠç·g/Ö5¶B Âd £Ë—ÇþÏ\pѾÛ×?Ðb]bà€³Ì¼ X°`±˜_XeŽ)Ü8ö9‹UXRM!_ ±^,ëFƒ!ýÈ»÷ï©“®z~fï*ëVwL*jÐþ²v@®ÞÝÓ›ð¨šþÀkpkpnÄ»+ÉéPz_ô÷õ‚÷¡‹ËáÀ‘Ë¥e‹”—¸×£Ñ –—WÖg- M3›|ìÑ“sóK›B03·@Ù=‰x×ÜFcn~†l› ±ƒ9jØ0:>‰PϬ߼ |ÀíŸ9ç‹]¨+°«¯(S ¤@I=[æ „´Ê2@Û#!9m›AdûÅé"·ekÝ É<)W¨ÆL-R"#-,ïì&RùÌœB¤78¼\²KÞ{ò)õýv±ŒjeuíÉ“'d]J蹂ÚÜÉ…+ÅÍb]ÝŠü¢Šæv¹#ȺÔíân"™ ²=ZE]âÎ{TÞË0 Ѱ¹¸ûý­¡; óýA›fîÑøOd?Øôêm Z)·ý(Ð?‰©Mñê‡/Únzèñ«T‘1qÕ~œ-˜çûõ7g¢3!%ƒð› •rieÃ{2Ñ¿ÿ6Ÿ¿xä.>9#15 VXd<”~¡Ô³T‹ÑñÉQ éP"ÿ6„EÝ`0€ÉN¨VÕ6£ê¸‘ʽèr%$*ƒG<ÿêRªí ¹Ò2³“ÓÁaÑWÃâ“yÔ3²Ä” ÿàˆì¼B2$(vH5K;9=¿ µ m~!ðÈÓ³ p¬ÔMhx±u?aa™†¼±“Bµ‹Œ¥îëè Ä“«×"üƒB•½º¯Nx„\ŠMB›”4"íVöôÁ£Q@F›žIxüÁáÑ­làg iõŽHbœ;ÅÖh YH:•hP×Ð ¹¸´ª´².,2μG¦W3@ ËÂ0ù´$<&<)LÍ|„¥•µˆˆFGNžFË‘Qó˜y e/[øÍés¨ Ɖæv¢hj¡J©‹—¯Úæ2:>%|w@ðuÎ2ó2`Á‚Å`n~…9:$¥árlÜl¯äå·BEÒ.ÈDðî]PX,³ç?î’çwê]¥r¢(.¯F›lò4r\È~ÁpD÷ðÔhÇMST~ %•^Ûºôé†]´.×ÛÚ†bi7ÚÈê’òšAýà :ÛÓ«Û½ÁD™ö! G<bsÔ°Á86ijÍSsž>¨L³Y9Ôñ¯#ÓúvQ'PÜ3y´J,!‚ÜBÛq¶D¶Pœ.r[¶VרþìÙóyë‚D¦hnC™-,¥Rù ~~»¤ â5Ôi{5:Nf `eúÒÕëÞ¾>|üä Æ”v*ˆ”‰'¤Í\¸RÜfæ–¶"· ¬¡EêÔÛÿ”Ü&îÆæÈTÐ4¶HÛ% ›R$U2 C´l`.L÷ÈoåþÎÚ³JóæÝ›#ª’¿ TÃ\øü ÊŸwýå õ?Rø™üÏ¡ñü9m€Oªù4—ÿk'ó|žü6">Ín¤VP2R›3sóØ|ðà!äÉé9Ȃ܂”´Ì‡ÇÌaqíb¢Üìîé{ýæÍòÊêÅ+¡h‰šaÎ2|=†Á&;¡š]P~÷ÞýªšzNFÖêñByM³=ò‹ÂmDt¼yb ´ãS³°ú¡DÒÇÍÊY[߀œSX±Cª™¼l¸’MPöh‰ïÑž» È-ª­oññ»B¾…"WôhÉç¿¥æÉ¹ó~WŽŸ:ƒ2›HUý®C À“¢MW0fžùê¸;äòªzŒI=ˆML˺¯†„ŸöòјЌxˆ9hØÊÁ.O@«wD»àQé©Ô:Z£Éi™P‡EUÖ4ž#ÙªÈ7”0 {…F~0Ô«#½§ðcR ¿q=*Þ^IÝžéRô¶ù=åÐQÏgóKQ”žðð2ÍMmbêæ ”Ô÷p<šÚOñމOF/w/Ÿ+Aa s¼læeÀ‚‹=Àôì"stHH%~ídtÜl¯äf¡¶C"‡¬7޽{÷>*61<ŽÃ0Î1—<¿Sï*–) •U¡ ŸL@{4ýáÿሠxúø¡ñ ~”ÃåA~{Jï‹—/úÚºôö ºh]®#¶zdM­â󗮞ôð5M33Üêc¥ÊM¡Ð | éã€CŒŸ{Ñ?¨O§w;˜£† z#ñQÕ‡›ñù¦>vñ><ßè7MÄ¿„’d  Z%*¯ó~¨ÒyÙ'Ü=k[·D¶Pœ.r[¶–!(¤Ò¿Â2⻿øyÅR9•ÊçqÈ×á,óV$<ÖâÃ=j-º/.¯>}úLXX"WÏ P@)‘¯«¤fæÒæN.\)nS3‹[‘WZ×$q‘TÕÔÖiÛlíè†èªjÅÐÔ7K[E”í%ÃP0DKÀ†ÒÒR†|úõÛWîš!ÿþ‘è·Î÷ÿ4aìܱž¿§~ôáË{ À7©[þú;=6¥j£…z pïûÛ´@ÞLÔÖB⣠L‡y¾_}íq=&ÕR2ˆÿo ÐS›Y¹%ð’?¡v›§^½"^÷¿uûNzVAv~ùÛ·ïVÖ6°·¯_½\¡¬õêÕôì<ƒ!LvB¨o-,®PÿÆamý¦X¦¤ôö”½Ú‡¿'ÿ¹A]S4XýØ4MLS?—ÙÊv¨fff›f7abÒIeð—B*ªê&§¬ ¥–ÌPKÑF£¢Ü pî‚¿¶_Oõåd^µº®²ùð†§§„¥§Ï^ø‚|‹±¹UD4&=¾¶ß°•ƒ iiY´zG$±+5=ëØ7ß^ ¡5šÌ! €è¸dĆ_û&/¿CÍY––W6ìa]X¥ )U¤ç ?–!…þA²ˆŒ·WjuzŠÕÙ —CÂc?®0OÌEÇß8vê 6±·¢ª-‘÷ûú‘1©õ@|;±yñràÀ  Ü= ßÍ@ÀYf^,X°ØLN/0G‡ÄTâÕM1H ,#¦>È5 í?y÷þ}TBÃ8G\òüN½«HJ…¥UhÃÏ. ïžôS®Ž¼Ö‘ÄWN£RNxœ…J"½¾hëÒ£t9к\GlMæ9~N>¤ÚÅNnõ±“ó›B€‘)ÓDàígc—Ä!îÊ÷ 9ÌQýÁdÿÆÒ÷ˆØDÈ »x‚|êøƒLyUûowOï òË<¾Ð‘RÖ©¤~¢¸‘ʘ°l3ˆl? 8]ä¿ÉÖbSŸ=ñöÝ»˜$®¤“¸ñ/,ªêí#^uæ ŠÐÕ •"5Â_”mP–T6|ÿýK*[^]öì9”*5ñ~D¿€6wráJq3OÎoJÌê†vGhwÕ·ˆí5Mí2êþªú6JSÓØÑÒ!‡¦U$g †h ØP]]ýäɆ”ú΋ð‘“Ô ú Ï?ž°o³µ¨¶f’·ÿÿâí»ßü—±ožQ¿)T»À§-¨Ÿý‰ì÷¿ÿÎ…Át˜çûëc§®EÝpQ‰éÉ9N›…ŤD&¤1·“]¡˜‘Èá3¾"øzl µ©Rÿê""ž›œ‰élÇ„Sªé\¾qlj+&¦,ëòôÌü¸iz~aeŠx95nžYZ^Ÿš±R²uqU?b2Žš!`“ê83·ˆ6è!™>ìšž±B3l·XW¨3³ h0:>MËBJj†£]´$Ù¹Åyë2¢­Qx=ø>óäìÄÔÜ ùF#ƒuüArzvÁ†f‡îsóK›Æ«Ñ± ëŠe~™òwBÃã8»H•“ÆÓL8‚0N24Ðvù¨ö‰IiÌ œ’Üd4)…K>h6¢—ác˜¸ÌÐ1+zÚ̇Èร#à,3/,XìŒã3{Èvèù?Ê»î¤Ëdžf—Kkä¬Åл[Spºþ‘“ßž=yú¬ ñs|§Îx÷éô´J»Ã>ù±§ÕÌeÏù'½RÜ £Ó[‘‘•_ZÝâHëkÅ[õ5MⲚV{ 6k›% CÁ-4š>]ÿ~§î»óÁD0æùþ÷W'¯'€É¾P-®¨ïRiB"“v‘j 'sPo:ȈKHÙÝ›ZÅÙyEºÁ±Ëp׳̼ X°`±Ð§ö&ÏÿY»Ü½œÂÁ4¤«¬iLã J*j Fóðˆ™V¹[™Êž-òOz¥¸ LnEOX\Ùä%Uw},`ˆ–€ ã¦ÉÚº:ûÿ¼û™~0LdÜ4Å<ß_þúd@XüA˜ª)©™CãÑ1‰ûÎásgˆ³Ì¼ X°`±Ú«èp<ÿgír÷˜Êž-òOz¥¸ ›·‚“‘[TÖPTÖø©C´lŸ°H¥2£Ñ¸ß üN?˜‚D"5MX˜çû‹/_¹{åZܾã—_?4T“’Óµ£QñûÎásgˆ³Ì¼ X°`±7Ø›èp<ÿgír÷œ”ƒ“¹|¥¸iƶ"5#GXR›_Z÷I©é9´ìa™_¬¬¬\YYÙïÞõÏÆÆFiiéœeÁéd¿<úÍ¥ hÿØý8üê«o Õ¸„T•zH£9°‹ˆÝwŸ5Cœ_œe§× ,ö{‡çÿ|]îážÂvÊIvr¥¸õölOPÈVäÕ~R„YÙE´ì1¨7ÏÌÌ#ÞïLÞ•J_]]ÒO8왳Ïù…\ŽÙ_x_ºæåíwh¨&&qÚD •Z`q-,jß9|Ö q~q–^_,X°ØìAt8žÿóu¹‡{ Û ($ÚÉ•âF;ùv‰2•›—_•SXý‰€ÁaB$QmçdŒŽÏ¬¯o”””ŒŸÑ÷@„ËËË-–ydÿÛ™iM}Û×§Î] ˆ@Ѷ_€up¨mh?4TÛ:äüœ¢Îî>eïÐÁDеˆ}çðù2Ä™ÅùÅYÞ÷°Á‚ Õ§‡Æó¦.÷pOa›å ¤@;¼RܺTƒ[¡è.«jJÉÈËÌ)ÍÊ«äWî"0 †Åà0¡è¢%°ýCã7o55·VW×ètº[·n1ÿ€}ü€è$¨‚ðÚÚ†atj›ÓìÑ’Ӳ޹{Ÿó»v! Â/(z/‹° ëà Òè U4((®ä–4·uIäšNE¿\9@8  ßwN´ƒàlâœâÌâü:],X°Ø|ºè°+žÿ ù1G.wß9ì| ŸÑïüÈ€²¿)Ю\)n²î~Z(z†[;º³rKR¹yÉé9»‚”Œ\üÅ€ƒÃ„#ë´èÕŽ¬­ßž³X¥²®ªªšòòŠâââ¢P±êêZU횦Zk¬mè¸vÊóJ·=‚;ña·¦¡ÕvqwfV—ŸŸ•Sœ#,²óJ¾q÷„Óqˆ¼RvÝ´ýà Àð 4œGœMœSœÙm.,Xì v=:÷ð¶yþÚyþåÇ\ [B爛 Øv¼Ø5>‹îB@ÙŸh÷®7‘LãR¹¶[5¨ìFõ°‹À€ƒ3˜f€Z;25³pçîƒGŸ¾øþå÷/_(€ˆH‚ªksD%ªé7›† { X„]Xg©îõtôæ}çð92ta°`Áboð)\î!óüL3=.÷pOá0­®íÌÅ­]¢fÁ‚ ,X°`Á‚ÅÿüÿÿìÙÁ ÂÁkÛ—-¤‰€’ àC!%ØR,d¦‰eçñ:€ˆÙž_ bnûˆ˜õþ"™Ëu"æ<@„€!B„" D@ˆ€!B„üÿÿìÛÁK*kÇñ?͵‹Ù´—º:¸Ò8´ÝŒ‹°6¶¨®‹ŠG»F Ɖ¤$„„8$Ä+""ÑqæÔí8çžîÜð+ŸÅ4ã¼>‰‹ç7ó X!`…€BVX!`…€B›žïðÿâøO>Øäx¿‹Žÿ$àS!€MŽ÷»˜áøO>Øäx¿‹Žÿ$àS!€Mã¾sP.çvO³©úSÍ™ÆwpQ.¦òÅLwΡóüáfú0ÕüÁO¬ÕÏ“q5 DŠ>*fûËYÊîžæŽÛƒ·Ûpl÷ÿË.ýµuYq&tDkåΜC’~È]²ú=½³Ÿkö%…ë=;E¾S0þ+°iÒg¾mðNÕ¡`ཱ^Pï¥áxb»ùg®µ×NƒfÏïSµÒåÁQÂoþ­¦†Ké¹ê¼Ý&€C`Ór }›R|k.—[’ÖBj¬üøm´³ÿRÖý¡ˆ&úòf1 z•dZŸ¥év"~%±ý÷IL–Fg¹C‰ä÷qûÞ+¤U¯dì÷7JÕ颉°Or»ôSvÛ¯ïßWƒQm³ÙûÅÊÃÇñu½Ny=œ9Ñ” ß¬gÊð1%‰î?y0Þy•ôû¼õÁkäP½¯w<ûÅ» ’Ñü¡ +'ÞV+íG_Eüä+>lZ" v-ã2Æà®[ÕŒm˜1{h9¦wíŒuÄFNë  ÑÙ#žÒÓ¤€7§$3/“ÕŒzgå^6d9dÖ3¥U »æ]¹ïw¾õ{âù‡³¸e%[XjyÕ­oú6»Æ?(ʈ/ðÑ`Ó u¾1Ú/­k­ç»îõæ¸éï^kÓôÍžqÉ\ÖºS«)‡Ù—çJ&â÷âÍ“€qÄ}t[é?¤ÄƒÑâùø”øIvø\9š:e^Û=gåÆëÊéêE÷ñ8*–õL¹Ù3‚ŠÏÜß¿O)Á@T Ž(‘X£w×ÌŠu<§·•—A%Ÿ7ô̳hhüUŒ¾–áí¶±íÿõø×`ÓR#@µzq; |ѧ€\.K×»8x®Œ&¸¬¹Ç=÷•迃»bÚ¾ýxÖ¸/´:µÉ3Æ)õ¿¼“6}nÛ½`eY3{̤a f²&î t«Súõ^¼AФÌSÌ‘!ãþÃÂgÎÄm­Ë‹Æ¡^¹¤¦§û'€M°Éö«Õ™–ô{îõ™YÙ5'ãç³e—--ûÛl ¶Í¡}`¦6Ôf§kŠˣ·Ö•}bjh\¶%´/EÇïÎÿ0œ:ûó›Üd.h¶Â§ƒÉÒâJÄ”‰m­ë™dÿzök$ÀGø ÿÿìÝÏKÛ`Çñ?mg¹ôÖÍI¨ìT/2ñà¼èA¶]âÁy1‡N†ìPa™…¢` Ò¡¨ˆ`¡”RŠŒ"¥”âÌó$é“þpfVCÞð:”¤ùÏáûI¾OB€ˆ†ÀêÞVó¨Q÷´;»¢ÍÆ+ˆo¬àNyû\¶¥ n%íØ™©§¯£FL·-®z7Î €-/œªåûÎÁ¦z>ªæ7o¹xZ/‹k?ØÌNõ€·Ÿ¬ìá¹ÎËü3í>s&Ý+Ky’­øO*¥\áWîTNtî8'Å\¡ø]~: UÍíÃÒ~—ÿ‹)`xr­[š—œã¢ó'=³nͧ½Åoe5ìmb¤L…×ZãÇÇá2ýVRœžžõ¶JÖÛ$´ê‘¿Õmcø̡л¸ü:¬7ÒSÊ¿Ån›9ÿjRs¯ëÉEãÏä¾wôÉ?|ÿéA¯´.rIøÓ'–عž¦¬}H@¬ ¢~È¿„çheéVsÁ*óý;ST´ ;î[q.óóA鼺"ªêÌgåž½ßÐ/ nù’ñÂPå©íßÎý¸M2kêÞ”ûî£÷ܾ±L/®|Èʃo’®÷–Õ´0gm캓}§åíüÛsKCæ’Õ=' Ið6¡k?Wl_•ƒ`gÜ%³_òƒ›»MSòäÃEû€X!@DOlLï”jÕb£Y^Õýã4šN;ê'ºîœÊÍÁƒÖd¾í%:j®ìÍ­5{k£æfƒ³ŸK)q3>7v“‡‹çàNAñ‡²\[«¸ê‘*r"±ØxÎ…h+ˆhBÅ÷kàÏIp?Ý´$Ííì¿ôq…ÒvfBGÔ>$ V‘îª}¢ÎNò˳ýž~å ¾/lÑ3ddWjÏ|¦¡}H@¬ "ýUû¿u;gí»r÷åô*h+ˆH{½‹Ú‡Ä "Ò^ïb€ö!±B€ˆ´×» }H@¬€! B„$H  A@‚€ù ÿÿì×I 1A“Œéqì‚ÂZ­ºFE`ž- D@ˆ€!B„" D@ˆ€!ãifffff™ýþB„k€ÜÒk}'7ç¼ü#œðÿÿì÷SÙ–ÇùËvkÞ}ïͼçŽc‚ &EF€@ Bä ,$‘PB„DÎÆÛãì‰ö~E¿¥fhd0¶\ÕÔ§¨ÓçÞ¾ç«ãîÛç@3C5ß%T@Aq:È€EO$’öôttv}}8Ün|Gth€’à?Ò7”}jÍ¡‰NoLNI»~õþþÃáoÿøß± –ÅâÁ+ù:;Û©7±/ž¨Sð÷þyºÜR|¿ Êô_úëÇ_ªÐé ÷“S/_ ÿï¿ýýoØp¹þí¡ÀüçÅÅLJ8.\üæNTŸ¾¹‚;qqIII ¦ ’Ë2 7O@ Æ <dr•nÜl4[¾>¦‰i|Gth€è9NjèÈ>f ŠÐ¤™Éº~-;¯°®fÇ¡…ÍÁw,ˆe±8Ö FÉWÛÙN·‰G¢NAk[ç)rKñ]óôÙ‹ónΨ°‰ÙzéJxfN^u]ƒÉjfµ¦Vv(ûÐîp‡Ã9÷Õ ‘Ñ×? "É:çæÁ×Ì 6»Ãh4õ dees:»Ž»27îEßÀ Ü8iµáó¸óžo¢C” ò<Þ%òÛ,Dd–f ŠÐD§7FFÇ66³y‘T)‘k¾ XËbñ[Q·Çfr%_gû¬Mì\õYHGµŸ›[ŠïotzÃÍÈèz³/ˆ¤£â€ ÔÔ7½{÷>Ä1šÌß\É ß¿ÿ|s%‡¼zõzÿñÌŒµ¬¬lbÒðâ ÃÍsP¢Õg.ûœ;€Î Tš²ƒÔLAAšÜON«®cðDrшêœÀâUu)©éäJ¾ÕÎä&öu~¹¥øÞùééÏçÝœE[RrJE }/æ‹e!HUmãÛ·ïBœqƒé›køNþüó £ÑD£•¼>Ãp…ÇOZl³vWè0i™åñEÕ†¬ì`4SPP„& ÷R:{‡xbù¹ÒÙ;˜p7™\ÉßÙ&¦f¿à&öuuN¹¥øÞyòÓóón΢->1‰Ãíâ‹CZýõë7!ÎØ˜þ›kø~nmm××7¼>Ã?y~¾@25mŸ¶:C誀jCVv0š)((B“{Éz…|鹂D®ä‹ïlSÓ6½aÒ2ãø"›Ø×IÔ9å–â{gÿñ³ónN¯íɳ»I)]}C}C‚Ф˜VýâåëG­Ñ~s ߯Ÿž>ïèà¼>Ãpó…/™œ¶ON;B ;TT²OÖLAAšÜOÍìöŠÎ„@ r%_|g³9Ü«S«Ÿ0MΞ}û:‰:§ÜR|ï<ÚzÞ ÀYäÝKNåö¢M ‹Ëþùeˆ£Pª¿¹†ïWáóç/º»{^œa{~:Ê0_‚C¨UÕ†²ì5SPP„&÷’Ó¹½¼¯‘+ùâ;ÛŒmXfœIo´œqûj‰:ÜR|ïìî=9ïà,ò“’;ºúB–œ‚Ò§OŸ‡82¹â›kø®vuu¼8ÃvöžepX8nž5 * ÚP–}¢f ŠÐ$1)µ½kà+€@äJ‚ÙÙd í'¨Æ ‡£cã8T¨õr•X¬‚É»ZgTϲ‰}µDGn)¾w¶wŸwpyq‰I¬Ž®%3»àñ“§!ŽH2òÍ5|× ;;»^œa¸yŽÒ?$ЧŽC©5äÕÒ‡ž‚ÂÒ²Šj’SéêÊ{X,ȃ™ü PPm²5z3dò°¸ A® &t ½±¨´â<4SPP„&w“[;zO$)53:6!+¯øÐ“WHƒ§¾¹­ŽÁ‚ñ°¤’|"WB¾³¼#ôÿ0NZýûžÎ$Sj½Î8iœ˜1MYÍ–ÙOfjõæQµ~Ì0yºMŒžZg>4^ï’eÚzèq/zlv'É)‡huÆEW©fò'@U@µAÊV™ ×ÇÖöð-­è ¦Æ¦Ö`B[ffçæÎC3Ehr;î^‹KNm#km}µ‚Áhf´vNݸ žŽ®nï ͘|"WB¾³ Üÿ+z£N™R';øÇ'£GÑê'äJÝé61òDµ´wÿµ¢ò--s¸=u ö‰¹=„Ãíå DÁÏÿ¬ÜR‡B©ŠŠ¾ø_´òÊåÕMøç]ÞÞ¾A½ÁLrî0OÈã‹NzD¦LHH4š-ÁL^ßÜ;ïàÔd}k/:6¾¡™M“ÍùkÐgÏžwu÷fdçŸxâÙIJÉÚÙÝž•Õ\'øñRă¬¼aþI‹v7àYÓä¿®\â‹?+Ö!ƒÃ|ò <¡4)5~¸‘’ž£Òè›Édq0Íæ˜>º\©ÁtF…`εHä­¼šNx°,áA~N—™ ikç¼>Ãpó¥«wUþqŒªõ¯oÊ2sèYp/ÎÚ0:¸}åUµ]}Ce50zxÄ„vga ­¢š.Uá\…z NžH†9¹EÅe•œî~’ˆPPm²šq„ž›w9æÝÎùEßòEæ‰)bw —V°Ú¹Ä|騺†ÎxXLkjiÇʼn„ŸÓ »¼ªN –ŸQ3Eh›Hon'§ªŽA<¶_¿~SRI'œZ½§·½«†J«'_È•ïl³üÕƒÒ_®#üÁ0f˜8Ý&Fž¨ÆÖN$áé³gæ)ëŒÍùüç(qÊk0”[H‹ML޾s7)-«¬Úï©e°3r‹nÇ'Áÿ û!J;·O::v¹fÑ㘜>ô¸ܨïa¨µz ­olá*Y][ŸµÙû‡ÅCTÞÛ;{Ë«x `‚T®iïìsÎÍc&®•Í8¹Ýý$ATT¤l©\‹(cºñ¼‚’ü‡¥ Œ×â Ñ x—Ö|Ëk¨ìûùp*”šå•Uü#­Aä¢já„H,²¹µ Ùkë›v»³ƒK&ûDÍ¡ÉµÈØŠ:& E´ºÍ-£ìNÿOú Fsym3üØqÈhíDcT¥%_È•œ°³ ÑO€ÃCшJ¥5ÎU≑' U8’€móft<žX"‰ ‡‘qð›ýÇ?Y¬ö_ýu{g“ûy£†ùŒž˜/–?>ø(žÙE´Ú­íß~ûmÞí}ñòåo¿ýN«ª?cn)â˜ó\»v åoÒý䦿V™\íñ­Ã?k_(-+‡?99e˜'²9\¨Ñ 42˜÷î%Á/–޶wp¯âëÚ58—V¶<ȸ|ùrI -;'Ð`z=£¤”ö ‡Ñ««ë0S¥Ö#!λ8u¡-âFdiœêú&„C½tèAù½©Uoð¿Oøîýû_~ý•ÑÚ¾»÷èÝ»÷Ó³ö½G௩oš˜š†ªzX ‚b¬¸¢v}}cÿñ‰qAÔí»«k[Á³èYFÁšž]@6¼QÓÙÕo4[`°Ú¹pæ–ÂÎ/*CC2¢Ô›` ˜FU}Ð0ô®ol”Ãé&µÙçÿyùÚ¿®\ÏÊ+êêr8vv÷×Ö·Í3?\Œˆ‰»‡ä\¿y/%“[£ 8ÊH1š”–ž£„V‚ûÎÝdØ M¬¥åõÓ)ü·N‡ ëÔ54_¿ÆiÆêÀac3ßuzÿ täíøÒò|œˆÑ n´|ÿoNœN«¬ýñÒU8*'‡ÙÂx}†ù–7ÂîèhŽC<¢q/zMæ©CϼË=3k‡¡Të0¤Ñ™akÆŒ°…åˆL±èñ(ôp:ÐË,zÅ#*‘d†Î0 ç¨Êàñ.éÇM$ATT¤lш½>ôÛh<––Wm6G ›+”ªÑ½LYf2² 2² `ONM÷ 펹«‡öÀᜇ=n0A*ñY  D²³h¦  M"nÄ”V1H(©¨Ã×41•œžÿhÿñ›·o³ hðc„¿¾¹½é ÆÅ#„|"WrÒÎæG¥5ÃC¡DExê{lYù˜X¦ýëd Ôšº…3m¼ä‰ª¨e" ¨Ú?ùéå«W°ÿüóÏ–öÞ–ö<Øî&§'§e=ùé)ªyLvλQuuõÀ‰Gc3› '.8 £¥†X*¿v+¶¬¢ÆŸÛQÕsKqJ•.íA:Ê_âo¢¢¢‡ð«5ã8D{Êbïé4§&-6Zy%ümíxÆbrt´?ózÜ9¹ùv‡ÛîtÇÄܾr%|Îå‹‹¿üé×ïÒºªºg)TcÁèÄYçÝœ:‡ÐvåêÍ"Z595 gµzP|ôÿ¡]7n€*ŸV]_RQ+KKh‘ѱ:½ÿ׌ÜžaŒ¶®É<±÷hÿõ›79üñö¥ã‚Qq¨kƒgÁíEIŠ6êÎÝ«·b`£ò¶Ì؈—|Xm\¢ÌÍ-,ÙÞy4¿°XXZ1ÈjÇ þßä>Äwܹ›;Ÿ”ÕÆ!]^ÙÊ•ÐC¼O⸸¬þºúfNNYQ×аѥ0[ÛaLMÛŽ>ÈÌ»~}ee-D]#³ª¶am}«¤¼knnížZ!ÕæD:£%%=§™ÕÁHnÝŽïê€ùINÏùñR„Uùö·×ïìéžwyPô—UÔâôÑq™¹ña*'ÝÜÜðú [ô®¥…ÝÅ+ׇR˜8죘µ9`ãŽu/z¿_6Š‚Û#’*mvçÄä41Y*SÂ)”(´:´žþ!œC9NÇ4’ ªª R6_¬@D«Í1a±MN;\nùB)†ˆÆàð&¶wö¤£ZŒŠ¥£Ä¹“ô0Р=úý9j­á,š)((B“+×¢Š*êI Þÿ1Íx /-¯Ànd²áW¨Ç`×1Ø ëȨš|"WrÒÎæU>8<Ë48”)ôB©ú¸Ér%FU'®|â&Fž¨²ÿŸI¼}ûnmckyu]£31X\øS2òõÓ»wïQf½ÿËï¿ÿ'§g3‰òkÁ½˜_DƒsÚjûðñ#Œ¾!á'%†3æ–‚›cQ,-¯¨B)Œ"Ýî\T¨tЈÑ9×R­òÆÍ›¨’QñÃÏbs½k‘‘þx|ÉÅ#_ãF yÐÊÊL“+´Á(t{ÖεÀڧδ] ¿^PRINYáf¬6â0#§peeõÍÛ·°Çôþ ®±vfn«­cÿ±ÿ†zç¿MÚ8Ý´ªú??|‘+66·$2…¿mhnÅ÷žÞ‰qÁÕ[·=¾Õà!þ’5üFtFvAvA1zuçÜ‚oy]7n†¿…݉ÒÎÿƒm& “½Kk¨›WÖ6ÕÚñÃ?~XRþY³¥|ÂÊê&*·Yû\OÿÐí„$DQ¨uy…e‡A DÒѦ`ž²¼“w—X“xyFQY%€3*–ƒù×64ÓÖÔ7!Ü>8‘Ÿë‘±1ñ÷1ÌÔä°¾‰…Ì܂›1qD50,Äh@åä¡MÌ€×gØÂâêQš[;‡£$àŸ|zÆ–“_RÛÐZTR¹àö˜&¦áÇ {X ‡-•©`óE£3³N÷´Ê††¦vž@|à”ë S0ZX&»»¼ªaÞµ0k›# UÕ-[Žˆã3q(ÑàP7n‚Àhšèàp{yE¥UôÆV<5=Þ%¡hš¡w¦Íî—çpºœs.Ze}3««Ó@o´œE3Ehr)âVAiíqdä–nïì~R1LùÅÕ£J-ìêúVz†T¦$Y ¹’7d0¢ÐƒÃC©|L<¢%™,‘ ƒ|ù‰+Ÿ¸‰‘'ª¸¢þ£ÿ ~ß'~¤å£ÿ×#Úì6Ûß~ÿÎä9 Ii(ô‰W€Îy8ý À‡iY…=Ãþ†J®,¯aä–ßKÎÈ/®ªƒQ[×g+«vMmý¬}DØðÀO40ˆÉyù§­s`jÚi™Æ#t©°¨$==ócUTVã,™\ŒT—{å¼€S§ÚþuùjNa9ÅåÕ7i™Žº“x3æNJzæüáöx1¤Ñé?úýU»¼Æß'¸ÜeÕôήج.ükë¯÷?ÿ¬¢3ž>{期Çé…´ªãtÈnÏJð8^d·±µ»±¹»²º…ú~­þ `qóž^¾VQ]§ÕîâtõªtJÞVV~Vn! ŠŸ´±©•dt`Xœ˜œ~P¯¡)Ôþ7všYÐcLo‚f—Û×ÄlƒÓ41p4;¿8üz4±ì OÔ;À‡QˆÀÿÖþéLMÛý @}3O ½|=ònJz{gOG§¿@~â“R/\¹1çò`fß NŒú?ÝÐÿª¢#«ÎùEx*'ÝÀ`¼>Ãæ–Âhá ðd$Øn¯oY?nÂ=N`iyÕ<9 ¿lUõâ o¶dD ›'”cËÀþ>Äââp-xàÈð|Z]Û4š&kéM"ñV0¬@TT´ì„Ö›=¨ûÇæÞA >4·´AŒÝ1gµÍaÔ1·›ÙÚ.ËðaÑÃÀižšõ-­ð…’ºú&“yrumC,ÓžE3Ehr!üfnqõq•ùŸÙn¯¡…Cðúõ›wïÞ¥fÊ UÒ™µþ×ßÅ# ’u‘+9qCØQÁá¡@¬"™,øGû%ݼW>q#OÔCšÿE©Eï¿Þ8‰++×Úþw„~OÏ+s¹½oÞ¾-,)OJÍ€át¹1Ójw~øð1¿°´´šñË/¿î?~’[P"¼{÷¾Ÿ'9cn)b0MGDD„‡‡–p»úPâ_¾|96öŽsÞGÔôéY*Ù†ÝÒÚŽG\|lfKNGùÓù)ƒ¨¨hœÛÕ3Àéì…3!ñ.IKK‰¹ý h ˆèåþ@*S#gwpê4BÛÃ3óKÈ),­B¸]ž@¤Tk^¾|… ¾oH€!µV»£¸¼vc‹ÿïé…bIL\âæÖl“ ¿Jãçðå«W°Q´à\ßÒò‰A n_ðÌ:üÉš™÷‰_}ð’Osk촌܈›ÑÃBiiE-œBÉè¨j FïÏ4aùábÄÝäô9—7ø uõ ’Ñ1½kÞˆ‰c0ÛQ.Ç&ÞG,\âé“N É•°ØÝ;IçæŽtt ¶*¦ßíP=VÇŒ¤‚MvêÀ÷>Ì-ªtF„Lbâ’ NbaI oºýÒ1OÖ`úäþä}x~q5 /ê›Ý·÷žš]bˆÀDÌ&> 2@}_ßó”*ÈÌüÒ=DÕº‹s¢ JÝ ×Îî±~QcÛ?ÿõlúÛßÿ±årÿ_ ºñ‹®ýƒ÷ÿq?>¾ÿkcK'Œì…‘pô´¤¦S2…šº>ÓÌùÅÂs‹œ„txâöÏ÷vÒÓ3§gUÐÿVg¥úóŸ.ªÞRí„„ÐýËÝ‚Âg0¦ªºŽÚKk°)fçq3Ô€z|üøqoÿ°_:BmR­¸ã[R)¢ž:7Ü_5ü÷￯éŒÐP(g óy['´íÎMhÃ¥ö'÷æ|NJ›¸nr²gM÷¿À±~X ºÏÛ¡=©œû>égêWP]o±n*&çŽnÔÓí’ŠjhwIÙOZUUϰbJåYyOà*"Ãê¢KÒoµ¹ìöí–?ÝÃ'.á†L>ƒšÜ €…E íVÞò “O™ß}õV»ÒáqjØšÖâŸ!…jÙ½¨ªm2[6`½—øƒýe{÷ÑG"sf‹ÓóÝž˜ø¤Þ™&§É¼‘wôÛ‰þA9‡Öœ™ÚÚ&Úó“·¦·ySÛÐúkï°O$£Ò‘É®>9›ÁÊîþã#a_ˆïUl"€­íiµO>œ‘™â˜h{ìcyà>!“èØþÓò 1›°©lÒQ%pªŠEŒÍ.>‹˜ß‰Ê+(/¯nòî/®¨Žu–‰!“ˆè2> 0³ ›ÊÖ;4î± %Š‹Ü"箸鿻“šõˆX¾¸ª^]'œ‚ÂÒ;„µa¥ –öüä-¾Ñ{S!llmïkmï' °¢µ%YÛ§3‚ dr)*>_”Î/暈¨xf“ÐV6ŸE,h‰â"·È9€ë@nºo"¢ïeæË×—¢ß¨ „“ÿôYÈÂÚ°¬¢šöüäÍ/®yS.l¿ìinë%ð)4ÐÚ«ÍÆA2‰ºv=5» -·ˆS`ŠË1×™MBXÙØ±à$Š£Ü"箸]޾v'-çnŸL¾úKÔÒ²Žpæ…Ü!| çW‹K´''oz^ãMu]K­¸£©UBu⎚úVZ[bµÙ8#B&?þœ’|?÷AN!§ÜJåßL¾ÇlÂÊÆ¦ˆ'Qå9p½Ä-áFòO·SSÒsÉäËo#C¾~ó ÿáÓ;„¯áÈølI©€öää)gÕÞÈF§Ë«ÄõÍ] -Ý$&à3<:CkK¦6KgAȤ»W—|7#?5»€# 8L!é“3›„ª²±,bAHw¹EÎ\/qëê‘ÆÄ'%ßϺ“–K _~}yîõ*ádóóCÊUƒ¸M&Ÿ¤=9yJ•7¯¦—Û:Ê„âê†vQSg]ó¯¡f0°¢µ%MûT΂ÉÔœºLP›x+ù>?%#ÿ~vÁ!,‡)`"f“àW¶S1NÅun‘s× €@Üà ,­EÇ'ýt;5ù^æí9Dñç¯"”³+„“•ó8ä> ṉÅÔ’ldº±ù—–—]'•AÞØ«EZ&g–‡†•¢Æ—UâRAcð)6Á_˜À|NR%GÛ?gAÈdöõª¤Ožš™—p#%.!ùlHtÿ…€¶»OS°1 Zeó¯ˆq’¨ÓŸtË“[ ëÜ"áN,ÇõŽ^²»iÙñ‰7câ¯~Ÿ@ƒþøÅŸàñDžw|NÓYóñOÖ¸žx“¥d Å-À™ øG½¸]Tß*ªkU2”Až||á$ÆŽÞu¦çÔ3óšP³Sï@ ž¤iûጠ™(”ª…%í²Æ¨~k:C „…àìM‚YÙü(b%*8¹E®’óêG–5ë!w;C6e'™EAAä‚ÀM#‚ ‚ rAàõ )AA¹ ð$ý AAA.¼Îž1AAA.¼žW‚ ‚ ‚\xàò…ñÏqüŒŒ Nã‡{~0>Æ'9>¾~1>ÆßøøúÅø>þ ÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/ìó•®½èß?AÒ1û•ºÙ¯–_øKþàó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËû|¥kïú÷OtÌ~¥nö«¥Çþ’ øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á Ã@A‡¨ü£±b˜}ˆ†êŠûÌÂùð÷ >¿ëÛ/Ÿßõí—Ì€¿çñù]ß~ùü®o¿üc>ü=ˆÏïúöËçw}ûåóàï9@|~×·_>¿ëÛ/ÿ˜Ïâó»¾ýòù]ß~ùÇ|ø{Ÿßõí—ÏïúöË?æÀßs€øü®o¿|~×·_þ1þžÄçw}ûåó»¾ýòùð÷ >¿ëÛ/Ÿßõí—Ì€¿çñù]ß~ùü®o¿üc>ü=ˆÏïúöËçw}ûåóàï9@|~×·_>¿ëÛ/ÿ˜Ïâó»¾ýòù]ß~ùÇ|ø{Ÿßõí—ÏïúöË?æÀßs€øü®o¿|~×·_þ1þžÄçw}ûåó»¾ýòùð÷ >¿ëÛ/Ÿßõí—Ì€¿çñù]ß~ùü®o¿üc¿GZ{Ð×O4f¿R7ûÕ¥÷ðÿÿìÙÁ 0 ±ý·Îäu’À?ÒúàïñÁçw}ýåó»¾þòŸqð÷ >¿ëë/Ÿßõõ—ÿŒ€¿Çñù]_ùü®¯¿ügü=ˆÏïúúËçw}ýå?ãàï1@|~××_>¿ëë/ÿâó»¾þòù]_ùÏ8ø{ Ÿßõõ—ÏïúúËÆÀßc€øü®¯¿|~××_þ3þÄçw}ýåó»¾þòŸqð÷ >¿ëë/Ÿßõõ—ÿŒ€¿Çñù]_ùü®¯¿ügü=ˆÏïúúËçw}ýå?ãàï1@|~××_>¿ëë/ÿâó»¾þòù]_ùÏ8ø{ Ÿßõõ—ÏïúúËÆÀßc€øü®¯¿|~××_þ3þÄçw}ýåó»¾þòŸqð÷ >¿ëë/Ÿßõõ—ÿŒ€¿Çñù]_ùü®¯¿ügÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcŸ¯tí=@ÿþ ’ŽÙ¯ÔÍ~µôøÀ_òŸßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þØç+]{cö+u³_-=¾ð—üÁçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]üùJ×ÞôïŸ é˜ýJÝìWK/ü%ÿ@ðù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËû|¥kïú÷OtÌ~¥nö«¥Çþ’ øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙ± „@AB"4ò·>‡«õÕ”7+xðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü±ç“$I’ô½þð—>_ øü¬o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?öÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÚÁ Ã@A‡¤Pœ4V ;ÓP@áÏ,œ‘ÿžÄçw}ûåó»¾ýòÇ>_éÚ{€þý$³_©›ýjéñ É?|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/ìÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þØç+]{cö+u³_-=¾ð—üÁçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?öùJ×ÞôïŸ é˜ýJÝìWK/ü%ÿ@ðù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûå}¾Òµ÷ýû'H:f¿R7ûÕÒã É?|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ>_éÚ{€þý$³_©›ýjéñ€¿ä>¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü±ÏWºö ÿIÇìWêf¿Zz|à/ù‚ÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×Á ±ý·îöuÈOA€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËÆàï1@|~××_>¿ëë/ÿ€¿Çñù]_ùü®¯¿ügþÄçw}ýåó»¾þòŸqø{ Ÿßõõ—ÏïúúËæÿÿìÙA Ã@Á@2”ðGcØyD-U(å3+]ìÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/ìó•®½èß?AÒ1û•ºÙ¯–_øKþàó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåyðï9@|~×·_>¿ëÛ/Ì€Ïâó»¾ýòù]ß~ùcü{Ÿßõí—ÏïúöËóàßs€øü®o¿|~×·_þ˜ÿžÄçw}ûåó»¾ýòÇ<ø÷ >¿ëÛ/Ÿßõí—?æÀ¿çñù]ß~ùü®o¿ü1þ=ˆÏïúöËçw}ûåýÿÿì×OKTaÇñycÑÊMLjA¡Ô&‚Z”¸!Êu‹¨`ú‹:ý–BÔ¢µÉ}E/¢1í t–4Á½uŸ9ÝÏ/®¾ÏáÁsæ õ@üüyýú—Ÿ?¯_ÿò׌€¿z ~þ¼~ýËϟׯùkÆÀ_=?^¿þåçÏë׿ü5cைŸ?¯_ÿòóçõë_þš±ðWÄϟׯùùóúõ/ÍXø«ÇâçÏë׿üüyýú—¿f,üÕcñóçõë_~þ¼~ýË_3þê1€øùóúõ/?^¿þå¯ õ@üüyýú—Ÿ?¯_ÿò×L禈ˆˆ4’‘ HçàÛw-Á´ Ð",@‹èŒŽ´ Ð",üe¾Ž¢|=F¿6æÎø§·ln ®-,ÎÍŸëNÏ6Ìôìé8ãê( Ê(þ  Μ“3§rÍœOŸ¿ll¼zþâåêúÓ†Yë?‹3®Ž¢ŒâOñGÞo /_½Ñ={娉‹Mr¼{)θ7nŠ¿Ðr þÄLà÷sçw{Cïþ£¹ùóË×Wnß?Wæá“õ8ãê( ʈ Š/Rþ)eg΃Çk‰f·Á0¾¿_¿y»¹½3ØÙk˜Ãý8ãê( ʈbŠ?ÈîôúSg/,õn½[º·Û$˽ý8ãÞ¸=jˆJŠ¿ÐZÊþÄLà÷óÿÿì÷S[Y–Çù[ö‡­­šªýa§¦¦«¦k·g¦k{zÇmWÝÁœMÆ`Œ & $$P!ƒMFY ‘±A ( $Adl¢{Ä›aÝæ!iðv?.õ)×¹çÝ«{8%Î÷\=IÆ?À¡áö]_›[^%ˆëE2ůŒX®„ak¸uç~K[áÏñ AxÍÁø jΈn¼¬¼º¥­KÝ7¨íé%Ø€0ÊÊ«FÇô„§Esçå› ´¶ÔRsFÕµfñ×$³v þ…}awˆá‹ñªÖ—„縀x‰ÄxUÿ쳸´z’аG³J HÂÈ 1†?Æ @œPÍñœšZ‘RÕÖ«Ò Œ„¡PµÖ %„§—;!ÉÁ$EÚ‹™ôÊEb‚ÓžââUã%Zæ³°¸r’À‡üÒŠ*¡ÌKà—–‡á†Š@ ΨæxNUµ°ëU_¯fÈKèzÕ[U- <-¸\ó§Æðô)evo š7~ÍBxNˆ ˆ·IŒ7h™Ï¼}ù$!a%åµeÕb/‚pCE çTs<§ºFô²[Ó­î÷ ‰ð´àr5ËŸŠ/™ó ˆ‡ðœ o“oÐ2Ÿ¹ù¥“„†G–”Õ–– ¼B @œPÍñœêZIW·¦«[ë5h $ÂÓ‚ËÕ`^t¡-š?ãÚ Âs‚@\@¼Mb¼AË|ffNö¸¨´Ê«€pCE çTs<§²ZÔÞÕëU@H„§—+¼®Í{€xÏ qñB‰!\Ë|¦gì' zÎ+.ó* $ÜPÄ9ÕÏ)¯¬méèþDÙÒùž!ž\.ùqCs§ÜÄ03MžÌ|O Âs‚@\@~e‰áòŸ³òø„«˜k-ó™²ÍŸÄ/(ŒSPêFNÁ]ßÀûþ!LN!æ ~èváÙ€pCE ç·5''ÿœc|„E<ÉbóN›ÿ4! ¦e±óÏ_ÍyQQ£j{é I}L\"‡WtÚ¡´!1™”˜BªS´xø˜¸@H„§—Ïîq|ß~)°ä›Ð«Á¼/‚žßHV»žÿž@<„縀¸–&‡Ï?ø@tp'>xöS™{~Aï¨ ™÷(òiЃGÑOCÂc“H¿PWüþZæ3i= ´õ¬¼"×äóŸîìì$¥R0Ϥź²ºêváÙ€pCE ç·5'—÷ìð­ŸíííѱñÄ”ôÓæ«ZÚaZAqÙù«9%Ï«UžÐ lÓ7·ž:÷þ¡iÛlSk—‡‰ „DxZpùôvÞ=ÚäiÜHNç*Ç'—‡õ³QTÉŠÁÅ’÷â!<'ÄĵÄ䔜øÉå•àNž·Ûm¶™ÓT&•œ©íØÝuÀ¥¥¥e¡Xš”Fý…ã÷Ô2³eæ$·}ƒèlžkŽõ¸¹µDe‚Çš"€….¶ Âs‚@\@\K #§JÁàÐpäÓ$Œ¤4· ÔäEy L`çñÁ®¬=€iÇ*óöCííí™'-÷üCEű8ü>í HÚþ˜ø´g%/l¶@"­‹zšÎþÁ!™¼¡F †ª‹+U'Ûipööi›¤²úyûB×ËîræÙ´ÌÇ`š:É·}É´×d嫽óÕÒò Dó4)}Â< ¸T+”À¥ ³uÒ: FyUíó ‘,ÆÂî¤fd Ä2çÝ“gån÷ $ÜPÄ9ÀmÍ*†üƒ?¤Ò0´X§áRGW7ØY9<°M­`³¹EÊf0˜>‰’upp°¼¼242æp8Œ¦‰„Ô̺æðŠž‹åMž ‘+t£c°{5ZÈžujÆ`š׃¨´uöhúa‚vP'’)äu  pzã¤ÑdÑLb©¼FTïáFáiÁå£ë9W“Œ§À˜ÜÛ?tìtôM¤ç«®ñ?¹_åôÓG6»-îZØÚq˜¬Kà0¬ìí\é¾ÝûfsW«_¾ü¤×hYÜÞÝWõ¯Í¯ìììîßJlu±ñžââZbh¬|ø“Ÿšžæ—bÐ~I98EÒz˜À9zÏK]cØssóSÓ60ŽUæí‡š¶Í‚Ójª®%$¥Ýö J"ÑÁŸ_ø »É`™²ÑÓ«çêêÚÆæ¦ón¶e Wª°vÚ4a… X; «—à˜±þúÍÔÑ^p9›–ùŒ,'ùîÆ½” ¦k2™\ØXÕÚQ+®ƒ”A7M˜—WV’ÓKË˳ss?Þò½qÇ~½iÛL• Õ±[Ý—Wðlqiy{{›WGœÕµu·a@H¸¡"ˆs€ÛšCÎÌ9üùÏÚúzt\*\jï|ÃLl¬"3r ëUÎS›‡y¢c¸å«èšÃæð+jäžP-ŒÖ54Ý£Ött¾Âü”>- Šf˜PY#ËU£cz‰´žÎäÒܺ% …R¥‡AH„§—ÿ’ýi¤þ4ø¦Aý\@’ô£»òZÃ2ðT)®›ÊŒ‘+´~ö¨[£›6_=ºšñ“üíëŸÄ§»{KnÇK56ÌÎ)„ʸ¾þ»40¤Ã¾un~šÍÅæ¼Ùp~eP|*rôy¾™Ùy·»!ᆊ@ ÎnkN\Šó0n˜8ölln iôT ˾°W_¿~ƒ•K:‹§jí:ºà,>M-«kë‡GÿoIyµøC¯9Y,^i…ØÄrÕ´mlã„E7fÄücú “y µf&”UKÁJ•0Ç:5蓉ÂÃ]‰ð´àòo_°þðp܉¥³ãæÞ¾óÅ)u;[`çw$³}ÅŠ6ißíÑo€ñUòø?18öw‰6`Ëq§Í[Øûd=kÿùÈÕ^ÄCxNˆ ˆk‰IIgÀŸðè¸ñ¿ºo`ÿàpoÿ ˜ Pu€saqyvΨ 81•9&‹] 0hÓ¡óƒj¯»ÕÚdr6¶öù`¬1N§å‚sýõ‹Õv¼öXª¶ÿ!UX;½óóvzeeÍ:=ƒ-Fk¼Ï e>jî$_~õýO±iïIl •”É~ÿÇÁ€pCE ç€÷¯9I䬨xòiW#ãÒ2²8ONðÕ:#¯øEí/DE­ øgWAH„§—½Äú}è¸[þiøk¬ñmÏGaãWLž¬.Ç›>2x2â!<'ÄäÌ­ll2õŸ]GJ§çžô§QYdZŽË…8RõžíôiZæÓÝ;|’+×¾ˆIõ* $ÜPÄ9ÕÏÉÌâðKk¼ ‰ð´àò/ÿÃþm°Þ{€xÏ qñB‰!\ËþÿÿìØ[KTaÆñ÷{D'-: Ñ½D0Ë¢’2Ãj$S+˲"è<•“™:nÉT4uR1+-mÍ2óÐ9ºêüYZu3Û˜+ßåÞÿ‡sû>³Ø¼kö˜ñWŸmÚºóØéKªH%ת<€;'yáŠÚ†–.U¤’õ±¸š¿ÆY^ðUéc}&€)\1Öw™ÿhÖŧ.ª"•\«ðîœä]+wn7uª"•¬ÅÕÜ€“žÿMéc}&€)\1Öw™yù>Ñú̬#¥ç”^ÐcCf–kUÀ“¼«áH]c{]c‡RÉúX\ÍÔ,=ðuéoJÌ8ÖgøÂc}—™á‘7‰2·í**9{øÄy%¤ÌÆ­»\«ðîœä] W;õÑÚ†»JH™PYµõ±¸Z°.²hÿçÅyß5&©«#Ögø¶£a—™øðd¢=ûòƒ…'?§D^QéÞ`kUÀ“¼òÊ[7¦šº6%*¦UuÖÇâjEveJÎÛ…Á¤æ¼[¹§ÊúLÒ¶b4ì2šHÔz·{Gvð`ñyu°NjH™¶ö®UxwNòº{âW®;Uµ-Õ·Z­“Ræ~Ï õ±¸ºÝ›³¹;%÷sêþŸvI‡9›ï5D¬Ïð!U+FÉ.3c£‰žN„Ênnß,,Í/>SXrÖ 9Z H )#•\«ðîœäõÇÇš;Ca§¼º±¢¦¹²öŽr´RF*YËTÏUI¨cÖ¦žyÙæç~IÙ÷czý”O9WN—%¡vµàmJVŒª]fzûG\ =%/ EGOfçæË Ä4ËÊÉ“O9Z H )3UOÞ`÷ÎÙ±;øïÎiUç<뺫ˆÔ_½î\.‹L³P¸F>åh) 5¤Œõüÿ¹ª®/hY²½K~…O«Ì>ù”såté ü¡¼ÍòŠÑ÷ûÙa¢ýÌPÖÿH€ÇB!„B|”U„B!„ßÄ,#„B!„ø&&¢5iii@`í߬ñJäKÉW“/h{Æ„Bˆïò ÿÿìÝíoS×pÿ0?ĹŽ‡<8@pqlbãÈx¬ÆCD@Há‘€ÅC&d‡®Ó) ŠJet­6i›4iR;µ¢+}³½[yÑnÚ$6¦ioF*…Ò·ûrreìÄ77ç†ûýÈ:º>¹ç|9¿“X`YKDF…Yv¡®/± ""¢¥dYCDFÕÕÕµýµ† ÊΘŒ¢©©Éï÷7ªü*ôÈÔò–i>fKDÜ—ìú|)ÈΘ õh}}½¢(N§Óáp¸Ýn¯×‹Ö©åAn(ô}>"u¹\ŽŸïí"è\=\‚ eÝCmm-2É$‰Œç‡‰rçHçr¥åv»OžŸoB5>>.Zí t?ÊYÙc7xåÊ•K—.y<ìÄoHÐér¹òC§ìÁ"ŠD"³´%744„og»ÝŽ'rFÂápøÌ™3Åk5 re™‡e¾ßS‘t¢ רþQüþÏÞÿ|ú¦ß{0ý»¿ƒm ÷dg\>Ô¬7Tccc¢ÕJ÷רP±‰À˜–àðð0jÓêêjô úïíí-H¬ÄGª°E½1KDwúôi| •ýOU"Itž8q"?a8{ölUU•É×$‘yXj‰È¨ô.Ác±X$iooÿíß¾yçÓ'wî?yûþ“_ýõ)zЯêúô¸ºqùP°^Ÿ…ÊÉf³}o!p>ê]Ù“ Ó×¼páBee¥Ýn?zôèõe³Y“õRÈ߰׋477£âÇW‘!Þf2,ZqIcc#zr¹\ÁùŒšÈ$,5DdT›7oŽé ÷ß´iÓÆùÕÓ¾zúþ—Ï_ï}ù=è×ûéb²3.Ÿ×뽪¬¨¨¸ºp¸ƒìIÈ„é_»v 9ˆ1öõõ§tøða“õRÈçØ±cZ’§Ó‰­©¢(,Xrè/ާ1j"“°T‘QE£ÑÍzÂýÅ`ݺu ê¿"‚Çè ‡Ã‘H$ú"= ;ãò¡„ú‰ª§§§££ã-ÞŠV;xk~¸ƒìIÈ„Z3™LΗ˜ö¶­­ û+“gUÂI§ÓÅIîÞ½{ÅŠ‡C|DŒh±7(^çÎcÎD&a©""£*.Áî @0 k×®]³f ZcpûáÌÔ3Sgn=œÿË \=ƒ{Êθ|Š¢¼©ÂNæÀo.î {’a±e2™Ò)á,HT±ˆËãñȲiK±´D"q2Âܲe ×$‘™YnºúøOl }<¸¡ìŒËçr¹FFF0…={öŒ,ÄÅ‹Ñbú²g`tÑh´ ºžž‡Ãát:± =:ÁR‹J´sòûýØÞc—UbM¢Å­dφˆ–‚¥‚ˆŒj 6ŹØì»ÿõ~ñúôù =â—‹þ8Ù—¥R"‘°ÙlÇž•N§E« ÏârÙ30:D´cÇŽ‚$ûúúV© Qœ:ujΕ¦E·råÊóçÏ—X“L&™*‘IXœDdTÁ`°}Q_F|þGü£@>Ÿ¯ºº-Ž›››[[[õìŒËçp8víÚÕÒÒòÃ…Û¹s§øI6•†”öîÝ[^*•ÂÊ´Z­ÌP˜3¥Øo¿tYb=3R"“ø?ÿÿìÝYLSYp0¬#ÚÐ…Ö–E"J+PÀJªqi@Pö5T[0PDäA¢bÔ4F™Í<˜‰ÑgãH4™HŒê³1d21:ð6ó·gètZP––ÛNÿ¿ÜÜœ{znýúy¿Ï²DÄQ°B9þÝ’}^ð„ùùùO?á¨|ú©êÙו}õ³Oâ¨qÙÙÙ5Ócq @cˆx¤ÎñÂÅÅÅ¡ú·Z­=ó‡œK~ÈP«Õ6›Í+N§3++K.—+•JüEH£ôðöDZ:´€Ýè†V_ê×ADK$"Žˆ‚Šu“ÿàÙPw¢f­ýœûóDŽ[µcŸõz=Îù·&Äqff¦× Ö Âðo<"$©s¼p(=Ñ566vwwwuuu»ˆA—‹ç¼§¦¦&Q¶Ò%%%uttøf²°°põêÕ …‚ùDÇŒ{£Ñˆ8϶'1YWWÇ4…" ZëÖ­K÷<[ZZZrrrÝ‹/¦_~/põ/¾h4œ P«Õ âÛ€ÄOýÃÙýA^3X‰õü€‚„Åb±ÛíJ¥ÕLLŒÝEê ‚ zäÄápØç ¨¨Hêx‰ˆˆÈC€¾`íÚµ¨éů¿TÕ}é;ƒÖã.ÜË€$UVVÖÐÐPRR‚sKKKqq±ÔA­V[UUÕòMX€>_êH‰ˆˆè¿шŸî¯ÓéP"è\Äå7fÄo`@A=ÀŽ;šššš››1À¥Ô)´îf³¹¢¢¢Ù.1ùõ§€Q DÁæ’:⿓΀ˆˆˆˆÈS €Åðo0élˆˆˆˆˆ<¢æ*lˆˆˆˆˆþÅ€ˆˆˆˆ(Œ° """" #lˆˆˆˆˆÂÈ"½^_>Í`0ø«j÷£Ðm”J¥ÉdÊÍÍ]³fÔ±„ •Je4e2Ù¼nQ«Õ éÿ$::Z«Õâ,.5\.÷]¦P(âãã—64"""š³E6{öìùkÚÔÔÔõë×}×X,–±±±ÒÒRŒïÞ½;00°˜?q¾B´0›ÍÃÃÃ?¹\¹r–Ô…€¾¾>¤kdddhhhË–-¾ bcc{{{1niikÚÚÚzzz–6ÒP…72ì~O]¾|¹ªªÊw™Ãáèîî^ÚЈˆˆhÎüÒ\ºt UÔóçÏ'''³³³½ÖX­V¬A¡€ñ›7onܸ±˜?q¾B±Éd/^<}ú´B¡Ðh4ƒƒƒ§NZ¶l™Ôq5­V‹Ú4''gåÊ•ýýýHšû¡ÈÈH1HHHÀš””Œ?^]]Z­Æ½žOå^?ãåŒ3a"}öÀ3'lˆˆˆ‚š_ü{ñÞ½{E¡<øðáZ³Ù<::ŠùwïÞ¡O˜ššš˜˜8xðàÎ;ïÝ»‡ñãÇ-Kff&\»víýû÷F£ñíÛ·wîÜÁÌ«W¯êëëí@PfŠËÒÒR\êtºææf»ÝÞÓÓsìØ±ââb<”””´oß¾óçÏwuuÅÆÆbf`` ±±ñäÉ“G Å×¾`6lY¿~=:%ÔôÈ^ù9|ø02‰äìÚµëêÕ«˜ÏËË«©©±Ùlx ħgΜ)))ÁL||Ä]Û¶m{ùòå£G0ƒ5¨þûûû3220~òäÉîÝ»ÇÇDZ2ܫՊ2kÕªUâRüßv~~>ªØÁÁAÔ¬•••ÃÃÃ111Hl\\\__ß°+Q{ádJú:–Tdd$2€´ *Å@|Ñ”W~RRRl6Ԭ蔖/_îþ ýû÷#½Ø~H/Ú™L†‡PÔb¦½½7* ô®GŽAcPVV†>Mê½ÔD?º`€w÷ÆÏž=«R©ä ûV4+V¬À‚ÞÞ^$ùçgDáæoÿÿì»K#QF£É* ¢ÆH ±’MÀ q#¨ˆˆ 66‚ˆˆµ–¾°ˆš( H¢‘øHga'ZøØØØ‹`a'Xh+({˜‹Ãlœ]XŒq~‹›ë8Þùñ;Ìd”Aøº|ˆœžžRëãñ8…žIŠ2@w¿»»;99y} P(zzzº¹¹á%¥ÿââB @,S»e¼¸¸ÈàèèˆÏ:MÚÛÛiN,¾à%@%e†êÏLkk+}7•J---% ¿K€ÎÎNjÆ!Ðé5M#™––z.—óz½ùXÞdfÀÙÈfh>088èz¹&ƒD"‘ÕÕUº/ç*½ÖÖ#¶%?tÔrËf³ä‰,%“Iâ5 ¾Êöööò³p»Ýv ‚ z Áíííææf8¾¿¿7`ll,  ÀÁÁƒ³³³ããcL`aaú¥`nnNí1ó§ -–ê9;;Ë≈jµ¶¶FÁ¥žnllTWW÷õõííí±5krr’^ÕÑÑÑÖÖæÒ ºœ'ýýýTÌææf4€Ö¾½½MP*Ç£òQÐÍŠTGGG] €ºŠb3l (à„Ç»ü~ÿüü¼²G°z@ww÷úú:±744Çc÷*Š’ÊÊJ‰NAAA¾?¿ÿÿd¤ZxÊ÷ÞIEND®B`‚golly-2.7-src/gui-ios/Golly/Golly-Prefix.pch0000644000175000017500000000047112536111364015701 00000000000000// // Prefix header for all source files of the 'Golly' target in the 'Golly' project // #import #ifndef __IPHONE_4_0 #warning "This project uses features only available in iOS SDK 4.0 and later." #endif #ifdef __OBJC__ #import #import #endif golly-2.7-src/gui-ios/Golly/pattern@2x.png0000644000175000017500000000031412536111364015415 00000000000000‰PNG  IHDR<<:üÙr“IDAThíØ1€0 ÅÐqÿ+‡‰™2$¿¹µÚ!¥º{%9þÞÀ× ¦3˜Î`:ƒé ¦‹ >§?PUÛ¯“î®É½¬xÂÓLg0ÁtqÁ•ö_z|–~kzöŽ»ÒÓLg0ÁtqÁÎÒOÞκÓëw×Þâ®´ÁtÓLg0]\pÜ,wÂÓLg0ÁtÓ]» o!üñIEND®B`‚golly-2.7-src/gui-ios/Golly/GollyAppDelegate.h0000644000175000017500000000261512536111364016221 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import @interface GollyAppDelegate : UIResponder @property (strong, nonatomic) UIWindow *window; @end // export these routines so we can switch tabs programmatically void SwitchToPatternTab(); void SwitchToOpenTab(); void SwitchToSettingsTab(); void SwitchToHelpTab(); // return tab bar's current view controller UIViewController* CurrentViewController(); // enable/disable tab bar void EnableTabBar(bool enable); golly-2.7-src/gui-ios/Golly/StatePickerController.xib0000644000175000017500000002566412536111364017665 00000000000000 1280 10K549 1938 1038.36 461.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 933 IBUISwitch IBUIView IBUILabel IBProxyObject com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 292 274 {{10, 10}, {748, 944}} 3 MC42NjY2NjY2NjY3AA IBIPadFramework 268 {{94, 966}, {94, 27}} NO IBIPadFramework 0 0 YES 268 {{10, 966}, {95, 24}} NO YES 7 NO IBIPadFramework Show icons 1 MCAwIDAAA 1 10 1 17 Helvetica 17 16 {{0, 20}, {768, 1004}} NO 2 IBIPadFramework view 5 spView 7 iconsSwitch 9 toggleIcons: 13 10 0 -1 File's Owner -2 2 6 8 11 StatePickerController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin StatePickerView com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 StatePickerController UIViewController toggleIcons: id toggleIcons: toggleIcons: id UISwitch StatePickerView iconsSwitch UISwitch spView StatePickerView IBProjectSource ./Classes/StatePickerController.h StatePickerView UIView IBProjectSource ./Classes/StatePickerView.h 0 IBIPadFramework YES 3 933 golly-2.7-src/gui-ios/Golly/InfoViewController.h0000644000175000017500000000310512536111364016624 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import // This view controller is used to display comments in the currently loaded pattern. // It can also be used (via ShowTextFile) to display the contents of a text file // and edit that text if the file is located somewhere inside Documents/*. @interface InfoViewController : UIViewController { IBOutlet UITextView *fileView; IBOutlet UIBarButtonItem *saveButton; } - (IBAction)doCancel:(id)sender; - (IBAction)doSave:(id)sender; - (void)saveSucceded:(const char*)savedpath; @end // Display the given text file. void ShowTextFile(const char* filepath, UIViewController* currentView=nil); golly-2.7-src/gui-ios/Golly/triangle-down.png0000644000175000017500000000032012536111364016135 00000000000000‰PNG  IHDRƒF(Â!tEXtSoftwareGraphicConverter (Intel)w‡újIDATxœ¬ÑK EQK·¼îª$&Uý<ôåä¢qÑZ%DDÛ<™P~5$*ÈaùF?9GÅ9¬~í9GC^Tš£!/*U èŒBr èŒB’Q`Ž É(Pq¡eáJÝnÿÿIyã•–9h‡IEND®B`‚golly-2.7-src/gui-ios/Golly/PatternViewController.xib0000644000175000017500000021730512536111364017712 00000000000000 1280 10K549 1938 1038.36 461.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 933 IBUIView IBUIBarButtonItem IBProxyObject IBUIToolbar IBUILabel IBUIProgressView IBUISegmentedControl IBUIButton com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 274 295 292 {{53, 7}, {70, 30}} NO IBIPadFramework 0 0 1 START 3 MQA 1 MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 3 MC41AA 2 15 Helvetica-Bold 15 16 292 {{247, 7}, {163, 30}} NO IBIPadFramework 2 3 0 Slower Step=1 Faster {0, 0} {0, 0} {0, 0} YES 292 {{501, 7}, {192, 30}} NO IBIPadFramework 2 3 0 Smaller Scale=1:1 Bigger {0, 0} {0, 0} {0, 0} YES {768, 44} NO NO IBIPadFramework IBIPadFramework 1 19 IBIPadFramework Next IBIPadFramework 1 Step IBIPadFramework 1 IBIPadFramework IBIPadFramework 5 Fit IBIPadFramework 1 IBIPadFramework Middle IBIPadFramework 1 295 {{0, 44}, {768, 63}} 3 MQA 2 NO 3 IBIPadFramework 311 265 {{677, 767}, {81, 30}} NO 0.69999998807907104 IBIPadFramework 0 0 1 Restore 1 MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA {{0, 151}, {768, 807}} NO IBIPadFramework 295 292 292 {{0, 5}, {65, 21}} NO YES 7 NO IBIPadFramework State=255 3 MC4zMzMzMzMzMzMzAA 1 10 2 2 13 Helvetica-Bold 13 16 {{416, 6}, {66, 32}} 3 MCAwAA NO NO NO IBIPadFramework 296 {{492, 6}, {33, 33}} IBIPadFramework 292 {{545, 8}, {216, 30}} NO IBIPadFramework 2 4 0 Draw Pick Select Move {0, 0} {0, 0} {0, 0} {0, 0} {{0, 107}, {768, 44}} NO NO IBIPadFramework IBIPadFramework 1 21 IBIPadFramework 1 22 IBIPadFramework 5 All IBIPadFramework 1 IBIPadFramework 1 9 Paste IBIPadFramework 1 IBIPadFramework 5 IBIPadFramework IBIPadFramework IBIPadFramework 10 6 IBIPadFramework 266 {{0, 960}, {768, 44}} NO NO IBIPadFramework New IBIPadFramework 50 1 IBIPadFramework 5 Rule IBIPadFramework 50 1 IBIPadFramework 40 6 Info IBIPadFramework 50 1 IBIPadFramework 40 6 IBIPadFramework 1 3 IBIPadFramework 5 Full Screen IBIPadFramework 1 301 292 {{20, 20}, {344, 21}} NO YES 7 NO IBIPadFramework Title 1 MCAwIDAAA 1 10 1 1 17 Helvetica 17 16 292 {{20, 49}, {344, 21}} NO YES 7 NO IBIPadFramework Estimated time remaining 1 10 1 1 14 Helvetica 14 16 292 {{20, 94}, {344, 9}} NO IBIPadFramework 0.5 292 {{155, 140}, {74, 37}} NO IBIPadFramework 0 0 1 Cancel 1 MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA {{192, 404}, {384, 197}} 3 MC42NjY2NjY2NjY3AA IBIPadFramework {{0, 20}, {768, 1004}} 3 MQA 2 IBIPadFramework view 12 pattView 13 statView 22 stepControl 51 scaleControl 52 startStopButton 55 modeControl 138 stateLabel 139 stateView 143 redoButton 156 undoButton 157 resetButton 160 restoreButton 192 topBar 200 editBar 201 bottomBar 202 actionButton 205 infoButton 213 cancelButton 222 progressBar 223 progressMessage 224 progressTitle 225 progressView 226 doStartStop: 7 45 doChangeStep: 13 49 doChangeScale: 13 54 doChangeMode: 13 141 doUndo: 152 doRedo: 154 doReset: 159 doNext: 163 doStep: 164 doFit: 166 doMiddle: 168 doSelectAll: 171 doPaste: 176 doNew: 182 doSave: 184 toggleFullScreen: 193 toggleFullScreen: 7 191 doAction: 204 doRule: 208 doInfo: 212 doCancel: 7 227 0 -1 File's Owner -2 2 5 10 17 16 19 21 41 40 42 43 106 114 112 120 119 127 129 132 131 133 150 151 158 161 162 165 167 169 175 178 179 181 187 188 189 203 206 207 209 210 211 214 217 218 219 221 220 PatternViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin PatternView com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin StateView com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin StatusView com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 227 PatternView UIView IBProjectSource ./Classes/PatternView.h PatternViewController UIViewController id id id id id id id id id id id id id id id id id id id id doAction: id doCancel: id doChangeMode: id doChangeScale: id doChangeStep: id doFit: id doInfo: id doMiddle: id doNew: id doNext: id doPaste: id doRedo: id doReset: id doRule: id doSave: id doSelectAll: id doStartStop: id doStep: id doUndo: id toggleFullScreen: id UIBarButtonItem UIToolbar UIButton UIToolbar UIBarButtonItem UISegmentedControl PatternView UIProgressView UILabel UILabel UIView UIBarButtonItem UIBarButtonItem UIButton UISegmentedControl UIButton StatusView UILabel StateView UISegmentedControl UIToolbar UIBarButtonItem actionButton UIBarButtonItem bottomBar UIToolbar cancelButton UIButton editBar UIToolbar infoButton UIBarButtonItem modeControl UISegmentedControl pattView PatternView progressBar UIProgressView progressMessage UILabel progressTitle UILabel progressView UIView redoButton UIBarButtonItem resetButton UIBarButtonItem restoreButton UIButton scaleControl UISegmentedControl startStopButton UIButton statView StatusView stateLabel UILabel stateView StateView stepControl UISegmentedControl topBar UIToolbar undoButton UIBarButtonItem IBProjectSource ./Classes/PatternViewController.h StateView UIView IBProjectSource ./Classes/StateView.h StatusView UIView IBProjectSource ./Classes/StatusView.h 0 IBIPadFramework YES 3 933 golly-2.7-src/gui-ios/Golly/PatternViewController.m0000644000175000017500000007317312536111364017367 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "viewport.h" // for MAX_MAG #include "utils.h" // for Warning, event_checker #include "status.h" // for SetMessage, DisplayMessage #include "algos.h" // for InitAlgorithms, algoinfo #include "prefs.h" // for GetPrefs, SavePrefs, userdir, etc #include "layer.h" // for AddLayer, currlayer #include "file.h" // for NewPattern #include "control.h" // for generating, StartGenerating, etc #include "view.h" // for nopattupdate, SmallScroll #include "undo.h" // for currlayer->undoredo->... #import "GollyAppDelegate.h" // for EnableTabBar #import "InfoViewController.h" #import "SaveViewController.h" #import "RuleViewController.h" #import "PatternViewController.h" @implementation PatternViewController // ----------------------------------------------------------------------------- // global stuff needed in UpdatePattern, UpdateStatus, etc static PatternViewController *globalController = nil; static PatternView *globalPatternView = nil; static StatusView *globalStatusView = nil; static StateView *globalStateView = nil; static UIView *globalProgress = nil; static UILabel *globalTitle = nil; static bool cancelProgress = false; // cancel progress dialog? static double progstart, prognext; // for progress timing static int progresscount = 0; // if > 0 then BeginProgress has been called static int pausecount = 0; // if > 0 then genTimer needs to be restarted // ----------------------------------------------------------------------------- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"Pattern"; self.tabBarItem.image = [UIImage imageNamed:@"pattern.png"]; } return self; } // ----------------------------------------------------------------------------- - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // free up as much memory as possible if (numlayers > 0) DeleteOtherLayers(); if (waitingforpaste) AbortPaste(); [self doNew:self]; // Warning hangs if called here, so use DisplayMessage for now!!! // (may need non-modal version via extra flag???) // Warning("Memory warning occurred, so empty universe created."); DisplayMessage("Memory warning occurred, so empty universe created."); } // ----------------------------------------------------------------------------- static void CreateDocSubdir(NSString *subdirname) { // create given subdirectory inside Documents NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:subdirname]; if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { // do nothing if subdir already exists } else { NSError *error; if (![[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:&error]) { NSLog(@"Error creating %@ subdirectory: %@", subdirname, error); } } } // ----------------------------------------------------------------------------- static void InitPaths() { // init userdir to directory containing Golly.app userdir = [NSHomeDirectory() cStringUsingEncoding:NSUTF8StringEncoding]; userdir += "/"; // init savedir to userdir/Documents/Saved/ savedir = userdir + "Documents/Saved/"; CreateDocSubdir(@"Saved"); // init downloaddir to userdir/Documents/Downloads/ downloaddir = userdir + "Documents/Downloads/"; CreateDocSubdir(@"Downloads"); // init userrules to userdir/Documents/Rules/ userrules = userdir + "Documents/Rules/"; CreateDocSubdir(@"Rules"); // supplied patterns, rules, help are bundled inside Golly.app supplieddir = userdir + "Golly.app/"; patternsdir = supplieddir + "Patterns/"; rulesdir = supplieddir + "Rules/"; helpdir = supplieddir + "Help/"; // init tempdir to userdir/tmp/ tempdir = userdir + "tmp/"; // init path to file that stores clipboard data clipfile = tempdir + "golly_clipboard"; // init path to file that stores user preferences prefsfile = userdir + "Library/Preferences/GollyPrefs"; /* NSLog(@"userdir = %s", userdir.c_str()); NSLog(@"savedir = %s", savedir.c_str()); NSLog(@"downloaddir = %s", downloaddir.c_str()); NSLog(@"userrules = %s", userrules.c_str()); NSLog(@"supplieddir = %s", supplieddir.c_str()); NSLog(@"patternsdir = %s", patternsdir.c_str()); NSLog(@"rulesdir = %s", rulesdir.c_str()); NSLog(@"helpdir = %s", helpdir.c_str()); NSLog(@"tempdir = %s", tempdir.c_str()); NSLog(@"clipfile = %s", clipfile.c_str()); NSLog(@"prefsfile = %s", prefsfile.c_str()); */ } // ----------------------------------------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; // now do additional setup after loading the view from the xib file // init global pointers globalController = self; globalPatternView = pattView; globalStatusView = statView; globalStateView = stateView; globalProgress = progressView; globalTitle = progressTitle; static bool firstload = true; if (firstload) { firstload = false; // only do the following once SetMessage("This is Golly 1.2 for iOS. Copyright 2013 The Golly Gang."); MAX_MAG = 5; // maximum cell size = 32x32 InitAlgorithms(); // must initialize algoinfo first InitPaths(); // init userdir, etc (must be before GetPrefs) GetPrefs(); // load user's preferences SetMinimumStepExponent(); // for slowest speed AddLayer(); // create initial layer (sets currlayer) NewPattern(); // create new, empty universe } // ensure pattView is composited underneath toolbar, otherwise // bottom toolbar can be obscured when device is rotated left/right // (no longer needed) // [[pattView layer] setZPosition:-1]; // we draw background areas of pattView and statView so set to transparent (presumably a tad faster) [pattView setBackgroundColor:nil]; [statView setBackgroundColor:nil]; progressView.hidden = YES; genTimer = nil; // init buttons [self toggleStartStopButton]; resetButton.enabled = NO; undoButton.enabled = NO; redoButton.enabled = NO; actionButton.enabled = NO; infoButton.enabled = NO; restoreButton.hidden = YES; // deselect step/scale controls (these have Momentary attribute set) [stepControl setSelectedSegmentIndex:-1]; [scaleControl setSelectedSegmentIndex:-1]; // init touch mode [modeControl setSelectedSegmentIndex:currlayer->touchmode]; [self updateDrawingState]; } // ----------------------------------------------------------------------------- - (void)viewDidUnload { [super viewDidUnload]; SavePrefs(); // release all outlets pattView = nil; statView = nil; startStopButton = nil; restoreButton = nil; resetButton = nil; undoButton = nil; redoButton = nil; actionButton = nil; infoButton = nil; stepControl = nil; scaleControl = nil; modeControl = nil; stateLabel = nil; stateView = nil; topBar = nil; editBar = nil; bottomBar = nil; progressView = nil; progressTitle = nil; progressMessage = nil; progressBar = nil; cancelButton = nil; } // ----------------------------------------------------------------------------- - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; SetMessage(""); // stop generating, but only if PauseGenTimer() hasn't been called if (pausecount == 0) [self stopIfGenerating]; } // ----------------------------------------------------------------------------- - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; UpdateEverything(); // calls [pattView refreshPattern] // restart genTimer if PauseGenTimer() was called earlier if (pausecount > 0) RestartGenTimer(); } // ----------------------------------------------------------------------------- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // return YES for supported orientations return YES; } // ----------------------------------------------------------------------------- - (void)updateDrawingState; { // reset drawing state if it's no longer valid (due to algo/rule change) if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) { currlayer->drawingstate = 1; } [stateLabel setText:[NSString stringWithFormat:@"State=%d", currlayer->drawingstate]]; [stateView setNeedsDisplay]; } // ----------------------------------------------------------------------------- - (void)updateButtons { resetButton.enabled = currlayer->algo->getGeneration() > currlayer->startgen; undoButton.enabled = currlayer->undoredo->CanUndo(); redoButton.enabled = currlayer->undoredo->CanRedo(); actionButton.enabled = SelectionExists(); infoButton.enabled = currlayer->currname != "untitled"; [modeControl setSelectedSegmentIndex:currlayer->touchmode]; } // ----------------------------------------------------------------------------- - (void)toggleStartStopButton { if (generating) { [startStopButton setTitle:@"STOP" forState:UIControlStateNormal]; [startStopButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; } else { [startStopButton setTitle:@"START" forState:UIControlStateNormal]; [startStopButton setTitleColor:[UIColor colorWithRed:0.2 green:0.7 blue:0.0 alpha:1.0] forState:UIControlStateNormal]; } } // ----------------------------------------------------------------------------- - (void)stopIfGenerating { if (generating) { [self stopGenTimer]; StopGenerating(); // generating now false [self toggleStartStopButton]; } } // ----------------------------------------------------------------------------- - (IBAction)doNew:(id)sender { // undo/redo history is about to be cleared so no point calling RememberGenFinish // if we're generating a (possibly large) pattern bool saveundo = allowundo; allowundo = false; [self stopIfGenerating]; allowundo = saveundo; if (event_checker > 0) { // try again after a short delay that gives time for NextGeneration() to terminate [self performSelector:@selector(doNew:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); NewPattern(); [modeControl setSelectedSegmentIndex:currlayer->touchmode]; [self updateDrawingState]; [self updateButtons]; [statView setNeedsDisplay]; [pattView refreshPattern]; } // ----------------------------------------------------------------------------- - (IBAction)doInfo:(id)sender { // if generating then just pause the timer so doGeneration won't be called; // best not to call PauseGenerating() because it calls StopGenerating() // which might result in a lengthy file save for undo/redo PauseGenTimer(); ClearMessage(); // display contents of current pattern file in a modal view InfoViewController *modalInfoController = [[InfoViewController alloc] initWithNibName:nil bundle:nil]; [modalInfoController setModalPresentationStyle:UIModalPresentationFullScreen]; [self presentModalViewController:modalInfoController animated:YES]; modalInfoController = nil; // RestartGenTimer() will be called in viewDidAppear } // ----------------------------------------------------------------------------- - (IBAction)doSave:(id)sender { [self stopIfGenerating]; if (event_checker > 0) { // try again after a short delay [self performSelector:@selector(doSave:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); // let user save current pattern in a file via a modal view SaveViewController *modalSaveController = [[SaveViewController alloc] initWithNibName:nil bundle:nil]; [modalSaveController setModalPresentationStyle:UIModalPresentationFormSheet]; [self presentModalViewController:modalSaveController animated:YES]; modalSaveController = nil; } // ----------------------------------------------------------------------------- - (IBAction)doUndo:(id)sender { [self stopIfGenerating]; if (event_checker > 0) { // try again after a short delay [self performSelector:@selector(doUndo:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); currlayer->undoredo->UndoChange(); UpdateEverything(); } // ----------------------------------------------------------------------------- - (IBAction)doRedo:(id)sender { [self stopIfGenerating]; if (event_checker > 0) { // try again after a short delay [self performSelector:@selector(doRedo:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); currlayer->undoredo->RedoChange(); UpdateEverything(); } // ----------------------------------------------------------------------------- - (IBAction)doReset:(id)sender { [self stopIfGenerating]; if (event_checker > 0) { // try again after a short delay [self performSelector:@selector(doReset:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); ResetPattern(); UpdateEverything(); } // ----------------------------------------------------------------------------- - (IBAction)doStartStop:(id)sender { ClearMessage(); if (generating) { [self stopGenTimer]; StopGenerating(); // generating is now false [self toggleStartStopButton]; // can't call [self updateButtons] here because if event_checker is > 0 // then StopGenerating hasn't called RememberGenFinish, and so CanUndo/CanRedo // might not return correct results bool canreset = currlayer->algo->getGeneration() > currlayer->startgen; resetButton.enabled = canreset; undoButton.enabled = allowundo && (canreset || currlayer->undoredo->CanUndo()); redoButton.enabled = NO; } else if (StartGenerating()) { // generating is now true [self toggleStartStopButton]; [self startGenTimer]; // don't call [self updateButtons] here because we want user to // be able to stop generating by tapping Reset/Undo buttons resetButton.enabled = YES; undoButton.enabled = allowundo; redoButton.enabled = NO; } pausecount = 0; // play safe } // ----------------------------------------------------------------------------- - (void)startGenTimer { float interval = 1.0f/60.0f; // increase interval if user wants a delay if (currlayer->currexpo < 0) { interval = GetCurrentDelay() / 1000.0f; } // create a repeating timer genTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(doGeneration:) userInfo:nil repeats:YES]; } // ----------------------------------------------------------------------------- - (void)stopGenTimer { [genTimer invalidate]; genTimer = nil; } // ----------------------------------------------------------------------------- // called after genTimer fires - (void)doGeneration:(NSTimer*)timer { if (event_checker > 0 || progresscount > 0) return; // advance by current step size NextGeneration(true); [statView setNeedsDisplay]; [pattView refreshPattern]; } // ----------------------------------------------------------------------------- - (IBAction)doNext:(id)sender { [self stopIfGenerating]; if (event_checker > 0) { // try again after a short delay [self performSelector:@selector(doNext:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); NextGeneration(false); [statView setNeedsDisplay]; [pattView refreshPattern]; [self updateButtons]; } // ----------------------------------------------------------------------------- - (IBAction)doStep:(id)sender { [self stopIfGenerating]; if (event_checker > 0) { // try again after a short delay [self performSelector:@selector(doStep:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); NextGeneration(true); [statView setNeedsDisplay]; [pattView refreshPattern]; [self updateButtons]; } // ----------------------------------------------------------------------------- - (IBAction)doFit:(id)sender { ClearMessage(); FitInView(1); [statView setNeedsDisplay]; [pattView refreshPattern]; } // ----------------------------------------------------------------------------- - (IBAction)doChangeStep:(id)sender { ClearMessage(); switch([sender selectedSegmentIndex]) { case 0: { // go slower by decrementing step exponent if (currlayer->currexpo > minexpo) { currlayer->currexpo--; SetGenIncrement(); if (generating && currlayer->currexpo < 0) { // increase timer interval [self stopGenTimer]; [self startGenTimer]; } } else { Beep(); } } break; case 1: { // reset step exponent to 0 currlayer->currexpo = 0; SetGenIncrement(); if (generating) { // reset timer interval to max speed [self stopGenTimer]; [self startGenTimer]; } } break; case 2: { // go faster by incrementing step exponent currlayer->currexpo++; SetGenIncrement(); if (generating && currlayer->currexpo <= 0) { // reduce timer interval [self stopGenTimer]; [self startGenTimer]; } } break; } // only need to update status info [statView setNeedsDisplay]; } // ----------------------------------------------------------------------------- - (IBAction)doChangeScale:(id)sender { ClearMessage(); switch([sender selectedSegmentIndex]) { case 0: { // zoom out currlayer->view->unzoom(); [statView setNeedsDisplay]; [pattView refreshPattern]; } break; case 1: { // set scale to 1:1 if (currlayer->view->getmag() != 0) { currlayer->view->setmag(0); [statView setNeedsDisplay]; [pattView refreshPattern]; } } break; case 2: { // zoom in if (currlayer->view->getmag() < MAX_MAG) { currlayer->view->zoom(); [statView setNeedsDisplay]; [pattView refreshPattern]; } else { Beep(); } } break; } } // ----------------------------------------------------------------------------- - (IBAction)doChangeMode:(id)sender { ClearMessage(); switch([sender selectedSegmentIndex]) { case 0: currlayer->touchmode = drawmode; break; case 1: currlayer->touchmode = pickmode; break; case 2: currlayer->touchmode = selectmode; break; case 3: currlayer->touchmode = movemode; break; } } // ----------------------------------------------------------------------------- - (IBAction)doMiddle:(id)sender { ClearMessage(); if (currlayer->originx == bigint::zero && currlayer->originy == bigint::zero) { currlayer->view->center(); } else { // put cell saved by ChangeOrigin (not yet implemented!!!) in middle currlayer->view->setpositionmag(currlayer->originx, currlayer->originy, currlayer->view->getmag()); } [statView setNeedsDisplay]; [pattView refreshPattern]; } // ----------------------------------------------------------------------------- - (IBAction)doSelectAll:(id)sender { ClearMessage(); SelectAll(); } // ----------------------------------------------------------------------------- - (IBAction)doAction:(id)sender { ClearMessage(); [pattView doSelectionAction]; } // ----------------------------------------------------------------------------- - (IBAction)doPaste:(id)sender { [self stopIfGenerating]; if (event_checker > 0) { // try again after a short delay [self performSelector:@selector(doPaste:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); if (waitingforpaste) { [pattView doPasteAction]; } else { PasteClipboard(); [pattView refreshPattern]; } } // ----------------------------------------------------------------------------- - (IBAction)doRule:(id)sender { [self stopIfGenerating]; if (event_checker > 0) { // try again after a short delay [self performSelector:@selector(doRule:) withObject:sender afterDelay:0.01]; return; } ClearMessage(); // let user change current algo/rule in a modal view RuleViewController *modalRuleController = [[RuleViewController alloc] initWithNibName:nil bundle:nil]; [modalRuleController setModalPresentationStyle:UIModalPresentationFullScreen]; [self presentModalViewController:modalRuleController animated:YES]; modalRuleController = nil; } // ----------------------------------------------------------------------------- - (IBAction)toggleFullScreen:(id)sender { if (fullscreen) { topBar.hidden = NO; editBar.hidden = NO; bottomBar.hidden = NO; statView.hidden = NO; // recalculate pattView's frame from scratch (in case device was rotated) CGFloat barht = topBar.bounds.size.height; CGFloat topht = barht * 2 + statView.bounds.size.height; CGFloat x = pattView.superview.frame.origin.x; CGFloat y = pattView.superview.frame.origin.y + topht; CGFloat wd = pattView.superview.frame.size.width; CGFloat ht = pattView.superview.frame.size.height - (topht + barht); pattView.frame = CGRectMake(x, y, wd, ht); [statView setNeedsDisplay]; } else { topBar.hidden = YES; editBar.hidden = YES; bottomBar.hidden = YES; statView.hidden = YES; pattView.frame = pattView.superview.frame; } fullscreen = !fullscreen; restoreButton.hidden = !fullscreen; [pattView refreshPattern]; UpdateEditBar(); } // ----------------------------------------------------------------------------- - (IBAction)doCancel:(id)sender { cancelProgress = true; } // ----------------------------------------------------------------------------- - (void)enableInteraction:(BOOL)enable { topBar.userInteractionEnabled = enable; editBar.userInteractionEnabled = enable; bottomBar.userInteractionEnabled = enable; pattView.userInteractionEnabled = enable; EnableTabBar(enable); } // ----------------------------------------------------------------------------- - (void)updateProgressBar:(float)fraction { progressBar.progress = fraction; // show estimate of time remaining double elapsecs = TimeInSeconds() - progstart; double remsecs = fraction > 0.0 ? (elapsecs / fraction) - elapsecs : 999.0; [progressMessage setText:[NSString stringWithFormat:@"Estimated time remaining (in secs): %d", int(remsecs+0.5)]]; // need following to see progress view and bar update event_checker++; [[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]]; event_checker--; } @end // ============================================================================= // global routines used by external code: void UpdatePattern() { [globalPatternView refreshPattern]; } // ----------------------------------------------------------------------------- void UpdateStatus() { if (inscript || currlayer->undoredo->doingscriptchanges) return; if (!fullscreen) { [globalStatusView setNeedsDisplay]; } } // ----------------------------------------------------------------------------- void UpdateEditBar() { if (!fullscreen) { [globalController updateButtons]; [globalController updateDrawingState]; } } // ----------------------------------------------------------------------------- void CloseStatePicker() { [globalStateView dismissStatePopover]; } // ----------------------------------------------------------------------------- void PauseGenTimer() { if (generating) { // use pausecount to handle nested calls if (pausecount == 0) [globalController stopGenTimer]; pausecount++; } } // ----------------------------------------------------------------------------- void RestartGenTimer() { if (pausecount > 0) { pausecount--; if (pausecount == 0) [globalController startGenTimer]; } } // ----------------------------------------------------------------------------- static bool wasgenerating = false; // generating needs to be resumed? void PauseGenerating() { if (generating) { // stop generating without changing STOP button [globalController stopGenTimer]; StopGenerating(); // generating now false wasgenerating = true; } } // ----------------------------------------------------------------------------- void ResumeGenerating() { if (wasgenerating) { // generating should be false but play safe if (!generating) { if (StartGenerating()) { // generating now true [globalController startGenTimer]; } else { // this can happen if pattern is empty [globalController toggleStartStopButton]; [globalController updateButtons]; } } wasgenerating = false; } } // ----------------------------------------------------------------------------- void StopIfGenerating() { [globalController stopIfGenerating]; } // ----------------------------------------------------------------------------- void BeginProgress(const char* title) { if (progresscount == 0) { // disable interaction with all views but don't show progress view just yet [globalController enableInteraction:NO]; [globalTitle setText:[NSString stringWithCString:title encoding:NSUTF8StringEncoding]]; cancelProgress = false; progstart = TimeInSeconds(); } progresscount++; // handles nested calls } // ----------------------------------------------------------------------------- bool AbortProgress(double fraction_done, const char* message) { if (progresscount <= 0) Fatal("Bug detected in AbortProgress!"); double secs = TimeInSeconds() - progstart; if (!globalProgress.hidden) { if (secs < prognext) return false; prognext = secs + 0.1; // update progress bar about 10 times per sec if (fraction_done < 0.0) { // show indeterminate progress gauge??? } else { [globalController updateProgressBar:fraction_done]; } return cancelProgress; } else { // note that fraction_done is not always an accurate estimator for how long // the task will take, especially when we use nextcell for cut/copy if ( (secs > 1.0 && fraction_done < 0.3) || secs > 2.0 ) { // task is probably going to take a while so show progress view globalProgress.hidden = NO; [globalController updateProgressBar:fraction_done]; } prognext = secs + 0.01; // short delay until 1st progress update } return false; } // ----------------------------------------------------------------------------- void EndProgress() { if (progresscount <= 0) Fatal("Bug detected in EndProgress!"); progresscount--; if (progresscount == 0) { // hide the progress view and enable interaction with other views globalProgress.hidden = YES; [globalController enableInteraction:YES]; } } golly-2.7-src/gui-ios/Golly/StatePickerController.h0000644000175000017500000000220612536111364017315 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import #import "StatePickerView.h" @interface StatePickerController : UIViewController { IBOutlet StatePickerView *spView; IBOutlet UISwitch *iconsSwitch; } - (IBAction)toggleIcons:(id)sender; @end golly-2.7-src/gui-ios/Golly/StateView.h0000644000175000017500000000263112536111364014750 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "algos.h" // for gBitmapPtr @interface StateView : UIView { UIPopoverController *statePopover; } // close statePopover when user clicks on a drawing state - (void)dismissStatePopover; @end void DrawOneIcon(CGContextRef context, int x, int y, gBitmapPtr icon, unsigned char deadr, unsigned char deadg, unsigned char deadb, unsigned char liver, unsigned char liveg, unsigned char liveb); golly-2.7-src/gui-ios/Golly/SaveViewController.h0000644000175000017500000000324712536111364016636 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import #import "InfoViewController.h" // This view controller creates a modal dialog that appears // when the user taps the Pattern tab's Save button. // It is also used (via SaveTextFile) to save a text file // when the user is editing a pattern file or .rule file. @interface SaveViewController : UIViewController { IBOutlet UITextField *nameText; IBOutlet UITableView *typeTable; IBOutlet UILabel *topLabel; IBOutlet UILabel *botLabel; } - (IBAction)doCancel:(id)sender; - (IBAction)doSave:(id)sender; @end // Ask user to save given text file currently being edited. void SaveTextFile(const char* filepath, const char* contents, InfoViewController* currentView); golly-2.7-src/gui-ios/Golly/open.png0000644000175000017500000000036012536111364014330 00000000000000‰PNG  IHDR;0®¢·IDATH‰í–Q ƒ0ç•©_Åkô”½†ø£wÚþXHKâÓ&i]ø@vQ“D‹\šPOð!ÀWï3‹{I–nÖØRïqªéÖ¤Ììw!?OPF}X`êÁ̹Ðï¬÷@WŒ¤èŒóõ8Ï9k Ÿï5~k¾è8„ƒ.©¹ÿ˜TWÓì©®¦–U×Óì€î “¤çpG%͸D[ˆh††ŸÅ$¸vŽ÷³w‚ÿ–7Ö•/”…IEND®B`‚golly-2.7-src/gui-ios/Golly/OpenViewController.h0000644000175000017500000000267212536111364016642 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import // This is the view controller for the Open tab. @interface OpenViewController : UIViewController { IBOutlet UITableView *optionTable; IBOutlet UIWebView *htmlView; } @end // if any files exist in the Documents folder (created by iTunes file sharing) // then move them into Documents/Rules/ if their names end with // .rule/tree/table, otherwise assume they are patterns // and move them into Documents/Saved/ void MoveSharedFiles(); golly-2.7-src/gui-ios/Golly/SettingsViewController.m0000644000175000017500000002304512536111364017543 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "utils.h" // for Beep #include "status.h" // for ClearMessage #include "prefs.h" // for SavePrefs, showgridlines, etc #include "layer.h" // for InvertCellColors #include "undo.h" // for currlayer->undoredo->... #include "control.h" // for generating #import "SettingsViewController.h" @implementation SettingsViewController // ----------------------------------------------------------------------------- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"Settings"; self.tabBarItem.image = [UIImage imageNamed:@"settings.png"]; } return self; } // ----------------------------------------------------------------------------- - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } // ----------------------------------------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. } // ----------------------------------------------------------------------------- - (void)viewDidUnload { [super viewDidUnload]; // release outlets modeButton = nil; percentageText = nil; memoryText = nil; percentageSlider = nil; memorySlider = nil; gridSwitch = nil; timingSwitch = nil; beepSwitch = nil; colorsSwitch = nil; iconsSwitch = nil; undoSwitch = nil; hashingSwitch = nil; } // ----------------------------------------------------------------------------- static bool oldcolors; // detect if user changed swapcolors static bool oldundo; // detect if user changed allowundo static bool oldhashinfo; // detect if user changed currlayer->showhashinfo static int oldhashmem; // detect if user changed maxhashmem - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // make sure various controls agree with current settings: [modeButton setTitle:[NSString stringWithCString:GetPasteMode() encoding:NSUTF8StringEncoding] forState:UIControlStateNormal]; [percentageText setText:[NSString stringWithFormat:@"%d", randomfill]]; percentageSlider.minimumValue = 1; percentageSlider.maximumValue = 100; percentageSlider.value = randomfill; [memoryText setText:[NSString stringWithFormat:@"%d", maxhashmem]]; memorySlider.minimumValue = MIN_MEM_MB; memorySlider.maximumValue = MAX_MEM_MB; memorySlider.value = maxhashmem; [gridSwitch setOn:showgridlines animated:NO]; [timingSwitch setOn:showtiming animated:NO]; [beepSwitch setOn:allowbeep animated:NO]; [colorsSwitch setOn:swapcolors animated:NO]; [iconsSwitch setOn:showicons animated:NO]; [undoSwitch setOn:allowundo animated:NO]; [hashingSwitch setOn:currlayer->showhashinfo animated:NO]; oldcolors = swapcolors; oldundo = allowundo; oldhashmem = maxhashmem; oldhashinfo = currlayer->showhashinfo; } // ----------------------------------------------------------------------------- - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if (swapcolors != oldcolors) InvertCellColors(); if (allowundo != oldundo) { if (allowundo) { if (currlayer->algo->getGeneration() > currlayer->startgen) { // undo list is empty but user can Reset, so add a generating change // to undo list so user can Undo or Reset (and then Redo if they wish) currlayer->undoredo->AddGenChange(); } } else { currlayer->undoredo->ClearUndoRedo(); } } if (currlayer->showhashinfo != oldhashinfo) { // we only show hashing info while generating if (generating) lifealgo::setVerbose(currlayer->showhashinfo); } // need to call setMaxMemory if maxhashmem changed if (maxhashmem != oldhashmem) { for (int i = 0; i < numlayers; i++) { Layer* layer = GetLayer(i); if (algoinfo[layer->algtype]->canhash) { layer->algo->setMaxMemory(maxhashmem); } // non-hashing algos (QuickLife) use their default memory setting } } // this is a good place to save the current settings SavePrefs(); } // ----------------------------------------------------------------------------- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // return YES for supported orientations return YES; } // ----------------------------------------------------------------------------- - (IBAction)changePasteMode:(id)sender { UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles: @"AND", @"COPY", @"OR", @"XOR", nil]; [sheet showFromRect:modeButton.frame inView:modeButton.superview animated:NO]; } // ----------------------------------------------------------------------------- - (void)actionSheet:(UIActionSheet *)sheet didDismissWithButtonIndex:(NSInteger)buttonIndex { // called when the user selects an option from UIActionSheet created in changePasteMode switch (buttonIndex) { case 0: [modeButton setTitle:@"AND" forState:UIControlStateNormal]; pmode = And; break; case 1: [modeButton setTitle:@"COPY" forState:UIControlStateNormal]; pmode = Copy; break; case 2: [modeButton setTitle:@"OR" forState:UIControlStateNormal]; pmode = Or; break; case 3: [modeButton setTitle:@"XOR" forState:UIControlStateNormal]; pmode = Xor; break; default: break; } } // ----------------------------------------------------------------------------- - (IBAction)changePercentage:(id)sender { randomfill = (int)percentageSlider.value; [percentageText setText:[NSString stringWithFormat:@"%d", randomfill]]; } // ----------------------------------------------------------------------------- - (IBAction)changeMemory:(id)sender { maxhashmem = (int)memorySlider.value; [memoryText setText:[NSString stringWithFormat:@"%d", maxhashmem]]; } // ----------------------------------------------------------------------------- - (IBAction)toggleGrid:(id)sender { showgridlines = !showgridlines; } // ----------------------------------------------------------------------------- - (IBAction)toggleTiming:(id)sender { showtiming = !showtiming; } // ----------------------------------------------------------------------------- - (IBAction)toggleBeep:(id)sender { allowbeep = !allowbeep; } // ----------------------------------------------------------------------------- - (IBAction)toggleColors:(id)sender { swapcolors = !swapcolors; } // ----------------------------------------------------------------------------- - (IBAction)toggleIcons:(id)sender { showicons = !showicons; } // ----------------------------------------------------------------------------- - (IBAction)toggleUndo:(id)sender { allowundo = !allowundo; } // ----------------------------------------------------------------------------- - (IBAction)toggleHashing:(id)sender { currlayer->showhashinfo = !currlayer->showhashinfo; } // ----------------------------------------------------------------------------- // UITextFieldDelegate methods: - (void)textFieldDidEndEditing:(UITextField *)tf { // called when editing has ended (ie. keyboard disappears) if (tf == percentageText) { if (tf.text.length > 0) { randomfill = [tf.text integerValue]; if (randomfill < 1) randomfill = 1; if (randomfill > 100) randomfill = 100; } [percentageText setText:[NSString stringWithFormat:@"%d", randomfill]]; percentageSlider.value = randomfill; } else if (tf == memoryText) { if (tf.text.length > 0) { maxhashmem = [tf.text integerValue]; if (maxhashmem < MIN_MEM_MB) maxhashmem = MIN_MEM_MB; if (maxhashmem > MAX_MEM_MB) maxhashmem = MAX_MEM_MB; } [memoryText setText:[NSString stringWithFormat:@"%d", maxhashmem]]; memorySlider.value = maxhashmem; } } - (BOOL)textFieldShouldReturn:(UITextField *)tf { // called when user hits Done button, so remove keyboard // (note that textFieldDidEndEditing will then be called) [tf resignFirstResponder]; return YES; } // ----------------------------------------------------------------------------- @end golly-2.7-src/gui-ios/Golly/RuleViewController.h0000644000175000017500000000316712536111364016650 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import // This view controller is used when the Pattern tab's Rule button is tapped. @interface RuleViewController : UIViewController { IBOutlet UIButton *algoButton; IBOutlet UITextField *ruleText; IBOutlet UILabel *unknownLabel; IBOutlet UIPickerView *rulePicker; IBOutlet UIWebView *htmlView; } - (IBAction)changeAlgorithm:(id)sender; - (IBAction)cancelRuleChange:(id)sender; - (IBAction)doRuleChange:(id)sender; @end std::string GetRuleName(const std::string& rule); golly-2.7-src/gui-ios/Golly/en.lproj/0000755000175000017500000000000012536111546014473 500000000000000golly-2.7-src/gui-ios/Golly/en.lproj/InfoPlist.strings0000644000175000017500000000005512536111364017733 00000000000000/* Localized versions of Info.plist keys */ golly-2.7-src/gui-ios/Golly/InfoViewController.m0000644000175000017500000001755012536111364016642 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "readpattern.h" // for readcomments #include "layer.h" // for currlayer, etc #include "prefs.h" // for userdir #import "GollyAppDelegate.h" // for CurrentViewController #import "SaveViewController.h" // for SaveTextFile #import "InfoViewController.h" @implementation InfoViewController // ----------------------------------------------------------------------------- static std::string textfile = ""; // set in ShowTextFile static bool textchanged = false; // true if user changed text // ----------------------------------------------------------------------------- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"Info"; } return self; } // ----------------------------------------------------------------------------- - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } // ----------------------------------------------------------------------------- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // Return YES for supported orientations return YES; } // ----------------------------------------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; // pinch gestures will change text size UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(scaleText:)]; pinchGesture.delegate = self; [fileView addGestureRecognizer:pinchGesture]; } // ----------------------------------------------------------------------------- - (void)viewDidUnload { [super viewDidUnload]; // release all outlets fileView = nil; saveButton = nil; } // ----------------------------------------------------------------------------- - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; textchanged = false; if (textfile.find(userdir + "Documents/") == 0) { // allow user to edit this file fileView.editable = YES; // show Save button saveButton.style = UIBarButtonItemStyleBordered; saveButton.enabled = YES; saveButton.title = @"Save"; } else { // textfile is empty (ie. not in ShowTextFile) or file is read-only fileView.editable = NO; // hide Save button saveButton.style = UIBarButtonItemStylePlain; saveButton.enabled = NO; saveButton.title = nil; } // best to use a fixed-width font // fileView.font = [UIFont fontWithName:@"CourierNewPSMT" size:14]; // bold is a bit nicer fileView.font = [UIFont fontWithName:@"CourierNewPS-BoldMT" size:14]; if (!textfile.empty()) { // display contents of textfile NSError *err = nil; NSString *filePath = [NSString stringWithCString:textfile.c_str() encoding:NSUTF8StringEncoding]; NSString *fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&err]; if (fileContents == nil) { fileView.text = [NSString stringWithFormat:@"Error reading text file:\n%@", err]; fileView.textColor = [UIColor redColor]; } else { fileView.text = fileContents; } } else if (currlayer->currfile.empty()) { // should never happen fileView.text = @"There is no current pattern file!"; fileView.textColor = [UIColor redColor]; } else { // display comments in current pattern file char *commptr = NULL; // readcomments will allocate commptr const char *err = readcomments(currlayer->currfile.c_str(), &commptr); if (err) { fileView.text = [NSString stringWithCString:err encoding:NSUTF8StringEncoding]; fileView.textColor = [UIColor redColor]; } else if (commptr[0] == 0) { fileView.text = @"No comments found."; } else { fileView.text = [NSString stringWithCString:commptr encoding:NSUTF8StringEncoding]; } if (commptr) free(commptr); } } // ----------------------------------------------------------------------------- - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; textfile.clear(); // viewWillAppear will display comments in currlayer->currfile } // ----------------------------------------------------------------------------- - (IBAction)doCancel:(id)sender { if (textchanged && YesNo("Do you want to save your changes?")) { [self doSave:sender]; return; } [self dismissModalViewControllerAnimated:YES]; } // ----------------------------------------------------------------------------- static std::string contents; - (IBAction)doSave:(id)sender { contents = [fileView.text cStringUsingEncoding:NSUTF8StringEncoding]; SaveTextFile(textfile.c_str(), contents.c_str(), self); } // ----------------------------------------------------------------------------- - (void)saveSucceded:(const char*)savedpath { textfile = savedpath; textchanged = false; } // ----------------------------------------------------------------------------- // UITextViewDelegate method: - (void)textViewDidChange:(UITextView *)textView { textchanged = true; } // ----------------------------------------------------------------------------- - (void)scaleText:(UIPinchGestureRecognizer *)pinchGesture { // very slow for large files; better to use A- and A+ buttons to dec/inc font size??? UIGestureRecognizerState state = pinchGesture.state; if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged) { CGFloat ptsize = fileView.font.pointSize * pinchGesture.scale; if (ptsize < 5.0) ptsize = 5.0; if (ptsize > 50.0) ptsize = 50.0; fileView.font = [UIFont fontWithName:fileView.font.fontName size:ptsize]; } else if (state == UIGestureRecognizerStateEnded) { // do nothing } } @end // ============================================================================= void ShowTextFile(const char* filepath, UIViewController* currentView) { // check if path ends with .gz or .zip if (EndsWith(filepath,".gz") || EndsWith(filepath,".zip")) { Warning("Editing a compressed file is not supported."); return; } textfile = filepath; // viewWillAppear will display this file InfoViewController *modalInfoController = [[InfoViewController alloc] initWithNibName:nil bundle:nil]; [modalInfoController setModalPresentationStyle:UIModalPresentationFullScreen]; if (currentView == nil) currentView = CurrentViewController(); [currentView presentModalViewController:modalInfoController animated:YES]; modalInfoController = nil; // only reset textfile in viewWillDisappear } golly-2.7-src/gui-ios/Golly/beep.aiff0000644000175000017500000003105612536111364014431 00000000000000FORM2&AIFFCOMM ~@ ¬DSSND2RR»»MMààààûû22ßß M M Ä Ä = =¶¶**••ìì..WW``GG——üü..,,õõ‡‡ÞÞþþãã‘‘  NN__ A A ö ö„„ïï;;nnýýú ú ÷¨÷¨ô¯ô¯ñºñºîÏîÏë÷ë÷é4é4æŽæŽääá³á³ßˆßˆÝÝÛÍÛÍÚHÚHÙÙ×ÿ×ÿ×A×AÖÆÖÆÖ’Ö’Ö¨Ö¨×××­×­Ø˜Ø˜ÙÆÙÆÛ8Û8ܿܿÞÊÞÊàèàèã9ã9å°å°èPèPëëíèíèðÒðÒóÄóÄö¿ö¿ùµùµü£ü£ÿ~ÿ~@@ææff » » ã ã Ó Óˆˆÿÿ77''ÑÑ77PP!!©©ììèè§§þþ & & $ $  ÂÂmm  ÿ¤ÿ¤ý:ý:úÜúÜøŠøŠöOöOô/ô/ò4ò4ðaðaî½î½íKíKììëëê[ê[éàéàé«é«é½é½êêê¶ê¶ëŸëŸìÉìÉî;î;ïïïïñáñáôôöuöuù ù ûÓûÓþÀþÀÐÐûû?? ææ@@““ÙÙ    ""$ß$ß'|'|)ã)ã,,../¬/¬112+2+2ù2ù3t3t3ž3ž3t3t2ù2ù2)2)1 1 /—/—-Ù-Ù+Ì+Ì)w)w&Ý&Ý$$ ï %%~~³³ÌÌ Ë Ë¸¸þ€þ€úgúgöXöXò[ò[îxîxê²ê²ççãšãšàSàSÝCÝCÚhÚh×Í×ÍÕtÕtÓ]Ó]ыыÐÐÎÂÎÂÍËÍËÍÍ̢̢̼̼ÌÐÌÐÍCÍCÍüÍüÎôÎôÐ'Ð'єєÓ7Ó7Õ Õ × × Ù3Ù3ÛzÛzÝßÝßà^à^âîâîå‰å‰è.è.êÖêÖí{í{ððòªòªõ,õ,÷š÷šùðùðü*ü*þEþE@@ËËYYÀÀ   Û Û ƒ ƒ s s ¼ ¼ ì ì     ñ ñ Ô Ô ª ª | | L L   ì ì È È ­ ­ ¤ ¤ ¨ ¨ Á Á ñ ñ : : œ œ   ± ±jj<<**55XX““ååLLÂÂDDÐÐbbôô‚‚! ! "†"†#ë#ë%=%=&s&s'ˆ'ˆ(v(v)8)8)Ê)Ê*****S*S*A*A)î)î)X)X(('c'c%ü%ü$M$M"R"R  ‡‡´´œœCCªª Ö ÖËË$$û•û•öåöåòòí?í?è]è]ãsãsÞÞٻٻÔýÔýÐ]Ð]ËãËãǘǘÅÅ¿±¿±¼"¼"¸â¸âµ÷µ÷³g³g±5±5¯l¯l®®­­¬£¬£¬œ¬œ­ ­ ­ñ­ñ¯Q¯Q±,±,³z³z¶<¶<¹p¹p½½Á!Á!ÅÅÊ^Ê^ττÔùÔùÚ¸Ú¸àµàµæéæéíKíKóÏóÏúpúpÍÍvv””!í!í((..3¶3¶99>#>#BÏBÏGGJ÷J÷NdNdQVQVSÑSÑUÈUÈW?W?X1X1XœXœXƒXƒWãWãVÁVÁUURúRúP_P_MMMMIÎIÎEåEåAžAž<ý<ý8 8 2Ð2Ð-Y-Y'¬'¬!Ô!ÔÝÝÐкº ¡ ¡––ýœýœ÷Å÷Åòòì”ì”çNçNâPâPݞݞÙ;Ù;Õ6Õ6ÑŽÑŽÎNÎNËwËwÉÉÇÇŌŌÄvÄvÃÖÃÖææÃêÃêĜĜŶŶÇ:Ç:É É ËbËbÍüÍüÐåÐåÔÔ××Û8Û8ßßããç9ç9ëoëoï¯ï¯óôóôø1ø1ü^ü^pp``&& ¼ ¼11ŒŒÅŧ§//]]--¡¡´´kkÄÄÂÂkk½½ÂÂ||ññ''&& ö ö$$üòüòùJùJõ¥õ¥òòîîëëçËçËä°ä°áÈáÈßßܯܯÚÚØ¸Ø¸×8×8ÖÖÕDÕDÔÖÔÖÔÈÔÈÕÕÕÔÕÔÖíÖíØjØjÚDÚDÜÜßßáþáþå9å9èÂèÂììððôãôãùXùXýõýõ´´ˆˆ l lSS99ÍÍ$m$m(å(å-*-*15154þ4þ88;±;±>†>†AACCDÐDÐFFFõFõGbGbGZGZFåFåEúEúD D B×B×@Ÿ@Ÿ=ÿ=ÿ:ú:ú7”7”3Ô3Ô/¹/¹+S+S&¦&¦!¸!¸’’;;¾¾ ! !ppµµúùúùõ?õ?ï˜ï˜ê ê äœäœßXßXÚJÚJÕtÕtÐâÐâ̕̕ȚȚÄóÄóÁ¦Á¦¾¸¾¸¼-¼-ºº¸I¸I¶ô¶ô¶ ¶ µ‹µ‹µtµtµÇµÇ¶‚¶‚·¤·¤¹$¹$»»½=½=¿Ë¿ËªªÅÑÅÑÉ:É:ÌàÌàннÔÈÔÈØýØýÝOÝOá¼á¼æ9æ9êÂêÂïIïIóÏóÏøJøJü²ü²00 ; ;  ÓÓSSœœ««}}  "a"a$m$m&8&8'Á'Á))***È*È+H+H+Ž+Ž+˜+˜+l+l++*u*u)¸)¸(Î(Î'Á'Á&‘&‘%F%F#ã#ã"m"m æ æTT½½  ……îî\\××``÷÷ŸŸ\\**      : : s s Á Á " "””¦¦BBéé””DDöö¦¦PPöö’’""¤¤vvÀÀôôÿÿþþüÒüÒû‰û‰ú'ú'ø¬ø¬÷÷õsõsó¸ó¸ñêñêð ð îîì)ì)ê+ê+è+è+æ,æ,ä2ä2â>â>àWàWÞÞܽܽÛÛÙÙØ$Ø$ÖâÖâÕÈÕÈÔÝÔÝÔÔÓ—Ó—ÓFÓFÓ-Ó-ÓOÓOÓ¯Ó¯ÔMÔMÕ)Õ)ÖHÖH×¢×¢Ù;Ù;ÛÛÝ(Ý(ßxßxââä¾ä¾ç¬ç¬êÇêÇîîñzñzõõøªøªüiüi22áá ¸ ¸ˆˆGGòò‚‚íí!6!6$Q$Q'8'8)è)è,^,^.“.“0„0„2-2-334ž4ž5b5b5Ô5Ô5ù5ù5É5É5I5I4{4{3^3^1ô1ô0C0C.I.I,,)“)“&á&á#ø#ø â ⢢==¼¼%%|| Ì ÌggÅÅý5ý5ùºùºö^ö^ó$ó$ððí9í9êŽêŽèèåëåëãõãõâCâCàØàØß³ß³ÞØÞØÞFÞFÝüÝüÝüÝüÞCÞCÞÎÞÎߟߟà±à±ââã‡ã‡åCåCç4ç4éIéIë‡ë‡íæíæð_ð_òêòêõõøøú¼ú¼ýSýSÿÜÿÜVV²²ññ   ø ø ¶ ¶AA––±±ŠŠ!!zzŒŒ\\åå,,..ññ u u ½ ½ Ï Ï««YYàà@@ý‚ý‚ú¬ú¬÷Å÷ÅôÓôÓñÛñÛîéîéììé+é+ænænãÒãÒáZáZßßÜúÜúÛÛككØ(Ø(××ÖXÖXÕèÕèÕËÕËÖÖÖ’Ö’×}×}ؽؽÚXÚXÜJÜJÞ‘Þ‘á*á*ääçIçIêÇêÇî†î†òƒòƒöµöµûûÿœÿœFF   Ø Ø±±‰‰WW!!%³%³*/*/.~.~2™2™6w6w::=]=]@V@VBøBøE:E:GGHHI™I™J2J2J[J[JJITITH"H"F|F|DeDeAáAá>ñ>ñ;š;š7Û7Û3Ä3Ä/R/R**%ƒ%ƒ 8 8°°÷÷  üâüâöÁöÁð¨ð¨êžêžä³ä³ÞîÞîÙSÙSÓòÓòÎÎÎÎÉõÉõÅhÅhÁ4Á4½_½_¹ë¹ë¶â¶â´C´C²²°`°`¯¯®Q®Q­þ­þ®%®%®Á®Á¯Õ¯Õ±Z±Z³S³Sµµµµ¸€¸€»«»«¿6¿6ÃÃÇCÇC˺˺ÐpÐpÕ]Õ]ÚzÚz߼߼ååê’ê’ððõšõšûû……àà  &&  ´´"""M"M&/&/)Å)Å--/õ/õ2‰2‰4À4À6Ÿ6Ÿ8899999ú9ú:[:[:b:b::9f9f8i8i775†5†3©3©1‰1‰/./., , )ß)ß&ø&ø#í#í È ÈBBðð  QQ Ý ÝÂÂÆÆççþ0þ0û£û£ùCùC÷÷õõóOóOñ»ñ»ðaðaï?ï?îXîXí¦í¦í-í-ìéìéìØìØìøìøíIíIíÄíÄîhîhï/ï/ððññò:ò:ólólô¬ô¬õúõú÷J÷Jøœøœùìùìû1û1ülülý™ý™þ°þ°ÿ²ÿ²——``  ’’öö44NN@@  °°00‹‹ÅÅÿÜÿÜþÕþÕý°ý°üuüuû#û#ù¾ù¾øJøJöÊöÊõCõCóºóºò1ò1ð­ð­ï2ï2íÆíÆìiìië$ë$é÷é÷èéèéç÷ç÷ç,ç,æ‡æ‡æ æ å³å³åŽåŽå™å™åÎåÎæ5æ5æÌæÌç”ç”è‰è‰é­é­êþêþì{ì{î î ïïïïñÝñÝóïóïööøgøgúÅúÅý5ý5ÿ´ÿ´;;ÆÆQQ Ø Ø V VÆÆ''qq¢¢³³¥¥rrÝÝ ù ù!è!è"¡"¡#(#(#x#x#˜#˜#ƒ#ƒ#:#:"¿"¿""!8!8 / /ýý    ~~¼¼ââððèèÕÕ¶¶ ‘ ‘ c c;;ýýííÿðÿðþþü3ü3úwúwøØøØ÷V÷Võöõöô¸ô¸óœóœò£ò£ñÍñÍññð‘ð‘ð(ð(ïâïâï¿ï¿ï¹ï¹ïÔïÔð ð ð_ð_ðÈðÈñFñFñÖñÖòtòtóóóÔóÔôŒôŒõHõHöööºöº÷j÷jøøø§ø§ù0ù0ù¨ù¨ú ú úZúZú“ú“ú®ú®úµúµúžúžújújú ú ùºùºù:ù:ø£ø£÷õ÷õ÷/÷/öXöXõoõoôzôzóxóxòoòoñ_ñ_ðOðOï?ï?î8î8í9í9ìIìIëgëgêžêžéíéíéWéWèâèâèŽèŽèbèbè^è^è‡è‡èÛèÛébébêêêþêþììíiíiîèîèðšðšò}ò}ôôöÏöÏù:ù:ûÌûÌþ…þ…^^TTdd † † º º÷÷77ww°°ÝÝ ö ö#ö#ö&Ø&Ø)•)•,),).Š.Š0¹0¹2®2®4f4f5Ù5Ù777è7è8}8}8Á8Á8´8´8R8R776’6’54543~3~1y1y/"/",~,~)Ž)Ž&U&U"Ú"Ú  ..±±66 š šààûEûEölölñ˜ñ˜ìÐìÐèèãƒãƒß ß Ú¿Ú¿Ö¢Ö¢Ò¿Ò¿ÏÏË·Ë·È È ÅÕÅÕÃ_Ã_ÁAÁA¿¿¾¾½½¼v¼v¼6¼6¼]¼]¼æ¼æ½Ñ½Ñ¿!¿!ÀËÀËÂÓÂÓÅ1Å1ÇçÇçÊêÊêÎ9Î9ÑÍÑÍՠՠ٫٫ÝèÝèâNâNæÙæÙë€ë€ð:ð:ôÿôÿùÇùÇþŒþŒDDëë v vÞÞ.. ¤ ¤$$'')ã)ã,^,^.‰.‰0^0^1Þ1Þ333Ô3Ô4M4M4i4i42423¤3¤2Ä2Ä1”1”00.R.R,I,I**'~'~$È$È!ä!䨨««bb¡¡11 à Ã[[¼¼ý“ý“úˆúˆ÷£÷£ôèôèò]ò]ððíäíäììêYêYèðèðçËçËæéæéæGæGåëåëåÐåÐåùåùæ^æ^çççäçäèþèþêKêKëÉëÉírírïDïDñ8ñ8óJóJõuõu÷®÷®ù÷ù÷üIüIþ™þ™ââ$$VVqq q q S S  ¦¦JJQQ!!¼¼AA,,ÚÚPP‡‡ˆˆSSèè L L ‹ ‹oo//ÐÐ[[ýÒýÒû9û9ø˜ø˜õóõóóQóQð´ð´î&î&ë­ë­éIéIççäâäââçâçááßxßxÞÞÜØÜØÛáÛáÛ$Û$Ú¦Ú¦ÚlÚlÚoÚoÚ´Ú´Û=Û=ÜÜÝÝÞcÞcßîßîáµáµã³ã³åëåëèTèTêëêëí­í­ð”ð”óœóœö¿ö¿ùúùúýEýE™™÷÷TT « « ö ö11WW``GG  ¦¦""$H$H&M&M(()¨)¨*ú*ú,,,à,à-r-r-¾-¾-É-É-“-“--,e,e+q+q*?*?(Õ(Õ'5'5%c%c#]#]!-!-ØØ]]  @@aaxx † †’’ŸŸ²²ÿÔÿÔýýú@ú@÷˜÷˜õõò˜ò˜ðJðJîîììê7ê7è„è„æùæùåœåœälälãjãjâ•â•áîáîáqáqá#á#àúàúàüàüá#á#ásásáãáãâsâsãããçãçäÉäÉå¾å¾æÇæÇçàçàééê4ê4ëiëiì¢ì¢íßíßïïðOðOññò«ò«óÌóÌôåôåõïõïöîöî÷Þ÷Þø¿ø¿ù•ù•úXúXûûûµûµüPüPüÜüÜý\ý\ýÒýÒþ<þ<þ þ þûþûÿPÿPÿ¤ÿ¤ÿôÿô@@åå@@žžvvîîtt¦¦TT  ÖÖ¯¯”” † † „ „ £ £ Á Áãã  88gg‘‘¹¹ÚÚòòþþüüéé„„++¶¶&&rr¢¢‚‚==ÍÍ22nn‚‚gg''»»''llŠŠ†† a a  ½½FF¹¹þpþpûºûºøþøþöAöAó†ó†ðÔðÔî-î-ë”ë”ééæ©æ©ä\ä\â0â0à(à(ÞHÞHܕܕÛÛÙ¿Ù¿Ø¢Ø¢×¸×¸× × Ö–Ö–Ö[Ö[Ö]Ö]Ö™Ö™×××Ê×ÊØºØºÙãÙãÛFÛFÜÝÜÝÞ¥Þ¥à à âÅâÅååç‹ç‹ê$ê$ìÖìÖï¤ï¤òƒòƒõsõsønønûlûlþkþk``PP11 ý ý ± ±FF¾¾33..ùù’’÷÷$$ÔÔ X X ¡ ¡ ¯ ¯ ‚ ‚ ! !††¹¹¶¶„„&&žžðð00'' Ú Ú ¡ ¡ ] ]ÛÛ  rrþWþWüPüPú`ú`øøöÜöÜõOõOóêóêò«ò«ññðºðºððï„ï„ï4ï4ïïï)ï)ïmïmïáïáð„ð„ñTñTòMòMóoóoôµôµöö÷¥÷¥ùEùEúüúüüÅüÅþžþž{{``FF&&ùù Á Á v v  ‘‘óó33HH77÷÷‡‡çç  ÊÊWW®®Ðм¼wwÿÿ Z Z ˆ ˆ kk++ÉÉNNýÂýÂû!û!øxøxõÆõÆóóðjðjíÉíÉë7ë7è·è·æUæUääáìáìßñßñÞ#Þ#܈܈ÛÛÙíÙíØøØøØAØA×È×È×’×’×××í×íØØÙXÙXÚsÚsÛÍÛÍÝlÝlßGßGá^á^ã®ã®æ2æ2èéèéëÏëÏîÝîÝò ò õ_õ_øÊøÊüJüJÿÕÿÕmm š š&&§§``ŽŽ™™!z!z$,$,&¨&¨(ï(ï*ø*ø,Å,Å.P.P/•/•0™0™1N1N1À1À1ç1ç1Ä1Ä1Y1Y0¤0¤/©/©.i.i,ã,ã+#+#)!)!&è&è$x$x!Ø!Ø  ûûÂÂqq  ˜ ˜  %%ý³ý³úPúPöüöüóÃóÃð¤ð¤í¨í¨êÐêÐè"è"åžåžãNãNá.á.ßGßGݕݕÜÜÚáÚáÙßÙßÙÙؒؒØDØDØ2Ø2Ø[Ø[ؽؽÙSÙSÚÚÛÛÜHÜHݡݡß!ß!àÇàÇâŒâŒärärænænè‚è‚ê§ê§ìØìØïïñRñRó“ó“õÏõÏøøú1ú1üPüPþ`þ`UU55««;;ªª ú ú ( ( 4 4   å 円  hh¨¨ÊÊÌ̳³33ÓÓ__ Ú Ú F F ¦ ¦ ü ü K K – – á á + +xxËË$$††òòmmôô‹‹00ææ®®‡‡rrmmyy––ÂÂýýDD––öö[[ÆÆ99­­!!––rrÚÚ 6 6 † † Ë Ë   & & ; ; ; ; ( (   Æ Æ q q  ŠŠòòHHˆˆ°°ÆÆË˽½  uuÿ@ÿ@þþü·ü·ûjûjúúøÇøÇ÷u÷uö*ö*ôæôæó¬ó¬òzòzñZñZðFðFïFïFî[î[í†í†ìÉìÉì'ì'ë ë ë4ë4êæêæê·ê·ê¦ê¦ê´ê´êâêâë-ë-ë™ë™ì ì ìÈìÈí‰í‰îfîfï[ï[ðjðjññòÆòÆôôõfõföÌöÌø<ø<ù±ù±û0û0ü®ü®þ,þ,ÿ§ÿ§  ððII’’ÉÉëë û û ô ô Ö Ö œ œ L L Ý ÝVV±±ïïáážžCC Ñ Ñ L L ´ ´ V V ‘ ‘ Á Áíí22TTxx››ÇÇýý;;……ÞÞEEÿÀÿÀÿKÿKþéþéþ›þ›þbþbþ<þ<þ0þ0þ5þ5þRþRþ€þ€þÇþÇÿÿÿ…ÿ…ÿþÿþ„„µµ]]  ÀÀvv))ÛÛ‹‹//ËËYYØØ F F ¢ ¢ ê ê   1 1 + +   Ö Ö   zzËËÿÿöö½½nn þ’þ’ý ý ûpûpùÎùÎø!ø!önönô¸ô¸óóñTñTï©ï©î î ìyìyêûêûé’é’è@è@ç ç åðåðäùäùä%ä%ãwãwâñâñâ•â•âgâgâcâcâŽâŽâéâéãsãsä,ä,ååæ+æ+çnçnèàèàêyêyì=ì=î&î&ð6ð6òdòdô±ô±÷÷ù˜ù˜ü*ü*þÎþÎyy--ää š š H HîppÀÀòòýýää ¢ ¢"2"2#“#“$¿$¿%º%º&}&}'''Z'Z'u'u'S'S&ú&ú&e&e%š%š$˜$˜#]#]!ñ!ñ R R‚‚‰‰gg··,,ŠŠ Ó Ó 66[[{{ÿ›ÿ›üÂüÂùñùñ÷3÷3ôƒôƒñíñíïrïrííêÝêÝèÉèÉæÞæÞååãŒãŒâ*â*àüàüßþßþß7ß7Þ£Þ£ÞEÞEÞÞÞ(Þ(ÞhÞhÞÜÞÜß~ß~àSàSáSáSâ€â€ãÓãÓåLåLæéæéè¤è¤êyêyìiìiîiîið{ð{òšòšôÁôÁöìöìùùû>û>ý^ý^ÿtÿtyynnOO Q Q Á Á  <<AA!!ÞÞqqÞÞ%%EE<<ÇÇUUÇÇOOmm u u l l M M $ $ïï²²pp--ëë®®wwKKÿ,ÿ,þþýýü3ü3û^û^ú ú ùúùúùpùpøÿøÿø¨ø¨øqøqøUøUøUøUøqøqøªøªøÿøÿùlùlùñùñúúû@û@üüüÜüÜýÂýÂþµþµÿ´ÿ´µµÂÂÐÐßßëëððññææÏÏ ¨ ¨ q q & & Æ Æ Q Q Á Á   V V v v | | c c - - Ý Ý q q æ æ A A ª ªºº´´››mm00ææ00þÌþÌýbýbûõûõúŠúŠù%ù%÷Ã÷Ãölölõõóßóßò±ò±ñ”ñ”ðŠðŠï™ï™î¿î¿íûíûíTíTìÉìÉìYìYì ì ëÖëÖëÀëÀëÉëÉëôëôì9ì9ìŸìŸííí¹í¹îoîoï?ï?ð&ð&ñ$ñ$ò4ò4óXóXôôõÏõÏ÷÷øuøuùÕùÕû:û:ü¢ü¢þ þ ÿpÿpÒÒ00„„ÏÏ  ==aa o o o o Z Z / / ñ ñ œ œ11¯¯ff¡¡ÅÅÓÓÌ̯¯??ì숈 ˜ ˜   z z Ü Ü 4 4 ‹ ‹ Û Û * *vvÁÁ``²²  iiÍÍ99««''««;;ÐÐnnÿÇÿÇÿ‚ÿ‚ÿBÿBÿ ÿ þÙþÙþ®þ®þ‡þ‡þeþeþGþGþ+þ+þþý÷ý÷ýÜýÜýÃýÃý©ý©ý‰ý‰ýeýeý@ý@ýýüåüåü®ü®üpüpü,ü,ûãûãû‘û‘û:û:úÜúÜúwúwú ú ùžùžù(ù(ø¯ø¯ø3ø3÷µ÷µ÷5÷5ö¶ö¶ö8ö8õºõºõAõAôÏôÏô_ô_óúóúóœóœóFóFòÿòÿòÄòÄò˜ò˜òzòzòjòjòmòmòòò¨ò¨òãòãó1ó1ó”ó”ôôô•ô•õ3õ3õæõæö®ö®÷†÷†øuøuùpùpú€ú€ûšûšüÇüÇýüýüÿ@ÿ@‰‰ÛÛ00‹‹ääAA–– æ æ / / m m ¡ ¡ÆÆØØÜÜÌÌ¡¡cc  ——  bb——²²®®ŠŠGGééiiÌÌ<<LLAA æ æ œ œ : : Ë ËMMÄÄ22™™ýý\\þÂþÂý)ý)û•û•úúøŽøŽ÷÷õ¼õ¼ôoôoó4ó4òòññððï9ï9îîíàíàíbíbìÿìÿì¿ì¿ì›ì›ì—ì—ì²ì²ìëìëíBíBí¶í¶îFîFîïîïï¯ï¯ðŠðŠñzñzò{ò{ó“ó“ôµôµõåõå÷÷øeøeù¬ù¬úùúùüGüGý’ý’þÙþÙPP~~  °°°°  {{AAïï † †   j j ¶ ¶ ê ê     ê ê ¸ ¸ q q   ¡ ¡  ÒÒTT„„©©ÉÉääûû++ÿKÿKþnþnýšýšüÎüÎüüû^û^úºúºú*ú*ùªùªù@ù@øèøèø¥ø¥øxøxøcøcøcøcøzøzø¨ø¨øìøìùEùEùµùµú5ú5úÌúÌûuûuü.ü.üõüõýÉýÉþ©þ©ÿ’ÿ’„„{{vvrrmmffYYFF++   Ï Ï ‹ ‹ 6 6 Ï Ï T T Æ Æ   a a Š Š œ œ • • s s 6 6 á á s s ì ì K K – – È ÈèèòòëëÖÖ¯¯}}>>ùùÿ°ÿ°þ`þ`ýýûÀûÀúpúpù'ù'÷å÷åö¯ö¯õõôdôdóVóVò[ò[ñsñsðŸðŸïßïßï9ï9î­î­î9î9íàíàí¤í¤í‚í‚í{í{í’í’íÄíÄîîîyîyîÿîÿï™ï™ðOðOñññúñúòïòïóøóøõõö:ö:÷o÷oø¯ø¯ù÷ù÷ûJûJüžüžýõýõÿLÿL¤¤õõFF‹‹ÈÈøø 1 1 4 4 & &   Ñ Ñ † †&&±±!!||ÁÁììÿÿææ¸¸uu¯¯11 ¡ ¡   V V œ œ Ö Ö   / /QQkk‚‚˜˜­­ÄÄÛÛùùDDÿtÿtþ«þ«ýìýìý:ý:ü’ü’ûõûõûeûeúáúáúlúlúúù¨ù¨ù^ù^ùùøèøèøÃøÃøªøªøšøšø˜ø˜øŸøŸø¯ø¯øÌøÌøîøîùùùJùJùùù¾ù¾úúúCúCú‡ú‡úÎúÎûûû\û\û£û£ûéûéü*ü*üjüjü¥ü¥üÞüÞýýý@ý@ýlýlý’ý’ý²ý²ýÐýÐýçýçýûýûþ þ þþþþþþþþþþþþþþþ þ þþýüýüýùýùýóýóýòýòýóýóýõýõýüýüþþþþþ+þ+þEþEþeþeþ‹þ‹þ³þ³þãþãÿÿÿUÿUÿ•ÿ•ÿÜÿÜ%%uuËË$$€€ÞÞ@@  ggÉÉ++‹‹ææ??’’àà))mm¦¦ÛÛ&&AAOOTTOOAA&&ÖÖYY  ¸¸[[öö‡‡——––  €€òòeeÿÙÿÙÿKÿKþ¾þ¾þ5þ5ý°ý°ý2ý2üµüµü@ü@ûÐûÐûiûiû û ú±ú±úeúeú!ú!ùçùçù¸ù¸ù•ù•ùzùzùlùlùhùhùpùpù€ù€ùšùšùÀùÀùîùîú%ú%úeúeú¬ú¬úúúúûPûPûªûªüüüjüjüÐüÐý:ý:ý¢ý¢þ þ þuþuþÜþÜÿBÿBÿ¥ÿ¥``µµPP’’ÎÎ00VVpp„„’’€€kkPP++ÔÔžžee++ëë©©ee""ÿàÿàÿœÿœÿ[ÿ[ÿÿþàþàþ©þ©þuþuþGþGþ þ ýþýþýâýâýÐýÐýÂýÂý¾ý¾ýÂýÂýÎýÎýâýâþþþ#þ#þPþPþ…þ…þÀþÀÿÿÿLÿLÿœÿœÿðÿðII¥¥  mmÒÒ77  iiËË''€€ÖÖ  ii¨¨àà22OO``ffbbPP88àत]]  °°KKßßggëëddÛÛKKµµÿ…ÿ…þëþëþPþPý³ý³ýýüƒüƒûðûðûaûaúÚúÚúXúXùÞùÞùlùlùùø¥ø¥øOøOøø÷È÷È÷•÷•÷q÷q÷X÷X÷N÷N÷N÷N÷Z÷Z÷u÷u÷Ÿ÷Ÿ÷Ó÷Óøøø^ø^øµøµùùùùù÷ù÷úuúuúúúúû‡û‡üüü°ü°ýJýJýéýéþ‰þ‰ÿ)ÿ)ÿËÿËeežž55ÇÇTTÙÙWWÐÐ==  ûûOO””ÐÐ&&AAOOQQII88ôôÄĉ‰FFýý««TTôô))»»MMÞÞkk÷÷……¤¤77ÿÌÿÌÿgÿgÿÿþ¥þ¥þNþNýûýûý®ý®ýgýgý)ý)üòüòüÀüÀü—ü—üuüuüYüYüEüEü:ü:ü5ü5ü5ü5ü@ü@üNüNübübüzüzüšüšü¾ü¾üçüçýýý@ý@ýrýrý¥ý¥ýÛýÛþþþKþKþ‚þ‚þ¹þ¹þðþðÿ%ÿ%ÿ[ÿ[ÿŒÿŒÿ¼ÿ¼ÿëÿë;;\\~~››´´ÉÉ××ååððôôõõôôîîççÛÛÍÍ»»©©••€€eePP77 ÿìÿìÿÕÿÕÿ¾ÿ¾ÿ©ÿ©ÿ”ÿ”ÿ€ÿ€ÿlÿlÿ\ÿ\ÿPÿPÿDÿDÿ<ÿ<ÿ5ÿ5ÿ2ÿ2ÿ2ÿ2ÿ3ÿ3ÿ7ÿ7ÿ@ÿ@ÿGÿGÿRÿRÿ`ÿ`ÿpÿpÿ‚ÿ‚ÿ”ÿ”ÿ©ÿ©ÿÀÿÀÿÕÿÕÿîÿî 99PPkk‚‚››²²ÉÉÞÞòò""0099BBIIKKNNNNMMEE@@77--""ôôààÎ뻥¥{{eeRR<<))ÿìÿìÿÛÿÛÿËÿËÿ¹ÿ¹ÿ©ÿ©ÿ›ÿ›ÿÿÿ‚ÿ‚ÿyÿyÿpÿpÿiÿiÿbÿbÿ`ÿ`ÿ[ÿ[ÿYÿYÿWÿWÿYÿYÿ[ÿ[ÿ\ÿ\ÿ`ÿ`ÿeÿeÿiÿiÿpÿpÿuÿuÿ~ÿ~ÿ…ÿ…ÿŽÿŽÿ•ÿ•ÿžÿžÿ¥ÿ¥ÿ°ÿ°ÿ·ÿ·ÿ¾ÿ¾ÿÇÿÇÿÎÿÎÿÕÿÕÿÛÿÛÿâÿâÿçÿçÿìÿìgolly-2.7-src/gui-ios/Golly/RuleViewController.m0000644000175000017500000006367112536111364016663 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "prefs.h" // for allowundo, SavePrefs #include "algos.h" // for algo_type, NumAlgos, etc #include "layer.h" // for currlayer, etc #include "undo.h" // for currlayer->undoredo #include "view.h" // for SaveCurrentSelection #include "control.h" // for ChangeAlgorithm, CreateRuleFiles #include "file.h" // for OpenFile #import "InfoViewController.h" // for ShowTextFile #import "OpenViewController.h" // for MoveSharedFiles #import "RuleViewController.h" @implementation RuleViewController // ----------------------------------------------------------------------------- const char* RULE_IF_EMPTY = "B3/S23"; // use Life if ruleText is empty static algo_type algoindex; // index of currently displayed algorithm static std::string oldrule; // original rule on entering Rule screen static int oldmaxstate; // maximum cell state in original rule static CGPoint curroffset[MAX_ALGOS]; // current offset in scroll view for each algoindex static NSString *namedRules[] = // data for rulePicker { // keep names in alphabetical order, and rules must be in canonical form for findNamedRule and GetRuleName @"3-4 Life", @"B34/S34", @"AntiLife", @"B0123478/S01234678", @"Banners", @"2367/3457/5", @"Bloomerang", @"234/34678/24", @"Brian's Brain", @"/2/3", @"Caterpillars", @"124567/378/4", @"Cooties", @"23/2/8", @"Day and Night", @"B3678/S34678", @"Diamoeba", @"B35678/S5678", @"Fireworks", @"2/13/21", @"Fredkin", @"B1357/S02468", @"Frogs", @"12/34/3", @"HighLife", @"B36/S23", @"Hutton32", @"Hutton32", @"JvN29", @"JvN29", @"Lava", @"12345/45678/8", @"Life", @"B3/S23", @"LifeHistory", @"LifeHistory", @"Life without Death", @"B3/S012345678", @"Lines", @"012345/458/3", @"LongLife", @"B345/S5", @"Morley", @"B368/S245", @"Nobili32", @"Nobili32", @"Persian Rug", @"B234/S", @"Plow World", @"B378/S012345678", @"Replicator", @"B1357/S1357", @"Seeds", @"B2/S", @"Star Wars", @"345/2/4", @"Sticks", @"3456/2/6", @"Transers", @"345/26/5", @"WireWorld", @"WireWorld", @"Wolfram 22", @"W22", @"Wolfram 30", @"W30", @"Wolfram 110", @"W110", @"Xtasy", @"1456/2356/16", @"UNNAMED", @"Bug if we see this!" // UNNAMED must be last }; const int NUM_ROWS = (sizeof(namedRules) / sizeof(namedRules[0])) / 2; const int UNNAMED_ROW = NUM_ROWS - 1; // ----------------------------------------------------------------------------- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"Rule"; } return self; } // ----------------------------------------------------------------------------- - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } // ----------------------------------------------------------------------------- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // return YES for supported orientations return YES; } // ----------------------------------------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; htmlView.delegate = self; // init all offsets to top left for (int i=0; i deprecated, keeprules; while (path = [dirEnum nextObject]) { std::string filename = [path cStringUsingEncoding:NSUTF8StringEncoding]; if (IsRuleFile(filename)) { if (EndsWith(filename,".rule")) { // .rule file exists, so tell CreateRuleFiles not to change it keeprules.push_back(filename); } else { // this is a deprecated .table/tree/colors/icons file deprecated.push_back(filename); } } } if (deprecated.size() > 0) { // convert deprecated files into new .rule files (if not in keeprules) // and then delete all the deprecated files CreateRuleFiles(deprecated, keeprules); } } // ----------------------------------------------------------------------------- static void CreateRuleLinks(std::string& htmldata, const std::string& dir, const std::string& prefix, const std::string& title, bool candelete) { htmldata += "

"; htmldata += title; htmldata += "

"; NSFileManager *fm = [NSFileManager defaultManager]; NSString *rdir = [NSString stringWithCString:dir.c_str() encoding:NSUTF8StringEncoding]; NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath:rdir]; NSString *path; while (path = [dirEnum nextObject]) { std::string pstr = [path cStringUsingEncoding:NSUTF8StringEncoding]; size_t extn = pstr.rfind(".rule"); if (extn != std::string::npos) { // path is to a .rule file std::string rulename = pstr.substr(0,extn); if (candelete) { // allow user to delete .rule file htmldata += "DELETE   "; // allow user to edit .rule file htmldata += "EDIT   "; } else { // allow user to read supplied .rule file htmldata += "READ   "; } // use "open:" link rather than "rule:" link so dialog closes immediately htmldata += ""; htmldata += rulename; htmldata += "
"; } } } // ----------------------------------------------------------------------------- - (void)showAlgoHelp { NSString *algoname = [NSString stringWithCString:GetAlgoName(algoindex) encoding:NSUTF8StringEncoding]; if ([algoname isEqualToString:@"RuleLoader"]) { // first check for any .rule/tree/table files in Documents // (created by iTunes file sharing) and move them into Documents/Rules/ MoveSharedFiles(); // now convert any .tree/table files to .rule files ConvertOldRules(); // create html data with links to the user's .rule files and Golly's supplied .rule files std::string htmldata; htmldata += ""; htmldata += "

The RuleLoader algorithm allows CA rules to be specified in .rule files."; htmldata += " Given the rule string \"Foo\", RuleLoader will search for a file called Foo.rule"; htmldata += " in your rules folder (Documents/Rules/), then in the rules folder supplied with Golly."; htmldata += "

"; CreateRuleLinks(htmldata, userrules, "Documents/Rules/", "Your .rule files:", true); CreateRuleLinks(htmldata, rulesdir, "Rules/", "Supplied .rule files:", false); htmldata += "

TOP
"; [htmlView loadHTMLString:[NSString stringWithCString:htmldata.c_str() encoding:NSUTF8StringEncoding] baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]]; // the above base URL is needed for links like to work } else { NSBundle *bundle=[NSBundle mainBundle]; NSString *filePath = [bundle pathForResource:algoname ofType:@"html" inDirectory:@"Help/Algorithms"]; if (filePath) { NSURL *fileUrl = [NSURL fileURLWithPath:filePath]; NSURLRequest *request = [NSURLRequest requestWithURL:fileUrl]; [htmlView loadRequest:request]; } else { [htmlView loadHTMLString:@"
Failed to find html file!
" baseURL:nil]; } } } // ----------------------------------------------------------------------------- static bool keepalgoindex = false; - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if (keepalgoindex) { // ShowTextFile has finished displaying a modal dialog so we don't want to change algoindex keepalgoindex = false; [self showAlgoHelp]; // user might have created a new .rule file return; } // save current location curroffset[algoindex] = htmlView.scrollView.contentOffset; // show current algo and rule algoindex = currlayer->algtype; [algoButton setTitle:[NSString stringWithCString:GetAlgoName(algoindex) encoding:NSUTF8StringEncoding] forState:UIControlStateNormal]; [self showAlgoHelp]; oldrule = currlayer->algo->getrule(); oldmaxstate = currlayer->algo->NumCellStates() - 1; [ruleText setText:[NSString stringWithCString:currlayer->algo->getrule() encoding:NSUTF8StringEncoding]]; unknownLabel.hidden = YES; // show corresponding name for current rule (or UNNAMED if there isn't one) [rulePicker selectRow:[self findNamedRule:ruleText.text] inComponent:0 animated:NO]; // selection might change if grid becomes smaller, so save current selection // if RememberRuleChange/RememberAlgoChange is called later SaveCurrentSelection(); } // ----------------------------------------------------------------------------- - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [htmlView stopLoading]; // in case the web view is still loading its content // save current location of htmlView curroffset[algoindex] = htmlView.scrollView.contentOffset; } // ----------------------------------------------------------------------------- - (IBAction)changeAlgorithm:(id)sender { UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil]; for (int i=0; i= 0 && globalButton < NumAlgos()) { // save current location curroffset[algoindex] = htmlView.scrollView.contentOffset; // save chosen algo for later use algoindex = globalButton; // display the chosen algo name [algoButton setTitle:[NSString stringWithCString:GetAlgoName(algoindex) encoding:NSUTF8StringEncoding] forState:UIControlStateNormal]; // display help for chosen algo [self showAlgoHelp]; // if current rule (in ruleText) is valid in the chosen algo then don't change rule, // otherwise switch to the algo's default rule std::string thisrule = [ruleText.text cStringUsingEncoding:NSUTF8StringEncoding]; if (thisrule.empty()) thisrule = RULE_IF_EMPTY; lifealgo* tempalgo = CreateNewUniverse(algoindex); const char* err = tempalgo->setrule(thisrule.c_str()); if (err) { // switch to tempalgo's default rule std::string defrule = tempalgo->DefaultRule(); size_t thispos = thisrule.find(':'); if (thispos != std::string::npos) { // preserve valid topology so we can do things like switch from // "LifeHistory:T30,20" in RuleLoader to "B3/S23:T30,20" in QuickLife size_t defpos = defrule.find(':'); if (defpos != std::string::npos) { // default rule shouldn't have a suffix but play safe and remove it defrule = defrule.substr(0, defpos); } defrule += ":"; defrule += thisrule.substr(thispos+1); } [ruleText setText:[NSString stringWithCString:defrule.c_str() encoding:NSUTF8StringEncoding]]; [rulePicker selectRow:[self findNamedRule:ruleText.text] inComponent:0 animated:NO]; unknownLabel.hidden = YES; } delete tempalgo; } } // ----------------------------------------------------------------------------- // called when the user selects an item from UIActionSheet created in changeAlgorithm - (void)actionSheet:(UIActionSheet *)sheet didDismissWithButtonIndex:(NSInteger)buttonIndex { // user interaction is disabled at this moment, which is a problem if Warning gets called // (the OK button won't work) so we have to call the appropriate action code AFTER this // callback has finished and user interaction restored globalButton = buttonIndex; [self performSelector:@selector(doDelayedAction) withObject:nil afterDelay:0.01]; } // ----------------------------------------------------------------------------- - (void)checkRule { // check displayed rule and show message if it's not valid in any algo, // or if the rule is valid then displayed algo might need to change std::string thisrule = [ruleText.text cStringUsingEncoding:NSUTF8StringEncoding]; if (thisrule.empty()) { thisrule = RULE_IF_EMPTY; [ruleText setText:[NSString stringWithCString:thisrule.c_str() encoding:NSUTF8StringEncoding]]; [rulePicker selectRow:[self findNamedRule:ruleText.text] inComponent:0 animated:NO]; } // 1st check if rule is valid in displayed algo lifealgo* tempalgo = CreateNewUniverse(algoindex); const char* err = tempalgo->setrule(thisrule.c_str()); if (err) { // check rule in other algos for (int newindex = 0; newindex < NumAlgos(); newindex++) { if (newindex != algoindex) { delete tempalgo; tempalgo = CreateNewUniverse(newindex); err = tempalgo->setrule(thisrule.c_str()); if (!err) { // save current location curroffset[algoindex] = htmlView.scrollView.contentOffset; algoindex = newindex; [algoButton setTitle:[NSString stringWithCString:GetAlgoName(algoindex) encoding:NSUTF8StringEncoding] forState:UIControlStateNormal]; [self showAlgoHelp]; break; } } } } unknownLabel.hidden = (err == nil); if (err) { // unknown rule must be unnamed [rulePicker selectRow:UNNAMED_ROW inComponent:0 animated:NO]; Beep(); } else { // need canonical rule for comparison in findNamedRule and GetRuleName NSString *canonrule = [NSString stringWithCString:tempalgo->getrule() encoding:NSUTF8StringEncoding]; [rulePicker selectRow:[self findNamedRule:canonrule] inComponent:0 animated:NO]; } delete tempalgo; } // ----------------------------------------------------------------------------- - (IBAction)cancelRuleChange:(id)sender { [self dismissModalViewControllerAnimated:YES]; } // ----------------------------------------------------------------------------- - (IBAction)doRuleChange:(id)sender { // clear first responder if necessary (ie. remove keyboard) [self.view endEditing:YES]; if (unknownLabel.hidden == NO) { Warning("Given rule is not valid in any algorithm."); // don't dismiss modal view return; } // dismiss modal view first in case ChangeAlgorithm calls BeginProgress [self dismissModalViewControllerAnimated:YES]; // get current rule in ruleText std::string newrule = [ruleText.text cStringUsingEncoding:NSUTF8StringEncoding]; if (newrule.empty()) newrule = RULE_IF_EMPTY; if (algoindex == currlayer->algtype) { // check if new rule is valid in current algorithm // (if not then revert to original rule saved in viewWillAppear) const char* err = currlayer->algo->setrule(newrule.c_str()); if (err) RestoreRule(oldrule.c_str()); // convert newrule to canonical form for comparison with oldrule, then // check if the rule string changed or if the number of states changed newrule = currlayer->algo->getrule(); int newmaxstate = currlayer->algo->NumCellStates() - 1; if (oldrule != newrule || oldmaxstate != newmaxstate) { // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { ClearOutsideGrid(); } // rule change might have changed the number of cell states; // if there are fewer states then pattern might change if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { ReduceCellStates(newmaxstate); } if (allowundo) { currlayer->undoredo->RememberRuleChange(oldrule.c_str()); } } UpdateLayerColors(); UpdateEverything(); } else { // change the current algorithm and switch to the new rule // (if the new rule is invalid then the algo's default rule will be used); // this also calls UpdateLayerColors, UpdateEverything and RememberAlgoChange ChangeAlgorithm(algoindex, newrule.c_str()); } SavePrefs(); } // ----------------------------------------------------------------------------- // UITextFieldDelegate methods: - (void)textFieldDidBeginEditing:(UITextField *)tf { // probably best to clear any message about unknown rule unknownLabel.hidden = YES; } - (void)textFieldDidEndEditing:(UITextField *)tf { // called when rule editing has ended (ie. keyboard disappears) [self checkRule]; } - (BOOL)textFieldShouldReturn:(UITextField *)tf { // called when user hits Done button, so remove keyboard // (note that textFieldDidEndEditing will then be called) [tf resignFirstResponder]; return YES; } - (BOOL)disablesAutomaticKeyboardDismissal { // this allows keyboard to be dismissed if modal view uses UIModalPresentationFormSheet return NO; } // ----------------------------------------------------------------------------- // UIPickerViewDelegate and UIPickerViewDataSource methods: - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { return 1; } - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { return NUM_ROWS; } - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component; { return namedRules[row * 2]; } - (CGFloat)pickerView:(UIPickerView *)pickerView rowHeightForComponent:(NSInteger)component { return 38.0; // nicer spacing } - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { if (row < UNNAMED_ROW) { [ruleText setText:namedRules[row * 2 + 1]]; [self checkRule]; } } // ----------------------------------------------------------------------------- // UIWebViewDelegate methods: - (void)webViewDidStartLoad:(UIWebView *)webView { // show the activity indicator in the status bar [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; } - (void)webViewDidFinishLoad:(UIWebView *)webView { // hide the activity indicator in the status bar [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // restore old offset here htmlView.scrollView.contentOffset = curroffset[algoindex]; } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { // hide the activity indicator in the status bar and display error message [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // we can safely ignore -999 errors if (error.code == NSURLErrorCancelled) return; Warning([error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding]); } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if (navigationType == UIWebViewNavigationTypeLinkClicked) { NSURL *url = [request URL]; NSString *link = [url absoluteString]; // look for special prefixes used by Golly (and return NO if found) if ([link hasPrefix:@"open:"]) { // open specified file, but dismiss modal view first in case OpenFile calls BeginProgress [self dismissModalViewControllerAnimated:YES]; std::string path = [[link substringFromIndex:5] cStringUsingEncoding:NSUTF8StringEncoding]; OpenFile(path.c_str()); SavePrefs(); return NO; } if ([link hasPrefix:@"rule:"]) { // copy specified rule into ruleText [ruleText setText:[link substringFromIndex:5]]; [self checkRule]; return NO; } if ([link hasPrefix:@"delete:"]) { std::string path = [[link substringFromIndex:7] cStringUsingEncoding:NSUTF8StringEncoding]; FixURLPath(path); std::string question = "Do you really want to delete " + path + "?"; if (YesNo(question.c_str())) { // delete specified file path = userdir + path; RemoveFile(path); // save current location curroffset[algoindex] = htmlView.scrollView.contentOffset; [self showAlgoHelp]; } return NO; } if ([link hasPrefix:@"edit:"]) { std::string path = [[link substringFromIndex:5] cStringUsingEncoding:NSUTF8StringEncoding]; FixURLPath(path); // convert path to a full path if necessary std::string fullpath = path; if (path[0] != '/') { if (fullpath.find("Patterns/") == 0 || fullpath.find("Rules/") == 0) { // Patterns and Rules directories are inside supplieddir fullpath = supplieddir + fullpath; } else { fullpath = userdir + fullpath; } } // we pass self to ShowTextFile so it doesn't use current tab's view controller ShowTextFile(fullpath.c_str(), self); // tell viewWillAppear not to reset algoindex to currlayer->algtype keepalgoindex = true; return NO; } } return YES; } @end // ============================================================================= std::string GetRuleName(const std::string& rule) { std::string result = ""; NSString* nsrule = [NSString stringWithCString:rule.c_str() encoding:NSUTF8StringEncoding]; for (int row = 0; row < UNNAMED_ROW; row++) { if ([nsrule isEqualToString:namedRules[row * 2 + 1]]) { result = [namedRules[row * 2] cStringUsingEncoding:NSUTF8StringEncoding]; break; } } return result; } golly-2.7-src/gui-ios/Golly/StatusView.m0000644000175000017500000000702212536111364015157 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "status.h" // for UpdateStatusLines, status1, status2, status3 #include "algos.h" // for algoinfo #include "layer.h" // for currlayer #import "StatusView.h" @implementation StatusView // ----------------------------------------------------------------------------- - (void)drawRect:(CGRect)dirtyrect { UpdateStatusLines(); // sets status1 and status2 CGContextRef context = UIGraphicsGetCurrentContext(); // int wd = self.bounds.size.width; int ht = self.bounds.size.height; // background color of status area depends on current algorithm [[UIColor colorWithRed:algoinfo[currlayer->algtype]->statusrgb.r / 255.0 green:algoinfo[currlayer->algtype]->statusrgb.g / 255.0 blue:algoinfo[currlayer->algtype]->statusrgb.b / 255.0 alpha:1.0] setFill]; CGContextFillRect(context, dirtyrect); // draw thin gray line along bottom /* only do this if edit toolbar is ever hidden [[UIColor grayColor] setStroke]; CGContextSetLineWidth(context, 1.0); CGContextMoveToPoint(context, 0, ht); CGContextAddLineToPoint(context, wd, ht); CGContextStrokePath(context); */ // use black for drawing text [[UIColor blackColor] setFill]; // add code to limit amount of drawing if dirtyrect's height is smaller than given ht??? NSString *line1 = [NSString stringWithCString:status1.c_str() encoding:NSUTF8StringEncoding]; NSString *line2 = [NSString stringWithCString:status2.c_str() encoding:NSUTF8StringEncoding]; // get font to draw lines (do only once) static UIFont *font = nil; if (font == nil) font = [UIFont systemFontOfSize:13]; // set position of text in each line float lineht = ht / 3.0; CGRect rect1, rect2; rect1.size = [line1 sizeWithFont:font]; rect2.size = [line2 sizeWithFont:font]; rect1.origin.x = 5.0; rect2.origin.x = 5.0; rect1.origin.y = (lineht / 2.0) - (rect1.size.height / 2.0); rect2.origin.y = rect1.origin.y + lineht; // draw the top 2 lines [line1 drawInRect:rect1 withFont:font]; [line2 drawInRect:rect2 withFont:font]; if (status3.length() > 0) { // display message on bottom line NSString *line3 = [NSString stringWithCString:status3.c_str() encoding:NSUTF8StringEncoding]; CGRect rect3; rect3.size = [line3 sizeWithFont:font]; rect3.origin.x = 5.0; rect3.origin.y = rect2.origin.y + lineht; [line3 drawInRect:rect3 withFont:font]; } } // ----------------------------------------------------------------------------- @end golly-2.7-src/gui-ios/Golly/SettingsViewController.xib0000644000175000017500000013601712536111364020075 00000000000000 1280 10K549 1938 1038.36 461.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 933 IBUIView IBProxyObject IBUILabel IBUISwitch IBUITextField IBUISlider IBUIButton com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 292 301 301 {{249, 430}, {94, 27}} NO IBIPadFramework 0 0 301 {{250, 180}, {94, 27}} NO IBIPadFramework 0 0 301 {{250, 230}, {94, 27}} NO IBIPadFramework 0 0 301 {{250, 280}, {94, 27}} NO IBIPadFramework 0 0 301 {{250, 330}, {94, 27}} NO IBIPadFramework 0 0 301 {{139, 430}, {117, 24}} NO YES 7 NO IBIPadFramework Show grid lines 1 MCAwIDAAA 1 10 1 17 Helvetica 17 16 301 {{129, 230}, {128, 24}} NO YES 7 NO IBIPadFramework Play beep sound 1 10 301 {{128, 280}, {128, 24}} NO YES 7 NO IBIPadFramework Invert cell colors 1 10 2 301 {{128, 330}, {128, 24}} NO YES 7 NO IBIPadFramework Show icons 1 10 2 301 {{128, 380}, {128, 24}} NO YES 7 NO IBIPadFramework Can undo/redo 1 10 2 301 {{80, 180}, {177, 24}} NO YES 7 NO IBIPadFramework Show timing messages 1 10 301 {{66, 130}, {190, 24}} NO YES 7 NO IBIPadFramework Show hashing messages 1 10 2 301 {{33, 80}, {223, 24}} NO YES 7 NO IBIPadFramework Maximum hash memory (MB) 1 10 2 301 {{78, 30}, {182, 24}} NO YES 7 NO IBIPadFramework Random fill percentage 1 10 2 301 {{138, 480}, {117, 24}} NO YES 7 NO IBIPadFramework Paste mode 1 10 2 301 {{264, 480}, {78, 30}} NO IBIPadFramework 0 0 1 OR 3 MQA 1 MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 3 MC41AA 2 15 Helvetica-Bold 15 16 301 {{355, 32}, {120, 23}} NO IBIPadFramework 0 0 100 1 100 301 {{355, 82}, {120, 23}} NO IBIPadFramework 0 0 300 10 300 301 {{250, 380}, {94, 27}} NO IBIPadFramework 0 0 301 {{250, 130}, {94, 27}} NO IBIPadFramework 0 0 301 {{264, 79}, {78, 31}} NO YES IBIPadFramework 0 300 3 3 MAA 2 1 YES 17 4 9 IBCocoaTouchFramework 3 1 14 Helvetica 14 16 301 {{265, 29}, {78, 31}} NO YES IBIPadFramework 0 100 3 3 MAA 1 YES 17 4 9 IBCocoaTouchFramework 3 {{131, 233}, {506, 538}} 3 MC42NjY2NjY2NjY3AA IBIPadFramework {{0, 20}, {768, 1004}} NO 2 IBIPadFramework view 3 gridSwitch 11 timingSwitch 12 beepSwitch 25 modeButton 26 percentageSlider 28 colorsSwitch 34 hashingSwitch 45 memorySlider 47 undoSwitch 48 percentageText 54 memoryText 55 iconsSwitch 62 toggleGrid: 13 10 toggleTiming: 13 9 changePasteMode: 7 35 changePercentage: 13 36 toggleBeep: 13 24 toggleColors: 13 33 toggleUndo: 13 50 toggleHashing: 13 51 changeMemory: 13 49 delegate 56 delegate 57 toggleIcons: 13 61 0 -1 File's Owner -2 2 14 4 5 6 7 15 17 18 20 21 23 31 32 37 38 39 40 42 43 52 53 58 59 SettingsViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 62 SettingsViewController UIViewController id id id id id id id id id id changeMemory: id changePasteMode: id changePercentage: id toggleBeep: id toggleColors: id toggleGrid: id toggleHashing: id toggleIcons: id toggleTiming: id toggleUndo: id UISwitch UISwitch UISwitch UISwitch UISwitch UISlider UITextField UIButton UISlider UITextField UISwitch UISwitch beepSwitch UISwitch colorsSwitch UISwitch gridSwitch UISwitch hashingSwitch UISwitch iconsSwitch UISwitch memorySlider UISlider memoryText UITextField modeButton UIButton percentageSlider UISlider percentageText UITextField timingSwitch UISwitch undoSwitch UISwitch IBProjectSource ./Classes/SettingsViewController.h 0 IBIPadFramework YES 3 933 golly-2.7-src/gui-ios/Golly/iTunesArtwork0000644000175000017500000011014412536111364015427 00000000000000‰PNG  IHDR{C­!tEXtSoftwareGraphicConverter (Intel)w‡úþIDATxœìÕ1 0 À°¢<;¦ÁèK/óî hÖ XaQeQeQeQeQeQeQeQeQeQeQeQeQeQeQeQeQeQeQÿÿìyT”UÇwyf@dRÔÊ MSRSËÑ´c¾iêÛª˜šŠhn¹à–)äV.˜¦wÙaXfY†mAÀdSÙåUs9eõ÷Î…‚§Þ£Î\Ç{Îç̹Ï<÷¹ó9ßûÇ÷\VQ@ðŒ" @ žQžÊ¨®t {ø€ÛNïwnÿÀçдõjá#|„QÂ[>¼ù< OM”Oپ壡Î-Íf´6™%‘™NðlŒgaä&Q7Bf¶k»jÆŒÕ~>ó„ð>O5¼åÛÏãâ)(€Ã>3 X.“¦›Ñ¯:Øì~Ý)hÌÛÁ«Vh6mËÞ¶+wë÷yë¾ÉŸ4YíìÑ¥óa‹ÖÛåt•å’Ó¿(=?MøáótÁ[>¼ù<^¸.€Èˆ;/&xeÛ¯½6wö™ÀëÅE ׯ7\»þû•›woýÖpë׆úk ×o5TU7$%^_çyzäˆØîÝ}dt‰‰löô© j*çá#|ø‡·|xóypZUn®“ÜØ!ËÖrë73\§ä…DݸP÷ßÚ›·.ÖÖUÕܨ¿|§¾öN]ͯu5?ÕÕ²Ë[µÕ7ëjn_½r'«àΪµEcÞMsêÕJò´³ý<$h¾ð>‡[xˇ7Ÿ'5¾Cg3³õ}z%]üåòœlÍÝ’Ò†¢âŸ‹Ëo”0Ê~.-ý­´ô·KÙeÊËbw÷¨ž0.mÔˆâ¶mŽÊ¥%³f®>ÂGøpoùðæóDᮊy¦æS­¬6–7bdƲe%šô†üÜßssÎ=u5çÔåœSÿÉɽ–“s3'÷Gíà~rs¯ž)¸š}òZnþÝzïÝ‚ÃN÷ï%—-û¯„ðyÆ}xƒ·|xóyÒðU¡!îdm±{„ËEçœO?K‹N¸­N¹¬¾‘š~59µZV¥N«U§^Q§\S§Ö«S/?@Jj}Jb}JJ}rÚ­ÄÔ»ë7Ô uNîœíÔC%§‹^qúÿzXøcòá ÞòáÍGpT9YZ™M´¶ôvyãÒ€WŠ\œ“÷¬Š­ˆRU©¢«£T¢c.*£/(£/)UµJåe¥ªJ©ªlFõ±¨+JeuL\¥BU¥PþòÉ'ç×sÞè_Ü÷¥4‰z¼3j‚ð>Ï oð–o>ú—(/™Ò¡ã2kËoûöÉèçtv`ÿ¬)S |ý® * *kBy@Ð¥€Àª€Àê€ÀŠ€ÀKͨ ô¯ ¬ . 9ë\³uÛõ~}’ú÷*èTÞùùIš;ÁßOFøcòá ÞòáÍGoðR¯^%Ik»v‰wì–åä”Ó«wΝ*öï¿|ðÀŽ{‹µì;¯”ìÝ[¦eOÙƒæì)ß»·tß¾sûöåò)ß¾ãÇ¡C2œz:õ>÷rÏL‡¶ ¤ŒZ*|„ϳãüåÛÞà¢ü|çÊ¥¹öí|»g::žîÒ-ݱGà†M—½·”íØV²Ý»ØûAм½ u5£Ð{ûéíÞç¿ÛZ²s[áwÛ‹6o­õNViã{dté”dmáݵËâ+—ÚÃÂGø“oð–o>ú„‹pp˜gaº­S·¨öÏ'8t8ùb§Ì—zF®\qÁkMÁF¯ü¯=O{yž¹G—g¾—×)/¯\/¯¼–8å¹NóµgÞú5…ëל]çyÆÓóÒ¨Ñé/vnß%¬c§„βì"ät¡÷–÷…ðy|xƒ·|xóÑ'†/€ïwºb¼°mXÛö1ϵ?áÐ.¡½ÃqÇ.sÜË–{œYµ2ÇciîÒ¥yM8u6ÎoFÁÒ¥gÙ­%Ë3—,Ó,ò8õÅÒŠa.šöí¢ÚµKlëÐÎ}D¼…Ù;Û%ÂGø½oð–o>zÆðàè¸ÀÄt£ý1{•­]Œ]›ãövJ{Û£XàîvÒÝ=ÙÝ=}–{FKhf¹g>Ȭ¬Yn¹l0sNòÌ9IŸ¹¥»Í.ëÖ%¼M¸]›8¶¾­ÊÎîX;û0Šçûš)|„qûðoùðæ£g \q±+$ÙTsó]­Í#[Y†™™‡›·Ž°0µ±::䄉ŸdNœ˜8yrj˸¦µDú$×ÌI“Ó'}š4qJÒÇ®ÞÏ·±ñ±¶ c+›Y„˜Y·6W˜· 0•­òæá#|ŒØ‡7xˇ7ýcàXÿõ™´ØÌì0‘Be¦A2“`yˆ©<ÈÌÔ÷9û#£GkÞ{/uìØ¤±cÿ1l2{$y̸Ä1ãØkf¿q¦&%ÉßÄ$ÈÄÔWÖÊWÆR€\Ú,—»VUÌ>ÂÇX}xƒ·|xóÑ?.€>=WË¥u ò@Gù"8Ê ÈЮÎ]#†¿¥ñVâðañÃ]âß~âŸàâ’0r¤zèÐø¡.Ƀ«M[íÃø F~ü>dûŠƒ0ìK‹öü0Cøcõá ÞòáÍGÿ²êkçId†œìðE8¡#ˆ ÀŸÁò"ø•õ야Á[>¼ùC€*b¹™ÌƒÀJCAȧq$“‡J2¿Î/„÷êíôòqöÚ»gL¢[¤çKÊÞ½âºu‹mmæOÈQL E(˜€‚•0àC€ü£4@’6õè¹Nø£ôá ÞòáÍÇ ²vípŰØD›Q¢¾H{þòC,}Æ8L ð£ô[ÿç;Dth¯x¡cø=/<ÖÃ::(ìÛɤC”°2gÅ F ³Å1;ÜùbëûºÕÆv‘ð>FéüåÛA0d|»ñßVPt”à(@¡Ât(îÞ@A¡rIaj¢°¶Š²¶Š°¶VX[‡Y[‡þ…Uˆ•Uˆ¥e°¥E¨ÄÚ‡ŽÿZЉàmÕöÇ$’ÊþN¢óά>ÂÇø|xƒ·|xó1†,€o6L`@AÇ@[…€RÂJ”ˆB"! ’h vð'4”½Rm¦¡))R±Gî_„]¤`éÁäF ‚wJtAîɵÂGøŸoð–o>Á °q¼v €@ÀqÑ-‚!iï²þT¬"$ŠB" Ž!(¶Šãfƒã,eŒX¸ÚTMÖ9F ¡H–>`%Æ E´[¢ ³4_ ác|>¼Á[>¼ùƒ~ hÓ8‚Á°çW„æÊI Ž` @À‰f°7“ÔI Û§&ĶÛ§øæë H º=ÃV£8#FÞóÏÙ |„ñùðoùðæc YêdO‰~ŽÑa9I%(Pòƒh£Oi6ÇŽkF< ¤æë PHeMŽÛ9¶Ù2rŒMí;.¸Zï.|„ñùðoùðæc ü›À’4ÝDv„bPBé!õ~öþŸ¤5_£t ݤ!8É6ÀD °øå¾K„ð1VÞà-Þ|ô `À -2i7%숔‰¡ - Ñ^ji|§i²iÌa“!›EÙŒlÝã‚AC!“@Ö®ŸËÞ15Qiᇮ;…ð1VÞà-Þ|ô `óæñ€æS)£Ài@’³ãU@>‚ÓÚ4Q*»<Ù9¡…Él)m÷¢4@@§0I£t¿‰É”Ý»× ác¬>¼Á[>¼ùè@YÉTy+wBb”Çr” Ú/Ƽ·¬*3u™æ>"r°¶ä³tŸ’‡‰ãÍÓNf¯>ÂÇX}xƒ·|xóÑ?†ÿ‡0}û¯ÆØ[Âì t´œÖÆ(_GÁãAÓ˜-…leJcZùöÛ-ü–ð>ÆäüåÛž1|,’Ik$Nà<†r efUÉò*8§Ý•GåÖ®_‚ âtŒöXXÌÝ·÷á#|ŒÛ‡7xˇ7=cø`ô æ¦y¬!1\Ó‹Ÿ’¸à"Ò¦Vü@…)E ‘Ka-uvþòrMËÿ’Møcòá ÞòáÍGŸpQѪerùT€ýgÈðE × tHv"«DPŽ ì1€ÎS|šÒãolc7u×®‡þ á#|ŒÉ‡7xˇ7}ÂE0ÜfM£Ò*Sy4Eì T‹Ñ g®Àp ÃÅG]`­NeJ:mÜúºéÂGø<#>¼Á[>¼ùè ^  ®Ö½{/O‰~/¡,Šjª©¤2 •WÔH¥Žª{TÞ£¢ ì²Zw÷þ§ð%™ì, @kz¿²8Jõ7?~+|„1ùðoùðæ£7þÿÿì{TTÕÇ{ïsæÌˆ¼)ˆ¥&fT^¬ì¦hÖ²nšy{*¥¥"*¢%¦™¯J…4+5ˆ¼axÌð–ÇðVyˆ/Ää ¢\õæ]y¹{Æ[‘кÝRf3îµ>ë¬=gÎìù¬ïïï: ¬¥¬ä5+«y’¸M†5©Áä­_j¢waµê0Ôh E€VmZ4"h@P‡´wjµº=sÁD+U#T#º¦='ƒD‰|bßìM[¾å>Üçnóa Öòaͧo`¨(¥E¯š™-ñ7 ©@k€v©Ø@i7jB¨^Gö­ºó­ÝhÔè f ֽж±LÞÛØp{~ãŠûpCòa ÖòaÍçNÀtܤò»¹îîK¬¬‹‚FÛRHj™˜(àT¥‹(S NpFß|.áåfÄ?`Uiéíÿ®%îÃ} ɇ5Xˇ5ŸÛK?(€Ÿ :à±tÉ:ÇѬmÖÂD<1YŽÉ{ô(*–4™7ÌÁsâs¾^^;r³½Û/¸qîÃ}ú/¬åÚÏm¡?@wJKü4YÞ)Iž ªÅɉšLï’âuíqîÃ} ÖòaÍçÓ_ €Ãáp8^‡s—Ò/  ¾Ö-*ÊãÀ^·þoìx5pÿ;Ùš¸÷á> kù°æógè7P]1'`Ëë'l25š?P¾P$ ¼„àE/ÄÈMÜY0xÐêùó? \Ê}¸÷é×°–k>·‹~P8;¯”‰óŒ„µC,¾zÒ)|Ús«WlÞvtÛÎâ­_–®ÿôøì·4&ÄŽ~Àd`€$¬¶0õš?ェïÞá>܇ûô/Xˇ5ŸÛ Ó»jøðhe¹ý‰¿D{,:ÖQQÞÕÑÑÕÞñïÖË7:¯wuþÐÕÒÞÕÑÙUWß•™Ñ±Þ÷ijSRx P&xÉe‹æÍ]ÖP»˜ûpîÃ>¬åÚπѨ«qsíFo²,M·>ý×|×9¥‘ñ—Î5ý«ñrç÷Mu —Zšliü±©á‡¦†+Môagcý妆km­?)ûqõºòi/æ:9Æ}­-—D†{rîÃ}˜…µ|Xó¹s°XG¼Ü‡û0kù°æsGa®”Ê¥ ã¹ffŸOžT:åÙü>¨,Èë:^üïââ«Å%mE%ÍE%ŠŠÛ‹Š._Ô.~MqqÛɲ¶£ÇÚ‹ßØ»ïÊK/–M™tbì˜xI¶lúß^å>Üç.÷a ÖòaÍçNÃVDEºüº¹ÉWS\¾w™Pôö»¹ é×4Ùײ4—ròÚ²rê5¹ušÜFMN«&»]“Ó¢Éi¾…윖쌖ìì–¬ÜÎŒœ66Mœ1yÂQ§QjIxÿ§ÿ¯‡¹÷1$Ö`-Ö|ú†  èÈÌF³ÌMý]ž:ïüH¹Ë„¬]ûZâSjâÕuê„úxõ¹„¤ïU çT çUêF•ªY¥®S©k{PŸߪRÕ'¥Ö*ÕuJÕ?ß|³`“EO­xôÁ\Qðy~êLîÃ}îBÖ`-Ö|úV  ºrÎûÌM?{ôáüÇœN{dÎܲ àöCáå¡ág»Q~>4¬.4¬>4¬&4ì|jÃBZÂÂjÂ"΄Fž Žhغ­ã±‡3ÇŽ>;ΩzøÐXQôð\ö¿&Ã}¸!ù°kù°æÓg°ROŽ_-Šëî‘æ0òˆ“SÑè1±«×Ö|ûmó¾½ßïÞ]¡eÏwºEåîÝgµì:ûßEOvUïÞ]µgÏé={Žï¬Ø~qâÓùN£Ï89ýc¡í }D˜­Š÷æ>Üçîña ÖòaͧÏ`¢‚ƒ<$ÑÃfpÃ…'FŒÌs¶qs³ÿ–³Û·UøWøßJ¹¿ÿå=8ãp"Àÿ»/¶VîØvæ‹€òÏ·6M}þȨQ¹ÃÒFå–inâÿˆ­Í¿ÙÃ܇û’k°–k>} `k»ÔD±mØÈx»¡é¶CŽÝ7¬ðAǸWóû¸l“ßñO|Oøùžü‰2?ßã~~%~~Å~~¥½Q⻾àßÒ ŸÙðñ©õ¾'}}ÏO}!ï¾ûìFDÛK>쨭u¬$,÷ßò ÷á>wƒk°–k>}‰þ àË®/·²Œd—tÝaÛÁév¶É#b»Ÿ]ésrõ‡E>ÞÅÞÞ¥Ý(ù º>Þƒ2oïSô)¯•…^¼ïSòžwÍ$—»Áñƒg ²MlKß"ÍÄh—µ¥÷á>ïìåÚO£ÿppX&Wl²¶I´°Q[Z'Y[%ÛX«l,½ñZ™»Û1w÷,w÷¼…îù½Q°Ð½ðVYèVL g-Xœù®[žÛ¢³#GÄXYÄX[¥Òý-­ÕÖÖ‰ƒm¢ì¸÷á>†íìåÚO£çHMY%Êæïh7À4ÚÈ8Æx`¬‰q”…Ù¡§ŸJŸõfá¬Yo½•Ó;®¹½‘7Ûµpö[y³ßΜ5'ó ×ü™¯·°47¦;™D™D 4VUÈÖ=ý×[ÿc'÷á>†äìåÚOߣçØðÉ4™¸ÂÈè£dŠp™=ãwC/¦/Éš6#cÚ z,|Ì9U!ß'Š!ry¸\$$£ 1T?—$׺šE܇ûªk°–k>}ž àaÇ$q=B{)ÐA@AQ ´søý±“Ÿ)˜òLÆäIi“]Òž™|ø÷àâ’þ쳚‰Ó&ºd=>^£°ã}cFx=ô]Ža»$¾¿ëëù܇ûªk°–k>}>  ¥q©HæKd'@¡Dt!šÁq¿ãè¬ÇÇ¥?1.íqçTç±Éãþ’Ò¤^yâñ´q·ÇÏ}llޱIÀnLB0ŽÀNßð^ÀÁ‰!tà3ãå@îÃ} Ò‡5Xˇ5½ ÏPÇ®4’ùØ%‘€"xsa€B —IQ¢,xø½1£G%8=”Lc“º‘Ð+ŽªÆŒN92e Q!‡0 #BB”´„ï‚p´ „ŠâæQŽë¹÷1HÖ`-Ö|ô‚> `çvW +äÚŒ"‘„´÷_Áˆ¦Gk!QÁ‚ðµ¥EÈÐ!±Cì”÷ÚÇü„òޡѽ`mo«´± —‰ûBËœ{@8@4xL7Çôæ.Ý?˜[-,ßç>ÜÇ }Xƒµ|XóÑ ú,€Ï6ýÀ*"8P‚hÊŸˆ¹ @$AQ’¨TÈ•æfñæf±ææJsóhsó¨_0‹43‹4505‰i»â‚bð/[Qâ$"ÐV=àLâèMÁ_ˆÂÒ“e¸÷1<Ö`-Ö|ô‚> àÓ3é &(´õø›P‰X%âD¢I¤(„‹B˜vñ3B= ÚL£¤š¾äכЇɀ”4}À‘˜$b¤$x‡(,+>¶ŽûpÃóa ÖòaÍG/èµ6½¬„HHFÐ+R‘öYÚŸj‚Õ„ÄKHÁI¥ÜDÀ©ÓE2M#®ö…ênû$HA(ަX…q:Fñ}% ˬá>ÜÇð|Xƒµ|XóÑ zýhó ‚|tÈÈ@4 mз@cÍÄÚ n‰^“t3PÝ:õ&¦ HÓ­S°n+Ð^Ùmú,RŽD¯É¡sÒ ÀóçpîcH>¬ÁZ>¬ùè}À®¯]òH Žà€t€Ã= '³4™ ›S7RzƒÎ)­ç>Ò‰nÆ€’èn>Š‘#ÏÓ'7rîcx>¬ÁZ>¬ùè}€&ËW–`t@"9ÒʺmôÙ½@/Æi€S{(³ç>4rh“#D'G‡/#‰„l¶³_ÖÖâÎ}¸áù°kù°æ£ôü—À¢8O.;(`P>By¿Aίù­ó?“ÛsŒò(ÐÍ Á1:¹,`ÅCzqîc¨>¬ÁZ>¬ùô=ÿÿÿìÝ TMùðÿcï³;¥ÐkTÌBÄpi01cFb°Œ;Œ±†ñ©(1Ty1.ªaŠH¨<ÓChzŸ:•ÞÒû¡÷[4˜1kÜîÿãÞ†fÍÜQ§¿ã¿Ögõßûì³ÏwýÎZ}ÛuÖ9Ý\&ãö‹ø#&—HIJ!L”R٦̳=í'+ùír0H!£|IŠüá/B@Ê$ ‘ìüidXå2æ×Î3?Äò°<Êš‡6´Í‡¶<Š×ͰoßçÚsüU³’¹¼J ‚lÙ4a<dóVGRÿ@“SɺJ”˜Ž°„㎫¨,=rÄåay”5mh›my¯›  ¸ÐBPµÁÜ3È\L²?ÆÝzþªL’Ï4íAŠd%Ÿ,– „cÚ§¯¿ìVÊv–‡åQÖ<´¡m>´åQ¼îÿB˜Qc¶"äÁ#r¡”dric˜)—ÕY È ‘“ƒ\rfŽ ‡pó´i¼‹åay”)mh›my¬û ÀˆßΣ+ä#P‚@ñ³Dª’Ì«€;²WåUÝA²óBË¡ihØy{íeyXåÎCÚæC[ëþ FŒØánuqiHJ® ¢Ûg”@”M­ À\A øK:ššn©«îø+ÙX–G™òІ¶ùЖG‘¨(€°Ð ‚`Àq%ŠPª!Ì8 `rEVA Åæs(›ã®c´G[Çâðá?ü–‡åQ¦<´¡m>´åQ$* €°²^ÆñÎb!ŒƒäB©ÁRÀå® rî"Pöª`)iuN$å8Ì-›=Ç©¾v9ËÃò¼!yhCÛ|hË£0´@mÍá.<÷“9Xaà‹_ ¸ „Ê1|¦B®ò¹ŠçÊÛ!›Uò{ÿ(tW$Ê0Àí#Þ]ú'o¿eyXeÊCÚæC[…¡¥ˆ¬ôyÚÚËÞ]„b9\Žp©_ ”CH®Â*¨D  ƒjÔs ƒ&ê!¨ ‚J(»R«/Èž4@R¹°Âr“5yEKEàš€wöë¿hÏþã,Ëó¦å¡ mó¡-bPTDFêÜ^½lytT,Hy¾.å› š7¬…°J®Rv åûÛi°Àë$icŸƒq8†[úõ³Þ¶ëû{ÍV,Ëóæ¡ mó¡-ÐUDvÆGŒöªp"TÈ#2ÄåZ¼P#ÀÕWÈ :€äãnúÙ5²ýà>IW‹ùl„O¸öíþs]¿mj´dyXž76mh›myºu@”}5Él?·q @ŒS0ªƒè„äxàc€É=¸¨ ¢fˆZä·M7Ô P µ"\"` ‡Žbn¹±‰Ûþ¿ùw7–‡åQ¦<´¡m>´åéR4À3;¶íí!Øóh7D×D*éåAXáÇ>Aè)Oø‘t,?cð„¿ÈÖð¾ˆkEà _!ñ…hc/-Ëé³6]yÕé³<,2å¡ mó¡-O¡·ˆ‚;KæÏ[ʉ!Ú¡·XˆVU¹Ã£Jê0jûhÀ#<æ@‹6ˆPsÙçí‚ÐIMcÉ(“•[¶Ÿ¨©îœw\±<,2å¡ mó¡-OW ºž)Ì·°±±ÕÖ^Åsºcä'BEü5Ýäa$£eÐu x€}Z«ÙkÙøñ¶ž›22:ÿ³–X–G™òІ¶ùЖ§s½ð_~§ìVÛî6ÜMGw ÇÙBlðZ„¿&·¼xuåŒì'Nsqp8$‰sln°byX–çõEÛ|hËÓ)^§h/#Ý56ÆñF¸}XȪë×ìb£ÓÓv47¬dyX–GùÐ6Úòüm¯k0 Ã0¯ˆÃ0ÌŠÃ0T«ª°ºxÑîÔ «CóyÎõ=¹,.v+ËÓ)X0 C’‚¥žû¿œhº§§šek¯à-F+²FЊç¬0^¡×ÇÙÒrëYßÕo`žÎ €aŠœò]ab²QÄ/Wã¶õÕ<òqàÌiç7I¿qOq?œv໌]{3-Ž55 2xJ£‡§À9köt°\þuQþ²7!OçbÀ0 ®m8p=F›µµ¾ÿÞ%»•·/´äµµ´´5·ü»ñÁÓÖ'm­?·Õ7·µ´¶UVµEGµìrÉž:åÆ!¾"ÎAE´r¹ÅšêŠUÊš§+°`¦›U–[™/²â­VÏ>J4_šq!ø~ií/5ZËjj+«ï××ýZ_ókmõϵÕkkÈfkMÕƒÚêÇM¿&gýê¼#oæ§ãaÁª¼‹Ž–í…@{%ËÓuX0 ÓR’?ï;ÐIMÍmäð˜Y3 ¶lLM‘>-,jË+xTPr¿(~TTô¤¨è'¹ÇEd³’’‡äÞã'ªæÌ–LŸRÐGûŒÀ;X¯Ø¤4yº+†aºÍåË«Åê½zí›<)cÊÔÄ  ¥ m™iÿNK{”–Þ”š^—šÞšÖœšú 5ížlñ{iiM·³šRn5§e>=áóð³O³¦LÊ3"X­™õϹJ§«±`¦{\¼`ƒÑ—½5ŽL1+33M]ò•$,òqlÜã˜Øûñ M1ñU±’ÊXIMl|cl\sl|}l|Ý ââëã¢êãâêc$­QñOÝv×N4šlšb<4TàÖ½küÿýÞM[`À0L7HMž£ª¶°wO³ïš¼›gfş>øFyphehXUphiXxYHXiHØÝКºÐÊЊ—T] n © ¿Yq9´òrÈO HM?HýpLÁ¨w$<çôÉô9¯iÅ`À0Œ¢•.íÛoCïžÿ52q´qÎØ1ÉK-²üÎ6Ÿ Ìó,n§Ä?ð®@¥@•@¹ÀÝ—Tœ«(8Ÿë!çìùêî-£GF^<Ö¸dàÛAzñziË£x¬†Q·3Eüz5µS˜¿(ŠTΫÄB šØï-ÝÓ3fH?û,~Ö¬èY³¢þ2r0yHÌÌÙQ3g“Û¤Ñ&7Å*><NE%PEì'Rõ‘ï/ðûÁ¼²|%ÍyÃ0 2rØVßá Nð4€~œ!0ôððÀAA“?–Nù8jò¤ˆÉfOþá¯03‹œ:5vâĈ‰f1ãÆÇŠU½òAð,g!òØ›< ‡8(ðëŽ}oIsÅcÀ0Œ"Ô׬汥€à‘?„§!Y€sùùˆÑiŽ?9lx̸±‘ïgrÓdÌõ±ïÝh'¼Cï‹kòÃøñ’ÑcâÕ5üðBøBç$OÐ €Îrø &?|ÓìÏ}©ÍÓ-þÿÿìÝ{T”uðçy~¿wÔ¸¨uÚkÝÓV𑹶[í’uÌÓîV[î±Ë榦¢&¢å=ÍKë5¯ešnšš"ƒÀ(Ì^R@QÜA@”Ô²£±¿wX OgWxyÅçœÏ™óÎ;ïüüþó~ŸŸãœ‘cÌÎãš[ÆX&e8Ð׈«k À*D˜Å¡YBÚß¿¡ãÃ1þnR:ÄÕS§8:uÜòàƒ›[4_'ÄZ6!#× °«M7ÐJÀuH‘R†jÚ¬‡;L3mžFÁ€1f„ÅŸõ&é¡wb8Ê5¨Þ‚ªma=Q¤ND„HùE«–ëÚµÝØ¶ý~¿ WÙïoY¿H¿ûì÷´³h+¥P›wµ‘_) šÔâ´Z. Z?DÈy-[}`Ú<‚cÌŸÌü»€ñ× ŠŒ@ˆt³_µ¡@¸À«f÷ô°ûúDûúlôõµûúFúúFüÌ'ÜÇ'ÜÛ{½·W„¦vÓ´Aàúy)% !AßÚ­#E´^Чšv sº9ó4 Œ1#ÌžÑS®À± o‡oJ€C#‡EFi®‰pM†iÒ¦üDF¨G©wh„D‡D§z˵‹¨§›íªmÂIÄÚ-Òäðô=SÌ™§Qð`ŒaöÌ×ôÂ…P[6!ÄÔ‰` ꯪý²SSˆh!6 %(Nàæ’¶R›T«ª2ÕßଵN¬€ÍˆQªmDÛ£.ÑäˆÝ)Í™§Qð`Œá“Y¯ ã.ÜíÛQ¢^¬×Q5Oú5¥¬®‰«)P÷ñ–„ß([ÝǛɽèWÖZG½ŠN (@uM’êewáÿT¸fËÓ(x0ÆŒ°ì‹ÞˆAVaSE)(`À77P'\ñàîåZ6×EõòÖ×AØ&ܧV“”Jè$\àå|èÀ sæi<cFp%LÕäPÂUV‘$p  0ázzÕ&ÖA]L[¶Ü`+`üë ¸$©;¢jjUî;-"VˆYmü†——6gžFÁ€1fMëïaùZ’*Ĉ;n"éZ7;ÿ“ä!Ü!!ÅݹÉ{TázX¢F>Úy”™ócÌ ]?×¢-‘â„]ˆ)ˆ;u¢?ÕÕœ©Ý¤Éÿ½F] ©ª:oê~ûõR$ì°“ôõÓÕO»ÐF¼Þ{‘™ócÌ sæ¼,µ(ÂL d @‰€»ö!ì×Û“ÔÓ=uI»‰:.VKé{mLLÜK"YÊå}–,™næ<ÆãÀ3Èñc}­Í ¹–0Cõ `*è¾ï¹Z¸jk¼ËÝ¡é·!ôMýn÷Ÿ’AÂE4ç¾ûúíIlæ<ÆãÀ3Nç.-Ð(á(è‚Ú}ã>·Ìú‚)`?©Åá°ZYÊ8Ä{ô¨ã —fËc0Œ1ãØB?°h“5Ú à(AÁñšNR[cÕY‡ô¾U‡H_ÿÂaI;—yy}ùïÙæÏc0Œ1Cuê4qÆ]žjGLpÂ*O"‘tà$ê-™Uð°&²R¬Z$á耀‰%…uÿŒfËc$Œ1CÅ8ÇZ­}–KÚi¡“"‘ â(@BÂñz€G%í—r“ ™­ïî»xñMrÇlyŒÄ€1f´ÀAý¤6ÁÓ#ñ(Aá Afåœ"8y«ð„ÚÅKKŠ”_ ÙïÕžcJ‹ûßFy À1f´â¢ÁuœªÉÏ5Ü-±P`hÙ ™G”+°Fž[þUyWåÖ¢ž¸_½ö]tÊb9¸pr§ÇGF;áëöfËcŒ±F¹÷õÖ­û[µùrI‘Kâ´Únƒ51! Ÿ @@¡„R eÊ JŠ òQÿd&Ï} ÎœC8j‹9ˆ¹R¨cÕà',kÿò{àí™s—ߎyŒÁ€1Ö82Òzùø Õh©§5EÓrAíµ ¥T½b1b[¾þeîóeµ”Vž,QÈý.µû¶h…ˆ8ÑÏoФi_œ©¼Mó€c¬ÑìÏx«M›Ñ‚f{È­:¦‘*Íoݪϕ(‘§£ Óîz-ÿ™~A‘~Î 8¯öæžÚ~+G´{ ×„?-/p[çih<c)'ûÝçºÍÕÄ$ 6O‘*¨é ¢*Üó€.¸QŠ •#U UºËQ”UU’(¶ˆ«H–´TÈþþ]ƒ¦Ïý??g7[žÅ€1Öø¦LšÝÂ¬Ñ ¤X‹Ç^AG‹$]$¼DtáÁ·jO-à{—$ü ãY‹¬"8ç¡åY­IˆK‘Æù´ðâ+ãíŽ[m[³åi <c¦uè7_ï#-£‘¦!~éioæqH£|‚A•8k…*+\°ÂE •Xо^Kºw;Ù- íw“c¶]t%^LpMÚQžTàJÎw%¹’Ê\‰®¤RWRÉu“J·—&&–&$WmOº2}Fñ³ÛŸHõØi•<îÿ¿Ía³åa¬)1Ûýe¶<0ÑHÛݳYóøz/èöÌ©®é°ì«Òè͹ÑÎ|gLA´óDLÜIGÌ GÌ)‡³Èá(q8óμÄF—9q[òìÎ|»ã»·ÞJ x*í™.YIÖä˜?¿Øó6ÍÃXSb¶ûËlyŒa–s¬O[¿±¾ÞŸt~lçþŸì²»OßÌ5!kÃŽ„†¯%'4ìT¨-?ÔVjË µºAžm]©Í–k[84ü`ÈúÂyó+Ÿx,¾KÇãOúç´o·QÓ‚‚‡ÿò¿É˜-cM‰Ùî/³å1ÌÿÿìÝ pUðïûÞëîBBI”D"‚,«.à²ë‚¸Z®U"ºJ! ‚`§AH¸$r†;¹’’˜“+!á `Â}+µnÕVíë‰h$¡Ö˜yi_Õ¯¦zzzÞüë{õÕW=•C–ð箓4mZëV™mvw츯}‡„IS*W¯¾´vÍ™U«Ž›Â9N¬ZUaZYñãAm+O­Zu2<üHxøuN-\|£Ûs…Û—wìpäÉvÅ~¯e¼_rRpýÊ£(V"[É–Çi¤‘# m„oÓˆ€Ç‹¶jSÐvë¬9—ÂæW,^pbaØñ°; +w8ZKyØÂƒ ÃŽ-úìÄ’å‹÷ÙÅ—ÿ±»mÛü–™m [µÌöòkÝjìÕKwòåQ+‘­¿dËãLR ?¿‘ö-Û$ù7Ïò{do‹–ÅO´KüdâéЩe³CL9r趲С¡%¡¡ûCCKëR2£hzHéÌ©å3§žr($äË—_)hÑz»«Øf-³k¹ÇÏ'Áà£Ãæ¿Y_ò(Š•ÈÖ_²åq&׀ϗô'íÝ$öaÿ´‡üwú5Íò÷Kh•0,¨bÂøC“>Ù7>xppi %·‰ãµ”/›P<îã¢1ãK> ®|¾{‘Ó¤¦Mw=ì—ÕÔO|D¦‡ÛJŸ&ãêEE±ÙúK¶ÛÇ7µ±oJŸ4ït_Ÿdß&›úô. Ü”T0$¨°.EC‚Šï4d÷Àýâàƒa9 Ë~?° phE›VñÞã}¼3ÄúM|R||R›úÆrµaÝòçQ+‘­¿dËãd.;&júw÷¥ Ý4Šuswo˜àáÓØsÓsÉêûvqß¾»Þy'¯nýóëRЯq¿w ú½›Ý÷½ì>ý ßxó@ãÆ¼ÅŠ•Ý<¢Ý<¶5tso°Å®O{î¯wþÇNÙò(Š•ÈÖ_²åq>€™Ó_Õµ±nn뙣ۣtÛ6›m7¢Üìùn|å•¢×^ËëÙ3»gÏ]¿š¸X¼%çÕ^»^í%‹Ÿî”a·­Õ´Í6[”Í¡7ˆÐŶÅÐæFÿ³•CeΣ(V"[É–Çù\<þÐîSC›¸† €#6 7.}¬uBŠþþ®ÏgöèžùB¿F÷îY/¾˜Û­[f·î9]ºæÚ„­%Œ$ˆDZ ,\| §(‚ņ6fåòÁ2çQ+‘­¿dËã|®—/ŒÔØ`ƒ-ˆ@Ú‚¸ÅlD½mäÚºvísºtÎz¶sf—NžIïü§5¤ÕéÙ.™;íìÚ5ÿégòÜ="VÛL´ J|РHÎâ™Ø ßëõ ÒæQ+‘­¿dËã®) Üôñ Vr ´qCõlÜÂX”nÄhzäcÆ·o»½ã“éâ±C»´¶×©ÝÉÚg´i³£¡ÛfÆ6ÛÊx â6qb­ÜŒËùM›Ó¶Ý ió(Š•ÈÖ_²åq W€¥‹ûŒµ™5ŠFæýW$ŠêÃ6¢X‹ˆä|y“Æ››?’ðˆÜ£Íâo‹{´ylšÅ6ó‹óõŽÒµuœ‰a.û6€(€XI$'qs·P¬Éøg›Œ‘6¢X‰lý%[—påø×ì2˜Èq£$À„X‡¸Ûâ«D3Œ1´8»-ÎË3ÉË3ÁË+ÎË+ÖË+ægžÑžžÑmk䣉éJñ ãé祄D„TsÔm&–(nÊ-ÒøÈCe3åÌ£(V"[É–Ç%\9æÎzClÃH†©`ŽÇ»b¬Q²Î5§±hGi|«yð#¹YÓŽÉSÄ[~¹ˆxš'ªM,•0ŽÑ¸ï49ó(Š•ÈÖ_²åq —€Ù¯›[d¤#l¯Aš¯Šù™Â(…±$ÆKd”ÆpG5NŒÄAº¨2¡(®ùF€”ë¤2ؘ(ª”L”E˜Äp™ÆGï.š,gE±ÙúK¶<.áÒ¯€æôb8Þ±»v¡(Yè;ˆ²f“yAõ&‰kÒª ê8ΨF¸S@Ètï ÇR`^Ycñ*¦%ŠkòÄ>96`ÔO [E±ÙúK¶<.áʰryÄÛ* Ǩ `g-âd@.@68ö©†uû”Y{„,æØcÀ4±§=„)„a£Žš%gE±ÙúK¶<.áÊ›¢ñá„ë –Ç°00çNf鿨ƒ¸˜22jÉÌ®½B.ƒ<1ÉÅΉÍ.ÔY*csü›}xírœyÅJdë/Ùò¸„‹XÓÙôœD  î"ï—îvþ'ùµ!,àPäØƒ|„½blz"ÀØ'Ÿ'sE±ÙúK¶<ÎçâЩË|][Æ™¸E*F,B,4A‘ùÔT}¦feó¼F\ {D)kÙãxûŠ83($sýýâŒÝǴѽû/‘9¢X‰lý%[çsñ˜7ïuÀQ\K$,Ê–$n¯v@8hVóÄÓ½uÙwu\,–2g/æ–Ëç|µÍöÞ²e3eΣ(V"[É–Çù\<*N 01¾‰°TÔp˜_Æí½½bT;jºÿ!ì#sÈïv|J)±\¢y~~÷î™*sE±ÙúK¶<ÎçúóÔ3Ÿ…i$n”Žé0ˆiŒÊî„2I,åbeÎÓ?yé¥:~K¶<Šb%²õ—lyœÌõ`ë–1º6U£xÇNTT×HŒJQ¯ãGÌ]¹WGÈ\ÿB9§•#ÂWÍ•?¢X‰lý%['sý:t˜8ËÝ^*&$ÁiƒŸA:¬è(À4«vü>ÀrD(2´XÂà¿ýmò¥óuÿK6Ùò(Š•ÈÖ_²åq&)Àö” cÀjN…:Ñè<â1`eÀÄYÂ)„Šûq:Èy:£ÙÞ>–.½ëŸà-¢X‰lý%[g’bCrm’ÝØÎQÜ(] < ü0ðã@•_œ¹WxZLu®q¾–ñ½Þùâ z”GQ¬D¶þ’-ÓÈ2.^z¼}ˆÆ?×p7Çó Ïv´ àUD• «U9œ½­ê¶ÊÄÓsŽWù.úR×&NíðDZI)ÿçÇoeË£(V"[É–ÇidBYIooïA†¶@§\Î*‰]ãŒJDqVEp–àƒó.s¸ÊàÁe„ ç΢y§Vå8g¾F¸‚bäâ)ÄJÎıØÑÓ:¤lz³ýfÏ_]ó(Š•ÈÖ_²åq‰€Pºï-OÏá­°EšV b–jׄk ÊÏ9œ5áªãüÕ®^¼xI Ç»Ä4ֵÌ¥1œÜ¬Ù)3–߸XOó(Š•ÈÖ_²åq¹€p°ômÿ`FsmK¾µaÝÀ/r?UyÅ’dë/ÙòÜ‹ÿÿÿìÝ TÕUðß]þï=DvpÄR“L3*Gm™Ì:M3š9S3)6*`¹ jT¹5.˜¥{ˆì;ﲇóÿ»|Ͻçw¾ç¯C¦jíÝõ»™nÛ­Ì—WyIdÅo¼c/Œ<%êIȲQ#ý–.}/$håÿaAÞæ‹·*_ø†ÖÍ-~ü¸Ï-‡ïUR?[«õK—ü©îâ›ÿyANx›/ÞòÜ]\@Bü¦qãÖüŽ½Ý¾'~³bù¹¨ðk5Õ½×®õö\ûW×ooþ£÷æß{;{z¯ÝìmnéÍʼ¶Å¿òùÙ©>¤ ëUŠåK¯nmzK®yANx›/ÞòÜ œ@s£§ÇBOöegµû™_ä{,*‹J¼~©ýŸm7n^nkon½ÞÙñMgÛ7í­ooý²½½¼ÙÖr£½õëî®o +¾ñû zίs]'%“üìÞŽŠX%³<‚ '¼Íoyî  ¨ð•Ñã|ÍÍ·>29{îK5ïn,.Ò}[[×[]óUMÃõZ¦þ«ººÔÕýÍàë:ö²Ÿ††/Ùwm™?/÷ÅÙ5#íO*¥õ^Ë6É& È oóÅ[ž{Š»ˆ]if±ØÚzç¬gËf?Ÿ¿aC­.¯·¼ä_%%_•”v—v—^-.é).¾Q\ò…þâÇJJºÏUtí))ÿöè±/_þuÅìg+§NIT*VÏýÕ«2È#rÂÛ|ñ–ç^ã«¢£¼ þåÙî—ÝÝŠÿðÇܤŒ¯µg¾ÎÖ^ÏÉëÎÎiÑæ6ksÛ´9]Ú3=ÚœNmNÇmÎätžÉì$²u÷žk?’5urýt׆qcâ%iŪÕÿùïdxË#rÂÛ|ñ–Çhx)€'Ÿò“¤Ÿî2¡ÐÕµxò”x¿÷é8vôò¡C5z‡/.jª×;XÿÝÅ@ª;|øÂáÃåǃöîûbæ3ù®“«\§\xxRãÈc„.T'ú ­<‚ '¼ÍoyŒ†‹ ^¡”VŒìò`‹Kåø y.÷íèÜU¿oOíÞÀšÀÛUVTP¸·roàÅw×~²§êã½Õ;w·¿øË‰sǺ¤»LÌ?6ËÆ2ðñëº:îØÃ¼å9ám¾xËcL\€£ãJK³=c'$:Ép}öþ±MJxgÓ¥€ÍÛÊ?ô¯ ð?wKE€y@@i@@I@@Ù`Jý·è>ô/Ûº¹jëæó[üÏùû_yñ¥¼ûHrã<6cÜØ"G‡x%]¸ë·C% È oóÅ[c2}|ú‰ÆkìíbF:¥üÌé´ã¨ 'ÇS.ããßò®ßè{Îïb_ŸŸ²~Joa×åTøøœgßZ¿±`ýÝZßÒ?ù4>ë®s•8jTæHÇŒQŽìG¤[št°[?$ò‚œð6_¼å12Ó€‹Ëj•Ùv‡ɶ#4v)ö§F8¨GØüýkÞžg½½³½½ó¼¼ó£óò.¸W¡—g »XöVö²·²þè™ç¹¼~Âø8{Û8û4¶¾ƒÆÁ!yÔˆŠW_ÆAÞæ‹·~; : ò±~ýöŽ™*–Hk^óø„ç<‚ '¼ÍoyŒÏİsç+€VQ)£ À¹@²³Ç«B€r•úÝD9ìåÙÁßÁ 7³¥ôÝ‹ré•b’Ké•jÑ[yÎ#rÂÛ|ñ–ÇøL\õµ‹•ü =‰QÛ@E ÿø³·€UeaOK~"ÅX_ò…†ŸR†‰㎎ož-ÚÌsAÞæ‹·<Ægú_óØÔ÷0”0{Pºzçµ1*7¨¸[T¨Älq¨b+Sš‚Ð;/¼0È?Àâ- È oóÅ[#3}„‡­UH›%Gà"† õ}{˜U%Û¯€ úSù©.`ýúµª(ÎÃè ¥åŠÃ‡>â? È oóÅ[#3}0S¦lGh›…YkH —”ô2Â瀔®¸Œô»Vs *‰Ô!Ð)¥Œ|ÜÜÞíhüW²ñ–Gä„·ùâ-1qQIš Jåb€#ç+ðe ·"tHöDÖ„ Aý]€.R\Ié)‚·Û;,Þ¿ÿŽÿ Þò‚œð6_¼å1&. €ñôz“J~fÊ$ŠØƒRF—€žZ¸Ã —*t‰µ:Uè(=Fè›óæûv¶/ByANx›/Þò /ÐÞæýàd‰~*¡BŠZ j©¤z M7Ô§É ù–¦[ûa/[ ßýñ§ð…â< x@›§<º.Qóþù-oyANx›/Þò /ÀT”¾fo¿D)íQ`-%˜\eõ ÊF„ØSX†f -Z)tRè"СA‚VÍHÿ¤Öd¸`ïÜ@p±ÊE 5R®ى^R@²’|è|ÿÂí»Ž Å<‚ '¼ÍoyŒƒ£`ÊŠ_µ¶~[Â1Sê$©X—J=L7°íFíµ4ë¿B—áý®~ºõº ¨ƒÁ†O±6VHç I!è]gg¯÷·|öEçÍ#rÂÛ|ñ–Çø*¦²ìu''‚?RÑt®•0ÛÄ¿Üôà. ­@šôp૆íîþþ†6ýûpÀ—¬«Í¤JLŽZ3æþWý>îîZ:¤ó‚œð6_¼å¹×þ ÿÿìÝ TÔÕð»üÿ3Ⱦ¤¨•¨d˜RZ–ˆ¦󥙯UI-Q-%+…D-HÓRsAömXfØef`M‰­TE%”—–wgH#Áóz©Ìåï=çsæügæÏå{î=¿ó=ƒŠÔQWóþ$—m<þ”‘¸£fˆ~‚ÀÏ^èŠÎe€[ .BÔ Q›îñ"Äj¨ á&®c‡¾ÁÜBG'€mÿðçn´åa!¡m¾hËs_ÑX6|úy?±'6A”"’”bT a#‡®"x ¡\Cà?¤c1øƒkøM{ /‰¸v.Kø³b±Âo Zkf¹hÚL_©ìnwŸ¶< #$´Ímyîz €¨:9ïí7çs"oˆ6B¸ß@œc(9É£zš1jKbÐ.WÄà*ÚDð¼åñ)±ö÷í†ÐÇÈdÞSNK?^ ñܽùW´åa!¡m¾hËs?P]ª¿_àî¾ÜÊjÏy!¸£±\ħp(ƒ‡Y<ÌÑBiŠDð¶ŠÑ* ³÷Æ_ä[Vvï×myFHh›/ÚòÜ[} n 9ì±bù‡‘Ö6sÜrˆ=^…ðä‘7XÑÏdá{ω/ùyyíRåy·žw{Ðò0ŒÐ6_´å¹'úRtUVê¯ÈõNOõL–-KKñPäx—j6´ž_Êò0ŒðÐ6_´åùÇúj0 Ã0w‰Ã0̪O@ÃY·ØXÃÜv¾½+èàCïå)>ayFh›/ÚòÜ>SuU󃶽5Ñy³©Ñ¢~’%<^Ì¡å-Eh ‚n<ç†ñâý×-ZôIXðŠ0à móE[ž{¥ÀáàÅNNkEüB#îÓA{žsŒšñRô:_õ–Å;vk¶U¶ñóò¹ï*œ†Ú6é$æÖY˜z-ZøAÍ÷ï=yFHh›/ÚòÜ[T@b‚¯ÝjŒ>²²Üùì3qKOÄD¶UUv´µu´¶ý~áòökí¿v´´v´µwÔ7täd·mô;>uJúc‹8/‰héÂ+Ï]&Ô< #$´ÍmyîJ  þŒ›ë\7ò!ËÒtû„ \ç—Å$]ú¡é·ÆËí?66ÕŸ»ÔÒ|½¥ñzÓ¹_›ÎýÜÔHž¶76\n:wõâ…ëE××m¨œñŠÊÑ!É÷³¶\å)°< #$´Ímyî  ¸èµAv>FF£GæÎœ^õñÚ’bõꚎʪ+Uu—ª‰Ú+55×jj~ѹZCžvQW÷3y÷Û ³g©¦M©êo*æ½–,öL†Úæ‹¶<÷u •®00^`f¶uò¤²)S Ö¬©Vçw”k~×h®hJ/–”6—”ž/Ñ´–”\.Ñü¤½ø+æâ‰Š‹ÅÇZ5å7üùÕW*¦L:>fT’X´ræ¿Þ@†Úæ‹¶<÷]ãŽÑ[æ&{¦¸üèâ\2ï}UrÖUEÞÕ\Å%eþÅ\eƒBU¯P5*”y­ e‹BÙ|›³^ ¦6à móE[½ÐgÈÖ‰|0ØËq10¸óˆ0ã(‘8–…Ù=?rD²ãiäq”CjÉ=rx\6jdÆðáéýŒÂ1E8s±Fc %% Ð!Ã!Šã¸žß2Âa#µyFHh›/Úòè…> `÷NWVK´{¹¨ýüÉîƒh„â´p,a÷µ¥EøÃƒ ”>28þ&é#Çõ`pÜ`[©U”ˆ?ÄaRæ¤Ø£ˆ ƒ$DGäÃ]8€dý0Ìm·°üÚ< #$´ÍmyôBŸðÅæcàËÁPŒ’Œ… NGzS|'b0ŒóR‰ÔÜ,ÉÜ,ÁÜ\jngnû'³3³SÓhS“Xž´+ŠÇ0ý¹‘A Úª(áDò¡ £/ynʼnŠ:ó0ŒÐ6_´åÑ }Àç›f“À0 à­Ç;Â@Æ#™ˆKä±”Ç1<Ås‘Ú‹[¸XòÈi÷4–ƒ2ÊÉ—üuò4 @)Ù}€bNAPŠÑ.ž[©9¶Î< #$´ÍmyôB¯°ù5í€ 2Hƒ ¹Gd@í»¤?åÉ1NÂ8ãDŒR1LïÄ¡ ŒÈEÙeÉæj¿y—uR0H‡0‘ì>@2„²LÂpÏ­*RLg†Úæ‹¶Ôº3PApŒ€D”Àê'žò¢9à móE[žÞ§çp·MÄïá0ùˆT¡Â- Ö>Õê|¥ëΪþ¸‡Ü ŠÉVvS¬ûòÛ! æ@!H»¾†¼b ‘b~Õ›®»hÎÃ0BBÛ|Ñ–§÷é¹¶n} @OŽOD° À¹‘WE”Cp\»›P yz¬'%wÐÃÍd)m÷B€jKVqÜ·Éü={hÎÃ0BBÛ|Ñ–§÷é¹j«ˆ Ý1Š`Ù‹ö‡qÇn©ÊBÝžjî%H[òEºïR†°¡­¶¶ï+^Os†Úæ‹¶<½ï¿ÿÿìÝPT×ðSîÝËŠô5V4$jÐÄ$ˆFã‹Æøbb/QK°`[ŒÔ˜¨Ø‘^¤ˆJè jè*HSé JÔÄŒ>ÞY|¾%“"ÈaýÏüæÎÙv÷›»sîwïîÎnëÿ!L¿kq ;QºŠ.#ÖÆ8£QfsÁ(“¢,ÂVŽ²Ùš!ãU#G6ñ,Þò Lx›_¼åyÉZ¿¼½–ÊÄu" ¢è*A…<ÞFˆ°ªdÛ+¡+ŠWåE]!Šõça”-$‚÷««ÛºØÊ” oó‹·ecŸ–º¾öæ<È€òám~ñ–çk«àAÀ+ªM@i±•¿¿íÑCV{\&îqà~dV|ÜÈK›)€Âܮۿb±ECuN{k‘ÎÈJæbM°•(XQ:·cÇ9sÖxº/|óÀßÕ à¨û\só2q¶ª°¶“öwïšùŒéë¸2ùëwîMÝñmúÆ­S¦ÅYX÷è~T½½«$8jkØÍ™ýUþÕY¯Bøg¸.€“Á+»w_FÉ*]Ýï¼`;ï’Ÿw]nNC]]Cmݪï<ªÐPÿKCUmC]}CIiCLtÝF§¬ÃÏôîí.ìTdófÏ\\V<_YóÀ‹à´JЬ¦N±È¼nêŒt¿Û×*~-¿S½¼¢¤ìvUåêò‡e¿T”Ý­(gëËKïT”ݯ©~x!ó¡ãúœ1'š‡´ôtøù,R²<ðâx,€‹>íÔÝAUuS_“ر£sW¯H¹˜ü(/¿!'÷^náí<¦à^~þƒüüŸÝÏgŸRXx—ÝzðPéøq‰£†çvÐ=.‰vÖsW*MhÜ@`àB¹ÚLMÍmƦqnùò¼ä¤†ŒÔÿ¤¦ÞKM«II«LI»™’Z›’r'%õ–bð{©©5—2k.þX›šñèÐở|œ9|hÖÓI¶xì¿&(Ah.|€¿Ÿ %_h©7Üòº¥EÊô/ãîÇÅß»T›P—X—X—P_—P—PùŒø„ªøèªøøªØÄúè„G›6W ±ˆfqѬO˜$,}Ëìïwó–šGra|;ÕÉZ.–ïÝ0+ÇÒ"vÿáª3E!a%aá¥!a×Â#®‡†_ ¿VZVVüœÒS!Õ¡¡¥g‹ÃJCž4)ÙâÝ”÷äö{#Q>5¾æ€æÅKæÍèÔy¹–Æ7ýúžëovyà€ 3ffzxÖ÷Éñò)xJ¡—Ï /ï/ïR/ï"/ïÏ)ö>Qåí]äí›íåwÙÓ·lÇκþ}c˜ 4+ìÞ%Xm-þóÏ`yËÍŽ—xw°£(®ïÙ#Ò¨×3³Ó`ǵEV>týÀ\·«ƒ¼ öüoð¼ý…仹]qsË8â^èºûÖΙ™d›™^yÓø¼A‡ÃT˜bß¶ò@³ã¢<=l%ÑV¿£‡QïóFFY=z%õñÞüu¥Ëö‚Ý;ó\]r]ž•ãâ’Ý(ç9Ù.®Y®.WwíÈÛ³3{—kζ£>ºÐ§Ob7£H£>çzt‹ÑRwéÙcYuåwó–Z``°P]¾³[¯Ã.Q~ìÚíüÆ'W­¼æ¼.s‹sƧ,g§KOd:;e8;§9;§:;§7%Íicò§ôMë²7­»¼Ñé’“ÓQ£“ºö 7ìй[T÷n ô‚%a‰ËöÏÚJh ­_ßî™JÈ]€†¯þ`Ð1ÊÐà´Qàù6+.9®Jq°Oµ·OJÚlœñœL{ûËì&»çí–'/uHûʾh¨e²aÇŽ£;Du4`O©®º_OÇ®Mä€Òú`d´XE¾EOÿ”¶~˜Ž^„žîi}½P}ã?Ï´±úÑÆ&ÖÆ&ÉÚæ\S’­mÎ?Ëú‚µU*Ì;w~Ì—VIVó zõÒÕÒÓ=ËÖ¯£¦§wª£~€@¹™Ëh!­\gϬe3ÕÔö¶W;ÙN#@U-H­}°ºš¿¶æñÞ‹š<éüäÉÑÓ¦%4mjbS’¦L=?eZÒ”é1“gÄLœznügÚÚîZlͪê~ªê¾íÕÕÚyÉeë?xÿÙìä-´œV.€MÆÈÄeªªG©è/“ûÈT|U$?¹ä£*÷xMÿØèÑÉŸ|’0vlÌØ±Ñ»3{Hì˜qÑcƱåùþægå*‡Eñ„ŠŠŠÜCÖÎCÆ¢—$n“¤©%EóxÎ-§•  ¯ñI܈ñ!A FøÂg(vGxo÷žÁÃ>Lþaô°¡‘Ã,#?öÃ_ai5bDÜ!‘C,c Ž“·s#ä0ÁžybrQ7ö,ñ!h·$.Ýÿýžó@Ëiͨ*_(Ò9Ý‹&^Ãl€N0lÿHÉ1Aó@‹ú/ÿÿìÝ{TUUðßoï}î5ÔÔVùhù(5ÍÈ›©&´–¹¬©¦\cÑI E DËW¦©ÏQ²Ìw:æ€iŒr/à#… ‚¼UÞ¨¼ß¢¤–-Ùç’Š®¦àÊæú[ë³îÚçÜs6ßµÿøý6—˽ÍÙV,) .ÇC@ßß“ÆL±Wãߥ‰šÐ׉ÝòQè5t·@“@³¼åÆIäá>À@Ymíb<„a gk41-áØ"5óBˆM5kXöº^pÁŸÃ€}Á·ÄàêÏÊý²™33çAœïá|/g¡÷×ìgr°OVU†²˜ê7˜ëÍÂa?â^Ym™;Ä0ˆãZML™¯fB±©f} hùkg[ îa€Ã( ¢^Xo"ËhÓ/¨+ÊòšÐºj¨Ãð; á u¼ŸY§ýÊzóÈgÑ l/ ¼&RÖekÁõ¼^pUËC!6Õœ `ý—c=Œ<@JÎb|×€<`k]®gÿ­Èº|°á<‡¸µ¦†ÊÙ‹chfèëääyòøR5óBˆM5g°„{iÂáV#äxÐ~3½ÔFÜ‚¼˜v ƒ€a çA°pˆ”;wDY©eq6ðΗwé6­²l²šy!Ħšù?5ÍÕÁð/ÁdAŒF‚<ãèȵéoŒY£rB±fn+W¾è)´½ S€E ŒªWOŒ‡Çn%þ6nq±œJßkc` `"ãQBlrp»ví•óBˆí4sÈÉgl5™‹¯&É:ú‹ïÇ®\¹5>j­¡ „ÏôM}¬õ§$1naleçÎãÅ-T9!„ØNó!ÌÀA3櫱„ йûÆd«”¦‚Â!•ÉÉ!MÎ,D(âGÇßâ —ªå!„iþàÿA[¨±ÿpÈ`Ë §®&“[cY3NêU¸±N2}þ,„4ÁŽ0\ïää±qà õóBˆ4 X†¸ôÇ$¹#fpÊ(N#;< X:ÀiÔ«dfÀ4g#ĵoÎrq™_Ztë¯`T-!„Ø‚ Ø<Çh°I°h;­±"Ä à)À3òrršf–*Ä>Ζuì4î‹/nû‘;ªå!„[P¢Hn“Æ mž£1X`ƒb†§@œ‘ ,Á§ OÉ]¼0ı…‹ñ¯œ]VâÚ‚òBH“S¥”OîÓßKŸk+°ˆc!hÙ å€Èg,c|«‚kò¯É«GZŸ½ñ.vÆ`8¸pá€Çg™åíöªå!„&§JRßèØÑÕ¨ù˜Eð<ÆËåvŒyˆùù r(P& ‚C%ƒ2„b„"„Ô_™É·ä™óå(·Ø˜‹˜'¸Ë ~Ê!FþI·î£—­ÚÔóBHÓR¨HIñ£Úµsר:GcŒ¦åÜ;kUR%ÈòŠ%ˆ…Vú#TXÏWÔS XXX*1ë]r÷mÐNpÊq~·n“,þòl•[ ÍC!MH­ ¥&½Ý¥Ë,ÎV8ˆƒ–¥1Y4¿·ª< ¬xð|+Vn-¯•ÿ£_P¬Ÿ‡s.Ƚ¹£–ÊøW€Óì>jž÷§•ZtBi*Ê5)7ûÝç†®ÒøŽ<޳RdgeÁ½x ØE«óÀËPb•ȪU[+‘W«VÍx‰çy”`ë¸puì±dÕï|]µ<„Ò$Tlu-XÑÆè©±¥ÈB ‰œ¥# v‰áeÆ®"\fð½ÜSsø‘Ãe?écpÿ¼ >Þ±mê]˜G5ª­å¡<ö”§©´€°uÛÄÁƒ?4h®­Å‚®÷®}Êyç+ÿ™77f¹OœÏ «?OZ¼"yô?,..{zõÜêÔÆÏ(æÝÛvæ×÷³3Æß yT£ÚúPÊcOyš–Ò `ïž¹={Îà죎>ûÓ¾õ˜r|W@ufzmuumUõÏç¯Ö\®­ù±¶¬ª¶º¦¶ °6ìpõb¯Ô†íïÓg›AÌt0Lq7­(ÿ={Í£ÕÖ‡òP{Êc Š6€‚<·1£Ýä/YÚ®~öÏÑcÆ&í :wªä§âó5§‹K ŠÎ••^)+¾RRôcIÑ…’byXS\x¾¤èReŕؔ+ó¥¿òr”s¿ VšW§î»vzÚYÕ¨¶>”‡òØSÛQ±Äž޵çìÖ­—<Ö?üÕ—2çs5+»6=óbfî¹,)çbvöåìì¬.eËÃzrs/Èg7m.ùZÔˆa™÷wüڨ͜4q®ÝäQjëCy(=å±)å@`àTÇ{Ƶk·òùç’†½=gNVÌ‘Ú䄟.&$VÆ'–Æ'–Ç'TÅÇŸO8«n”Py<¥2îXUBòÕÍ[.üõå”aÏ¥d4L{õ/£ì jT[ÊCyì)­©ÕvïšÌÙ›íÖzz¨Kü;ïFºd‰¸n9y¤2<²ÐU`‰*¶DVX"ª,‘e–ÈÒ›DD–E.‹ˆ( ª9yuÉÒ’!.‡Ÿw‰sîk6Šwþm}Xµ<ªQm}(å±§vd«ÖoßÖwè3g?ž>Ô%|ý–² ýyAæspaùTpèiSð)Sð“¹Ød*5™ Læü C‚*L¦ÂÐùæ‚@Óo¿ãòTü3ƒ2>¥‰Ù/ŽÙBó¨Fµõ¡<”Çžòܪ4€Ü¬±]»ÍißöŸ‹~ÂùÄ“ƒbÇŽKÙ¾£êëéþ;sêÉõßyÆ? À? Ð? Ï?àLùÿ. È ø&Í׉ß­ö©~â±°AýsžtÎíùàMóðœöë“Q-jT[ÊCyì)Ï£Jxêéyš¶è¡^{?ëìßÀžy ò6m*ݲùô† ™ºÖAÖ† 9ºõ9¿ ZŸ»aCöÆ'7nLþj[®ßgg‡<íÜ?ÍyÀÉGûí|ÿ.F›‚fµ¬<ªQm}(å±§”‡òØSž;é¿ÿÿìypTEÇ¿_÷{o†äV@ÔÅ]u=.»¢R[Vè®,Bá  ‚œ*ç‚€"—ÈB!7 9Ée g¸åÆ™Á£d«\¶ßdÁ¡Ö’0ÓytÕ§^õ¼y¯çSßþã[=5‡ë àÓ…AD£ü|ãïo–~_³ÍM›ä4kšÑò‘¤¡!ÇÇÝ?á½cÃw…‡—Öb÷uÄxÏ-ì ? ž Wönñè±»ß /{¡Sq³&›4ɽ¿iN“¦â%²=Ý–ùû†5Ù-å£|¬äãd\_-[Ž´Ùgú¤ù¤úú§ûûeø§ø®íÙcoHðŽü-ƒC¶ÖEñà’›¼mpð.144Ðм·ƒ·9þè#‰~>‰þ~Yb~_ÿTÿ´&ñœB#V ’ßG6dËGù(+ù8@VæxMïçá±ÈÝ#¹Qãx7D÷$O8¯µÏÿ%§×›%½zåöéSX7AEu±¥wPIï>[z¿•׫o^Ï ­¯ÿcO„wãx1³›g¬›çwFëìúÔçÿzó?ôÊæ#²å£|”•|œ‹ `ú‡]umŒ›Ûj¦ÅéöݶÁfÄÚ7{ä}k^y¥øÕW »uËëÖ-÷W#.·äwížÛµ»8–<˜e·­Ô´h›-ÆfÔEêb ­3´9†tºlˆÌ>²![>ÊGùXÉÇù¸¸þØj’¡MC\Á$À5€‘k #µø}Rç‹_z1·ó Ù;e¿Øyó¯¡S§œ—_.èØ1»c§üví ì–­$Œ"ˆBZ l¹xN1ŸÚèeKÊì#²å£|”•|œ+ àÂÙh°E‘Hë× @´@äÅh ×Vµjß®mÎsm³Ûf>“ÑöÙÌZ¤×Ésí²Ûnnß¾èég =<#>#M´ F¼Ð  (ΙX Ûýµi}dC¶|”ò±’Kpe¤&sÓÇ2XÆy,ÐĈšX¸Ž±݈Óô¨%¶~|Ó“Odˆc›V鵨T'­þÒ¦uÖ£fº»E3¶–ØzÆã70H% ´ 0)žóuš6ëñVÓ¤õ‘ ÙòQ>ÊÇJ>.Á•°è“ ‚163£Xä‘hî¿¢P¤ˆâMX@çK|}¢| éf 5O¼NÂCÆ×AóøæMübtmg¢ÌE±oˆˆg°‘Ää$6wÑ€bþ(Æ?òñ-­lÈ–òQ>Vòq ®,€Íü;ƒñ×2Ú‡ï á:‰5Ä2Œ3´»-ÁÛk£·W’·w‚·w¼·wÜÏxÅzyÅ6n¼¡±gœ&Ú•&ÒÏS ’Ò̪Š&–,6eŒ>Öøˆý{§Ëé#²å£|”•|\‚+ `öŒ×Å0Œb˜f=Þ)¥è+ú3•Q*cKb,™Q:ÃÌ8e1ƒ ‘2¡×¼ µÖÊÇJ>.Á¥oÍêÎp¬crrQd}"Ö<2/¨Y$qMzM ŽqV „›ÙŽq&9¦óÊZóˆg1(P\S(Öɱ¡7@6Ù-å£|¬äã\YË–!7Øz£b€€Í· Næäcj‘Yb²o!‡9Ö0]ÌÆi;a*á|OÏЃûgÈé#²å£|”•|\‚+   ÿ}#\m°B†%€€ù7cFÿEˆ‹)(ë²ón¡€A¡hrD±rb±·ê,±YÍš¬¼"§lÈ–òQ>Vòq .þ&°¦ °ék8‰€¶"n¹ …¿ävçoPtë$„[8;Ö a‡X›ž 0执Âdö‘ ÙòQ>ÊÇJ>ÎÇÅØn®®-æLl‘J‹·š@±ùФæLíd‹þw¸¶‹(oa»ãö›!(æPÂ`+™óïg춦ê´PfÙ-å£|¬äã|\\sæ¼ʵd½@EÀòÄöjÀ„}fšX ·¡Ž‹ÅTf÷b`1ànbEœn³õ]¼xºÌ>²![>ÊGùXÉÇù¸¸Žíg4 a|-a©Èp;˜oÆí¸¾¢*K™îºCv’YòÛ¯RJ¬€hNÓ¦ýwlŸ"³lÈ–òQ>Vòq>®ÿC˜§ž™D4_#±Q: &@´1îq°·¾@ØË`‰ÉᘙótÄ÷ºt©ãX²ùȆlù(åc%'ãúX¿n´®MÑ(‘Áa‚Çk2U)ò:pÐ\•;å ™óE8Äi á2OÏáË?›-¿lÈ–òQ>Vòq2®/A›63gxØKECœ4ø)¤ýÀJ¾8…fjGê<¤±cņOÞ¡ÃÄóuÿ%›l>²![>ÊGùXÉÇ™HQ›Rß5Œ~ŸsÚªÓ)*Û LìÈÊN ¯ð0§}œg0šéçßoÑ¢Ûþ‡l>²![>ÊGùXÉÇ™HQ‚àÁý¹6Ánlâ(6Jg O?üPÁW§î<)ZëÅœ¯d¼÷×Ç^87 ùȆlù(åc%§!Kœ;òXë÷5þ©†Û8V0<Ú1ÐŽ/'*cXC¹ƒÓ×)¿NY-ÄÃ3Žgy}¥ë“§´ùÓ˜©ÿçã·²ùȆlù(åc%§!Köîîáç7ÀÐæéTÀY±‹¢~Á(C»°r‚ÓgTp¸ÀáƒJ‚ g*N£¹S+w Ä™ËQT.ž@,ãLŒÅŠžÔ!Í`6¸÷̹Ÿ7DÙ-å£|¬äã$*AéÎ7¼¼†i´ÔnkZˆ.Õª• âÆsˆgœ6pÉqþR-*«/žã.ÑÆºv€±t†›7Vòqr€`_é›Íš…3šmãÙ:ÕH„ø­ƒ+€_]V¬Ü„Î]tÄ]ù3ægÍóð ƒïDWÛµ}ÄVŽzðá7&|ðqå¥ ÚG6dËGù(+ùÜm¤+Á‰co¿Ði®Æ&sXogÛGúQ,Àw€?}ïà2° ( J¤*¤jDZÙ% +@ÕÄÎéì„ÁŠ8-e|À“çÏýï»Éæ#²å£|”•|î*2@ S'Ïv7B5š”¦Ûv3úñ,§¯ý„p•à[ѱ ~dp•ÿÍ1~£ó+—mZ¹a".Eçå;ðoÝÆ'¤Üiú²ùȆlù(åc%Ÿ»„¼ 8rð­ž=úr=iâr»‘×ÈvP£ÓçUëðW øÞ€8TëxQ§r2ÌßÛ[8ÖÍ󭧇Lœ²âlEý|âJ6Ù-å£|¬äs7ºj8z¸_HÈ0?¿¡#œÇ(Òn¤êZ§, s4Ì3¡ Në —Ì1h”Wÿöí‡Í_0¾´´þkI6Ù-å£|¬äS¿4€¸Aäêá#†MmÕzºÀD·! %6ŠØ;â¨ÙG¸{ø]ËÐŽ]Þ [XôExÕÅà{ÍG6dËGù(+ùÔ ©jSºûƒ‚üðÌôÐM)C3Ò†ä…ïÞ5µêâå#'²å£|”•|~3 µ …Bq‡¨P(Š{”Ygʃã↯^¼p~Ï… ÞˆXÕÿ‹‚IÊGZdËGù(+ùÜ ¦Né»`î?;v˜ÙØm »m°ÆqÆhÑ`Â`36¨Éýœ1âô‘ ÙòQ>ÊÇJ>õE(€ÕƒÇéÚ7>ùŸÅ~2¦k— ÆÏš·}Þ¢]}Z:möžÞ} :tHz¤ÅjO÷ŸàÓ8là€wŽî/øÈ†lù(åc%ŸúEêHNߢÅFïùù~òܳñÇì]_}äËkÕÕתªÿséòOW®^»òãµ Uת¯\;}æZ^nõ´÷÷½üRæcEè<̦ÐodEùP«úȆlù(åc%Ÿ»Áÿÿì{T•UÞÇ¿½÷sApÔR“1ÍÈ|Õ™šÍf9½“™35¥”vS*S_ÔtRÈK¬FKñ’"÷;@Anr9€\ä¦rÁë¨3ͪ™ÙçE‚kfÞòœí³öZŸõ¬ý<çyöù¬ïþã»öñÈ´ëç{ΙÏ7YŽý¶>ù«<Ϲ¥ñWζþ½åêµs-­ÍWÚÛ¾noùºµùo­Í×[[øéµ–¦«­Í7;;¾.(ûzõºÊg›ã>*¾âëìønDØ"ùˆ†hùHé£%Ÿ»‡ˆPXðü a>669㙪5+‹ ßT×ü³²êFUÝ•jNíšš¯jjþjâf ?íF]Ýuþêž½M³fæLŸVuŸÓ!UY¾à­Ušñ Ñò‘>ÒGK>wá :ú=kÛyöö›§N)ötފՆܞ(þGqñâ’΢’¶¢’ EŋЮ_2~HqqçɲÎÂã‹O|³wßõç~[6mJù¸1ñªnñŒÿ}A>¢!Z>ÒGúhÉçn#VDFxQò»Ó<ÎyL*zõõœÄ´›YÇnff]ÉÎíÌÌnÊÊiÌÊiÉÊîÈ:v1+»=+»í6Že·Ko?v¬=3çZzö76¶Nž”>uR¡ûH½Ê–>êþßõ°h>¢!Z>ÒGúhÉÇ TE³úØÌvèçïñÄùñVzLÊܵ¯=þH}¼¾QŸØ¯?›˜|.!ñlBâù}KBB[‚¾1AßЃ¦¤øŽ„„¦ä”†h}ctÂ__~Ù0é—EOŒ«ûPŽÂ|~3}Ö=ê#¢å#}¤–|̃(PW=wÐàýþ4ö‘¼ÇÜOMW0w^Y`ÐÅCa•!aµÝ¨ ;ÚÚZz¾ ¡Áí¡¡õ¡á!§‚›·n»üØ#ãF×Np¯6$VQ.ZüïÿMF4Ñ-é#}´äc6D)€_>¾ZQÖ=8<ÕmD»{Ñè1±«?¨ß³§mßÞs»wW 8cTïÞ]kdWí·ƒžìªÛ½»& àt@À‰ýê¶ziò“yî£+ÜÇœ~xT¾Ë}û(›“ï}oùˆ†hùHé£%³!D.T•…ºý<ßÍ­|øˆ\·‘¡?jóßRûé¶êíþUþ·Séï_a¢²þÛË·ûŸùdkõgÛ*>Ù^¹ykëôߌ™3Ô-ÕmdÞð¡vþ_ÖÑvÇÍG4DËGúH-ù˜! ÀÅå=;ëmCGÄ»Istü¡ùŠ{ÕY¿µe›üN|è[îç{òe~¾'üüJüüŠýüJ{£Äw½áCßÒ k+6¬=µÞ÷¤¯ïùéÏä>ð`¢ëð¨ÁCÓ† -tqŽUÙÿ-¿¿W|DC´|¤ôÑ’9±|üù3OB–89FÝçšü3×£.Ó\]» }Ç«v¥ÏÉÕïùx{{—v£ä||¢eÞÞ§øKËWæ/_aXêSòÞõS< ®ãL¿Ï%m  ‹T;›]ÎŽËï Ñ-é#}´äcf,_nn‹­¬79Hê?@ïèœììtx€sÂÇC/½Xæ5ÿ¸—W¦—WÞ0,ðÊ¿ æóÁ[ïd¾õNÆëósç¿];bxŒSÿg§>¿£³ÞÙ9ià€(FØÿ–ø>¢!Z>ÒGúhÉÇÌX¸RެRtólmwôµëÓ/ÊÆ6ƶo¬mdûCO>‘6ûåüÙ³Ó_y%»w|V§,³±ù’*‘:ë0U¸•a­†ÙXþlÀÁgž1<÷\öŒ3f¤ÿÇð›ù#™ÏÎLv&?æ?6>ÅÚjŸ¢[Y…YYêúêø@ Q•ͪêÙXÿ¶È>¢!Z>ÒGúhÉÇüX¸õGUY¸—©±€q(Ü1ìÁØ©O¦=•>uJêTÔ§¦ýOððH{úé¬É“S'{dN|<˺O!ûB²hFÂ|ª*Kw}þ¦È>¢!Z>ÒGúhÉÇüX²Ú[ÞSè›*݈$ñ òsx^”dÊþQ£3'NHûńԉãSÆ;<áŽt#¹W~11uÂø£?žóظl[»@€Ý„N Œ¿½@‚¡|1Àgæó„õ Ñò‘>ÒGK>Á’ ]i£ó¡°‹± t-@(`¥a:5RÑ »?fôÈD÷‡óã˜QÉÝHì•Q%Œ2bÄ‘¾6Á”"4”²HÄp Ѽ„ì FÅXˆ¢|4rÔza}DC´|¤ôÑ’E°dìøÔ“À2+cFÈѸÿ Bž>„e„F1ö¹cÿà!ƒb¹Fß?8æÑ÷‰ê…ÁQƒ]¢8…é”ýŒò2çÅE!žðÉ ßÜòùƒ(ÛÚßq©°>¢!Z>ÒGúhÉÇ"X²þ´éwV1ÂÞ>¢_¿ð~v‘ oWC1†|?'! ÁXõ@‚ ã›2J>QØ{'Ë6ˆé#¢å#}¤–|,‚% àã³øP ¢˜Æz¼#’ cq Vh„ÂÂj|‹äGfÌ4’aC=䇓ðÓÀÑ<} „&Œ¦ä3…-.>¾NLÑ-é#}´äc,Z›ž7.„PH8ŒØ+RÐø*ïO=%zJã)¥4Ž’dŠGº`$…>8ÌS&ÈÃ5> ï6O…#ˆq<} „¤Œ§¸SaK kÄô Ñò‘>ÒGK>Á¢}4“¢iÒÒ‘d ú6x¬ÄxC×"ñ{’»5Sº x”ƒj!¦©Àxg·yø«¨ÈïÉæëdZ€Eß-€h>¢!Z>ÒGúhÉÇ"X²v}P¥¡<8J iG{À/fdd€iºq¤7ø:¥öœ!šÖ0™ÏÆH!A=A;»E§OnÓG4DËGúH-ùXK@V¦¯ÂÞ%ø¥J³)æffÞŽ1úc½Ào&©@Rz ˜Ñs„, Ù¼ÉùÊñÅÎÓÑ$J?r¼¸³ÝKLÑ-é#}´äc,ü?å +ÝAFx@yˆ¹w û‡Üéúwäôœ„`.ƒi rŽó°ÒÅ,{xìr‘}DC´|¤ôÑ’ù±pŒŸ¸E§ìd”o‘ò ˆyFÀ`<5Òu¥{²9ßÞÃo†Be M߃| yÄ81¿bmM•%/z~&²hˆ–ô‘>Zò1?.€Í›Ÿ\Ä”8‚e@r€fáÛ«€åÆ41€Ÿï¢;ÐËÍ|*c÷b °„ÐÆöXYÍݹsƒÈ>¢!Z>ÒGúhÉÇüX¸j«ç©}¼(;D°”çXÆãŽßZ^•ù¦L‹$EÄXò¦w)%4‹Í..¯/\+²hˆ–ô‘>Zò1?–ÿA˜±ãþHˆ¿BøFé 9¼ñ„‰²Ÿ „2 å„O|fÆ’ßÿõ¯{ù–h>¢!Z>ÒGúhÉÇÌX¾BC–ꔵ ‰¡p†@Ú®Œ€ðªäyUœ6®Êå41Î_PÁH.Á]vv v,¾hˆ–ô‘>Zò13–/Θ1›7ÚZ—ò†$pVeçœZ ¤àS«ú À …Ö T%Š ÷¤IkÚš{ÿI6Ñ|DC´|¤ôÑ’9¢õ+TuÀFòtäœBšÏ-Êwd uµ?x†‘rÆS²ÉÉyÞŽwü¢ùˆ†hùHé£%s"Dpæ/x)«­ÕD†|£ÔBð,°SÀª€Ô8OàÜÏòVg:cû({mæ,ŸöÖ7î!Ñ-é#}´äc6D)€Ö¯ŸöUØŸ,`ØL± ”Pj5RO±‹·h¸E}7øi“éÕ>EÎët§c׎ytY¼þß|ýV4Ñ-é#}´äc6D)NYÉ‹NNo¨Ê6Éb´žÐ ¼~A­Gä»°š(43hgÐA¡“@;B B3B#wj ¦¿ráòÊÅ:ÄzFù˜¯èY$©ôÃÁÌÙ´eϽè#¢å#}¤–|̃@À)-zÁÞþ]…|a­¥x—*8ÀãÆVÄ&Æ#t˜®wt£ð"àÀ61=ÅÛX§œ¢4™âšÁƒ|°þóKçߣ>¢!Z>ÒGúhÉÇ ˆUœòÒ—]]½)ùØŠ¥êHµBxˆ1q ð Í@Œ6 Lqw~ñ†ãu¸Bá:ïjk¥œÐý€K†<ðÂj¿O:;Þ¼§}DC´|¤ôÑ’ÏÝF¸àÔÕ¼>Åc‹B?`jM )iCr ‘/ÀuÀ›@n˜¸ ´9¤ÉE$—MÇN¤@®¹Lh«ŽÖ©4‡‘/({Ã}ü [þŸŸ»‰æ#¢å#}¤–|î*"@ë>ø¸¯ºH!‘$é¬J(©Dlaä&Á¯ùá+áKáo¾bðwã¯èØ5W­”UÍFüÉJ{Ç7§ÏXðcÓÍG4DËGúH-ùÜ%Ä-NÕéW_zq.Óy#Y`­fô±:­Fm”\ÖÁ®©pC…› .ëð‚Ž4(´B5þ½½/}lì^;þí5k÷¶4ÿ4߸ÍG4DËGúH-ùÜ þÿÿìÜ1K•aÆaßç¼o"DH˜»‹C~·>G!„yô pÎ4¨Ð$TÐÒ¸¸WfA¨ášg ?‚àw( ¢ÙÎðžs_pñÌ7ÿå·=­À—?¯­uçæÖ›º_ªWr03ýñNsT—¯Mõ­©Nn”㺖êÝÔÔþtÙº?ûdy¹ûúÍóápô-µmOÛ´í>öØ3I{Fk ð×ÁûÍîÎÃ¥—æ_Ôu·êôJg«t¶¿ÍÌæÝ{« ‹½•G»ýþÛóïƒë«§i{Ú¦m÷±ÇžIÚ3〠/öÎN_>÷>}X?>Ú8;\üع¾zfO;µí>öØ3I{nm\À€PJB @(%¡ ”„€PJB @(%¡ ”„€PJB @(%¡ ”„€PJB @(%¡ ”„€PJBýÿÿìÕ € ÿ¯’à0%€)L `JSÿÿŸçìû—9°•IEND®B`‚golly-2.7-src/gui-ios/Golly/PatternView.m0000644000175000017500000004773612536111364015331 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include "lifealgo.h" #include "viewport.h" #include "utils.h" // for event_checker #include "prefs.h" // for tilelayers, etc #include "status.h" // for ClearMessage #include "render.h" // for stacklayers, tilelayers #include "layer.h" // for currlayer, numlayers, etc #include "control.h" // for generating #include "render.h" // for DrawPattern #include "view.h" // for TouchBegan, TouchMoved, TouchEnded, etc #import #import #import #import #import #import "PatternViewController.h" // for PauseGenerating, ResumeGenerating, StopIfGenerating #import "PatternView.h" @implementation PatternView // ----------------------------------------------------------------------------- // golbals for drawing with OpenGL ES static EAGLContext *context; static GLuint viewRenderbuffer = 0; static GLuint viewFramebuffer = 0; // ----------------------------------------------------------------------------- // override the default layer class (which is [CALayer class]) so that // this view will be backed by a layer using OpenGL ES rendering + (Class)layerClass { return [CAEAGLLayer class]; } // ----------------------------------------------------------------------------- - (id)initWithCoder:(NSCoder *)c { self = [super initWithCoder:c]; if (self) { // init the OpenGL ES stuff (based on Apple's GLPaint sample code): CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = YES; // note that we're using OpenGL ES version 1 context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; if (!context || ![EAGLContext setCurrentContext:context]) { self = nil; return self; } // set the view's scale factor self.contentScaleFactor = 1.0; // we only do 2D drawing glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glDisable(GL_MULTISAMPLE); glDisable(GL_STENCIL_TEST); glDisable(GL_FOG); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_BLEND); // this blending function seems similar to the one used in desktop Golly // (ie. selected patterns look much the same) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // add gesture recognizers to this view: [self setMultipleTouchEnabled:YES]; // pinch gestures will zoom in/out UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(zoomView:)]; pinchGesture.delegate = self; [self addGestureRecognizer:pinchGesture]; // one-finger pan gestures will be used to draw/pick/select/etc, depending on the current touch mode UIPanGestureRecognizer *pan1Gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(singleDrag:)]; pan1Gesture.minimumNumberOfTouches = 1; pan1Gesture.maximumNumberOfTouches = 1; pan1Gesture.delegate = self; [self addGestureRecognizer:pan1Gesture]; // two-finger pan gestures will move the view UIPanGestureRecognizer *pan2Gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(moveView:)]; pan2Gesture.minimumNumberOfTouches = 2; pan2Gesture.maximumNumberOfTouches = 2; pan2Gesture.delegate = self; [self addGestureRecognizer:pan2Gesture]; // single-taps will do various actions depending on the current touch mode UITapGestureRecognizer *tap1Gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)]; tap1Gesture.numberOfTapsRequired = 1; tap1Gesture.numberOfTouchesRequired = 1; tap1Gesture.delegate = self; [self addGestureRecognizer:tap1Gesture]; /* too many problems if we have gesture recognizers for single-taps and double-taps: // double-taps will do various actions depending on the location UITapGestureRecognizer *tap2Gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)]; tap2Gesture.numberOfTapsRequired = 2; tap2Gesture.numberOfTouchesRequired = 1; tap2Gesture.delegate = self; [self addGestureRecognizer:tap2Gesture]; // only do a single-tap if double-tap is not detected // (this works but the delay is way too long) // [tap1Gesture requireGestureRecognizerToFail:tap2Gesture]; */ } return self; } // ----------------------------------------------------------------------------- - (void)createFramebuffer { // generate IDs for a framebuffer object and a color renderbuffer glGenFramebuffersOES(1, &viewFramebuffer); glGenRenderbuffersOES(1, &viewRenderbuffer); glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer); glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); // associate the storage for the current render buffer with our CAEAGLLayer // so we can draw into a buffer that will later be rendered to screen [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer); if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { NSLog(@"Error creating framebuffer object: %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); Fatal("Failed to create frame buffer!"); } } // ----------------------------------------------------------------------------- - (void)destroyFramebuffer { // clean up any buffers we have allocated glDeleteFramebuffersOES(1, &viewFramebuffer); viewFramebuffer = 0; glDeleteRenderbuffersOES(1, &viewRenderbuffer); viewRenderbuffer = 0; } // ----------------------------------------------------------------------------- - (void)layoutSubviews { // this is called when view is resized (on start up or when device is rotated or when toggling full screen) // so we need to create the framebuffer to be the same size // NSLog(@"layoutSubviews: wd=%f ht=%f", self.bounds.size.width, self.bounds.size.height); [EAGLContext setCurrentContext:context]; // note that glLoadIdentity must be called after glMatrixMode but before glOrthof, // otherwise the display is blank glMatrixMode(GL_PROJECTION); glLoadIdentity(); CGRect frame = self.bounds; glOrthof(0, frame.size.width, frame.size.height, 0, -1, 1); // origin is top left and y increases down glViewport(0, 0, frame.size.width, frame.size.height); glMatrixMode(GL_MODELVIEW); if (viewFramebuffer != 0 || viewRenderbuffer != 0) { [self destroyFramebuffer]; } [self createFramebuffer]; [self refreshPattern]; } // ----------------------------------------------------------------------------- - (void)refreshPattern { // x and y are always 0 // float x = self.bounds.origin.x; // float y = self.bounds.origin.y; int wd = int(self.bounds.size.width); int ht = int(self.bounds.size.height); //!!! import from view.h if we ever support tiled layers int tileindex = -1; if ( numclones > 0 && numlayers > 1 && (stacklayers || tilelayers) ) { SyncClones(); } if ( numlayers > 1 && tilelayers ) { if ( tileindex >= 0 && ( wd != GetLayer(tileindex)->view->getwidth() || ht != GetLayer(tileindex)->view->getheight() ) ) { GetLayer(tileindex)->view->resize(wd, ht); } } else if ( wd != currlayer->view->getwidth() || ht != currlayer->view->getheight() ) { // set viewport size ResizeLayers(wd, ht); } [EAGLContext setCurrentContext:context]; DrawPattern(tileindex); // display the buffer glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer); [context presentRenderbuffer:GL_RENDERBUFFER_OES]; } // ----------------------------------------------------------------------------- - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { if ([touch.view isKindOfClass:[UIButton class]]){ // allow Restore button to work (when in fullscreen mode) return NO; } return YES; } // ----------------------------------------------------------------------------- - (void)zoomView:(UIPinchGestureRecognizer *)gestureRecognizer { static CGFloat oldscale = 1.0; static CGPoint zoompt; UIGestureRecognizerState state = [gestureRecognizer state]; if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged) { if (state == UIGestureRecognizerStateBegan) { // less confusing if we only get zoom point at start of pinch zoompt = [gestureRecognizer locationInView:self]; } CGFloat newscale = [gestureRecognizer scale]; if (newscale - oldscale < -0.1) { // fingers moved closer, so zoom out ZoomOutPos(zoompt.x, zoompt.y); oldscale = newscale; } else if (newscale - oldscale > 0.1) { // fingers moved apart, so zoom in ZoomInPos(zoompt.x, zoompt.y); oldscale = newscale; } } else if (state == UIGestureRecognizerStateEnded) { // reset scale [gestureRecognizer setScale:1.0]; oldscale = 1.0; } } // ----------------------------------------------------------------------------- static int startx, starty; - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { if ([touches count] == 1) { // get the only touch and remember its location for use in singleDrag UITouch *t = [touches anyObject]; CGPoint currpt = [t locationInView:self]; startx = (int)currpt.x; starty = (int)currpt.y; } } // ----------------------------------------------------------------------------- - (void)singleDrag:(UIPanGestureRecognizer *)gestureRecognizer { static CGPoint prevpt, delta; UIGestureRecognizerState state = [gestureRecognizer state]; if (state == UIGestureRecognizerStateBegan) { prevpt = [gestureRecognizer locationInView:self]; ClearMessage(); // the current location is not where the initial touch occurred // so use the starting location saved in touchesBegan (otherwise // problems will occur when dragging a small paste image) TouchBegan(startx, starty); TouchMoved(prevpt.x, prevpt.y); } else if (state == UIGestureRecognizerStateChanged && [gestureRecognizer numberOfTouches] == 1) { CGPoint newpt = [gestureRecognizer locationInView:self]; TouchMoved(newpt.x, newpt.y); if (currlayer->touchmode == movemode) { delta.x = newpt.x - prevpt.x; delta.y = newpt.y - prevpt.y; prevpt = newpt; } } else if (state == UIGestureRecognizerStateEnded) { if (currlayer->touchmode == movemode) { // if velocity is high then move further in current direction CGPoint velocity = [gestureRecognizer velocityInView:self]; if (abs(velocity.x) > 1000.0 || abs(velocity.y) > 1000.0) { TouchMoved(prevpt.x + delta.x * abs(velocity.x/100.0), prevpt.y + delta.y * abs(velocity.y/100.0)); } } TouchEnded(); } else if (state == UIGestureRecognizerStateCancelled) { TouchEnded(); } } // ----------------------------------------------------------------------------- - (void)moveView:(UIPanGestureRecognizer *)gestureRecognizer { static TouchModes oldmode; static CGPoint prevpt, delta; UIGestureRecognizerState state = [gestureRecognizer state]; if (state == UIGestureRecognizerStateBegan) { prevpt = [gestureRecognizer locationInView:self]; ClearMessage(); oldmode = currlayer->touchmode; currlayer->touchmode = movemode; TouchBegan(prevpt.x, prevpt.y); } else if (state == UIGestureRecognizerStateChanged && [gestureRecognizer numberOfTouches] == 2) { CGPoint newpt = [gestureRecognizer locationInView:self]; TouchMoved(newpt.x, newpt.y); delta.x = newpt.x - prevpt.x; delta.y = newpt.y - prevpt.y; prevpt = newpt; } else if (state == UIGestureRecognizerStateEnded) { // if velocity is high then move further in current direction CGPoint velocity = [gestureRecognizer velocityInView:self]; if (abs(velocity.x) > 1000.0 || abs(velocity.y) > 1000.0) { TouchMoved(prevpt.x + delta.x * abs(velocity.x/100.0), prevpt.y + delta.y * abs(velocity.y/100.0)); } TouchEnded(); currlayer->touchmode = oldmode; } else if (state == UIGestureRecognizerStateCancelled) { TouchEnded(); currlayer->touchmode = oldmode; } } // ----------------------------------------------------------------------------- static UIActionSheet *selsheet; - (void)doSelectionAction { selsheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles: @"Remove", @"Cut", @"Copy", @"Clear", @"Clear Outside", @"Shrink", @"Fit", [NSString stringWithFormat:@"Random Fill (%d%%)", randomfill], @"Flip Top-Bottom", @"Flip Left-Right", @"Rotate Clockwise", @"Rotate Anticlockwise", @"Advance", @"Advance Outside", nil]; [selsheet showInView:self]; } // ----------------------------------------------------------------------------- static UIActionSheet *pastesheet; - (void)doPasteAction { pastesheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles: @"Abort", [NSString stringWithFormat:@"Paste (%@)", [NSString stringWithCString:GetPasteMode() encoding:NSUTF8StringEncoding]], @"Paste to Selection", @"Flip Top-Bottom", @"Flip Left-Right", @"Rotate Clockwise", @"Rotate Anticlockwise", nil]; [pastesheet showInView:self]; } // ----------------------------------------------------------------------------- static UIActionSheet *globalSheet; static int globalButton; - (void)doDelayedAction { if (globalSheet == selsheet) { if (generating && globalButton >= 1 && globalButton <= 13 && globalButton != 2 && globalButton != 5 && globalButton != 6) { // temporarily stop generating for all actions except Remove, Copy, Shrink, Fit PauseGenerating(); if (event_checker > 0) { // try again after a short delay that gives time for NextGeneration() to terminate [self performSelector:@selector(doDelayedAction) withObject:nil afterDelay:0.01]; return; } } switch (globalButton) { case 0: RemoveSelection(); break; // WARNING: above test assumes Remove is index 0 case 1: CutSelection(); break; case 2: CopySelection(); break; // WARNING: above test assumes Copy is index 2 case 3: ClearSelection(); break; case 4: ClearOutsideSelection(); break; case 5: ShrinkSelection(false); break; // WARNING: above test assumes Shrink is index 5 case 6: FitSelection(); break; // WARNING: above test assumes Fit is index 6 case 7: RandomFill(); break; case 8: FlipSelection(true); break; case 9: FlipSelection(false); break; case 10: RotateSelection(true); break; case 11: RotateSelection(false); break; case 12: currlayer->currsel.Advance(); break; case 13: currlayer->currsel.AdvanceOutside(); break; // WARNING: above test assumes 13 is last index default: break; } ResumeGenerating(); } else if (globalSheet == pastesheet) { switch (globalButton) { case 0: AbortPaste(); break; case 1: DoPaste(false); break; case 2: DoPaste(true); break; case 3: FlipPastePattern(true); break; case 4: FlipPastePattern(false); break; case 5: RotatePastePattern(true); break; case 6: RotatePastePattern(false); break; default: break; } UpdateEverything(); } } // ----------------------------------------------------------------------------- // called when the user selects an option in a UIActionSheet - (void)actionSheet:(UIActionSheet *)sheet didDismissWithButtonIndex:(NSInteger)buttonIndex { // user interaction is disabled at this moment, which is a problem if Warning or BeginProgress // gets called (their OK/Cancel buttons won't work) so we have to call the appropriate // action code AFTER this callback has finished and user interaction restored globalSheet = sheet; globalButton = buttonIndex; [self performSelector:@selector(doDelayedAction) withObject:nil afterDelay:0.01]; } // ----------------------------------------------------------------------------- static double prevtime = 0.0; // used to detect a double tap - (void)singleTap:(UITapGestureRecognizer *)gestureRecognizer { if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) { CGPoint pt = [gestureRecognizer locationInView:self]; ClearMessage(); if (TimeInSeconds() - prevtime < 0.3) { // double tap if (waitingforpaste && PointInPasteImage(pt.x, pt.y)) { // if generating then stop (consistent with doPaste in PatternViewController.m) StopIfGenerating(); ClearMessage(); // now display action sheet that lets user abort/paste/flip/rotate/etc [self doPasteAction]; } else if (currlayer->touchmode == selectmode && SelectionExists() && PointInSelection(pt.x, pt.y)) { // display action sheet that lets user remove/cut/copy/clear/etc [self doSelectionAction]; } else if (currlayer->touchmode == drawmode) { // do the drawing TouchBegan(pt.x, pt.y); TouchEnded(); } prevtime = 0.0; } else { // single tap TouchBegan(pt.x, pt.y); TouchEnded(); prevtime = TimeInSeconds(); } } } // ----------------------------------------------------------------------------- @end golly-2.7-src/gui-ios/Golly/OpenViewController.xib0000644000175000017500000003014512536111364017171 00000000000000 1280 10K549 1938 1038.36 461.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 933 IBUIWebView IBUITableView IBUIView IBUILabel IBProxyObject com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 292 318 {{224, 0}, {544, 1004}} 1 MSAxIDEAA IBIPadFramework 1 YES 300 292 {{10, 20}, {194, 21}} NO YES 7 NO IBIPadFramework Which patterns? 1 MCAwIDAAA 1 10 1 1 17 Helvetica 17 16 316 {{10, 49}, {194, 176}} 3 MQA YES IBIPadFramework YES NO 1 0 YES 44 22 22 {{5, 379}, {214, 245}} 3 MC42NjY2NjY2NjY3AA IBIPadFramework {{0, 20}, {768, 1004}} NO 2 IBIPadFramework view 3 htmlView 9 optionTable 8 dataSource 10 delegate 11 0 -1 File's Owner -2 2 5 13 4 12 OpenViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 13 OpenViewController UIViewController UIWebView UITableView htmlView UIWebView optionTable UITableView IBProjectSource ./Classes/OpenViewController.h 0 IBIPadFramework YES 3 933 golly-2.7-src/gui-ios/Golly/StatusView.h0000644000175000017500000000200212536111364015143 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ // This is the view for displaying Golly's status info. @interface StatusView : UIView @end golly-2.7-src/gui-ios/Golly/HelpViewController.xib0000644000175000017500000003226312536111364017163 00000000000000 1280 10K549 1938 1038.36 461.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 933 IBUIWebView IBUIBarButtonItem IBUIToolbar IBUIView IBProxyObject com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 274 311 {768, 960} IBIPadFramework 2 266 {{0, 960}, {768, 44}} NO NO IBIPadFramework IBIPadFramework 5 < IBIPadFramework 1 > IBIPadFramework 1 Contents IBIPadFramework 1 {{0, 20}, {768, 1004}} 2 IBIPadFramework view 7 htmlView 30 backButton 31 contentsButton 32 nextButton 33 doBack: 34 doNext: 35 doContents: 36 0 -1 File's Owner -2 2 22 23 24 25 26 28 HelpViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 37 HelpViewController UIViewController id id id doBack: id doContents: id doNext: id UIBarButtonItem UIBarButtonItem UIWebView UIBarButtonItem backButton UIBarButtonItem contentsButton UIBarButtonItem htmlView UIWebView nextButton UIBarButtonItem IBProjectSource ./Classes/HelpViewController.h 0 IBIPadFramework YES 3 933 golly-2.7-src/gui-ios/Golly/RuleViewController.xib0000644000175000017500000006112712536111364017203 00000000000000 1280 10K549 1938 1038.36 461.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 933 IBUIView IBProxyObject IBUILabel IBUIToolbar IBUIBarButtonItem IBUITextField IBUIWebView IBUIPickerView IBUIButton com.apple.InterfaceBuilder.IBCocoaTouchPlugin PluginDependencyRecalculationVersion IBFilesOwner IBIPadFramework IBFirstResponder IBIPadFramework 301 293 {{303, 389}, {163, 21}} NO YES 7 NO IBIPadFramework Choose an algorithm: 1 MCAwIDAAA 1 10 1 1 17 Helvetica 17 16 293 {{303, 418}, {163, 31}} NO IBIPadFramework 0 0 1 Generations 3 MQA 1 MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA 3 MC41AA 2 15 Helvetica-Bold 15 16 293 {{330, 20}, {108, 21}} NO YES 7 NO IBIPadFramework Type in a rule: 1 10 1 293 {{173, 49}, {422, 31}} NO YES IBIPadFramework 0 B012345678/S012345678 3 3 MAA 2 1 YES 17 9 IBCocoaTouchFramework 3 2 17 Helvetica-Bold 17 16 293 {{312, 88}, {145, 21}} NO YES 7 NO IBIPadFramework UNKNOWN RULE! 1 MSAwLjA1OTcwMDA0ODE4IDAuMTE4Njg4NzQ0OQA 1 10 1 293 {{306, 117}, {156, 21}} NO YES 7 NO IBIPadFramework Pick a named rule: 1 10 1 293 {{173, 146}, {422, 216}} IBIPadFramework YES 266 {{0, 980}, {768, 44}} NO NO IBIPadFramework Cancel IBIPadFramework 1 IBIPadFramework 5 IBIPadFramework 1 0 279 {{-2, 457}, {773, 523}} 1 MSAxIDEAA IBIPadFramework 2 {768, 1024} 3 MC42NjY2NjY2NjY3AA IBIPadFramework ruleText 15 unknownLabel 16 rulePicker 21 algoButton 14 view 28 htmlView 36 changeAlgorithm: 7 17 delegate 18 delegate 20 dataSource 19 cancelRuleChange: 33 doRuleChange: 34 0 -1 File's Owner -2 12 9 11 8 10 7 5 6 29 30 31 32 35 RuleViewController com.apple.InterfaceBuilder.IBCocoaTouchPlugin UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin 36 RuleViewController UIViewController id id id cancelRuleChange: id changeAlgorithm: id doRuleChange: id UIButton UIWebView UIPickerView UITextField UILabel algoButton UIButton htmlView UIWebView rulePicker UIPickerView ruleText UITextField unknownLabel UILabel IBProjectSource ./Classes/RuleViewController.h 0 IBIPadFramework YES 3 933 golly-2.7-src/gui-ios/Golly/pattern.png0000644000175000017500000000022012536111364015037 00000000000000‰PNG  IHDR;0®¢WIDATH‰í”1 øÿ/ÇH‡ !ÍXhÚSŽL µÁ ¾™¥68ÞI¨sòV†ë¯–­®¢Úžwã<ðVW–ªõj~ÞóÀ6«óVÝàgÙ‹[ 3ü¨"MIEND®B`‚golly-2.7-src/gui-ios/Golly/settings.png0000644000175000017500000000105512536111364015231 00000000000000‰PNG  IHDR;0®¢ôIDATH‰å—Ï›P‡¿!–ÞqI›l‰“1”’Ö%8Ä[Av+ˆÓH„,xœˆ¼8ØGarÁö‚ÿ‘ùgß›ÇïÍDU¹…œ›Po œJÆq®øøE£&(€ˆD½€‹¢˜óÚ¹§´°Ö~è ‚àEUgWÀ]`™$ÉC'0Àd2ùŒTõ‰Có¬Ed&"áñÂDdQðbm™uJ’äAD5©¥1fzÉÒ `­ýL}Ë\cÂsðÖàÞt¾·EQ„e·«U§AÀ3Ö5)×qœè”ã;U eÙ]žçú¶ˆÌÆãñóq¼óèãyÞ®áæ@UŸêßËÌU9ÿU=ªê{ùL“$ùRMvÞꪪN÷}ÿM%þØú¾ÿvëuÊô}ÿX¤i:X­V÷eúÀ½·{§«ê4M¿ƒŸejñOÁžçíŒ1¡ˆ¬Ë©Ô‘¨\Ð_õú¯Ñÿ÷ óKšæáݯIEND®B`‚golly-2.7-src/gui-ios/Golly/SaveViewController.m0000644000175000017500000003247412536111364016647 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "writepattern.h" // for pattern_format, output_compression #include "utils.h" // for FileExists #include "prefs.h" // for savedir #include "layer.h" // for currlayer, etc #include "file.h" // for SavePattern, GetBaseName #import "SaveViewController.h" @implementation SaveViewController // ----------------------------------------------------------------------------- static NSString *filetypes[] = // data for typeTable { // WARNING: code below assumes this ordering @"Run Length Encoded (*.rle)", @"Compressed RLE (*.rle.gz)", @"Macrocell (*.mc)", @"Compressed MC (*.mc.gz)" }; const int NUM_TYPES = sizeof(filetypes) / sizeof(filetypes[0]); static int currtype = 0; // current index in typeTable static bool inSaveTextFile = false; // SaveTextFile was called? static const char* initpath; // path of file being edited static const char* filedata; // text to be saved static InfoViewController* callingVC; // the view controller that called SaveTextFile // ----------------------------------------------------------------------------- - (void)checkFileType { std::string filename = [[nameText text] cStringUsingEncoding:NSUTF8StringEncoding]; if (!filename.empty()) { // might need to change currtype to match an explicit extension int oldtype = currtype; size_t len = filename.length(); if (len >= 4 && len - 4 == filename.rfind(".rle")) { currtype = 0; } else if (len >= 7 && len - 7 == filename.rfind(".rle.gz")) { currtype = 1; } else if (len >= 3 && len - 3 == filename.rfind(".mc")) { currtype = 2; } else if (len >= 6 && len - 6 == filename.rfind(".mc.gz")) { currtype = 3; } else { // extension is unknown or not supplied, so append appropriate extension size_t dotpos = filename.find('.'); if (currtype == 0) filename = filename.substr(0,dotpos) + ".rle"; if (currtype == 1) filename = filename.substr(0,dotpos) + ".rle.gz"; if (currtype == 2) filename = filename.substr(0,dotpos) + ".mc"; if (currtype == 3) filename = filename.substr(0,dotpos) + ".mc.gz"; [nameText setText:[NSString stringWithCString:filename.c_str() encoding:NSUTF8StringEncoding]]; } if (currtype != oldtype) { [typeTable selectRowAtIndexPath:[NSIndexPath indexPathForRow:currtype inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone]; } } } // ----------------------------------------------------------------------------- - (void)checkFileName { std::string filename = [[nameText text] cStringUsingEncoding:NSUTF8StringEncoding]; if (!filename.empty()) { // might need to change filename to match currtype size_t dotpos = filename.find('.'); std::string ext = (dotpos == std::string::npos) ? "" : filename.substr(dotpos); if (currtype == 0 && ext != ".rle") filename = filename.substr(0,dotpos) + ".rle"; if (currtype == 1 && ext != ".rle.gz") filename = filename.substr(0,dotpos) + ".rle.gz"; if (currtype == 2 && ext != ".mc") filename = filename.substr(0,dotpos) + ".mc"; if (currtype == 3 && ext != ".mc.gz") filename = filename.substr(0,dotpos) + ".mc.gz"; [nameText setText:[NSString stringWithCString:filename.c_str() encoding:NSUTF8StringEncoding]]; } } // ----------------------------------------------------------------------------- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"Save"; } return self; } // ----------------------------------------------------------------------------- - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } // ----------------------------------------------------------------------------- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // return YES for supported orientations return YES; } // ----------------------------------------------------------------------------- - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. } // ----------------------------------------------------------------------------- - (void)viewDidUnload { [super viewDidUnload]; // release all outlets nameText = nil; typeTable = nil; topLabel = nil; botLabel = nil; } // ----------------------------------------------------------------------------- - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if (inSaveTextFile) { // user is saving a pattern (in Documents/Saved or Documents/Downloads) // or a .rule file (in Documents/Rules) std::string filename = GetBaseName(initpath); [nameText setText:[NSString stringWithCString:filename.c_str() encoding:NSUTF8StringEncoding]]; typeTable.hidden = YES; // change labels [topLabel setText:@"Save file as:"]; std::string filepath = initpath; if (filepath.find("Documents/Rules/") != std::string::npos) { [botLabel setText:@"File location: Documents/Rules/"]; } else if (filepath.find("Documents/Downloads/") != std::string::npos) { [botLabel setText:@"File location: Documents/Downloads/"]; } else { [botLabel setText:@"File location: Documents/Saved/"]; } } else { // user is saving current pattern via Pattern tab's Save button // [nameText setText:[NSString stringWithCString:currlayer->currname.c_str() encoding:NSUTF8StringEncoding]]; // probably nicer not to show current name [nameText setText:@""]; // init file type if (currlayer->algo->hyperCapable()) { // RLE is allowed but macrocell format is better if (currtype < 2) currtype = 2; } else { // algo doesn't support macrocell format if (currtype > 1) currtype = 0; } [typeTable selectRowAtIndexPath:[NSIndexPath indexPathForRow:currtype inSection:0] animated:NO scrollPosition:UITableViewScrollPositionNone]; [self checkFileName]; } // show keyboard immediately [nameText becomeFirstResponder]; } // ----------------------------------------------------------------------------- - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; inSaveTextFile = false; } // ----------------------------------------------------------------------------- - (IBAction)doCancel:(id)sender { [self dismissModalViewControllerAnimated:YES]; } // ----------------------------------------------------------------------------- - (IBAction)doSave:(id)sender { // clear first responder if necessary (ie. remove keyboard) [self.view endEditing:YES]; std::string filename = [[nameText text] cStringUsingEncoding:NSUTF8StringEncoding]; if (filename.empty()) { // Warning("Please enter a file name."); // better to beep and show keyboard Beep(); [nameText becomeFirstResponder]; return; } const char* replace_query = "A file with that name already exists.\nDo you want to replace that file?"; if (inSaveTextFile) { // user is saving a text file (pattern or .rule file) std::string initname = GetBaseName(initpath); std::string dir = initpath; dir = dir.substr(0,dir.rfind('/')+1); // prevent Documents/Rules/* being saved as something other than a .rule file if (EndsWith(dir,"Documents/Rules/") && !EndsWith(filename,".rule")) { Warning("Files in Documents/Rules/ must have a .rule extension."); [nameText becomeFirstResponder]; return; } std::string fullpath = dir + filename; if (initname != filename && FileExists(fullpath)) { // ask user if it's ok to replace an existing file that's not the same as the given file if (!YesNo(replace_query)) return; } FILE* f = fopen(fullpath.c_str(), "w"); if (f) { if (fputs(filedata, f) == EOF) { fclose(f); Warning("Could not write to file!"); return; } } else { Warning("Could not create file!"); return; } fclose(f); [self dismissModalViewControllerAnimated:YES]; // tell caller that the save was a success [callingVC saveSucceded:fullpath.c_str()]; } else { // user is saving current pattern in Documents/Saved/ via Pattern tab's Save button std::string fullpath = savedir + filename; if (FileExists(fullpath)) { // ask user if it's ok to replace an existing file if (!YesNo(replace_query)) return; } // dismiss modal view first in case SavePattern calls BeginProgress [self dismissModalViewControllerAnimated:YES]; pattern_format format = currtype < 2 ? XRLE_format : MC_format; output_compression compression = currtype % 2 == 0 ? no_compression : gzip_compression; SavePattern(fullpath, format, compression); } } // ----------------------------------------------------------------------------- // UITextFieldDelegate methods: - (void)textFieldDidEndEditing:(UITextField *)tf { // called when rule editing has ended (ie. keyboard disappears) if (!inSaveTextFile) [self checkFileType]; } - (BOOL)textFieldShouldReturn:(UITextField *)tf { // called when user hits Done button, so remove keyboard // (note that textFieldDidEndEditing will then be called) [tf resignFirstResponder]; return YES; } - (BOOL)disablesAutomaticKeyboardDismissal { // this allows keyboard to be dismissed if modal view uses UIModalPresentationFormSheet return NO; } // ----------------------------------------------------------------------------- // UITableViewDelegate and UITableViewDataSource methods: - (NSInteger)numberOfSectionsInTableView:(UITableView *)TableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)component { if (!currlayer->algo->hyperCapable()) { // algo doesn't support macrocell format return 2; } else { return NUM_TYPES; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // check for a reusable cell first and use that if it exists UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"]; // if there is no reusable cell of this type, create a new one if (!cell) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"]; [[cell textLabel] setText:filetypes[[indexPath row]]]; return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { // change selected file type int newtype = [indexPath row]; if (newtype < 0 || newtype >= NUM_TYPES) { Warning("Bug: unexpected row!"); } else { currtype = newtype; [self checkFileName]; } } @end // ============================================================================= void SaveTextFile(const char* filepath, const char* contents, InfoViewController* currentView) { inSaveTextFile = true; initpath = filepath; filedata = contents; callingVC = currentView; SaveViewController *modalSaveController = [[SaveViewController alloc] initWithNibName:nil bundle:nil]; [modalSaveController setModalPresentationStyle:UIModalPresentationFormSheet]; [currentView presentModalViewController:modalSaveController animated:YES]; modalSaveController = nil; // cannot reset inSaveTextFile here (it must be done in viewWillDisappear) // because doSave: is called AFTER SaveTextFile finishes } golly-2.7-src/gui-ios/Golly/Icon.png0000644000175000017500000000461312536111364014264 00000000000000‰PNG  IHDRHHÚ$!tEXtSoftwareGraphicConverter (Intel)w‡ú %IDATxœìZ PSW¾çTpA°V`wÛúDâ³NÇj}  *â|E*…º±¬ ‚…¡<!HxÈ;ÈVQ@ /åᣃ/DkgOr)ºæÚ{1˜„]g¾¹sóqÎÇÿÍÍùïÉ7ùõùÚÿI ¯àƒ±ÆþOõß¡ßë5ýo’Ö%¢?0yzBko3{þ”ö:ùèg“îú» â‚´àïko³>–œÉmKKk=ßÓ-V¬(µ Í˽ÐWÏ c¾d'xDG× ò;OG^ÊHu†Ìà#Ú‰Ðïrøí!Á¼×l• 4È 319åéQÇ ¼Ê ¬g0êl6ýÎ40Hc^“WéôK¡ÇÝ/lùê«bŒa^ùâ‹ÂºëC÷o´®Ææ:T?Ÿš4pß„¤ ®1’‚ÄÆzºè4AG‡;ŸšC5È™öQ¦ªê¹Èˆ(Ê™ñ’óøêji ÜwyOPM77’sçðUTR|öï›9ƒ¥ñ‡tê<þ|*ïÏÊFÑ”ïO9‘Ä5FRðá3c½Ý¦ðRbxE Ê=悈™a^©ÔX†òÛGìêéqpÖÌ80§"vG„»ÝézõîV˺£G<“ÙÛŸ>|k°ü>ðü)-ãÄôl¼fõû“%‘s( â–1DÜò1¦€ˆ[>ÆqËǘb"n9@1·¼¼É7â–+DÜò1¦€ˆ[>ÆqËǘ"nùSLÄ-ŒeÄ- Ãä‚\Fn‹›x»C­TÀ1& ¿ZëÌ9{V.·ËÞ®ðú«±­ã½|d"  l44~\oY*!Ëçð­­˜ /}tÆÚšéÒ²¿Ÿ;@xª*bRmÞÏš‰³=S*¼i ®Ké¹P` @õ Ú5«O)¼ôуÀ iö¶a´c¤¦FyE™­ÂKµ±_ñd¸ÕJOure°8r³ g7­lûˆ›d"+XW³å|| 'U{6±áêÆQ “%â&™Hã ¶5¯35ÍdžA¬]Íëé2S–ˆ›d"+èëã©­¶rE>$—//ÐÐH 9æª,7ÉDWÐé‡%“(€¤`·‹Ÿ²DÜ$i\Aø­à§‘a¹œ”è¤,7ùDZZ·Õ.²ÝjÃɃÆJq“O¤qËŠ·øûyäÙPŠˆ[ÆSܲ '6&‡C×c~,œØ˜Œ·,§¸e9þÞ#nYNqËr,ü½Gܲœâ–åX8©5&ŸC×c~,œØ†wÍú{Þ|¾½Ýæ~óÛ, ؾa~9dü‚ðÝÕÝañì±é» ïø`l¼áƒ±ñ†ÿÿÿ*³h©PާIEND®B`‚golly-2.7-src/gui-ios/Golly/StatePickerView.m0000644000175000017500000001412312536111364016112 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "prefs.h" // for showicons #include "layer.h" // for currlayer #include "algos.h" // for gBitmapPtr #import "PatternViewController.h" // for UpdateEditBar, CloseStatePicker #import "StateView.h" // for DrawOneIcon #import "StatePickerView.h" @implementation StatePickerView // ----------------------------------------------------------------------------- - (id)initWithCoder:(NSCoder *)c { self = [super initWithCoder:c]; if (self) { [self setMultipleTouchEnabled:YES]; // add gesture recognizer to this view UITapGestureRecognizer *tap1Gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)]; tap1Gesture.numberOfTapsRequired = 1; tap1Gesture.numberOfTouchesRequired = 1; tap1Gesture.delegate = self; [self addGestureRecognizer:tap1Gesture]; } return self; } // ----------------------------------------------------------------------------- - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); gBitmapPtr* iconmaps = currlayer->icons31x31; // use white lines [[UIColor whiteColor] setStroke]; CGContextSetLineWidth(context, 1.0); // font for drawing state numbers UIFont *numfont = [UIFont systemFontOfSize:10]; // draw boxes showing colors or icons of all states int x = 0, y = 0; int dx, dy; for (int i = 0; i < currlayer->algo->NumCellStates(); i++) { CGRect box = CGRectMake(x+1, y+1, 31, 31); if (showicons && iconmaps && iconmaps[i]) { // fill box with background color then draw icon CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGFloat components[4]; components[0] = currlayer->cellr[0] / 255.0; components[1] = currlayer->cellg[0] / 255.0; components[2] = currlayer->cellb[0] / 255.0; components[3] = 1.0; // alpha CGColorRef colorref = CGColorCreate(colorspace, components); CGColorSpaceRelease(colorspace); CGContextSetFillColorWithColor(context, colorref); CGContextFillRect(context, box); CGColorRelease(colorref); DrawOneIcon(context, x+1, y+1, iconmaps[i], currlayer->cellr[0], currlayer->cellg[0], currlayer->cellb[0], currlayer->cellr[i], currlayer->cellg[i], currlayer->cellb[i]); } else { // fill box with color of current drawing state CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGFloat components[4]; components[0] = currlayer->cellr[i] / 255.0; components[1] = currlayer->cellg[i] / 255.0; components[2] = currlayer->cellb[i] / 255.0; components[3] = 1.0; // alpha CGColorRef colorref = CGColorCreate(colorspace, components); CGColorSpaceRelease(colorspace); CGContextSetFillColorWithColor(context, colorref); CGContextFillRect(context, box); CGColorRelease(colorref); } // anti-aliased text is much nicer CGContextSetShouldAntialias(context, true); // show state number in top left corner of box, as black text on white NSString *num = [NSString stringWithFormat:@"%d", i]; CGRect textrect; textrect.size = [num sizeWithFont:numfont]; textrect.origin.x = x+1; textrect.origin.y = y+1; textrect.size.height -= 3; [[UIColor whiteColor] setFill]; CGContextFillRect(context, textrect); textrect.origin.y -= 2; [[UIColor blackColor] setFill]; [num drawInRect:textrect withFont:numfont]; // avoid fuzzy lines CGContextSetShouldAntialias(context, false); // draw lines around box (why do we need to add 1 to y coords???) CGContextMoveToPoint(context, x, y+1); CGContextAddLineToPoint(context, x+32, y+1); CGContextAddLineToPoint(context, x+32, y+33); CGContextAddLineToPoint(context, x, y+33); CGContextAddLineToPoint(context, x, y+1); CGContextStrokePath(context); if (i == currlayer->drawingstate) { // remember location of current drawing state dx = x; dy = y; } // move to next box if ((i+1) % 16 == 0) { x = 0; y += 32; } else { x += 32; } } } // ----------------------------------------------------------------------------- - (void)singleTap:(UITapGestureRecognizer *)gestureRecognizer { if ([gestureRecognizer state] == UIGestureRecognizerStateEnded) { CGPoint pt = [gestureRecognizer locationInView:self]; int col = pt.x / 32; int row = pt.y / 32; int newstate = row * 16 + col; if (newstate >= 0 && newstate < currlayer->algo->NumCellStates()) { currlayer->drawingstate = newstate; UpdateEditBar(); CloseStatePicker(); } } } // ----------------------------------------------------------------------------- @end golly-2.7-src/gui-ios/Golly/HelpViewController.m0000644000175000017500000002533412536111364016636 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "utils.h" // for Beep, Warning, FixURLPath #include "prefs.h" // for userdir, supplieddir, downloaddir #include "file.h" // for OpenFile, UnzipFile, GetURL, DownloadFile, LoadLexiconPattern #include "control.h" // for ChangeRule #import "GollyAppDelegate.h" // for SwitchToPatternTab, SwitchToHelpTab #import "InfoViewController.h" // for ShowTextFile #import "HelpViewController.h" @implementation HelpViewController // ----------------------------------------------------------------------------- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { self.title = @"Help"; self.tabBarItem.image = [UIImage imageNamed:@"help.png"]; } return self; } // ----------------------------------------------------------------------------- - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } // ----------------------------------------------------------------------------- - (void)showContentsPage { NSBundle *bundle=[NSBundle mainBundle]; NSString *filePath = [bundle pathForResource:@"index" ofType:@"html" inDirectory:@"Help"]; if (filePath) { NSURL *fileUrl = [NSURL fileURLWithPath:filePath]; NSURLRequest *request = [NSURLRequest requestWithURL:fileUrl]; [htmlView loadRequest:request]; } else { [htmlView loadHTMLString:@"
Failed to find index.html!
" baseURL:nil]; } } // ----------------------------------------------------------------------------- static UIWebView *globalHtmlView = nil; // for ShowHelp - (void)viewDidLoad { [super viewDidLoad]; globalHtmlView = htmlView; htmlView.delegate = self; // following line will enable zooming content using pinch gestures // htmlView.scalesPageToFit = YES; // along with a line like this in each .html file's header: // // BUT it's simpler to adjust font size using some JavaScript in webViewDidFinishLoad backButton.enabled = NO; nextButton.enabled = NO; [self showContentsPage]; } // ----------------------------------------------------------------------------- - (void)viewDidUnload { [super viewDidUnload]; // release delegate and outlets htmlView.delegate = nil; htmlView = nil; backButton = nil; nextButton = nil; contentsButton = nil; } // ----------------------------------------------------------------------------- - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; } // ----------------------------------------------------------------------------- - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; } // ----------------------------------------------------------------------------- - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [htmlView stopLoading]; // in case the web view is still loading its content } // ----------------------------------------------------------------------------- - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; } // ----------------------------------------------------------------------------- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { // return YES for supported orientations return YES; } // ----------------------------------------------------------------------------- - (IBAction)doBack:(id)sender { [htmlView goBack]; } // ----------------------------------------------------------------------------- - (IBAction)doNext:(id)sender { [htmlView goForward]; } // ----------------------------------------------------------------------------- - (IBAction)doContents:(id)sender { [self showContentsPage]; } // ----------------------------------------------------------------------------- // UIWebViewDelegate methods: - (void)webViewDidStartLoad:(UIWebView *)webView { [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; } // ----------------------------------------------------------------------------- static std::string pageurl; - (void)webViewDidFinishLoad:(UIWebView *)webView { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; backButton.enabled = htmlView.canGoBack; nextButton.enabled = htmlView.canGoForward; // increase font size NSString *jsString = @"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '110%'"; [htmlView stringByEvaluatingJavaScriptFromString:jsString]; // need URL of this page for relative "get:" links NSString *str = [htmlView stringByEvaluatingJavaScriptFromString:@"window.location.href"]; // note that htmlView.request.mainDocumentURL.absoluteString returns the // same URL string, but with "%20" instead of spaces (GetURL wants spaces) pageurl = [str cStringUsingEncoding:NSUTF8StringEncoding]; } // ----------------------------------------------------------------------------- - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; // we can safely ignore -999 errors (eg. when ShowHelp is called before user switches to Help tab) if (error.code == NSURLErrorCancelled) return; Warning([error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding]); } // ----------------------------------------------------------------------------- - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if (navigationType == UIWebViewNavigationTypeLinkClicked) { NSURL *url = [request URL]; NSString *link = [url absoluteString]; // NSLog(@"url = %@", link); // look for special prefixes used by Golly (and return NO if found) if ([link hasPrefix:@"open:"]) { // open specified file std::string path = [[link substringFromIndex:5] cStringUsingEncoding:NSUTF8StringEncoding]; FixURLPath(path); OpenFile(path.c_str()); // OpenFile will switch to the appropriate tab return NO; } if ([link hasPrefix:@"rule:"]) { // switch to specified rule std::string newrule = [[link substringFromIndex:5] cStringUsingEncoding:NSUTF8StringEncoding]; SwitchToPatternTab(); ChangeRule(newrule); return NO; } if ([link hasPrefix:@"lexpatt:"]) { // user tapped on pattern in Life Lexicon std::string pattern = [[link substringFromIndex:8] cStringUsingEncoding:NSUTF8StringEncoding]; std::replace(pattern.begin(), pattern.end(), '$', '\n'); LoadLexiconPattern(pattern); return NO; } if ([link hasPrefix:@"edit:"]) { std::string path = [[link substringFromIndex:5] cStringUsingEncoding:NSUTF8StringEncoding]; // convert path to a full path if necessary std::string fullpath = path; if (path[0] != '/') { if (fullpath.find("Patterns/") == 0 || fullpath.find("Rules/") == 0) { // Patterns and Rules directories are inside supplieddir fullpath = supplieddir + fullpath; } else { fullpath = userdir + fullpath; } } ShowTextFile(fullpath.c_str()); return NO; } if ([link hasPrefix:@"get:"]) { std::string geturl = [[link substringFromIndex:4] cStringUsingEncoding:NSUTF8StringEncoding]; // download file specifed in link (possibly relative to a previous full url) GetURL(geturl, pageurl); return NO; } if ([link hasPrefix:@"unzip:"]) { std::string zippath = [[link substringFromIndex:6] cStringUsingEncoding:NSUTF8StringEncoding]; FixURLPath(zippath); std::string entry = zippath.substr(zippath.rfind(':') + 1); zippath = zippath.substr(0, zippath.rfind(':')); UnzipFile(zippath, entry); return NO; } // no special prefix, so look for file with .zip/rle/lif/mc extension std::string path = [link cStringUsingEncoding:NSUTF8StringEncoding]; path = path.substr(path.rfind('/')+1); size_t dotpos = path.rfind('.'); std::string ext = ""; if (dotpos != std::string::npos) ext = path.substr(dotpos+1); if ( (IsZipFile(path) || strcasecmp(ext.c_str(),"rle") == 0 || strcasecmp(ext.c_str(),"life") == 0 || strcasecmp(ext.c_str(),"mc") == 0) // also check for '?' to avoid opening links like ".../detail?name=foo.zip" && path.find('?') == std::string::npos) { // download file to downloaddir and open it path = downloaddir + path; std::string url = [link cStringUsingEncoding:NSUTF8StringEncoding]; if (DownloadFile(url, path)) { OpenFile(path.c_str()); } return NO; } } return YES; } @end // ============================================================================= void ShowHelp(const char* filepath) { SwitchToHelpTab(); NSURL *fileUrl = [NSURL fileURLWithPath:[NSString stringWithCString:filepath encoding:NSUTF8StringEncoding]]; NSURLRequest *request = [NSURLRequest requestWithURL:fileUrl]; // NSLog(@"filepath = %s", filepath); // NSLog(@"fileUrl = %@", fileUrl); [globalHtmlView loadRequest:request]; } golly-2.7-src/gui-ios/Golly/HelpViewController.h0000644000175000017500000000260512536111364016625 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import // This is the view controller for the Help tab. @interface HelpViewController : UIViewController { IBOutlet UIWebView *htmlView; IBOutlet UIBarButtonItem *backButton; IBOutlet UIBarButtonItem *nextButton; IBOutlet UIBarButtonItem *contentsButton; } - (IBAction)doBack:(id)sender; - (IBAction)doNext:(id)sender; - (IBAction)doContents:(id)sender; @end // display given HTML file void ShowHelp(const char* filepath); golly-2.7-src/gui-ios/Golly/GollyAppDelegate.m0000644000175000017500000001102012536111364016214 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import "prefs.h" // for SavePrefs #import "PatternViewController.h" #import "OpenViewController.h" #import "SettingsViewController.h" #import "HelpViewController.h" #import "GollyAppDelegate.h" @implementation GollyAppDelegate @synthesize window = _window; // ----------------------------------------------------------------------------- static UITabBarController *tabBarController = nil; // for SwitchToPatternTab, etc - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // set variable seed for later rand() calls srand((unsigned int)time(0)); self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; UIViewController *vc0 = [[PatternViewController alloc] initWithNibName:nil bundle:nil]; UIViewController *vc1 = [[OpenViewController alloc] initWithNibName:nil bundle:nil]; UIViewController *vc2 = [[SettingsViewController alloc] initWithNibName:nil bundle:nil]; UIViewController *vc3 = [[HelpViewController alloc] initWithNibName:nil bundle:nil]; tabBarController = [[UITabBarController alloc] init]; tabBarController.viewControllers = [NSArray arrayWithObjects:vc0, vc1, vc2, vc3, nil]; self.window.rootViewController = tabBarController; [self.window makeKeyAndVisible]; return YES; } // ----------------------------------------------------------------------------- - (void)applicationWillResignActive:(UIApplication *)application { // this is called for certain types of temporary interruptions (such as an incoming phone call or SMS message) // or when the user quits the application and it begins the transition to the background state PauseGenTimer(); } // ----------------------------------------------------------------------------- - (void)applicationDidEnterBackground:(UIApplication *)application { // called when user hits home button PauseGenTimer(); SavePrefs(); } // ----------------------------------------------------------------------------- - (void)applicationWillEnterForeground:(UIApplication *)application { // undo any changes made in applicationDidEnterBackground RestartGenTimer(); } // ----------------------------------------------------------------------------- - (void)applicationDidBecomeActive:(UIApplication *)application { // restart any tasks that were paused in applicationWillResignActive RestartGenTimer(); } // ----------------------------------------------------------------------------- - (void)applicationWillTerminate:(UIApplication *)application { // application is about to terminate // (never called in iOS 5, so use applicationDidEnterBackground) } @end // ============================================================================= void SwitchToPatternTab() { tabBarController.selectedIndex = 0; } // ----------------------------------------------------------------------------- void SwitchToOpenTab() { tabBarController.selectedIndex = 1; } // ----------------------------------------------------------------------------- void SwitchToSettingsTab() { tabBarController.selectedIndex = 2; } // ----------------------------------------------------------------------------- void SwitchToHelpTab() { tabBarController.selectedIndex = 3; } // ----------------------------------------------------------------------------- UIViewController* CurrentViewController() { return tabBarController.selectedViewController; } // ----------------------------------------------------------------------------- void EnableTabBar(bool enable) { tabBarController.tabBar.userInteractionEnabled = enable; } golly-2.7-src/gui-ios/Golly/SettingsViewController.h0000644000175000017500000000362112536111364017534 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #import // This is the view controller for the Settings tab. @interface SettingsViewController : UIViewController { IBOutlet UIButton *modeButton; IBOutlet UITextField *percentageText; IBOutlet UITextField *memoryText; IBOutlet UISlider *percentageSlider; IBOutlet UISlider *memorySlider; IBOutlet UISwitch *gridSwitch; IBOutlet UISwitch *timingSwitch; IBOutlet UISwitch *beepSwitch; IBOutlet UISwitch *colorsSwitch; IBOutlet UISwitch *iconsSwitch; IBOutlet UISwitch *undoSwitch; IBOutlet UISwitch *hashingSwitch; } - (IBAction)changePasteMode:(id)sender; - (IBAction)changePercentage:(id)sender; - (IBAction)changeMemory:(id)sender; - (IBAction)toggleGrid:(id)sender; - (IBAction)toggleTiming:(id)sender; - (IBAction)toggleBeep:(id)sender; - (IBAction)toggleColors:(id)sender; - (IBAction)toggleIcons:(id)sender; - (IBAction)toggleUndo:(id)sender; - (IBAction)toggleHashing:(id)sender; @end golly-2.7-src/docs/0000755000175000017500000000000012536111364011230 500000000000000golly-2.7-src/docs/License.html0000644000175000017500000007602412536111364013431 00000000000000 License info for Golly
		    GNU GENERAL PUBLIC LICENSE
		       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

		    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

			    NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

		     END OF TERMS AND CONDITIONS

	    How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    
    Copyright (C)   

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA


Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  , 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Library General
Public License instead of this License.

======================================================================

Golly uses an embedded Python interpreter for its scripting language.
Here is the official license for the Python 2.4 release:

A. HISTORY OF THE SOFTWARE
==========================

Python was created in the early 1990s by Guido van Rossum at Stichting
Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
as a successor of a language called ABC.  Guido remains Python's
principal author, although it includes many contributions from others.

In 1995, Guido continued his work on Python at the Corporation for
National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
in Reston, Virginia where he released several versions of the
software.

In May 2000, Guido and the Python core development team moved to
BeOpen.com to form the BeOpen PythonLabs team.  In October of the same
year, the PythonLabs team moved to Digital Creations (now Zope
Corporation, see http://www.zope.com).  In 2001, the Python Software
Foundation (PSF, see http://www.python.org/psf/) was formed, a
non-profit organization created specifically to own Python-related
Intellectual Property.  Zope Corporation is a sponsoring member of
the PSF.

All Python releases are Open Source (see http://www.opensource.org for
the Open Source Definition).  Historically, most, but not all, Python
releases have also been GPL-compatible; the table below summarizes
the various releases.

    Release         Derived     Year        Owner       GPL-
                    from                                compatible? (1)

    0.9.0 thru 1.2              1991-1995   CWI         yes
    1.3 thru 1.5.2  1.2         1995-1999   CNRI        yes
    1.6             1.5.2       2000        CNRI        no
    2.0             1.6         2000        BeOpen.com  no
    1.6.1           1.6         2001        CNRI        yes (2)
    2.1             2.0+1.6.1   2001        PSF         no
    2.0.1           2.0+1.6.1   2001        PSF         yes
    2.1.1           2.1+2.0.1   2001        PSF         yes
    2.2             2.1.1       2001        PSF         yes
    2.1.2           2.1.1       2002        PSF         yes
    2.1.3           2.1.2       2002        PSF         yes
    2.2.1           2.2         2002        PSF         yes
    2.2.2           2.2.1       2002        PSF         yes
    2.2.3           2.2.2       2003        PSF         yes
    2.3             2.2.2       2002-2003   PSF         yes
    2.3.1           2.3         2002-2003   PSF         yes
    2.3.2           2.3.1       2002-2003   PSF         yes
    2.3.3           2.3.2       2002-2003   PSF         yes
    2.3.4           2.3.3       2004        PSF         yes
    2.3.5           2.3.4       2005        PSF         yes
    2.4             2.3         2004        PSF         yes
    2.4.1           2.4         2005        PSF         yes
    2.4.2           2.4.1       2005        PSF         yes

Footnotes:

(1) GPL-compatible doesn't mean that we're distributing Python under
    the GPL.  All Python licenses, unlike the GPL, let you distribute
    a modified version without making your changes open source.  The
    GPL-compatible licenses make it possible to combine Python with
    other software that is released under the GPL; the others don't.

(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
    because its license has a choice of law clause.  According to
    CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
    is "not incompatible" with the GPL.

Thanks to the many outside volunteers who have worked under Guido's
direction to make these releases possible.


B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
===============================================================

PSF LICENSE AGREEMENT FOR PYTHON 2.4
------------------------------------

1. This LICENSE AGREEMENT is between the Python Software Foundation
("PSF"), and the Individual or Organization ("Licensee") accessing and
otherwise using Python 2.4 software in source or binary form and its
associated documentation.

2. Subject to the terms and conditions of this License Agreement, PSF
hereby grants Licensee a nonexclusive, royalty-free, world-wide
license to reproduce, analyze, test, perform and/or display publicly,
prepare derivative works, distribute, and otherwise use Python 2.4
alone or in any derivative version, provided, however, that PSF's
License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved"
are retained in Python 2.4 alone or in any derivative version prepared
by Licensee.

3. In the event Licensee prepares a derivative work that is based on
or incorporates Python 2.4 or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python 2.4.

4. PSF is making Python 2.4 available to Licensee on an "AS IS"
basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.4 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.

5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
2.4 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.4,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.

7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between PSF and
Licensee.  This License Agreement does not grant permission to use PSF
trademarks or trade name in a trademark sense to endorse or promote
products or services of Licensee, or any third party.

8. By copying, installing or otherwise using Python 2.4, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.


BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
-------------------------------------------

BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1

1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
Individual or Organization ("Licensee") accessing and otherwise using
this software in source or binary form and its associated
documentation ("the Software").

2. Subject to the terms and conditions of this BeOpen Python License
Agreement, BeOpen hereby grants Licensee a non-exclusive,
royalty-free, world-wide license to reproduce, analyze, test, perform
and/or display publicly, prepare derivative works, distribute, and
otherwise use the Software alone or in any derivative version,
provided, however, that the BeOpen Python License is retained in the
Software, alone or in any derivative version prepared by Licensee.

3. BeOpen is making the Software available to Licensee on an "AS IS"
basis.  BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.

4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

5. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.

6. This License Agreement shall be governed by and interpreted in all
respects by the law of the State of California, excluding conflict of
law provisions.  Nothing in this License Agreement shall be deemed to
create any relationship of agency, partnership, or joint venture
between BeOpen and Licensee.  This License Agreement does not grant
permission to use BeOpen trademarks or trade names in a trademark
sense to endorse or promote products or services of Licensee, or any
third party.  As an exception, the "BeOpen Python" logos available at
http://www.pythonlabs.com/logos.html may be used according to the
permissions granted on that web page.

7. By copying, installing or otherwise using the software, Licensee
agrees to be bound by the terms and conditions of this License
Agreement.


CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
---------------------------------------

1. This LICENSE AGREEMENT is between the Corporation for National
Research Initiatives, having an office at 1895 Preston White Drive,
Reston, VA 20191 ("CNRI"), and the Individual or Organization
("Licensee") accessing and otherwise using Python 1.6.1 software in
source or binary form and its associated documentation.

2. Subject to the terms and conditions of this License Agreement, CNRI
hereby grants Licensee a nonexclusive, royalty-free, world-wide
license to reproduce, analyze, test, perform and/or display publicly,
prepare derivative works, distribute, and otherwise use Python 1.6.1
alone or in any derivative version, provided, however, that CNRI's
License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
1995-2001 Corporation for National Research Initiatives; All Rights
Reserved" are retained in Python 1.6.1 alone or in any derivative
version prepared by Licensee.  Alternately, in lieu of CNRI's License
Agreement, Licensee may substitute the following text (omitting the
quotes): "Python 1.6.1 is made available subject to the terms and
conditions in CNRI's License Agreement.  This Agreement together with
Python 1.6.1 may be located on the Internet using the following
unique, persistent identifier (known as a handle): 1895.22/1013.  This
Agreement may also be obtained from a proxy server on the Internet
using the following URL: http://hdl.handle.net/1895.22/1013".

3. In the event Licensee prepares a derivative work that is based on
or incorporates Python 1.6.1 or any part thereof, and wants to make
the derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary of
the changes made to Python 1.6.1.

4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
basis.  CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
INFRINGE ANY THIRD PARTY RIGHTS.

5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.

6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.

7. This License Agreement shall be governed by the federal
intellectual property law of the United States, including without
limitation the federal copyright law, and, to the extent such
U.S. federal law does not apply, by the law of the Commonwealth of
Virginia, excluding Virginia's conflict of law provisions.
Notwithstanding the foregoing, with regard to derivative works based
on Python 1.6.1 that incorporate non-separable material that was
previously distributed under the GNU General Public License (GPL), the
law of the Commonwealth of Virginia shall govern this License
Agreement only as to issues arising under or with respect to
Paragraphs 4, 5, and 7 of this License Agreement.  Nothing in this
License Agreement shall be deemed to create any relationship of
agency, partnership, or joint venture between CNRI and Licensee.  This
License Agreement does not grant permission to use CNRI trademarks or
trade name in a trademark sense to endorse or promote products or
services of Licensee, or any third party.

8. By clicking on the "ACCEPT" button where indicated, or by copying,
installing or otherwise using Python 1.6.1, Licensee agrees to be
bound by the terms and conditions of this License Agreement.


CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
--------------------------------------------------

Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
The Netherlands.  All rights reserved.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that the name of Stichting Mathematisch
Centrum or CWI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.

STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
golly-2.7-src/docs/Build.html0000644000175000017500000005150412536111364013102 00000000000000 How to build Golly

This document contains instructions for how to build the desktop version of Golly.

Contents

How to install wxWidgets
      On Windows
      On Mac OS X
      On Linux
How to install Perl and Python
How to build Golly
      On Windows
      On Mac OS X
      On Linux
Building Golly using configure
Building Golly using CMake
How to build bgolly
Source code road map
      Directory structure
      High-level GUI code
      Low-level base code

How to install wxWidgets

If you want to build Golly from source code then you'll have to install wxWidgets first. Visit http://www.wxwidgets.org/downloads and grab the appropriate source archive for your platform:

  • On Windows (XP+), get the wxMSW source installer.
  • On Mac OS X (10.6+), get the 2.9.x source archive with Unix line endings.
  • On Linux, get the wxGTK source archive.

Golly should compile with wxWidgets 2.8.0 or later, but it's best to use the latest version. Mac users should get 2.9 or later (this is necessary for a 64-bit Cocoa build).

On Windows

For a 64-bit build, open a x64 Visual Studio command prompt (e.g. VS2012 x64 Cross Tools Command Prompt) and type:

   cd \wxWidgets\build\msw
   nmake -f makefile.vc BUILD=release RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=0 DEBUG_FLAG=0 TARGET_CPU=AMD64
   nmake -f makefile.vc BUILD=debug RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=1 DEBUG_FLAG=1 TARGET_CPU=AMD64

For a 32-bit build, open a x32 Visual Studio command prompt (e.g. Developer Command Prompt for VS2012) and type:

   cd \wxWidgets\build\msw
   nmake -f makefile.vc BUILD=release RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=0 DEBUG_FLAG=0
   nmake -f makefile.vc BUILD=debug RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=1 DEBUG_FLAG=1

On Mac OS X

Unpack the wxWidgets source archive wherever you like, start up Terminal and type these commands (using the correct path and version number):

   cd /path/to/wxWidgets-2.9.4
   mkdir build-osx
   cd build-osx
   ../configure --with-osx_cocoa --disable-shared --enable-unicode
   make

If you plan to build Golly using CMake (see below) then also do "sudo make install".

WARNING: If your version of wxWidgets is later than 2.9.4 then you'll need to make the following patch before running make. Open src/osx/nonownedwnd_osx.cpp and edit the wxNonOwnedWindow::Update() routine so that it looks like this:

   void wxNonOwnedWindow::Update()
   {
       m_nowpeer->Update();
   }

This routine is called whenever Golly wants to update the viewport. Without this change, Golly will appear to run way too fast at step size 1 because any update requests faster than about 30Hz will simply be ignored!

On Linux

Unpack the wxGTK source archive wherever you like, start up a terminal session and type these commands (using the correct version number):

   cd /path/to/wxGTK-2.8.12
   mkdir build-gtk
   cd build-gtk
   ../configure --with-gtk --disable-shared --enable-unicode
   make
   sudo make install
   sudo ldconfig

This installs the wx libraries in a suitable directory. It also installs the wx-config program which will be called by makefile-gtk to set the appropriate compile and link options for building Golly.

How to install Perl and Python

Golly uses Perl and Python for scripting, so you'll need to make sure both are installed. Mac OS X users don't have to do anything because Perl and Python are already installed.

If you are running Linux, you probably have Perl installed. Type "perl -v" at the command line to print out the version. Golly's code should compile happily with Perl 5.10.x or later, but support for interpreter threads is required.

Windows users are advised to download the ActivePerl installer from
http://www.activestate.com/Products/ActivePerl.

Windows and Linux users can download a Python installer from
http://www.python.org/download.

How to build Golly

Once wxWidgets, Perl and Python are installed, building Golly should be relatively easy:

On Windows

First, locate local-win-template.mk in the gui-wx folder and copy it to a new file called local-win.mk. This file is included by makefile-win. Edit local-win.mk and specify where wxWidgets is installed by changing the WX_DIR path near the start of the file. Also make sure WX_RELEASE specifies the first two digits of your wxWidgets version. The headers for Perl and Python must also be included, so change the paths for PERL_INCLUDE and PYTHON_INCLUDE if necessary. Now you're ready to build Golly.

For a 64-bit build, open a x64 Visual Studio command prompt (e.g. VS2012 x64 Cross Tools Command Prompt) and type:

   cd \path\to\golly\gui-wx
   nmake -f makefile-win BUILD=release RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=0 DEBUG_FLAG=0 TARGET_CPU=AMD64

For a 32-bit build, open a x32 Visual Studio command prompt (e.g. Developer Command Prompt for VS2012) and type:

   cd \path\to\golly\gui-wx
   nmake -f makefile-win BUILD=release RUNTIME_LIBS=static UNICODE=1 DEBUG_INFO=0 DEBUG_FLAG=0

On Mac OS X

Go to the gui-wx folder and make a copy of makefile-mac called makefile. Edit makefile and specify where wxWidgets is installed by changing the WX_DIR path near the start of the file. Also make sure WX_RELEASE specifies the first two digits of your wxWidgets version.

On Mac OS 10.6 or later you can then build a 64-bit Cocoa version of Golly by opening a Terminal window and doing:

   cd /path/to/golly/gui-wx
   make

On Linux

You might need to add some development packages first. For example, from a default Ubuntu install (at the time of writing) you will need to install the following packages: libgtk2.0-dev, python2.6-dev (for GTK and Python respectively).

Open a terminal window and build the golly executable by doing:

   cd /path/to/golly/gui-wx
   make -f makefile-gtk

Note that the CXXFLAGS and LDFLAGS environmental variables may be used to append to (and override) the package default flags. Additionally, GOLLYDIR specifies an absolute directory path to look for the application data files. For system-wide installation, it probably makes sense to set GOLLYDIR to /usr/share/golly and install the Help, Patterns, Scripts and Rules directories in there.

Aternative methods for building Golly are also available, as discussed in the following two sections.

Building Golly using configure

Golly can be built using the standard GNU build tools. If you obtained the Golly source code from the Git repository instead of a source release, you need to generate the configure script first:

   cd /path/to/golly/gui-wx/configure
   ./autogen.sh

This requires that autoconf, automake and Perl 5.x are installed.

The configure script offers various options to customize building and installation. For an overview of the available options, run:

   ./configure --help

Run the configure script to create an appropriate Makefile for your operating system and then run make to build Golly. For example, for a system-wide installation, you could do this:

   cd /path/to/golly/gui-wx/configure
   ./configure
   make
   make install

Building Golly using CMake

The CMakeLists.txt file included in the gui-wx directory allows Golly to be built using CMake. Visit http://www.cmake.org and download a suitable installer for your operating system.

Once CMake is installed, you can build Golly using these commands:

   cd /path/to/golly/gui-wx     (location of CMakeLists.txt)
   mkdir cmakedir               (use any name for this subdirectory)
   cd cmakedir
   cmake ..
   make                         (or nmake on Windows)

CMake also comes with a GUI application if you'd prefer not to use the command line.

Some notes:

  • Although wxWidgets comes pre-installed on Mac OS X, it tends to be out-of-date and inappropriate for building Golly, so CMakeLists.txt sets wxWidgets_CONFIG_EXECUTABLE to /usr/local/bin/wx-config where /usr/local/bin is the default location for wx-config if you do "sudo make install" after building the wxWidgets libraries.
  • Also on Mac OS X, PERL_INCLUDE_PATH and PERL_LIBRARY are overridden to avoid statically linking the Perl library. Their settings assume Perl 5.10 so you might need to change the version numbers.
  • A common issue is that it doesn't find wxWidgets, especially when you have more than one version installed. Set wxWidgets_ROOT_DIR to the correct folder and re-configure.
  • If running CMake on the command-line, the location of wxWidgets can be specified like this:
    cmake -G"NMake Makefiles" -DwxWidgets_ROOT_DIR=C:/wxWidgets/wxWidgets-3.0.1_vs2012_x64_staticCRT 
    -DwxWidgets_LIB_DIR=C:\wxWidgets\wxWidgets-3.0.1_vs2012_x64_staticCRT\lib\vc_x64_lib c:\golly-git\golly-code\gui-wx
    
    (this example is for a x64 build using NMake).

How to build bgolly

The above make/nmake commands will also create bgolly, a simple "batch mode" version of Golly without any GUI. To build bgolly separately, just specify bgolly as the target of the make/nmake command. For example, on Linux:

   make -f makefile-gtk bgolly

You don't need to install wxWidgets, Perl or Python to build bgolly.

Source code road map

If you'd like to modify Golly then the following information should help you get started.

Directory structure

Golly's source code can be downloaded from Sourceforge as a Git repository or as a .tar.gz file. You should see the following directories:

cmdline

Contains source code for bgolly and RuleTableToTree (the latter program is no longer included in the binary distribution).

docs

Contains documentation in the form of .html files.

gollybase

Contains the low-level source code used by the client code in cmdline and the various gui-* directories. See below for a description of the various files.

gui-android

Contains source code and resources for the Android version of Golly.

gui-common

Contains the GUI code and help files shared by the Android and iPad versions of Golly.

gui-ios

Contains source code and resources for the iPad version of Golly.

gui-wx

Contains the high-level wxWidgets code for the desktop version of Golly (see below for more details). Also contains other files and resources needed to build Golly (make files, bitmap files, icon files, etc).

Help

Contains various .html files that are accessed from Golly's Help menu.

Patterns

Contains a state-of-the-art pattern collection.

Rules

Contains various .rule files. These files contain table/tree data (loaded by the RuleLoader algorithm) and optional color/icon data (used by the GUI code to render patterns).

Scripts

Contains Perl and Python scripts that can be run by Golly.

Note that the executables (Golly and bgolly) are created in the same location as the above directories. This means you can test a new Golly build without having to copy it somewhere else because the required directories (Help, Patterns, Rules and Scripts) are in the correct location.

High-level GUI code

The desktop version of Golly uses wxWidgets to implement the graphical user interface. All the GUI code is stored in the gui-wx directory in a number of wx* files. Each module is described in (roughly) top-down order, and some key routines are mentioned:

wxgolly.*

Defines the GollyApp class.
GollyApp::OnInit() is where it all starts.

wxmain.*

Defines the MainFrame class for the main window.
MainFrame::OnMenu() handles all menu commands.
MainFrame::UpdateEverything() updates all parts of the GUI.

wxfile.cpp

Implements various File menu functions.
MainFrame::NewPattern() creates a new, empty universe.
MainFrame::LoadPattern() reads in a pattern file.

wxcontrol.cpp

Implements various Control menu functions.
MainFrame::GeneratePattern() runs the current pattern.
MainFrame::ChangeAlgorithm() switches to a new algorithm.

wxtimeline.*

Users can record/play a sequence of steps called a "timeline".
CreateTimelineBar() creates timeline bar below the viewport window.
StartStopRecording() starts or stops recording a timeline.
DeleteTimeline() deletes an existing timeline.

wxrule.*

Users can change the current rule.
ChangeRule() opens the Set Rule dialog.

wxedit.*

Implements edit bar functions.
CreateEditBar() creates the edit bar above the viewport window.
ToggleEditBar() shows/hides the edit bar.

wxselect.*

Defines the Selection class for operations on selections.
Selection::CopyToClipboard() copies the selection to the clipboard.
Selection::RandomFill() randomly fills the current selection.
Selection::Rotate() rotates the current selection.
Selection::Flip() flips the current selection.

wxview.*

Defines the PatternView class for the viewport window.
PatternView::ProcessKey() processes keyboard shortcuts.
PatternView::ProcessClick() processes mouse clicks.

wxrender.*

Implements rendering routines for updating the viewport.
DrawView() draws the pattern, grid lines, selection, etc.

wxalgos.*

Implements support for multiple algorithms.
InitAlgorithms() initializes all algorithms and algoinfo data.
CreateNewUniverse() creates a new universe of given type.

wxlayer.*

Defines the Layer class and implements Layer menu functions.
AddLayer() adds a new, empty layer.
DeleteLayer() deletes the current layer.
SetLayerColors() lets user change the current layer's colors.

wxundo.*

Defines the UndoRedo class for unlimited undo/redo.
UndoRedo::RememberCellChanges() saves cell state changes.
UndoRedo::UndoChange() undoes a recent change.
UndoRedo::RedoChange() redoes an undone change.

wxstatus.*

Implements a status bar at the top of the main window.
StatusBar::DrawStatusBar() shows gen count, pop count, etc.
StatusBar::DisplayMessage() shows message in bottom line.

wxhelp.*

Implements a modeless help window.
ShowHelp() displays a given .html file.

wxinfo.*

Implements a modeless info window.
ShowInfo() displays the comments in a given pattern file.

wxscript.*

Implements the high-level scripting interface.
RunScript() runs a given script file.

wxperl.*

Implements Perl script support.
RunPerlScript() runs a given .pl file.

wxpython.*

Implements Python script support.
RunPythonScript() runs a given .py file.

wxprefs.*

Routines for loading, saving and changing user preferences.
GetPrefs() loads data from GollyPrefs file.
SavePrefs() writes data to GollyPrefs file.
ChangePrefs() opens the Preferences dialog.

wxutils.*

Implements various utility routines.
Warning() displays message in modal dialog.
Fatal() displays message and exits the app.

Low-level base code

The gollybase directory contains low-level code used by all the various clients (desktop Golly, bgolly, and the Android/iPad versions):

platform.h

Platform specific defines (eg. 64-bit changes).

lifealgo.*

Defines abstract Life algorithm operations:
lifealgo::setcell() sets given cell to given state.
lifealgo::getcell() gets state of given cell.
lifealgo::nextcell() finds next live cell in current row.
lifealgo::step() advances pattern by current increment.
lifealgo::fit() fits pattern within given viewport.
lifealgo::draw() renders pattern in given viewport.

liferules.*

Defines routines for setting/getting rules.
liferules::setrule() parses and validates a given rule string.
liferules::getrule() returns the current rule in canonical form.

lifepoll.*

Allows lifealgo routines to do event processing.
lifepoll::checkevents() processes any pending events.

viewport.*

Defines abstract viewport operations:
viewport::zoom() zooms into a given location.
viewport::unzoom() zooms out from a given location.
viewport::setmag() sets the magnification.
viewport::move() scrolls view by given number of pixels.

liferender.*

Defines abstract routines for rendering a pattern:
liferender::killrect() fills an area with the dead cell color.
liferender::pixblit() draws an area with at least one live cell.

qlifealgo.*

Implements QuickLife, a fast, conventional algorithm.

hlifealgo.*

Implements HashLife, a super fast hashing algorithm.

ghashbase.*

Defines an abstract class so other algorithms can use hashlife in a multi-state universe.

generationsalgo.*

Implements the Generations family of rules.

jvnalgo.*

Implements John von Neumann's 29-state CA and 32-state variants by Renato Nobili and Tim Hutton.

ruleloaderalgo.*

Implements the RuleLoader algorithm which loads externally specified rules stored in .rule/table/tree files.

ruletable_algo.*

Used by the RuleLoader algorithm to load table data.

ruletreealgo.*

Used by the RuleLoader algorithm to load tree data.

qlifedraw.cpp

Implements rendering routines for QuickLife.

hlifedraw.cpp

Implements rendering routines for HashLife.

ghashdraw.cpp

Implements rendering routines for all algos that use ghashbase.

readpattern.*

Reads pattern files in a variety of formats.
readpattern() loads a pattern into the given universe.
readcomments() extracts comments from the given file.

writepattern.*

Saves the current pattern in a file.
writepattern() saves the pattern in a specified format.

bigint.*

Implements operations on arbitrarily large integers.

util.*

Utilities for displaying errors and progress info.
warning() displays error message.
fatal() displays error message and exits.

Have fun, and please let us know if you make any changes!

Andrew Trevorrow (andrew@trevorrow.com)
Tom Rokicki (rokicki@gmail.com)
(on behalf of The Golly Gang)

golly-2.7-src/docs/ToDo.html0000644000175000017500000001212312536111364012702 00000000000000 To-do notes for Golly
Andrew's list:
==============

- Only have one panel for showing Patterns, Scripts, Rules, etc,
  and set initial location to directory containing those sub-folders.

- Add a new check box to Prefs > Layer: "Automatically show/hide layer bar".
  If ticked then layer bar is automatically shown whenever the number of
  layers becomes > 1, and automatically hidden when the number drops to 1.
  Only need to check in a few places (esp. after a script ends).

- Optimize rendering by using OpenGL (see gui-common/render.cpp).

- Auto stop script if it creates too many temp files (for undo).
  This can happen if a long-running script doesn't call new/open
  when it probably should.  See my email to Nathaniel with subject
  "Re: Golly methuselah search script".

- Change all Python commands to g_* for consistency with Perl commands.
  Unfortutely, we can't really keep the old commands in same module
  because doing "from golly import *" exposes old and new commands and
  so a script like goto.py that calls a non-Golly open command will fail.
  We could put old commands in a separate module called "oldgolly".
  Maybe best to leave this change for when the scripting API needs
  significant changes due to multi-rect selections.

- Avoid any remaining algo assumptions (search *_ALGO):
  - Need IsParityShifted() method to avoid QLIFE_ALGO assumption?

- Allow dragging zoom-in cursor to zoom into rect.

- Stop generating if pattern becomes empty, constant or p2 (qlife only)
  and display suitable message in status bar.  Or maybe just add
  Gabriel's oscillation detection as an option (see oscar.py).

- Allow non-rectangular (and disjoint) selections.

- Add simple methuselah/spaceship/osc/still-life searches as in LifeLab???

- Fix glitches in the way the algo button works:
  - On Mac we want button to look selected before menu appears.
  - On Win we want to be able to press-select-release.

- Add case studies to BUILD file: how to add a new menu item, how to add
  a new algorithm, etc.


Tom's list:
===========

File I/O

- Have hlifealgo .mc compatible with ghashbase .mc
- Generalized RLE in MC?

Algos

- Unzoom color merging
- Better status reports (% of hashtable full)

Scripting

- Tape construction script for replicator

Samples

- Small JVN examples

Fun

- htreebase
- hgridbase (finite universe; torus, etc.)
- allow (base) x (slow) algorithm "multiplication"
- pluggability of externally-defined algos
- perl/python slowcalc callbacks
- cache of slowcalc
- generational gc
- 32-bit indexed hashlife on 64-bit platforms

Other

- Improve batchmode.

- Fix qlifealgo::lowerRightPixel to prevent off-by-one error when
  selecting large pattern like caterpillar.


User suggestions:
=================

Nick Gotts:
- Need a way to copy exact gen/pop counts to clipboard.
  [No longer necessary now that a script can get this info.]

Jason Summers:
- For better viewing of patterns that move, have a way to automatically
  move the view X cells horizontally and Y cells vertically every Z gens.
  [Could be done quite easily via a script that prompts for X,Y,Z.]
- Allow diagonal selection rectangles.

Dave Greene:
- Provide a way to click-and-drag a selection to move it around.
- Make page and arrow scrolling amounts configurable (in Prefs > View).
- Add a getview() script command that returns current viewport rect
  and a setview(rect) command to change viewport size and location.
- Make info window a floating window and keep it open (but update
  its contents) when user loads another pattern.

H. Koenig:
- Multiple windows.  [No real need now that we have multiple layers.]

Gabriel Nivasch:
- Make paste pattern semi-transparent.  [Tried it -- somewhat confusing.]
- Add a Default button to each Preferences pane (at bottom left?).

Bill Gosper:
- Modify info window so it can be used to edit and save comments.
- For scales > 1:1 make the pixel color depend on lg(# of ones in it).

Brice Due:
- Provide MCell-like editing capabilities.
- Provide a thumbnail option as an alternative to tiled layers;
  ie. the current layer would be displayed in a large "focal" viewport.
  All layers would be displayed as small, active thumbnails (at left
  or top edge of focal viewport, depending on aspect ratio?).
- Allow mc files to set step base and/or exponent via comment line like
  #X stepbase=8 stepexp=3
  [No need now that zip files can contain pattern + script?]

Tim Hutton:
- Add a script command to save comments in a pattern file.  Add optional
  param to existing save() command?

William R. Buckley:
- Provide an option to increase spacing between buttons.

Dean Hickerson:
- Make Duplicate Layer faster by writing current pattern to temp file
  and reading it into new layer.

tod222:
- Provide a way to cleanly shut down Golly from within a script.
  Maybe just use special exit() string like exit("QUIT GOLLY")?
  [No need -- can now call doevent("key q cmd").]
- Allow a command line argument (-minimize?) to start up with the
  main window in minimized state.  Should be possible in OnInit.
golly-2.7-src/docs/ReadMe.html0000644000175000017500000000465412536111364013204 00000000000000 Read Me for Golly

Welcome to Golly, a sophisticated tool for exploring Conway's Game of Life and many other types of cellular automata.

Key features:

  • Free, open source and cross-platform (Windows, Mac, Linux).
  • Supports both bounded and unbounded universes.
  • Supports various topologies (plane, torus, Klein bottle, etc.).
  • Supports multi-state universes (cells can have up to 256 states).
  • Includes QuickLife, a fast, memory-efficient algorithm.
  • Use the HashLife algorithm to see large patterns evolve at huge time scales.
  • Supports many different rules, including Wolfram's 1D rules, WireWorld, Generations, and John von Neumann's 29-state CA.
  • Use the RuleLoader algorithm to load your own rules.
  • Responsive even while generating or garbage collecting.
  • Reads RLE, macrocell, Life 1.05/1.06, dblife, and MCell files.
  • Can also read common graphic formats: BMP, PNG, GIF, TIFF.
  • Can extract patterns, scripts and rules from zip files.
  • Download files from online archives.
  • Includes a state-of-the-art pattern collection.
  • Fast loading of large patterns.
  • Paste in patterns from the clipboard.
  • Unlimited undo/redo.
  • Unbounded zooming out for astronomical patterns.
  • Auto fit option keeps a generating pattern within view.
  • Full screen option (no menu/status/tool/scroll bars).
  • Supports multiple layers, including cloned layers.
  • HTML-based help with an integrated Life Lexicon.
  • Scriptable via Perl or Python.
  • User-configurable keyboard shortcuts.

The Golly application can be installed anywhere you like, but make sure you move the whole folder because the various subfolders must be kept with the application.

We also provide bgolly, a GUI-less version of Golly that can be run from the command line.

The latest information is available at the Golly web site:

http://golly.sourceforge.net/

Now go forth and generate!

Andrew Trevorrow (andrew@trevorrow.com)
Tom Rokicki (rokicki@gmail.com)
(on behalf of The Golly Gang)

golly-2.7-src/cmdline/0000755000175000017500000000000012536111546011715 500000000000000golly-2.7-src/cmdline/bgolly.cpp0000644000175000017500000004676412536111364013650 00000000000000 /*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "qlifealgo.h" #include "hlifealgo.h" #include "generationsalgo.h" #include "jvnalgo.h" #include "ruleloaderalgo.h" #include "readpattern.h" #include "util.h" #include "viewport.h" #include "liferender.h" #include "writepattern.h" #include #include #include #include #include #ifdef TIMING #include #endif using namespace std ; viewport viewport(1000, 1000) ; /* * This is a "renderer" that is just stubs, for performance testing. */ class nullrender : public liferender { public: nullrender() {} virtual ~nullrender() {} virtual void killrect(int, int, int, int) {} virtual void pixblit(int, int, int, int, char*, int) {} virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b) { static unsigned char dummy[256]; *r = *g = *b = dummy; } } ; nullrender renderer ; /* * This is a "lifeerrors" that we can use to test some edge * conditions. In this case the only real thing we use * it for is to check rendering during a progress dialog. */ class nullerrors : public lifeerrors { public: nullerrors() {} virtual void fatal(const char *) {} virtual void warning(const char *) {} virtual void status(const char *) {} virtual void beginprogress(const char *s) { abortprogress(0, s) ; } virtual bool abortprogress(double, const char *) ; virtual void endprogress() { abortprogress(1, "") ; } virtual const char* getuserrules() { return "" ; } virtual const char* getrulesdir() { return "Rules/" ; } } ; nullerrors nullerror ; #ifdef TIMING double start ; double timestamp() { struct timeval tv ; gettimeofday(&tv, 0) ; double now = tv.tv_sec + 0.000001 * tv.tv_usec ; double r = now - start ; start = now ; return r ; } #endif /* * This is a "lifeerrors" that we can use to test some edge * conditions. In this case the only real thing we use * it for is to check rendering during a progress dialog. */ class verbosestatus : public lifeerrors { public: verbosestatus() {} virtual void fatal(const char *) {} virtual void warning(const char *) {} virtual void status(const char *s) { #ifdef TIMING cout << timestamp() << " " << s << endl ; #endif } virtual void beginprogress(const char *) {} virtual bool abortprogress(double, const char *) { return 0 ; } virtual void endprogress() {} virtual const char* getuserrules() { return "" ; } virtual const char* getrulesdir() { return "Rules/" ; } } ; verbosestatus verbosestatus_instance ; char *filename ; lifealgo *imp = 0 ; struct options { const char *shortopt ; const char *longopt ; const char *desc ; char opttype ; void *data ; } ; bigint maxgen = -1, inc = 0 ; int maxmem = 256 ; int hyper, render, autofit, quiet, popcount, progress ; int hashlife ; char *algoName = 0 ; int verbose ; int timeline ; int stepthresh, stepfactor ; char *liferule = 0 ; char *outfilename = 0 ; char *renderscale = (char *)"1" ; char *testscript = 0 ; int outputgzip, outputismc ; int numberoffset ; // where to insert file name numbers options options[] = { { "-m", "--generation", "How far to run", 'I', &maxgen }, { "-i", "--stepsize", "Step size", 'I', &inc }, { "-M", "--maxmemory", "Max memory to use in megabytes", 'i', &maxmem }, { "-2", "--exponential", "Use exponentially increasing steps", 'b', &hyper }, { "-q", "--quiet", "Don't show population; twice, don't show anything", 'b', &quiet }, { "-r", "--rule", "Life rule to use", 's', &liferule }, { "-h", "--hashlife", "Use Hashlife algorithm", 'b', &hashlife }, { "-a", "--algorithm", "Select algorithm by name", 's', &algoName }, { "-o", "--output", "Output file (*.rle, *.mc, *.rle.gz, *.mc.gz)", 's', &outfilename }, { "-v", "--verbose", "Verbose", 'b', &verbose }, { "-t", "--timeline", "Use timeline", 'b', &timeline }, { "", "--render", "Render (benchmarking)", 'b', &render }, { "", "--progress", "Render during progress dialog (debugging)", 'b', &progress }, { "", "--popcount", "Popcount (benchmarking)", 'b', &popcount }, { "", "--scale", "Rendering scale", 's', &renderscale }, //{ "", "--stepthreshold", "Stepsize >= gencount/this (default 1)", // 'i', &stepthresh }, //{ "", "--stepfactor", "How much to scale step by (default 2)", // 'i', &stepfactor }, { "", "--autofit", "Autofit before each render", 'b', &autofit }, { "", "--exec", "Run testing script", 's', &testscript }, { 0, 0, 0, 0, 0 } } ; int endswith(const char *s, const char *suff) { int off = (int)(strlen(s) - strlen(suff)) ; if (off <= 0) return 0 ; s += off ; while (*s) if (tolower(*s++) != tolower(*suff++)) return 0 ; numberoffset = off ; return 1 ; } void usage(const char *s) { fprintf(stderr, "Usage: bgolly [options] patternfile\n") ; for (int i=0; options[i].shortopt; i++) fprintf(stderr, "%3s %-15s %s\n", options[i].shortopt, options[i].longopt, options[i].desc) ; if (s) lifefatal(s) ; exit(0) ; } #define STRINGIFY(ARG) STR2(ARG) #define STR2(ARG) #ARG #define MAXRLE 1000000000 void writepat(int fc) { char *thisfilename = outfilename ; char tmpfilename[256] ; if (fc >= 0) { strcpy(tmpfilename, outfilename) ; char *p = tmpfilename + numberoffset ; *p++ = '-' ; sprintf(p, "%d", fc) ; p += strlen(p) ; strcpy(p, outfilename + numberoffset) ; thisfilename = tmpfilename ; } cerr << "(->" << thisfilename << flush ; bigint t, l, b, r ; imp->findedges(&t, &l, &b, &r) ; if (!outputismc && (t < -MAXRLE || l < -MAXRLE || b > MAXRLE || r > MAXRLE)) lifefatal("Pattern too large to write in RLE format") ; const char *err = writepattern(thisfilename, *imp, outputismc ? MC_format : RLE_format, outputgzip ? gzip_compression : no_compression, t.toint(), l.toint(), b.toint(), r.toint()) ; if (err != 0) lifewarning(err) ; cerr << ")" << flush ; } const int MAXCMDLENGTH = 2048 ; struct cmdbase { cmdbase(const char *cmdarg, const char *argsarg) { verb = cmdarg ; args = argsarg ; next = list ; list = this ; } const char *verb ; const char *args ; int iargs[4] ; char *sarg ; bigint barg ; virtual void doit() {} // for convenience, we put the generic loop here that takes a // 4x bounding box and runs getnext on all y values until // they are done. Input is assumed to be a bounding box in the // form minx miny maxx maxy void runnextloop() { int minx = iargs[0] ; int miny = iargs[1] ; int maxx = iargs[2] ; int maxy = iargs[3] ; int v ; for (int y=miny; y<=maxy; y++) { for (int x=minx; x<=maxx; x++) { int dx = imp->nextcell(x, y, v) ; if (dx < 0) break ; if (x > 0 && (x + dx) < 0) break ; x += dx ; if (x > maxx) break ; nextloopinner(x, y) ; } } } virtual void nextloopinner(int, int) {} int parseargs(const char *cmdargs) { int iargn = 0 ; char sbuf[MAXCMDLENGTH+2] ; for (const char *rargs = args; *rargs; rargs++) { while (*cmdargs && *cmdargs <= ' ') cmdargs++ ; if (*cmdargs == 0) { lifewarning("Missing needed argument") ; return 0 ; } switch (*rargs) { case 'i': if (sscanf(cmdargs, "%d", iargs+iargn) != 1) { lifewarning("Missing needed integer argument") ; return 0 ; } iargn++ ; break ; case 'b': { int i = 0 ; for (i=0; cmdargs[i] > ' '; i++) sbuf[i] = cmdargs[i] ; sbuf[i] = 0 ; barg = bigint(sbuf) ; } break ; case 's': if (sscanf(cmdargs, "%s", sbuf) != 1) { lifewarning("Missing needed string argument") ; return 0 ; } sarg = strdup(sbuf) ; break ; default: lifefatal("Internal error in parseargs") ; } while (*cmdargs && *cmdargs > ' ') cmdargs++ ; } return 1 ; } static void docmd(const char *cmdline) { for (cmdbase *cmd=list; cmd; cmd = cmd->next) if (strncmp(cmdline, cmd->verb, strlen(cmd->verb)) == 0 && cmdline[strlen(cmd->verb)] <= ' ') { if (cmd->parseargs(cmdline+strlen(cmd->verb))) { cmd->doit() ; } return ; } lifewarning("Didn't understand command") ; } cmdbase *next ; virtual ~cmdbase() {} static cmdbase *list ; } ; cmdbase *cmdbase::list = 0 ; struct loadcmd : public cmdbase { loadcmd() : cmdbase("load", "s") {} virtual void doit() { const char *err = readpattern(sarg, *imp) ; if (err != 0) lifewarning(err) ; } } load_inst ; struct stepcmd : public cmdbase { stepcmd() : cmdbase("step", "b") {} virtual void doit() { imp->setIncrement(barg) ; imp->step() ; cout << imp->getGeneration().tostring() << ": " ; cout << imp->getPopulation().tostring() << endl ; } } step_inst ; struct showcmd : public cmdbase { showcmd() : cmdbase("show", "") {} virtual void doit() { cout << imp->getGeneration().tostring() << ": " ; cout << imp->getPopulation().tostring() << endl ; } } show_inst ; struct quitcmd : public cmdbase { quitcmd() : cmdbase("quit", "") {} virtual void doit() { cout << "Buh-bye!" << endl ; exit(10) ; } } quit_inst ; struct setcmd : public cmdbase { setcmd() : cmdbase("set", "ii") {} virtual void doit() { imp->setcell(iargs[0], iargs[1], 1) ; } } set_inst ; struct unsetcmd : public cmdbase { unsetcmd() : cmdbase("unset", "ii") {} virtual void doit() { imp->setcell(iargs[0], iargs[1], 0) ; } } unset_inst ; struct helpcmd : public cmdbase { helpcmd() : cmdbase("help", "") {} virtual void doit() { for (cmdbase *cmd=list; cmd; cmd = cmd->next) cout << cmd->verb << " " << cmd->args << endl ; } } help_inst ; struct getcmd : public cmdbase { getcmd() : cmdbase("get", "ii") {} virtual void doit() { cout << "At " << iargs[0] << "," << iargs[1] << " -> " << imp->getcell(iargs[0], iargs[1]) << endl ; } } get_inst ; struct getnextcmd : public cmdbase { getnextcmd() : cmdbase("getnext", "ii") {} virtual void doit() { int v ; cout << "At " << iargs[0] << "," << iargs[1] << " next is " << imp->nextcell(iargs[0], iargs[1], v) << endl ; } } getnext_inst ; vector > cutbuf ; struct copycmd : public cmdbase { copycmd() : cmdbase("copy", "iiii") {} virtual void nextloopinner(int x, int y) { cutbuf.push_back(make_pair(x-iargs[0], y-iargs[1])) ; } virtual void doit() { cutbuf.clear() ; runnextloop() ; cout << cutbuf.size() << " pixels copied." << endl ; } } copy_inst ; struct cutcmd : public cmdbase { cutcmd() : cmdbase("cut", "iiii") {} virtual void nextloopinner(int x, int y) { cutbuf.push_back(make_pair(x-iargs[0], y-iargs[1])) ; imp->setcell(x, y, 0) ; } virtual void doit() { cutbuf.clear() ; runnextloop() ; cout << cutbuf.size() << " pixels cut." << endl ; } } cut_inst ; // this paste only sets cells, never clears cells struct pastecmd : public cmdbase { pastecmd() : cmdbase("paste", "ii") {} virtual void doit() { for (unsigned int i=0; isetcell(cutbuf[i].first, cutbuf[i].second, 1) ; cout << cutbuf.size() << " pixels pasted." << endl ; } } paste_inst ; struct showcutcmd : public cmdbase { showcutcmd() : cmdbase("showcut", "") {} virtual void doit() { for (unsigned int i=0; icreator)() ; if (imp == 0) lifefatal("Could not create universe") ; imp->setMaxMemory(maxmem) ; return imp ; } struct newcmd : public cmdbase { newcmd() : cmdbase("new", "") {} virtual void doit() { if (imp != 0) delete imp ; imp = createUniverse() ; } } new_inst ; struct sethashingcmd : public cmdbase { sethashingcmd() : cmdbase("sethashing", "i") {} virtual void doit() { hashlife = iargs[0] ; } } sethashing_inst ; struct setmaxmemcmd : public cmdbase { setmaxmemcmd() : cmdbase("setmaxmem", "i") {} virtual void doit() { maxmem = iargs[0] ; } } setmaxmem_inst ; struct setalgocmd : public cmdbase { setalgocmd() : cmdbase("setalgo", "s") {} virtual void doit() { algoName = sarg ; } } setalgocmd_inst ; struct edgescmd : public cmdbase { edgescmd() : cmdbase("edges", "") {} virtual void doit() { bigint t, l, b, r ; imp->findedges(&t, &l, &b, &r) ; cout << "Bounding box " << l.tostring() ; cout << " " << t.tostring() ; cout << " .. " << r.tostring() ; cout << " " << b.tostring() << endl ; } } edges_inst ; bool nullerrors::abortprogress(double, const char *) { imp->draw(viewport, renderer) ; return 0 ; } void runtestscript(const char *testscript) { FILE *cmdfile = 0 ; if (strcmp(testscript, "-") != 0) cmdfile = fopen(testscript, "r") ; else cmdfile = stdin ; char cmdline[MAXCMDLENGTH + 10] ; if (cmdfile == 0) lifefatal("Cannot open testscript") ; for (;;) { cerr << flush ; if (cmdfile == stdin) cout << "bgolly> " << flush ; else cout << flush ; if (fgets(cmdline, MAXCMDLENGTH, cmdfile) == 0) break ; cmdbase::docmd(cmdline) ; } exit(0) ; } int main(int argc, char *argv[]) { cout << "This is bgolly " STRINGIFY(VERSION) " Copyright 2013 The Golly Gang." << endl << flush ; qlifealgo::doInitializeAlgoInfo(staticAlgoInfo::tick()) ; hlifealgo::doInitializeAlgoInfo(staticAlgoInfo::tick()) ; generationsalgo::doInitializeAlgoInfo(staticAlgoInfo::tick()) ; jvnalgo::doInitializeAlgoInfo(staticAlgoInfo::tick()) ; ruleloaderalgo::doInitializeAlgoInfo(staticAlgoInfo::tick()) ; while (argc > 1 && argv[1][0] == '-') { argc-- ; argv++ ; char *opt = argv[0] ; int hit = 0 ; for (int i=0; options[i].shortopt; i++) { if (strcmp(opt, options[i].shortopt) == 0 || strcmp(opt, options[i].longopt) == 0) { switch (options[i].opttype) { case 'i': if (argc < 2) lifefatal("Bad option argument") ; *(int *)options[i].data = atol(argv[1]) ; argc-- ; argv++ ; break ; case 'I': if (argc < 2) lifefatal("Bad option argument") ; *(bigint *)options[i].data = bigint(argv[1]) ; argc-- ; argv++ ; break ; case 'b': (*(int *)options[i].data) += 1 ; break ; case 's': if (argc < 2) lifefatal("Bad option argument") ; *(char **)options[i].data = argv[1] ; argc-- ; argv++ ; break ; } hit++ ; break ; } } if (!hit) usage("Bad option given") ; } if (argc < 2 && !testscript) usage("No pattern argument given") ; if (argc > 2) usage("Extra stuff after pattern argument") ; if (outfilename) { if (endswith(outfilename, ".rle")) { } else if (endswith(outfilename, ".mc")) { outputismc = 1 ; #ifdef ZLIB } else if (endswith(outfilename, ".rle.gz")) { outputgzip = 1 ; } else if (endswith(outfilename, ".mc.gz")) { outputismc = 1 ; outputgzip = 1 ; #endif } else { lifefatal("Output filename must end with .rle or .mc.") ; } if (strlen(outfilename) > 200) lifefatal("Output filename too long") ; } if (timeline && hyper) lifefatal("Cannot use both timeline and hyperthreading") ; imp = createUniverse() ; if (progress) lifeerrors::seterrorhandler(&nullerror) ; else if (verbose) { lifeerrors::seterrorhandler(&verbosestatus_instance) ; hlifealgo::setVerbose(1) ; } imp->setMaxMemory(maxmem) ; #ifdef TIMING timestamp() ; #endif if (testscript) { if (argc > 1) { filename = argv[1] ; const char *err = readpattern(argv[1], *imp) ; if (err) lifefatal(err) ; } runtestscript(testscript) ; } filename = argv[1] ; const char *err = readpattern(argv[1], *imp) ; if (err) lifefatal(err) ; if (liferule) imp->setrule(liferule) ; if (inc != 0) imp->setIncrement(inc) ; if (timeline) { int lowbit = inc.lowbitset() ; bigint t = 1 ; for (int i=0; istartrecording(2, lowbit) ; } int fc = 0 ; for (;;) { if (quiet < 2) { cout << imp->getGeneration().tostring() ; if (!quiet) cout << ": " << imp->getPopulation().tostring() << endl ; else cout << endl ; } if (popcount) imp->getPopulation() ; if (autofit) imp->fit(viewport, 1) ; if (render) imp->draw(viewport, renderer) ; if (maxgen >= 0 && imp->getGeneration() >= maxgen) break ; if (!hyper && maxgen > 0 && inc == 0) { bigint diff = maxgen ; diff -= imp->getGeneration() ; int bs = diff.lowbitset() ; diff = 1 ; diff <<= bs ; imp->setIncrement(diff) ; } imp->step() ; if (maxgen < 0 && outfilename != 0) writepat(fc++) ; if (timeline && imp->getframecount() + 2 > MAX_FRAME_COUNT) imp->pruneframes() ; if (hyper) imp->setIncrement(imp->getGeneration()) ; } if (maxgen >= 0 && outfilename != 0) writepat(-1) ; exit(0) ; } golly-2.7-src/cmdline/RuleTableToTree.cpp0000644000175000017500000001347012536111364015346 00000000000000#ifdef _MSC_VER #pragma warning(disable:4702) // disable "unreachable code" warnings from MSVC #endif #include #ifdef _MSC_VER #pragma warning(default:4702) // enable "unreachable code" warnings #endif #include #include #include #include #include #include "util.h" #include "ruletable_algo.h" using namespace std ; const int MAXPARAMS = 9 ; const int MAXSTATES = 256 ; struct ndd { int level, index ; vector vals ; bool operator<(const ndd &n) const { if (level != n.level) return level < n.level ; return vals < n.vals ; } bool operator==(const ndd &n) const { return level == n.level && vals == n.vals ; } } ; set world ; int nodeseq ; int shrinksize = 100 ; vector seq ; int n_states, neighborhood_size ; int curndd = 0 ; typedef unsigned char state ; static int getnode(ndd &n) { n.index = nodeseq ; set::iterator it = world.find(n) ; if (it != world.end()) return it->index ; seq.push_back(n) ; world.insert(n) ; return nodeseq++ ; } void initndd() { curndd = -1 ; for (int i=0; i cache ; int remap5[5] = {0, 3, 2, 4, 1} ; int remap9[9] = {0, 5, 3, 7, 1, 4, 6, 2, 8} ; int *remap ; int addndd(const vector > &inputs, const state output, int nddr, int at) { if (at == 0) return nddr < 0 ? output : nddr ; map::iterator it = cache.find(nddr) ; if (it != cache.end()) return it->second ; ndd n = seq[nddr] ; const vector &inset = inputs[remap[at-1]] ; for (unsigned int i=0; i > &inputs, const state output) { if (neighborhood_size == 5) remap = remap5 ; else remap = remap9 ; cache.clear() ; curndd = addndd(inputs, output, curndd, neighborhood_size) ; if (nodeseq > shrinksize) shrink() ; } int setdefaults(int nddr, int off, int at) { if (at == 0) return nddr < 0 ? off : nddr ; map::iterator it = cache.find(nddr) ; if (it != cache.end()) return it->second ; ndd n = seq[nddr] ; for (int i=0; i &oseq, int nddr, int lev) { if (lev == 0) return nddr ; map::iterator it = cache.find(nddr) ; if (it != cache.end()) return it->second ; ndd n = oseq[nddr] ; for (int i=0; i oseq = seq ; seq.clear() ; cache.clear() ; nodeseq = 0 ; curndd = recreate(oseq, curndd, neighborhood_size) ; cerr << "Shrunk from " << oseq.size() << " to " << seq.size() << endl ; shrinksize = (int)(seq.size() * 2) ; } void write_ndd() { shrink() ; printf("num_states=%d\n", n_states) ; printf("num_neighbors=%d\n", neighborhood_size-1) ; printf("num_nodes=%d\n", (int)seq.size()) ; for (unsigned int i=0; in_compressed_rules;iRule++) { for (unsigned int bitno=0; bitno > in ; int ok = 1 ; for (int i=0; i nv ; for (unsigned int j=0; jRules/rule.tree" << endl ; exit(0) ; } lifeerrors::seterrorhandler(&mylifeerrors) ; my_ruletable_algo *rta = new my_ruletable_algo() ; string err = rta->loadrule(argv[1]) ; if (err.size() > 0) { cerr << "Error: " << err << endl ; exit(0) ; } rta->buildndd() ; write_ndd() ; delete rta ; } golly-2.7-src/gui-web/0000755000175000017500000000000012536111546011641 500000000000000golly-2.7-src/gui-web/shell.html0000644000175000017500000021030712536111364013557 00000000000000 Golly
Abort Paste Paste Here Paste to Selection Flip Top-Bottom Flip Left-Right Rotate Clockwise Rotate Anticlockwise
Remove Selection Cut Copy Clear Clear Outside Shrink Fit Random Fill Flip Top-Bottom Flip Left-Right Rotate Clockwise Rotate Anticlockwise Advance Advance Outside
Open a file on your computer
Save current pattern
File name:   
list of valid extensions
Random fill percentage:
Maximum hash memory: MB
Ask to save changes:
Play beep sound:
contents
contents
title
percent
Clipboard data used by
Patterns
           
        
{{{ SCRIPT }}} golly-2.7-src/gui-web/patterns.py0000644000175000017500000000110612536111364013767 00000000000000# Enumerate the Patterns folder in a format suitable to paste into shell.html. import os from os.path import join, isfile def walkdir(dir): for item in os.listdir(dir): fullpath = join(dir, item) if isfile(fullpath): if item.startswith("."): # ignore hidden files (like .DS_Store on Mac) pass else: print "addfile(\"" + fullpath[2:] + "\");" else: print "dirStart(\"" + item + "\");" walkdir(fullpath) print "dirEnd();" walkdir("../Patterns") golly-2.7-src/gui-web/webcalls.cpp0000644000175000017500000005700612536111364014067 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include // for std::vector #include // for std::string #include // for std::list #include // for std::set #include // for std::count #include "util.h" // for linereader #include "utils.h" // for Warning, etc #include "algos.h" // for InitAlgorithms #include "prefs.h" // for GetPrefs, SavePrefs, userdir, etc #include "layer.h" // for AddLayer, ResizeLayers, currlayer #include "control.h" // for SetMinimumStepExponent, etc #include "file.h" // for NewPattern, OpenFile, LoadRule, etc #include "view.h" // for widescreen, fullscreen, TouchBegan, etc #include "status.h" // for UpdateStatusLines, ClearMessage, etc #include "undo.h" // for ClearUndoRedo #include "webcalls.h" #include // for EM_ASM // ----------------------------------------------------------------------------- // the following JavaScript functions are implemented in jslib.js: extern "C" { extern void jsAlert(const char* msg); extern bool jsConfirm(const char* query); extern void jsSetBackgroundColor(const char* id, const char* color); extern void jsSetMode(int index); extern void jsSetState(int state, int numstates); extern void jsSetClipboard(const char* text); extern const char* jsGetClipboard(); extern void jsEnableButton(const char* id, bool enable); extern void jsEnableImgButton(const char* id, bool enable); extern void jsSetInnerHTML(const char* id, const char* text); extern void jsSetCheckBox(const char* id, bool flag); extern void jsMoveToAnchor(const char* anchor); extern void jsSetScrollTop(const char* id, int pos); extern int jsGetScrollTop(const char* id); extern bool jsElementIsVisible(const char* id); extern void jsDownloadFile(const char* url, const char* filepath); extern void jsBeep(); extern void jsDeleteFile(const char* filepath); extern bool jsMoveFile(const char* inpath, const char* outpath); extern void jsBeginProgress(const char* title); extern bool jsAbortProgress(int percentage); extern void jsEndProgress(); extern void jsCancelProgress(); extern void jsStoreRule(const char* rulepath); extern const char* jsGetSaveName(const char* currname); extern void jsSaveFile(const char* filename); } // ----------------------------------------------------------------------------- bool refresh_pattern = false; void UpdatePattern() { refresh_pattern = true; // DoFrame in main.cpp will call DrawPattern and reset refresh_pattern to false } // ----------------------------------------------------------------------------- static int curralgo = -1; void UpdateStatus() { if (fullscreen) return; UpdateStatusLines(); // sets status1, status2, status3 // clear text area first EM_ASM( document.getElementById('statusbar').value = '\0'; ); if (curralgo != currlayer->algtype) { // algo has changed so change background color of status bar curralgo = currlayer->algtype; int r = algoinfo[curralgo]->statusrgb.r; int g = algoinfo[curralgo]->statusrgb.g; int b = algoinfo[curralgo]->statusrgb.b; char rgb[32]; sprintf(rgb, "rgb(%d,%d,%d)", r, g, b); jsSetBackgroundColor("statusbar", rgb); } printf("%s\n", status1.c_str()); printf("%s\n", status2.c_str()); printf("%s\n", status3.c_str()); } // ----------------------------------------------------------------------------- static bool paused = false; // generating has been temporarily stopped? void PauseGenerating() { if (generating) { StopGenerating(); // generating is now false paused = true; } } // ----------------------------------------------------------------------------- void ResumeGenerating() { if (paused) { StartGenerating(); // generating is probably true (false if pattern is empty) paused = false; } } // ----------------------------------------------------------------------------- std::string GetRuleName(const std::string& rule) { std::string result = ""; // not yet implemented!!! // (Set Rule dialog would need to let users create/delete named rules // and save them in GollyPrefs) return result; } // ----------------------------------------------------------------------------- void UpdateButtons() { if (fullscreen) return; jsEnableImgButton("reset", currlayer->algo->getGeneration() > currlayer->startgen); jsEnableImgButton("undo", currlayer->undoredo->CanUndo()); jsEnableImgButton("redo", currlayer->undoredo->CanRedo()); jsEnableImgButton("info", currlayer->currname != "untitled"); } // ----------------------------------------------------------------------------- void UpdateEditBar() { if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) { // this can happen after an algo/rule change currlayer->drawingstate = 1; } if (fullscreen) return; UpdateButtons(); // show current cursor mode jsSetMode(currlayer->touchmode); // show current drawing state and update number of options if necessary jsSetState(currlayer->drawingstate, currlayer->algo->NumCellStates()); // update check boxes jsSetCheckBox("toggle_icons", showicons); jsSetCheckBox("toggle_autofit", currlayer->autofit); } // ----------------------------------------------------------------------------- static int progresscount = 0; // if > 0 then BeginProgress has been called void BeginProgress(const char* title) { if (progresscount == 0) { jsBeginProgress(title); } progresscount++; // handles nested calls } // ----------------------------------------------------------------------------- bool AbortProgress(double fraction_done, const char* message) { if (progresscount <= 0) Fatal("Bug detected in AbortProgress!"); // don't use message (empty string) return jsAbortProgress(int(fraction_done*100)); } // ----------------------------------------------------------------------------- void EndProgress() { if (progresscount <= 0) Fatal("Bug detected in EndProgress!"); progresscount--; if (progresscount == 0) { jsEndProgress(); } } // ----------------------------------------------------------------------------- extern "C" { void CancelProgress() { // called if user hits Cancel button in progress dialog jsCancelProgress(); } } // extern "C" // ----------------------------------------------------------------------------- void ShowTextFile(const char* filepath) { // check if path ends with .gz or .zip if (EndsWith(filepath,".gz") || EndsWith(filepath,".zip")) { Warning("Compressed file cannot be displayed."); return; } // get contents of given text file and wrap in
...
std::string contents = "
";
    FILE* textfile = fopen(filepath, "r");
    if (textfile) {
        // read entire file into contents
        const int MAXLINELEN = 4095;
        char linebuf[MAXLINELEN + 1];
        linereader reader(textfile);
        while (true) {
            if (reader.fgets(linebuf, MAXLINELEN) == 0) break;
            contents += linebuf;
            contents += "\n";
        }
        reader.close();
        // fclose(textfile) has been called
    } else {
        contents += "Failed to open text file!\n";
        contents += filepath;
    }
    
    // update the contents of the info dialog
    contents += "
"; jsSetInnerHTML("info_text", contents.c_str()); // display the info dialog EM_ASM( document.getElementById('info_overlay').style.visibility = 'visible'; ); } // ----------------------------------------------------------------------------- extern "C" { void CloseInfo() { // close the info dialog EM_ASM( document.getElementById('info_overlay').style.visibility = 'hidden'; ); } } // extern "C" // ----------------------------------------------------------------------------- static const char* contents_page = "/Help/index.html"; static std::string currpage = contents_page; static std::vector page_history; static std::vector page_scroll; static unsigned int page_index = 0; static bool shifting_history = false; // in HelpBack or HelpNext? // ----------------------------------------------------------------------------- static bool CanGoBack() { return page_index > 0; } // ----------------------------------------------------------------------------- static bool CanGoNext() { return page_history.size() > 1 && page_index < (page_history.size() - 1); } // ----------------------------------------------------------------------------- static void UpdateHelpButtons() { jsEnableButton("help_back", CanGoBack()); jsEnableButton("help_next", CanGoNext()); jsEnableButton("help_contents", currpage != contents_page); } // ----------------------------------------------------------------------------- static void DisplayHelpDialog() { // display the help dialog and start listening for clicks on links EM_ASM( var helpdlg = document.getElementById('help_overlay'); if (helpdlg.style.visibility != 'visible') { helpdlg.style.visibility = 'visible'; // note that on_help_click is implemented in shell.html so CloseHelp can remove it window.addEventListener('click', on_help_click, false); } ); } // ----------------------------------------------------------------------------- void ShowHelp(const char* filepath) { if (filepath[0] == 0) { // this only happens if user hits 'h' key or clicks '?' button if (page_history.size() > 0) { // just need to show the help dialog DisplayHelpDialog(); return; } // else this is very 1st call and currpage = contents_page } else { currpage = filepath; } // if anchor present then strip it off (and call jsMoveToAnchor below) std::string anchor = ""; size_t hashpos = currpage.rfind('#'); if (hashpos != std::string::npos) { anchor = currpage.substr(hashpos+1); currpage = currpage.substr(0, hashpos); } if (!shifting_history) { // user didn't hit back/next button bool help_visible = jsElementIsVisible("help_overlay"); if (!help_visible && page_history.size() > 0 && currpage == page_history[page_index]) { // same page requested so just need to show the help dialog DisplayHelpDialog(); return; } if (help_visible) { // remember scroll position of current page page_scroll[page_index] = jsGetScrollTop("help_text"); // remove any following pages while (CanGoNext()) { page_history.pop_back(); page_scroll.pop_back(); } } page_history.push_back(currpage); page_scroll.push_back(0); page_index = page_history.size() - 1; } // get contents of currpage std::string contents; FILE* helpfile = fopen(currpage.c_str(), "r"); if (helpfile) { // read entire file into contents const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; linereader reader(helpfile); while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; contents += linebuf; contents += "\n"; } reader.close(); // fclose(helpfile) has been called } else { contents += "

Failed to open help file!
"; contents += currpage; } // update the contents of the help dialog jsSetInnerHTML("help_text", contents.c_str()); // if contents has 'body bgcolor="..."' then use that color, otherwise use white std::string bgcolor = "#FFF"; size_t startpos = contents.find("body bgcolor=\""); if (startpos != std::string::npos) { startpos += 14; size_t len = 0; while (contents[startpos+len] != '"' && len < 16) len++; // allow for "rgb(255,255,255)" bgcolor = contents.substr(startpos, len); } jsSetBackgroundColor("help_text", bgcolor.c_str()); UpdateHelpButtons(); DisplayHelpDialog(); if (anchor.length() > 0) { jsMoveToAnchor(anchor.c_str()); } else { jsSetScrollTop("help_text", page_scroll[page_index]); } } // ----------------------------------------------------------------------------- extern "C" { void HelpBack() { if (CanGoBack()) { // remember scroll position of current page and go to previous page page_scroll[page_index] = jsGetScrollTop("help_text"); page_index--; shifting_history = true; ShowHelp(page_history[page_index].c_str()); shifting_history = false; } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void HelpNext() { if (CanGoNext()) { // remember scroll position of current page and go to next page page_scroll[page_index] = jsGetScrollTop("help_text"); page_index++; shifting_history = true; ShowHelp(page_history[page_index].c_str()); shifting_history = false; } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void HelpContents() { // probably best to clear history page_history.clear(); page_scroll.clear(); page_index = 0; ShowHelp(contents_page); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void CloseHelp() { if (jsElementIsVisible("help_overlay")) { // remember scroll position of current page for later use page_scroll[page_index] = jsGetScrollTop("help_text"); // close the help dialog and remove the click event handler EM_ASM( document.getElementById('help_overlay').style.visibility = 'hidden'; window.removeEventListener('click', on_help_click, false); ); } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { int DoHelpClick(const char* href) { // look for special prefixes used by Golly and return 1 to prevent browser handling link std::string link = href; if (link.find("open:") == 0) { // open specified file std::string path = link.substr(5); FixURLPath(path); OpenFile(path.c_str()); // OpenFile will close help dialog if necessary (might not if .zip file) return 1; } if (link.find("rule:") == 0) { // switch to specified rule std::string newrule = link.substr(5); SwitchToPatternTab(); // calls CloseHelp ChangeRule(newrule); return 1; } if (link.find("lexpatt:") == 0) { // user clicked on pattern in Life Lexicon std::string pattern = link.substr(8); std::replace(pattern.begin(), pattern.end(), '$', '\n'); LoadLexiconPattern(pattern); // SwitchToPatternTab will call CloseHelp return 1; } if (link.find("edit:") == 0) { std::string path = link.substr(5); // convert path to a full path if necessary std::string fullpath = path; if (path[0] != '/') { fullpath = userdir + fullpath; } ShowTextFile(fullpath.c_str()); return 1; } if (link.find("get:") == 0) { std::string geturl = link.substr(4); // download file specifed in link (possibly relative to a previous full url) GetURL(geturl, currpage); return 1; } if (link.find("unzip:") == 0) { std::string zippath = link.substr(6); FixURLPath(zippath); std::string entry = zippath.substr(zippath.rfind(':') + 1); zippath = zippath.substr(0, zippath.rfind(':')); UnzipFile(zippath, entry); return 1; } // if link doesn't contain ':' then assume it's relative to currpage if (link.find(':') == std::string::npos) { // if link starts with '#' then move to that anchor on current page if (link[0] == '#') { std::string newpage = currpage + link; ShowHelp(newpage.c_str()); return 1; } std::string newpage = currpage.substr(0, currpage.rfind('/')+1) + link; ShowHelp(newpage.c_str()); return 1; } // let browser handle this link return 0; } } // extern "C" // ----------------------------------------------------------------------------- void SwitchToPatternTab() { CloseHelp(); } // ----------------------------------------------------------------------------- void WebWarning(const char* msg) { jsAlert(msg); } // ----------------------------------------------------------------------------- void WebFatal(const char* msg) { jsAlert(msg); exit(1); // no need to do anything else??? } // ----------------------------------------------------------------------------- bool WebYesNo(const char* query) { return jsConfirm(query); } // ----------------------------------------------------------------------------- void WebBeep() { jsBeep(); } // ----------------------------------------------------------------------------- void WebRemoveFile(const std::string& filepath) { jsDeleteFile(filepath.c_str()); } // ----------------------------------------------------------------------------- bool WebMoveFile(const std::string& inpath, const std::string& outpath) { return jsMoveFile(inpath.c_str(), outpath.c_str()); } // ----------------------------------------------------------------------------- void WebFixURLPath(std::string& path) { // no need to do anything } // ----------------------------------------------------------------------------- bool WebCopyTextToClipboard(const char* text) { jsSetClipboard(text); return true; } // ----------------------------------------------------------------------------- bool WebGetTextFromClipboard(std::string& text) { text = jsGetClipboard(); if (text.length() == 0) { ErrorMessage("There is no text in the clipboard."); return false; } else { return true; } } // ----------------------------------------------------------------------------- bool PatternSaved(std::string& filename) { // append default extension if not supplied size_t dotpos = filename.find('.'); if (dotpos == std::string::npos) { if (currlayer->algo->hyperCapable()) { // macrocell format is best for hash-based algos filename += ".mc"; } else { filename += ".rle"; } } else { // check that the supplied extension is valid if (currlayer->algo->hyperCapable()) { if (!EndsWith(filename,".mc") && !EndsWith(filename,".mc.gz") && !EndsWith(filename,".rle") && !EndsWith(filename,".rle.gz")) { Warning("File extension must be .mc or .mc.gz or .rle or .rle.gz."); return false; } } else { if (!EndsWith(filename,".rle") && !EndsWith(filename,".rle.gz")) { Warning("File extension must be .rle or .rle.gz."); return false; } } } pattern_format format = XRLE_format; if (EndsWith(filename,".mc") || EndsWith(filename,".mc.gz")) format = MC_format; output_compression compression = no_compression; if (EndsWith(filename,".gz")) compression = gzip_compression; return SavePattern(filename, format, compression); } // ----------------------------------------------------------------------------- bool WebSaveChanges() { std::string query = "Save your changes?"; if (numlayers > 1) { // make it clear which layer we're asking about query = "Save your changes to this layer: \"", query += currlayer->currname; query += "\"?"; } if (jsConfirm(query.c_str())) { // prompt user for name of file in which to save pattern // (must be a blocking dialog so we can't use our custom save dialog) std::string filename = jsGetSaveName(currlayer->currname.c_str()); // filename is empty if user hit Cancel, so don't continue if (filename.length() == 0) return false; if (PatternSaved(filename)) { ClearMessage(); // filename successfully created (in virtual file system), // so download it to user's computer and continue jsSaveFile(filename.c_str()); return true; } else { return false; // don't continue } } else { // user hit Cancel so don't save changes (but continue) return true; } } // ----------------------------------------------------------------------------- bool WebDownloadFile(const std::string& url, const std::string& filepath) { // jsDownloadFile does an asynchronous file transfer and will call FileCreated() // only if filepath is successfully created jsDownloadFile(url.c_str(), filepath.c_str()); // we must return false so GetURL won't proceed beyond the DownloadFile call return false; } // ----------------------------------------------------------------------------- extern "C" { void FileCreated(const char* filepath) { // following code matches that in gui-common/file.cpp after DownloadFile // returns false in GetURL std::string filename = GetBaseName(filepath); if (IsHTMLFile(filename)) { ShowHelp(filepath); } else if (IsRuleFile(filename)) { // load corresponding rule SwitchToPatternTab(); LoadRule(filename.substr(0, filename.rfind('.'))); // ensure the .rule file persists beyond the current session CopyRuleToLocalStorage(filepath); } else if (IsTextFile(filename)) { ShowTextFile(filepath); } else if (IsScriptFile(filename)) { Warning("This version of Golly cannot run scripts."); } else { // assume it's a pattern/zip file, so open it OpenFile(filepath); } } } // extern "C" // ----------------------------------------------------------------------------- void CopyRuleToLocalStorage(const char* rulepath) { jsStoreRule(rulepath); } // ----------------------------------------------------------------------------- void WebCheckEvents() { // event_checker is > 0 in here (see gui-common/utils.cpp) // it looks like JavaScript doesn't have any access to the browser's event queue // so we can't do anything here???!!! we'll need to use a Web Worker???!!! // note that glfwPollEvents() does nothing (see emscripten/src/library_glfw.js) // glfwPollEvents(); } golly-2.7-src/gui-web/zlib/0000755000175000017500000000000012536111546012601 500000000000000golly-2.7-src/gui-web/zlib/crc32.c0000644000175000017500000003156612536111364013612 00000000000000/* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results in about a * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for STDC and FAR definitions */ #define local static /* Definitions for doing the crc four data bytes at a time. */ #if !defined(NOBYFOUR) && defined(Z_U4) # define BYFOUR #endif #ifdef BYFOUR local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, unsigned)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, unsigned)); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ /* Local functions for crc concatenation */ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; local z_crc_t FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const z_crc_t FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ local void make_crc_table() { z_crc_t c; int n, k; z_crc_t poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* See if another task is already doing this (not thread-safe, but better than nothing -- significantly reduces duration of vulnerability in case the advice about DYNAMIC_CRC_TABLE is ignored) */ if (first) { first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0; for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) poly |= (z_crc_t)1 << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (z_crc_t)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = ZSWAP32(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = ZSWAP32(c); } } #endif /* BYFOUR */ crc_table_empty = 0; } else { /* not first */ /* wait for the other guy to finish (not efficient, but rare) */ while (crc_table_empty) ; } #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "local const z_crc_t FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH local void write_table(out, table) FILE *out; const z_crc_t FAR *table; { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", (unsigned long)(table[n]), n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ const z_crc_t FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t FAR *)crc_table; } /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long ZEXPORT crc32(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; uInt len; { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { z_crc_t endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } #ifdef BYFOUR /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = (z_crc_t)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *++buf4; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; unsigned len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = ZSWAP32((z_crc_t)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; buf4--; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf4++; buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(ZSWAP32(c)); } #endif /* BYFOUR */ #define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ /* ========================================================================= */ local unsigned long gf2_matrix_times(mat, vec) unsigned long *mat; unsigned long vec; { unsigned long sum; sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } /* ========================================================================= */ local void gf2_matrix_square(square, mat) unsigned long *square; unsigned long *mat; { int n; for (n = 0; n < GF2_DIM; n++) square[n] = gf2_matrix_times(mat, mat[n]); } /* ========================================================================= */ local uLong crc32_combine_(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { int n; unsigned long row; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ /* degenerate case (also disallow negative lengths) */ if (len2 <= 0) return crc1; /* put operator for one zero bit in odd */ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ row = 1; for (n = 1; n < GF2_DIM; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even) */ do { /* apply zeros operator for this bit of len2 */ gf2_matrix_square(even, odd); if (len2 & 1) crc1 = gf2_matrix_times(even, crc1); len2 >>= 1; /* if no more bits set, then done */ if (len2 == 0) break; /* another iteration of the loop with odd and even swapped */ gf2_matrix_square(odd, even); if (len2 & 1) crc1 = gf2_matrix_times(odd, crc1); len2 >>= 1; /* if no more bits set, then done */ } while (len2 != 0); /* return combined crc */ crc1 ^= crc2; return crc1; } /* ========================================================================= */ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc1; uLong crc2; z_off_t len2; { return crc32_combine_(crc1, crc2, len2); } uLong ZEXPORT crc32_combine64(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { return crc32_combine_(crc1, crc2, len2); } golly-2.7-src/gui-web/zlib/gzguts.h0000644000175000017500000001463012536111364014217 00000000000000/* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #ifdef _LARGEFILE64_SOURCE # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif # ifdef _FILE_OFFSET_BITS # undef _FILE_OFFSET_BITS # endif #endif #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include #include "zlib.h" #ifdef STDC # include # include # include #endif #include #ifdef _WIN32 # include #endif #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include #endif #ifdef WINAPI_FAMILY # define open _open # define read _read # define write _write # define close _close #endif #ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif #if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(__CYGWIN__) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #ifndef HAVE_VSNPRINTF # ifdef MSDOS /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), but for now we just assume it doesn't. */ # define NO_vsnprintf # endif # ifdef __TURBOC__ # define NO_vsnprintf # endif # ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ # if !defined(vsnprintf) && !defined(NO_vsnprintf) # if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) # define vsnprintf _vsnprintf # endif # endif # endif # ifdef __SASC # define NO_vsnprintf # endif # ifdef VMS # define NO_vsnprintf # endif # ifdef __OS400__ # define NO_vsnprintf # endif # ifdef __MVS__ # define NO_vsnprintf # endif #endif /* unlike snprintf (which is required in C99, yet still not supported by Microsoft more than a decade later!), _snprintf does not guarantee null termination of the result -- however this is only used in gzlib.c where the result is assured to fit in the space provided */ #ifdef _MSC_VER # define snprintf _snprintf #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ /* gz* functions always use library allocation functions */ #ifndef STDC extern voidp malloc OF((uInt size)); extern void free OF((voidpf ptr)); #endif /* get errno and strerror definition */ #if defined UNDER_CE # include # define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else # ifndef NO_STRERROR # include # define zstrerror() strerror(errno) # else # define zstrerror() "stdio error (consult errno)" # endif #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); #endif /* default memLevel */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default i/o buffer size -- double this for output when reading (this and twice this must be able to fit in an unsigned type) */ #define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 #define GZ_READ 7247 #define GZ_WRITE 31153 #define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ /* values for gz_state how */ #define LOOK 0 /* look for a gzip header */ #define COPY 1 /* copy input directly */ #define GZIP 2 /* decompress a gzip stream */ /* internal gzip file state data structure */ typedef struct { /* exposed contents for gzgetc() macro */ struct gzFile_s x; /* "x" for exposed */ /* x.have: number of bytes available at x.next */ /* x.next: next output data to deliver or write */ /* x.pos: current position in uncompressed data */ /* used for both reading and writing */ int mode; /* see gzip modes above */ int fd; /* file descriptor */ char *path; /* path or fd for error messages */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer */ unsigned char *out; /* output buffer (double-sized when reading) */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ int how; /* 0: get header, 1: copy, 2: decompress */ z_off64_t start; /* where the gzip data started, for rewinding */ int eof; /* true if end of input file reached */ int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ /* error information */ int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; typedef gz_state FAR *gz_statep; /* shared functions */ void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); #if defined UNDER_CE char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else unsigned ZLIB_INTERNAL gz_intmax OF((void)); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif golly-2.7-src/gui-web/zlib/zlib.h0000644000175000017500000025351312536111364013641 00000000000000/* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.8, April 28th, 2013 Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.2.8" #define ZLIB_VERNUM 0x1280 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 8 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header FAR *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field (though see inflate()) */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary (in interactive applications). Some output may be provided even if flush is not set. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed code block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space; if deflate returns with Z_OK, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least the value returned by deflateBound (see below). Then deflate is guaranteed to return Z_STREAM_END. If not enough output space is provided, deflate will not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. If next_in is not Z_NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. Also to assist in this, on return inflate() will set strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the stream completes, which reduces inflate's memory footprint. If the stream does not complete, either because not all of the stream is provided or not enough output space is provided, then a sliding window will be allocated and inflate() can be called again to continue the operation as if Z_NO_FLUSH had been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the effects of the flush parameter in this implementation are on the return value of inflate() as noted below, when inflate() returns early when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and perform their own processing of the gzip header and trailer. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output producted so far. The CRC-32 is checked against the gzip trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is desired. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute an adler32 check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to 255 (unknown). If a gzip stream is being written, strm->adler is a crc32 instead of an adler32. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been consumed and all output has been delivered when using any of the flush options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The adler32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the adler32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). If that first deflate() call is provided the sourceLen input bytes, an output buffer allocated to the size returned by deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed to return Z_STREAM_END. Note that it is possible for the compressed size to be larger than the value returned by deflateBound() if flush options other than Z_FINISH or Z_NO_FLUSH are used. */ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, unsigned *pending, int *bits)); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not provided would be due to the available output space having being consumed. The number of bits of output not provided are between 0 and 7, where they await more bits to join them in order to fill out a full byte. If pending or bits are Z_NULL, then those values are not set. deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head)); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an adler32 or a crc32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a crc32 instead of an adler32. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similary, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync searches for a 00 00 FF FF pattern in the compressed data. All full flush points have this pattern, but not all occurrences of this pattern are full flush points. inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, int windowBits)); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, int bits, int value)); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above or -1 << 16 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, gz_headerp head)); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func) OF((void FAR *, z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than inflate() for file i/o applications, in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. inflate() can be faster on modern CPUs when used with large buffers. inflateBack() trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the normal behavior of inflate(), which expects either a zlib or gzip header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero--buf is ignored in that case--and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ #ifndef Z_SOLO /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) 'T' will request transparent writing or appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. The addition of "x" when writing will create the file exclusively, which fails if the file already exists. On systems that support it, the addition of "e" when reading or writing will set the flag to close the file on an execve() call. These functions, as well as gzip, will read and decode a sequence of gzip streams in a file. The append function of gzopen() can be used to create such a file. (Also see gzflush() for another way to do this.) When appending, gzopen does not test whether the file begins with a gzip stream, nor does it look for the end of the gzip streams to begin appending. gzopen will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. When reading, this will be detected automatically by looking for the magic two- byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* gzdopen associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. If you are using fileno() to get the file descriptor from a FILE *, then you will have to use dup() to avoid double-close()ing the file descriptor. Both gzclose() and fclose() will close the associated file descriptor, so they need to have different file descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); /* Set the internal buffer size used by this library's functions. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Two buffers are allocated, either both of the specified size when writing, or one of the specified size and the other twice that size when reading. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not opened for writing. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream. Any number of gzip streams may be concatenated in the input file, and will all be decompressed by gzread(). If something other than a gzip stream is encountered after a gzip stream, that remaining trailing garbage is ignored (and no error is returned). gzread can be used to read a gzip file that is being concurrently written. Upon reaching the end of the input, gzread will return with the available data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then gzclearerr can be used to clear the end of file indicator in order to permit gzread to be tried again. Z_OK indicates that a gzip stream was completed on the last gzread. Z_BUF_ERROR indicates that the input file ended in the middle of a gzip stream. Note that gzread does not return -1 in the event of an incomplete gzip stream. This error is deferred until gzclose(), which will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip stream. Alternatively, gzerror can be used before gzclose to detect this case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or 0 in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len == 1, the string is terminated with a null character. If no characters are read due to an end-of-file or len < 1, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); /* Push one character back onto the stream to be read as the first character on the next read. At least one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatented gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ /* ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); Returns the current offset in the file being read or written. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Returns true (1) if the end-of-file indicator has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). When writing, gzdirect() returns true (1) if transparent writing was requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: gzdirect() is not needed when writing. Transparent writing must be explicitly requested, so the application already knows the answer. When linking statically, using gzdirect() will include all of the zlib code for gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file and deallocates the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ #endif /* !Z_SOLO */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note that the z_off_t type (like off_t) is a signed integer. If len2 is negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); #define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #ifndef Z_SOLO /* gzgetc() macro and its supporting function and exposed data structure. Note * that the real internal state is much larger than the exposed structure. * This abbreviated structure exposes just enough for the gzgetc() macro. The * user should not mess with these exposed elements, since their names or * behavior could change in the future, perhaps even capriciously. They can * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) #else # define gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) # ifdef Z_PREFIX_SET # define z_gzopen z_gzopen64 # define z_gzseek z_gzseek64 # define z_gztell z_gztell64 # define z_gzoffset z_gzoffset64 # define z_adler32_combine z_adler32_combine64 # define z_crc32_combine z_crc32_combine64 # else # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # endif # ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif #else /* Z_SOLO */ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif /* !Z_SOLO */ /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;}; #endif /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !defined(Z_SOLO) ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, const char *mode)); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, const char *format, va_list va)); # endif #endif #ifdef __cplusplus } #endif #endif /* ZLIB_H */ golly-2.7-src/gui-web/zlib/uncompr.c0000644000175000017500000000372312536111364014353 00000000000000/* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the compressed buffer. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted. */ int ZEXPORT uncompress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { z_stream stream; int err; stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; err = inflateInit(&stream); if (err != Z_OK) return err; err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) return Z_DATA_ERROR; return err; } *destLen = stream.total_out; err = inflateEnd(&stream); return err; } golly-2.7-src/gui-web/zlib/README0000644000175000017500000001210112536111364013372 00000000000000ZLIB DATA COMPRESSION LIBRARY zlib 1.2.8 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). All functions of the compression library are documented in the file zlib.h (volunteer to write man pages welcome, contact zlib@gzip.org). A usage example of the library is given in the file test/example.c which also tests that the library is working correctly. Another example is given in the file test/minigzip.c. The compression library itself is composed of all source files in the root directory. To compile all files and run the test program, follow the instructions given at the top of Makefile.in. In short "./configure; make test", and if that goes well, "make install" should work for most flavors of Unix. For Windows, use one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use make_vms.com. Questions about zlib should be sent to , or to Gilles Vollant for the Windows DLL version. The zlib home page is http://zlib.net/ . Before reporting a problem, please check this site to verify that you have the latest version of zlib; otherwise get the latest version and check whether the problem still exists or not. PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Mark Nelson wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at http://marknelson.us/1997/01/01/zlib-engine/ . The changes made in version 1.2.8 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . zlib is available in Java using the java.util.zip package, documented at http://java.sun.com/developer/technicalArticles/Programming/compression/ . A Perl interface to zlib written by Paul Marquess is available at CPAN (Comprehensive Perl Archive Network) sites, including http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . A Python interface to zlib written by A.M. Kuchling is available in Python 1.5 and later versions, see http://docs.python.org/library/zlib.html . zlib is built into tcl: http://wiki.tcl.tk/4610 . An experimental package to read and write files in .zip format, written on top of zlib by Gilles Vollant , is available in the contrib/minizip directory of zlib. Notes for some targets: - For Windows DLL versions, please see win32/DLL_FAQ.txt - For 64-bit Irix, deflate.c must be compiled without any optimization. With -O, one libpng test fails. The test works in 32 bit mode (with the -n32 compiler flag). The compiler bug has been reported to SGI. - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works when compiled with cc. - On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is necessary to get gzprintf working correctly. This is done by configure. - zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with other compilers. Use "make test" to check your compiler. - gzdopen is not supported on RISCOS or BEOS. - For PalmOs, see http://palmzlib.sourceforge.net/ Acknowledgments: The deflate format used by zlib was defined by Phil Katz. The deflate and zlib specifications were written by L. Peter Deutsch. Thanks to all the people who reported problems and suggested various improvements in zlib; they are too numerous to cite here. Copyright notice: (C) 1995-2013 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu If you use the zlib library in a product, we would appreciate *not* receiving lengthy legal documents to sign. The sources are provided for free but without warranty of any kind. The library has been entirely written by Jean-loup Gailly and Mark Adler; it does not include third-party code. If you redistribute modified sources, we would appreciate that you include in the file ChangeLog history information documenting your changes. Please read the FAQ for more information on the distribution of modified source versions. golly-2.7-src/gui-web/zlib/gzwrite.c0000644000175000017500000003750712536111364014372 00000000000000/* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); local int gz_zero OF((gz_statep, z_off64_t)); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on failure or 0 on success. */ local int gz_init(state) gz_statep state; { int ret; z_streamp strm = &(state->strm); /* allocate input buffer */ state->in = (unsigned char *)malloc(state->want); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* only need output buffer and deflate state if compressing */ if (!state->direct) { /* allocate output buffer */ state->out = (unsigned char *)malloc(state->want); if (state->out == NULL) { free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* allocate deflate memory, set up for gzip compression */ strm->zalloc = Z_NULL; strm->zfree = Z_NULL; strm->opaque = Z_NULL; ret = deflateInit2(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); if (ret != Z_OK) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* mark state as initialized */ state->size = state->want; /* initialize write buffer if compressing */ if (!state->direct) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = strm->next_out; } return 0; } /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ local int gz_comp(state, flush) gz_statep state; int flush; { int ret, got; unsigned have; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return -1; /* write directly if requested */ if (state->direct) { got = write(state->fd, strm->next_in, strm->avail_in); if (got < 0 || (unsigned)got != strm->avail_in) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } strm->avail_in = 0; return 0; } /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { have = (unsigned)(strm->next_out - state->x.next); if (have && ((got = write(state->fd, state->x.next, have)) < 0 || (unsigned)got != have)) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; } state->x.next = strm->next_out; } /* compress */ have = strm->avail_out; ret = deflate(strm, flush); if (ret == Z_STREAM_ERROR) { gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) deflateReset(strm); /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on error, 0 on success. */ local int gz_zero(state, len) gz_statep state; z_off64_t len; { int first; unsigned n; z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return -1; /* compress len zeros (len guaranteed > 0) */ first = 1; while (len) { n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; if (first) { memset(state->in, 0, n); first = 0; } strm->avail_in = n; strm->next_in = state->in; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return -1; len -= n; } return 0; } /* -- see zlib.h -- */ int ZEXPORT gzwrite(file, buf, len) gzFile file; voidpc buf; unsigned len; { unsigned put = len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* for small len, copy to input buffer, otherwise compress directly */ if (len < state->size) { /* copy to input buffer, compress when full */ do { unsigned have, copy; if (strm->avail_in == 0) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); copy = state->size - have; if (copy > len) copy = len; memcpy(state->in + have, buf, copy); strm->avail_in += copy; state->x.pos += copy; buf = (const char *)buf + copy; len -= copy; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); } else { /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ strm->avail_in = len; strm->next_in = (z_const Bytef *)buf; state->x.pos += len; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; } /* input was all buffered or compressed (put will fit in int) */ return (int)put; } /* -- see zlib.h -- */ int ZEXPORT gzputc(file, c) gzFile file; int c; { unsigned have; unsigned char buf[1]; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* try writing to input buffer for speed (state->size == 0 if buffer not initialized) */ if (state->size) { if (strm->avail_in == 0) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); if (have < state->size) { state->in[have] = c; strm->avail_in++; state->x.pos++; return c & 0xff; } } /* no room in buffer or not initialized, use gz_write() */ buf[0] = c; if (gzwrite(file, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ int ZEXPORT gzputs(file, str) gzFile file; const char *str; { int ret; unsigned len; /* write string */ len = (unsigned)strlen(str); ret = gzwrite(file, str, len); return ret == 0 && len != 0 ? -1 : ret; } #if defined(STDC) || defined(Z_HAVE_STDARG_H) #include /* -- see zlib.h -- */ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { int size, len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void (void)vsprintf((char *)(state->in), format, va); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else len = vsprintf((char *)(state->in), format, va); # endif #else # ifdef HAS_vsnprintf_void (void)vsnprintf((char *)(state->in), size, format, va); len = strlen((char *)(state->in)); # else len = vsnprintf((char *)(state->in), size, format, va); # endif #endif /* check that printf() results fit in buffer */ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->x.pos += len; return len; } int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { va_list va; int ret; va_start(va, format); ret = gzvprintf(file, format, va); va_end(va); return ret; } #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { int size, len; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that can really pass pointer in ints */ if (sizeof(int) != sizeof(void *)) return 0; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* do the printf() into the input buffer, put length in len */ size = (int)(state->size); state->in[size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) if (state->in[len] == 0) break; # else len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen((char *)(state->in)); # else len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif /* check that printf() results fit in buffer */ if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) return 0; /* update buffer and position, defer compression until needed */ strm->avail_in = (unsigned)len; strm->next_in = state->in; state->x.pos += len; return len; } #endif /* -- see zlib.h -- */ int ZEXPORT gzflush(file, flush) gzFile file; int flush; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* check flush parameter */ if (flush < 0 || flush > Z_FINISH) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* compress remaining data with requested flush */ gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ int ZEXPORT gzsetparams(file, level, strategy) gzFile file; int level; int strategy; { gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ if (level == state->level && strategy == state->strategy) return Z_OK; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) return state->err; deflateParams(strm, level, strategy); } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ int ZEXPORT gzclose_w(file) gzFile file; { int ret = Z_OK; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing */ if (state->mode != GZ_WRITE) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) ret = state->err; } /* flush, free memory, and close file */ if (gz_comp(state, Z_FINISH) == -1) ret = state->err; if (state->size) { if (!state->direct) { (void)deflateEnd(&(state->strm)); free(state->out); } free(state->in); } gz_error(state, Z_OK, NULL); free(state->path); if (close(state->fd) == -1) ret = Z_ERRNO; free(state); return ret; } golly-2.7-src/gui-web/zlib/inffixed.h0000644000175000017500000001427412536111364014474 00000000000000 /* inffixed.h -- table for decoding fixed codes * Generated automatically by makefixed(). */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of this library and is subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {0,9,255} }; static const code distfix[32] = { {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {22,5,193},{64,5,0} }; golly-2.7-src/gui-web/zlib/adler32.c0000644000175000017500000001155012536111364014121 00000000000000/* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #define local static local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #define BASE 65521 /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /* use NO_DIVIDE if your processor does not do division in hardware -- try it both ways to see which is faster */ #ifdef NO_DIVIDE /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 (thank you to John Reiser for pointing this out) */ # define CHOP(a) \ do { \ unsigned long tmp = a >> 16; \ a &= 0xffffUL; \ a += (tmp << 4) - tmp; \ } while (0) # define MOD28(a) \ do { \ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) # define MOD(a) \ do { \ CHOP(a); \ MOD28(a); \ } while (0) # define MOD63(a) \ do { /* this assumes a is not negative */ \ z_off64_t tmp = a >> 32; \ a &= 0xffffffffL; \ a += (tmp << 8) - (tmp << 5) + tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ uLong ZEXPORT adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ local uLong adler32_combine_(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32_combine(adler1, adler2, len2) uLong adler1; uLong adler2; z_off_t len2; { return adler32_combine_(adler1, adler2, len2); } uLong ZEXPORT adler32_combine64(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { return adler32_combine_(adler1, adler2, len2); } golly-2.7-src/gui-web/zlib/gzclose.c0000644000175000017500000000124612536111364014334 00000000000000/* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ int ZEXPORT gzclose(file) gzFile file; { #ifndef NO_GZCOMPRESS gz_statep state; if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); #else return gzclose_r(file); #endif } golly-2.7-src/gui-web/zlib/deflate.h0000644000175000017500000003074612536111364014306 00000000000000/* deflate.h -- internal compression state * Copyright (C) 1995-2012 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef DEFLATE_H #define DEFLATE_H #include "zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256 /* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30 /* number of distance codes */ #define BL_CODES 19 /* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ #define Buf_size 16 /* size of bit buffer in bi_buf */ #define INIT_STATE 42 #define EXTRA_STATE 69 #define NAME_STATE 73 #define COMMENT_STATE 91 #define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* Stream status */ /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } FAR ct_data; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; typedef Pos FAR Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to * save space in the various tables. IPos is used only for parameter passing. */ typedef struct internal_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ uInt pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ uInt gzindex; /* where in extra, name, or comment */ Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Posf *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ struct tree_desc_s l_desc; /* desc. for literal tree */ struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uchf *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt last_lit; /* running index in l_buf */ ushf *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ #ifdef DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ ulg high_water; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ #define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. * See deflate.c for comments about the MIN_MATCH+1. */ #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) extern uch ZLIB_INTERNAL _length_code[]; extern uch ZLIB_INTERNAL _dist_code[]; #else extern const uch ZLIB_INTERNAL _length_code[]; extern const uch ZLIB_INTERNAL _dist_code[]; #endif # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->d_buf[s->last_lit] = 0; \ s->l_buf[s->last_lit++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (length); \ ush dist = (distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ golly-2.7-src/gui-web/zlib/infback.c0000644000175000017500000005426512536111364014274 00000000000000/* infback.c -- inflate using a call-back interface * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* This code is largely copied from inflate.c. Normally either infback.o or inflate.o would be linked into an application--not both. The interface with inffast.c is retained so that optimized assembler-coded versions of inflate_fast() can be used with either inflate.c or infback.c. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) z_streamp strm; int windowBits; unsigned char FAR *window; const char *version; int stream_size; { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL || window == Z_NULL || windowBits < 8 || windowBits > 15) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; state->wbits = windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } /* Macros for inflateBack(): */ /* Load returned state from inflate_fast() */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Set state from registers for inflate_fast() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Assure that some input is available. If input is requested, but denied, then return a Z_BUF_ERROR from inflateBack(). */ #define PULL() \ do { \ if (have == 0) { \ have = in(in_desc, &next); \ if (have == 0) { \ next = Z_NULL; \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflateBack() with an error if there is no input available. */ #define PULLBYTE() \ do { \ PULL(); \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflateBack() with an error. */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* Assure that some output space is available, by writing out the window if it's full. If the write fails, return from inflateBack() with a Z_BUF_ERROR. */ #define ROOM() \ do { \ if (left == 0) { \ put = state->window; \ left = state->wsize; \ state->whave = left; \ if (out(out_desc, put, left)) { \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* strm provides the memory allocation functions and window buffer on input, and provides information on the unused input on return. For Z_DATA_ERROR returns, strm will also provide an error message. in() and out() are the call-back input and output functions. When inflateBack() needs more input, it calls in(). When inflateBack() has filled the window with output, or when it completes with data in the window, it calls out() to write out the data. The application must not change the provided input until in() is called again or inflateBack() returns. The application must not change the window/output buffer until inflateBack() returns. in() and out() are called with a descriptor parameter provided in the inflateBack() call. This parameter can be a structure that provides the information required to do the read or write, as well as accumulated information on the input and output such as totals and check values. in() should return zero on failure. out() should return non-zero on failure. If either in() or out() fails, than inflateBack() returns a Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) z_streamp strm; in_func in; void FAR *in_desc; out_func out; void FAR *out_desc; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* Check that the strm exists and that the state was initialized */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* Reset the state */ strm->msg = Z_NULL; state->mode = TYPE; state->last = 0; state->whave = 0; next = strm->next_in; have = next != Z_NULL ? strm->avail_in : 0; hold = 0; bits = 0; put = state->window; left = state->wsize; /* Inflate until end of block marked as last */ for (;;) switch (state->mode) { case TYPE: /* determine and dispatch block type */ if (state->last) { BYTEBITS(); state->mode = DONE; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN; /* decode codes */ break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: /* get and verify stored block length */ BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); /* copy stored block from input to output */ while (state->length != 0) { copy = state->length; PULL(); ROOM(); if (copy > have) copy = have; if (copy > left) copy = left; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: /* get dynamic table entries descriptor */ NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); /* get code length code lengths (not a typo) */ state->have = 0; while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); /* get length and distance code code lengths */ state->have = 0; while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = (unsigned)(state->lens[state->have - 1]); copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; case LEN: /* use inflate_fast() if we have enough input and output */ if (have >= 6 && left >= 258) { RESTORE(); if (state->whave < state->wsize) state->whave = state->wsize - left; inflate_fast(strm, state->wsize); LOAD(); break; } /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); state->length = (unsigned)here.val; /* process literal */ if (here.op == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); ROOM(); *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; } /* process end of block */ if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } /* invalid code */ if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } /* length code -- get extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); } Tracevv((stderr, "inflate: length %u\n", state->length)); /* get distance code */ for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; /* get distance extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); } if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } Tracevv((stderr, "inflate: distance %u\n", state->offset)); /* copy match from window to output */ do { ROOM(); copy = state->wsize - state->offset; if (copy < left) { from = put + copy; copy = left - copy; } else { from = put - state->offset; copy = left; } if (copy > state->length) copy = state->length; state->length -= copy; left -= copy; do { *put++ = *from++; } while (--copy); } while (state->length != 0); break; case DONE: /* inflate stream terminated properly -- write leftover output */ ret = Z_STREAM_END; if (left < state->wsize) { if (out(out_desc, state->window, state->wsize - left)) ret = Z_BUF_ERROR; } goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; default: /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } /* Return unused input */ inf_leave: strm->next_in = next; strm->avail_in = have; return ret; } int ZEXPORT inflateBackEnd(strm) z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } golly-2.7-src/gui-web/zlib/inflate.c0000644000175000017500000015041012536111364014306 00000000000000/* inflate.c -- zlib decompression * Copyright (C) 1995-2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, unsigned copy)); #ifdef BUILDFIXED void makefixed OF((void)); #endif local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; return inflateResetKeep(strm); } int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits; { int wrap; struct inflate_state FAR *state; /* get the state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 1; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; const char *version; int stream_size; { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->window = Z_NULL; ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_(strm, version, stream_size) z_streamp strm; const char *version; int stream_size; { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime(strm, bits, value) z_streamp strm; int bits; int value; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += value << state->bits; state->bits += bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed() { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow(strm, end, copy) z_streamp strm; const Bytef *end; unsigned copy; { struct inflate_state FAR *state; unsigned dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char FAR *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ if (copy >= state->wsize) { zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, end - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate(strm, flush) z_streamp strm; int flush; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; else if (len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if (state->flags & 0x0200) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = len; } while (len && copy < have); if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if (hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (const code FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if (out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if (( #ifdef GUNZIP state->flags ? hold : #endif ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if (hold != (state->total & 0xffffffffUL)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (out != strm->avail_out && state->mode < BAD && (state->mode < CHECK || flush != Z_FINISH))) if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if (state->wrap && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; { struct inflate_state FAR *state; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ if (state->whave && dictionary != Z_NULL) { zmemcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); zmemcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); } if (dictLength != Z_NULL) *dictLength = state->whave; return Z_OK; } int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state; unsigned long dictid; int ret; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary identifier */ if (state->mode == DICT) { dictid = adler32(0L, Z_NULL, 0); dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; } /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ ret = updatewindow(strm, dictionary + dictLength, dictLength); if (ret) { state->mode = MEM; return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader(strm, head) z_streamp strm; gz_headerp head; { struct inflate_state FAR *state; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch(have, buf, len) unsigned FAR *have; const unsigned char FAR *buf; unsigned len; { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync(strm) z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy(dest, source) z_streamp dest; z_streamp source; { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; /* allocate space */ copy = (struct inflate_state FAR *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine(strm, subvert) z_streamp strm; int subvert; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->sane = !subvert; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR return Z_OK; #else state->sane = 1; return Z_DATA_ERROR; #endif } long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; state = (struct inflate_state FAR *)strm->state; return ((long)(state->back) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } golly-2.7-src/gui-web/zlib/trees.h0000644000175000017500000002043012536111364014011 00000000000000/* header created automatically with -DGEN_TREES_H */ local const ct_data static_ltree[L_CODES+2] = { {{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, {{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, {{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, {{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, {{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, {{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, {{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, {{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, {{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, {{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, {{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, {{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, {{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, {{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, {{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, {{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, {{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, {{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, {{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, {{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, {{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, {{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, {{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, {{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, {{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, {{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, {{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, {{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, {{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, {{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, {{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, {{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, {{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, {{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, {{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, {{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, {{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, {{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, {{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, {{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, {{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, {{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, {{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, {{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, {{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, {{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, {{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, {{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, {{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, {{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, {{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, {{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, {{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, {{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, {{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, {{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, {{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, {{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} }; local const ct_data static_dtree[D_CODES] = { {{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, {{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, {{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, {{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, {{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} }; const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; local const int base_length[LENGTH_CODES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; local const int base_dist[D_CODES] = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; golly-2.7-src/gui-web/zlib/zconf.h0000644000175000017500000003622412536111364014016 00000000000000/* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. * Even better than compiling with -DZ_PREFIX would be to use configure to set * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET /* all linked symbols */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align # define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block # define _tr_tally z__tr_tally # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams # define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset # define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table # ifndef Z_SOLO # define gz_error z_gz_error # define gz_intmax z_gz_intmax # define gz_strwinerror z_gz_strwinerror # define gzbuffer z_gzbuffer # define gzclearerr z_gzclearerr # define gzclose z_gzclose # define gzclose_r z_gzclose_r # define gzclose_w z_gzclose_w # define gzdirect z_gzdirect # define gzdopen z_gzdopen # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets # define gzoffset z_gzoffset # define gzoffset64 z_gzoffset64 # define gzopen z_gzopen # define gzopen64 z_gzopen64 # ifdef _WIN32 # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf # define gzvprintf z_gzvprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread # define gzrewind z_gzrewind # define gzseek z_gzseek # define gzseek64 z_gzseek64 # define gzsetparams z_gzsetparams # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit_ z_inflateBackInit_ # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetHeader z_inflateGetHeader # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateSetDictionary z_inflateSetDictionary # define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflateResetKeep z_inflateResetKeep # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress # endif # define zError z_zError # ifndef Z_SOLO # define zcalloc z_zcalloc # define zcfree z_zcfree # endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion /* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte # define Bytef z_Bytef # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func # ifndef Z_SOLO # define gzFile z_gzFile # endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func # define intf z_intf # define out_func z_out_func # define uInt z_uInt # define uIntf z_uIntf # define uLong z_uLong # define uLongf z_uLongf # define voidp z_voidp # define voidpc z_voidpc # define voidpf z_voidpf /* all zlib structs in zlib.h and zconf.h */ # define gz_header_s z_gz_header_s # define internal_state z_internal_state #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) # define OS2 #endif #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) # ifndef WIN32 # define WIN32 # endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) # ifndef SYS16BIT # define SYS16BIT # endif # endif #endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ #ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # ifndef STDC99 # define STDC99 # endif # endif #endif #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC #endif #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) # define STDC #endif #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) # define STDC #endif #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) # define STDC #endif #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ # define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ # define const /* note: need a more gentle solution here */ # endif #endif #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif /* Some Mac compilers merge all .h files incorrectly: */ #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # define NO_DUMMY_DECL #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K # define MAX_MEM_LEVEL 8 # else # define MAX_MEM_LEVEL 9 # endif #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus a few kilobytes for small objects. */ /* Type declarations */ #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ #ifdef SYS16BIT # if defined(M_I86SM) || defined(M_I86MM) /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER # define FAR _far # else # define FAR far # endif # endif # if (defined(__SMALL__) || defined(__MEDIUM__)) /* Turbo C small or medium model */ # define SMALL_MEDIUM # ifdef __BORLANDC__ # define FAR _far # else # define FAR far # endif # endif #endif #if defined(WINDOWS) || defined(WIN32) /* If building or using zlib as a DLL, define ZLIB_DLL. * This is not mandatory, but it offers a little performance increase. */ # ifdef ZLIB_DLL # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) # ifdef ZLIB_INTERNAL # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif # endif # endif /* ZLIB_DLL */ /* If building or using zlib with the WINAPI/WINAPIV calling convention, * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) # ifdef ZLIB_DLL # ifdef ZLIB_INTERNAL # define ZEXPORT __declspec(dllexport) # define ZEXPORTVA __declspec(dllexport) # else # define ZEXPORT __declspec(dllimport) # define ZEXPORTVA __declspec(dllimport) # endif # endif #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef FAR # define FAR #endif #if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void const *voidpc; typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte const *voidpc; typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) # include # if (UINT_MAX == 0xffffffffUL) # define Z_U4 unsigned # elif (ULONG_MAX == 0xffffffffUL) # define Z_U4 unsigned long # elif (USHRT_MAX == 0xffffffffUL) # define Z_U4 unsigned short # endif #endif #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_STDARG_H #endif #ifdef STDC # ifndef Z_SOLO # include /* for off_t */ # endif #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO # include /* for va_list */ # endif #endif #ifdef _WIN32 # ifndef Z_SOLO # include /* for wchar_t */ # endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) # define Z_HAVE_UNISTD_H #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif # endif #endif #if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 # define Z_LFS64 #endif #if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) # define Z_LARGE64 #endif #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) # define Z_WANT64 #endif #if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) #pragma map(deflateInit_,"DEIN") #pragma map(deflateInit2_,"DEIN2") #pragma map(deflateEnd,"DEEND") #pragma map(deflateBound,"DEBND") #pragma map(inflateInit_,"ININ") #pragma map(inflateInit2_,"ININ2") #pragma map(inflateEnd,"INEND") #pragma map(inflateSync,"INSY") #pragma map(inflateSetDictionary,"INSEDI") #pragma map(compressBound,"CMBND") #pragma map(inflate_table,"INTABL") #pragma map(inflate_fast,"INFA") #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ golly-2.7-src/gui-web/zlib/compress.c0000644000175000017500000000474112536111364014524 00000000000000/* compress.c -- compress a memory buffer * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; int level; { z_stream stream; int err; stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; #ifdef MAXSEG_64K /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; #endif stream.next_out = dest; stream.avail_out = (uInt)*destLen; if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = deflateInit(&stream, level); if (err != Z_OK) return err; err = deflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { deflateEnd(&stream); return err == Z_OK ? Z_BUF_ERROR : err; } *destLen = stream.total_out; err = deflateEnd(&stream); return err; } /* =========================================================================== */ int ZEXPORT compress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ uLong ZEXPORT compressBound (sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } golly-2.7-src/gui-web/zlib/trees.c0000644000175000017500000012633712536111364014021 00000000000000/* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2012 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ /* @(#) $Id$ */ /* #define GEN_TREES_H */ #include "deflate.h" #ifdef DEBUG # include #endif /* =========================================================================== * Constants */ #define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */ #define END_BLOCK 256 /* end of block literal code */ #define REP_3_6 16 /* repeat previous bit length 3-6 times (2 bits of repeat count) */ #define REPZ_3_10 17 /* repeat a zero length 3-10 times (3 bits of repeat count) */ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; local const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; local const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ /* =========================================================================== * Local data. These are initialized only once. */ #define DIST_CODE_LEN 512 /* see definition of array dist_code below */ #if defined(GEN_TREES_H) || !defined(STDC) /* non ANSI compilers may not accept trees.h */ local ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ local ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ uch _dist_code[DIST_CODE_LEN]; /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ local int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ local int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ #else # include "trees.h" #endif /* GEN_TREES_H */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; local static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ local void tr_static_init OF((void)); local void init_block OF((deflate_state *s)); local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); local void build_tree OF((deflate_state *s, tree_desc *desc)); local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); local int build_bl_tree OF((deflate_state *s)); local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, int blcodes)); local void compress_block OF((deflate_state *s, const ct_data *ltree, const ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); local void copy_block OF((deflate_state *s, charf *buf, unsigned len, int header)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif #ifndef DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits(s, value, length) deflate_state *s; int value; /* value to send */ int length; /* number of bits */ { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } #else /* !DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } #endif /* DEBUG */ /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ local void tr_static_init() { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ #ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse((unsigned)n, 5); } static_init_done = 1; # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef DEBUG # include # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width)-1 ? ",\n" : ", ")) void gen_trees_header() { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { fprintf(header, "%2u%s", _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { fprintf(header, "%2u%s", _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { fprintf(header, "%1u%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "%5u%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void ZLIB_INTERNAL _tr_init(s) deflate_state *s; { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Initialize a new block. */ local void init_block(s) deflate_state *s; { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->last_lit = s->matches = 0; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ local void pqdownheap(s, tree, k) deflate_state *s; ct_data *tree; /* the tree to restore */ int k; /* node to move down */ { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ local void gen_bitlen(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; s->opt_len += (ulg)f * (bits + xbits); if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); } if (overflow == 0) return; Trace((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ local void gen_codes (tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ ush code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { next_code[bits] = code = (code + bl_count[bits-1]) << 1; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ local void scan_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ local void send_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ local int build_bl_tree(s) deflate_state *s; { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*(max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ local void send_all_trees(s, lcodes, dcodes, blcodes) deflate_state *s; int lcodes, dcodes, blcodes; /* number of codes for each tree */ { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ #ifdef DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; #endif copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ void ZLIB_INTERNAL _tr_flush_bits(s) deflate_state *s; { bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ void ZLIB_INTERNAL _tr_align(s) deflate_state *s; { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and output the encoded block to the zip file. */ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) deflate_state *s; charf *buf; /* input block, or NULL if too old */ ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len+3+7)>>3; static_lenb = (s->static_len+3+7)>>3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->last_lit)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len+4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1)+last, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally (s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } #ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", s->last_lit, in_length, out_length, 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } #endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ local void compress_block(s, ltree, dtree) deflate_state *s; const ct_data *ltree; /* literal tree */ const ct_data *dtree; /* distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ local int detect_data_type(s) deflate_state *s; { /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long black_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("black-listed") bytes. */ for (n = 0; n <= 31; n++, black_mask >>= 1) if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("white-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ local unsigned bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ local void bi_flush(s) deflate_state *s; { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ local void bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } /* =========================================================================== * Copy a stored block, storing first the length and its * one's complement if requested. */ local void copy_block(s, buf, len, header) deflate_state *s; charf *buf; /* the input data */ unsigned len; /* its length */ int header; /* true if block header must be written */ { bi_windup(s); /* align on byte boundary */ if (header) { put_short(s, (ush)len); put_short(s, (ush)~len); #ifdef DEBUG s->bits_sent += 2*16; #endif } #ifdef DEBUG s->bits_sent += (ulg)len<<3; #endif while (len--) { put_byte(s, *buf++); } } golly-2.7-src/gui-web/zlib/gzread.c0000644000175000017500000004440612536111364014147 00000000000000/* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); local int gz_avail OF((gz_statep)); local int gz_look OF((gz_statep)); local int gz_decomp OF((gz_statep)); local int gz_fetch OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ local int gz_load(state, buf, len, have) gz_statep state; unsigned char *buf; unsigned len; unsigned *have; { int ret; *have = 0; do { ret = read(state->fd, buf + *have, len - *have); if (ret <= 0) break; *have += ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (ret == 0) state->eof = 1; return 0; } /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ local int gz_avail(state) gz_statep state; { unsigned got; z_streamp strm = &(state->strm); if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; if (state->eof == 0) { if (strm->avail_in) { /* copy what's there to the start */ unsigned char *p = state->in; unsigned const char *q = strm->next_in; unsigned n = strm->avail_in; do { *p++ = *q++; } while (--n); } if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1) return -1; strm->avail_in += got; strm->next_in = state->in; } return 0; } /* Look for gzip header, set up for inflate or copy. state->x.have must be 0. If this is the first time in, allocate required memory. state->how will be left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ local int gz_look(state) gz_statep state; { z_streamp strm = &(state->strm); /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ state->in = (unsigned char *)malloc(state->want); state->out = (unsigned char *)malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { if (state->out != NULL) free(state->out); if (state->in != NULL) free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } state->size = state->want; /* allocate inflate memory */ state->strm.zalloc = Z_NULL; state->strm.zfree = Z_NULL; state->strm.opaque = Z_NULL; state->strm.avail_in = 0; state->strm.next_in = Z_NULL; if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ free(state->out); free(state->in); state->size = 0; gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* get at least the magic bytes in the input buffer */ if (strm->avail_in < 2) { if (gz_avail(state) == -1) return -1; if (strm->avail_in == 0) return 0; } /* look for gzip magic bytes -- if there, do gzip decoding (note: there is a logical dilemma here when considering the case of a partially written gzip file, to wit, if a single 31 byte is written, then we cannot tell whether this is a single-byte file, or just a partially written gzip file -- for here we assume that if a gzip file is being written, then the header will be written in a single operation, so that reading a single byte is sufficient indication that it is not a gzip file) */ if (strm->avail_in > 1 && strm->next_in[0] == 31 && strm->next_in[1] == 139) { inflateReset(strm); state->how = GZIP; state->direct = 0; return 0; } /* no gzip header -- if we were decoding gzip before, then this is trailing garbage. Ignore the trailing garbage and finish. */ if (state->direct == 0) { strm->avail_in = 0; state->eof = 1; state->x.have = 0; return 0; } /* doing raw i/o, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; if (strm->avail_in) { memcpy(state->x.next, strm->next_in, strm->avail_in); state->x.have = strm->avail_in; strm->avail_in = 0; } state->how = COPY; state->direct = 1; return 0; } /* Decompress from input to the provided next_out and avail_out in the state. On return, state->x.have and state->x.next point to the just decompressed data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ local int gz_decomp(state) gz_statep state; { int ret = Z_OK; unsigned had; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; do { /* get more input for inflate() */ if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { gz_error(state, Z_BUF_ERROR, "unexpected end of file"); break; } /* decompress and handle errors */ ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { gz_error(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ gz_error(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); /* update available output */ state->x.have = had - strm->avail_out; state->x.next = strm->next_out - state->x.have; /* if the gzip stream completed successfully, look for another */ if (ret == Z_STREAM_END) state->how = LOOK; /* good decompression */ return 0; } /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ local int gz_fetch(state) gz_statep state; { z_streamp strm = &(state->strm); do { switch(state->how) { case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ if (gz_look(state) == -1) return -1; if (state->how == LOOK) return 0; break; case COPY: /* -> COPY */ if (gz_load(state, state->out, state->size << 1, &(state->x.have)) == -1) return -1; state->x.next = state->out; return 0; case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ strm->avail_out = state->size << 1; strm->next_out = state->out; if (gz_decomp(state) == -1) return -1; } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ local int gz_skip(state, len) gz_statep state; z_off64_t len; { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ if (state->x.have) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? (unsigned)len : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; len -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) break; /* need more data to skip -- load up output buffer */ else { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; } return 0; } /* -- see zlib.h -- */ int ZEXPORT gzread(file, buf, len) gzFile file; voidp buf; unsigned len; { unsigned got, n; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids the flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return -1; } /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* first just try copying data from the output buffer */ if (state->x.have) { n = state->x.have > len ? len : state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && strm->avail_in == 0) { state->past = 1; /* tried to read past end */ break; } /* need output data -- for small len or new stream load up our output buffer */ else if (state->how == LOOK || len < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ } /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ if (gz_load(state, (unsigned char *)buf, len, &n) == -1) return -1; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ strm->avail_out = len; strm->next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) return -1; n = state->x.have; state->x.have = 0; } /* update progress */ len -= n; buf = (char *)buf + n; got += n; state->x.pos += n; } while (len); /* return number of bytes read into user buffer (will fit in int) */ return (int)got; } /* -- see zlib.h -- */ #ifdef Z_PREFIX_SET # undef z_gzgetc #else # undef gzgetc #endif int ZEXPORT gzgetc(file) gzFile file; { int ret; unsigned char buf[1]; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* try output buffer (no need to check for skip request) */ if (state->x.have) { state->x.have--; state->x.pos++; return *(state->x.next)++; } /* nothing there -- try gzread() */ ret = gzread(file, buf, 1); return ret < 1 ? -1 : buf[0]; } int ZEXPORT gzgetc_(file) gzFile file; { return gzgetc(file); } /* -- see zlib.h -- */ int ZEXPORT gzungetc(c, file) int c; gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* can't push EOF */ if (c < 0) return -1; /* if output buffer empty, put byte at end (allows more pushing) */ if (state->x.have == 0) { state->x.have = 1; state->x.next = state->out + (state->size << 1) - 1; state->x.next[0] = c; state->x.pos--; state->past = 0; return c; } /* if no room, give up (must have already done a gzungetc()) */ if (state->x.have == (state->size << 1)) { gz_error(state, Z_DATA_ERROR, "out of room to push characters"); return -1; } /* slide output data if needed and insert byte before existing data */ if (state->x.next == state->out) { unsigned char *src = state->out + state->x.have; unsigned char *dest = state->out + (state->size << 1); while (src > state->out) *--dest = *--src; state->x.next = dest; } state->x.have++; state->x.next--; state->x.next[0] = c; state->x.pos--; state->past = 0; return c; } /* -- see zlib.h -- */ char * ZEXPORT gzgets(file, buf, len) gzFile file; char *buf; int len; { unsigned left, n; char *str; unsigned char *eol; gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) return NULL; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return NULL; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return NULL; } /* copy output bytes up to new line or len - 1, whichever comes first -- append a terminating zero to the string (we don't check for a zero in the contents, let the user worry about that) */ str = buf; left = (unsigned)len - 1; if (left) do { /* assure that something is in the output buffer */ if (state->x.have == 0 && gz_fetch(state) == -1) return NULL; /* error */ if (state->x.have == 0) { /* end of file */ state->past = 1; /* read past end */ break; /* return what we have */ } /* look for end-of-line in current output buffer */ n = state->x.have > left ? left : state->x.have; eol = (unsigned char *)memchr(state->x.next, '\n', n); if (eol != NULL) n = (unsigned)(eol - state->x.next) + 1; /* copy through end-of-line, or remainder if not found */ memcpy(buf, state->x.next, n); state->x.have -= n; state->x.next += n; state->x.pos += n; left -= n; buf += n; } while (left && eol == NULL); /* return terminated string, or if nothing, end of file */ if (buf == str) return NULL; buf[0] = 0; return str; } /* -- see zlib.h -- */ int ZEXPORT gzdirect(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) (void)gz_look(state); /* return 1 if transparent, 0 if processing a gzip stream */ return state->direct; } /* -- see zlib.h -- */ int ZEXPORT gzclose_r(file) gzFile file; { int ret, err; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) return Z_STREAM_ERROR; /* free memory and close file */ if (state->size) { inflateEnd(&(state->strm)); free(state->out); free(state->in); } err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); free(state); return ret ? Z_ERRNO : err; } golly-2.7-src/gui-web/zlib/crc32.h0000644000175000017500000007354212536111364013617 00000000000000/* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const z_crc_t FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; golly-2.7-src/gui-web/zlib/inftrees.h0000644000175000017500000000556012536111364014515 00000000000000/* inftrees.h -- header to use inftrees.c * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* Structure for decoding tables. Each entry provides either the information needed to do the operation requested by the code that indexed that table entry, or it provides a pointer to another table that indexes more bits of the code. op indicates whether the entry is a pointer to another table, a literal, a length or distance, an end-of-block, or an invalid code. For a table pointer, the low four bits of op is the number of index bits of that table. For a length or distance, the low four bits of op is the number of extra bits to get after the code. bits is the number of bits in this code or part of the code to drop off of the bit buffer. val is the actual byte to output in the case of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { unsigned char op; /* operation, extra bits, table bits */ unsigned char bits; /* bits in this part of the code */ unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work)); golly-2.7-src/gui-web/zlib/inftrees.c0000644000175000017500000003134412536111364014507 00000000000000/* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.8 Copyright 1995-2013 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) codetype type; unsigned short FAR *lens; unsigned codes; code FAR * FAR *table; unsigned FAR *bits; unsigned short FAR *work; { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ int end; /* use base and extra for symbol > end */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ end = 19; break; case LENS: base = lbase; base -= 257; extra = lext; extra -= 257; end = 256; break; default: /* DISTS */ base = dbase; extra = dext; end = -1; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if ((int)(work[sym]) < end) { here.op = (unsigned char)0; here.val = work[sym]; } else if ((int)(work[sym]) > end) { here.op = (unsigned char)(extra[work[sym]]); here.val = base[work[sym]]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ if (huff != 0) { here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; next[huff] = here; } /* set return parameters */ *table += used; *bits = root; return 0; } golly-2.7-src/gui-web/zlib/inflate.h0000644000175000017500000001437712536111364014326 00000000000000/* inflate.h -- internal inflate state definition * Copyright (C) 1995-2009 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif /* Possible inflate modes between inflate() calls */ typedef enum { HEAD, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ EXLEN, /* i: waiting for extra length (gzip) */ EXTRA, /* i: waiting for extra bytes (gzip) */ NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ TYPEDO, /* i: same, but skip check to exit inflate on new block */ STORED, /* i: waiting for stored size (length and complement) */ COPY_, /* i/o: same as COPY below, but only first time in */ COPY, /* i/o: waiting for input or output to copy stored block */ TABLE, /* i: waiting for dynamic block table lengths */ LENLENS, /* i: waiting for code length code lengths */ CODELENS, /* i: waiting for length/lit and distance code lengths */ LEN_, /* i: same as LEN below, but only first time in */ LEN, /* i: waiting for length/lit/eob code */ LENEXT, /* i: waiting for length extra bits */ DIST, /* i: waiting for distance code */ DISTEXT, /* i: waiting for distance extra bits */ MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> HCRC -> TYPE (zlib) -> DICTID or TYPE DICTID -> DICT -> TYPE (raw) -> TYPEDO Read deflate blocks: TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK STORED -> COPY_ -> COPY -> TYPE TABLE -> LENLENS -> CODELENS -> LEN_ LEN_ -> LEN Read deflate codes in fixed or dynamic block: LEN -> LENEXT or LIT or TYPE LENEXT -> DIST -> DISTEXT -> MATCH -> LEN LIT -> LEN Process trailer: CHECK -> LENGTH -> DONE */ /* state maintained between inflate() calls. Approximately 10K bytes. */ struct inflate_state { inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if needed */ /* bit accumulator */ unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ /* for string and stored block copying */ unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ /* fixed and dynamic code tables */ code const FAR *lencode; /* starting table for length/literal codes */ code const FAR *distcode; /* starting table for distance codes */ unsigned lenbits; /* index bits for lencode */ unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ unsigned have; /* number of code lengths in lens[] */ code FAR *next; /* next available space in codes[] */ unsigned short lens[320]; /* temporary storage for code lengths */ unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ int sane; /* if false, allow invalid distance too far */ int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; golly-2.7-src/gui-web/zlib/deflate.c0000644000175000017500000021346412536111364014301 00000000000000/* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions * of the input text which are identical to earlier input (within a * sliding window trailing behind the input currently being processed). * * The most straightforward technique turns out to be the fastest for * most input files: try all possible matches and select the longest. * The key feature of this algorithm is that insertions into the string * dictionary are very simple and thus fast, and deletions are avoided * completely. Insertions are performed at each input character, whereas * string matches are performed only when the previous match ends. So it * is preferable to spend more time in matches to allow very fast string * insertions and avoid deletions. The matching algorithm for small * strings is inspired from that of Rabin & Karp. A brute force approach * is used to find longer strings when a small match has been found. * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze * (by Leonid Broukhis). * A previous version of this file used a more sophisticated algorithm * (by Fiala and Greene) which is guaranteed to run in linear amortized * time, but has a larger average cost, uses more memory and is patented. * However the F&G algorithm may be faster for some highly redundant * files if the parameter max_chain_length (described below) is too large. * * ACKNOWLEDGEMENTS * * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and * I found it in 'freeze' written by Leonid Broukhis. * Thanks to many people for bug reports and testing. * * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. * * Fiala,E.R., and Greene,D.H. * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 * */ /* @(#) $Id$ */ #include "deflate.h" const char deflate_copyright[] = " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* =========================================================================== * Function prototypes. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); #ifndef FASTEST local block_state deflate_slow OF((deflate_state *s, int flush)); #endif local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif #ifdef DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ #ifndef TOO_FAR # define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; compress_func func; } config; #ifdef FASTEST local const config configuration_table[2] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ #else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ #endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ #define EQUAL 0 /* result of memcmp for equal strings */ #ifndef NO_DUMMY_DECL struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #endif /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to to UPDATE_HASH are made with consecutive * input characters, so that a running hash key can be computed from the * previous key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. * IN assertion: all calls to to INSERT_STRING are made with consecutive * input characters and the first MIN_MATCH bytes of str are valid * (except for the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* ========================================================================= */ int ZEXPORT deflateInit_(strm, level, version, stream_size) z_streamp strm; int level; const char *version; int stream_size; { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, version, stream_size) z_streamp strm; int level; int method; int windowBits; int memLevel; int strategy; const char *version; int stream_size; { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; s->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); s->pending_buf = (uchf *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } s->d_buf = overlay + s->lit_bufsize/sizeof(ush); s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= */ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { deflate_state *s; uInt str, n; int wrap; unsigned avail; z_const unsigned char *next; if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) return Z_STREAM_ERROR; /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); s->wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ if (dictLength >= s->w_size) { if (wrap == 0) { /* already empty otherwise */ CLEAR_HASH(s); s->strstart = 0; s->block_start = 0L; s->insert = 0; } dictionary += dictLength - s->w_size; /* use the tail */ dictLength = s->w_size; } /* insert dictionary into window and hash */ avail = strm->avail_in; next = strm->next_in; strm->avail_in = dictLength; strm->next_in = (z_const Bytef *)dictionary; fill_window(s); while (s->lookahead >= MIN_MATCH) { str = s->strstart; n = s->lookahead - (MIN_MATCH-1); do { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; } while (--n); s->strstart = str; s->lookahead = MIN_MATCH-1; fill_window(s); } s->strstart += s->lookahead; s->block_start = (long)s->strstart; s->insert = s->lookahead; s->lookahead = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateResetKeep (strm) z_streamp strm; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = Z_NO_FLUSH; _tr_init(s); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateReset (strm) z_streamp strm; { int ret; ret = deflateResetKeep(strm); if (ret == Z_OK) lm_init(strm->state); return ret; } /* ========================================================================= */ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; gz_headerp head; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePending (strm, pending, bits) unsigned *pending; int *bits; z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) *bits = strm->state->bi_valid; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; int value; { deflate_state *s; int put; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do { put = Buf_size - s->bi_valid; if (put > bits) put = bits; s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); s->bi_valid += put; _tr_flush_bits(s); value >>= put; bits -= put; } while (bits); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateParams(strm, level, strategy) z_streamp strm; int level; int strategy; { deflate_state *s; compress_func func; int err = Z_OK; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && strm->total_in != 0) { /* Flush the last buffer: */ err = deflate(strm, Z_BLOCK); if (err == Z_BUF_ERROR && s->pending == 0) err = Z_OK; } if (s->level != level) { s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; s->nice_match = configuration_table[level].nice_length; s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return err; } /* ========================================================================= */ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) z_streamp strm; int good_length; int max_lazy; int nice_length; int max_chain; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; s = strm->state; s->good_match = good_length; s->max_lazy_match = max_lazy; s->nice_match = nice_length; s->max_chain_length = max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. * They are coded as constants here for a reason--if the #define's are * changed, then this function needs to be changed as well. The return * value for 15 and 8 only works for those exact settings. * * For any setting other than those defaults for windowBits and memLevel, * the value returned is a conservative worst case for the maximum expansion * resulting from using fixed blocks instead of stored blocks, which deflate * can emit on compressed data for some combinations of the parameters. * * This function could be more sophisticated to provide closer upper bounds for * every combination of windowBits and memLevel. But even the conservative * upper bound of about 14% expansion does not seem onerous for output buffer * allocation. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; uLong complen, wraplen; Bytef *str; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ if (strm == Z_NULL || strm->state == Z_NULL) return complen + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; if (str != Z_NULL) do { wraplen++; } while (*str++); str = s->gzhead->comment; if (str != Z_NULL) do { wraplen++; } while (*str++); if (s->gzhead->hcrc) wraplen += 2; } break; default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return conservative bound */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ local void putShortMSB (s, b) deflate_state *s; uInt b; { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output goes * through this function so some applications may wish to modify it * to avoid allocating a large strm->next_out buffer and copying into it. * (See also read_buf()). */ local void flush_pending(strm) z_streamp strm; { unsigned len; deflate_state *s = strm->state; _tr_flush_bits(s); len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len; s->pending_out += len; strm->total_out += len; strm->avail_out -= len; s->pending -= len; if (s->pending == 0) { s->pending_out = s->pending_buf; } } /* ========================================================================= */ int ZEXPORT deflate (strm, flush) z_streamp strm; int flush; { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); s->strm = strm; /* just in case */ old_flush = s->last_flush; s->last_flush = flush; /* Write the header */ if (s->status == INIT_STATE) { #ifdef GZIP if (s->wrap == 2) { strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (s->gzhead == Z_NULL) { put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; } else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + (s->gzhead->extra == Z_NULL ? 0 : 4) + (s->gzhead->name == Z_NULL ? 0 : 8) + (s->gzhead->comment == Z_NULL ? 0 : 16) ); put_byte(s, (Byte)(s->gzhead->time & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) { put_byte(s, s->gzhead->extra_len & 0xff); put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); } if (s->gzhead->hcrc) strm->adler = crc32(strm->adler, s->pending_buf, s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } else #endif { uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) level_flags = 2; else level_flags = 3; header |= (level_flags << 6); if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); s->status = BUSY_STATE; putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s->strstart != 0) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } strm->adler = adler32(0L, Z_NULL, 0); } } #ifdef GZIP if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) break; } put_byte(s, s->gzhead->extra[s->gzindex]); s->gzindex++; } if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (s->gzindex == s->gzhead->extra_len) { s->gzindex = 0; s->status = NAME_STATE; } } else s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) { s->gzindex = 0; s->status = COMMENT_STATE; } } else s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { uInt beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); flush_pending(strm); beg = s->pending; if (s->pending == s->pending_buf_size) { val = 1; break; } } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); if (s->gzhead->hcrc && s->pending > beg) strm->adler = crc32(strm->adler, s->pending_buf + beg, s->pending - beg); if (val == 0) s->status = HCRC_STATE; } else s->status = HCRC_STATE; } if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) flush_pending(strm); if (s->pending + 2 <= s->pending_buf_size) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); strm->adler = crc32(0L, Z_NULL, 0); s->status = BUSY_STATE; } } else s->status = BUSY_STATE; } #endif /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s->last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : (s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush)); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; s->insert = 0; } } } flush_pending(strm); if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); put_byte(s, (Byte)(strm->total_in & 0xff)); put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); } else #endif { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int ZEXPORT deflateEnd (strm) z_streamp strm; { int status; if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; if (status != INIT_STATE && status != EXTRA_STATE && status != NAME_STATE && status != COMMENT_STATE && status != HCRC_STATE && status != BUSY_STATE && status != FINISH_STATE) { return Z_STREAM_ERROR; } /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int ZEXPORT deflateCopy (dest, source) z_streamp dest; z_streamp source; { #ifdef MAXSEG_64K return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; ushf *overlay; if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); ds->pending_buf = (uchf *) overlay; if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ local int read_buf(strm, buf, size) z_streamp strm; Bytef *buf; unsigned size; { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, buf, len); } #endif strm->next_in += len; strm->total_in += len; return (int)len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ local void lm_init (s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; #ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif #endif } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ #ifndef ASMV /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan+best_len-1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match+best_len-1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef DEBUG /* =========================================================================== * Check that the match at match_start is indeed a match. */ local void check_match(s, start, match, length) deflate_state *s; IPos start, match; int length; { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ local void fill_window(s) deflate_state *s; { register unsigned n, m; register Posf *p; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize+MAX_DIST(s)) { zmemcpy(s->window, s->window+wsize, (unsigned)wsize); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; /* Slide the hash table (could be avoided with 32 bit values at the expense of memory usage). We slide even when level == 0 to keep the hash table consistent if we switch back to level > 0 later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ n = s->hash_size; p = &s->head[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); } while (--n); n = wsize; #ifndef FASTEST p = &s->prev[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m-wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif more += wsize; } if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead + s->insert >= MIN_MATCH) { uInt str = s->strstart - s->insert; s->ins_h = s->window[str]; UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif while (s->insert) { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; s->insert--; if (s->lookahead + s->insert < MIN_MATCH) break; } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "not enough room for search"); } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ (ulg)((long)s->strstart - s->block_start), \ (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \ FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * This function does not insert new strings in the dictionary since * uncompressible data is probably not useful. This function is used * only for the level=0 compression option. * NOTE: this function should be optimized to avoid extra copying from * window to pending_buf. */ local block_state deflate_stored(s, flush) deflate_state *s; int flush; { /* Stored blocks are limited to 0xffff bytes, pending_buf is limited * to pending_buf_size, and each stored block has a 5 byte header: */ ulg max_block_size = 0xffff; ulg max_start; if (max_block_size > s->pending_buf_size - 5) { max_block_size = s->pending_buf_size - 5; } /* Copy as much as possible from input to output: */ for (;;) { /* Fill the window as much as possible: */ if (s->lookahead <= 1) { Assert(s->strstart < s->w_size+MAX_DIST(s) || s->block_start >= (long)s->w_size, "slide too late"); fill_window(s); if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; if (s->lookahead == 0) break; /* flush the current block */ } Assert(s->block_start >= 0L, "block gone"); s->strstart += s->lookahead; s->lookahead = 0; /* Emit a stored block if pending_buf will be full: */ max_start = s->block_start + max_block_size; if (s->strstart == 0 || (ulg)s->strstart >= max_start) { /* strstart == 0 is possible when wraparound on 16-bit machine */ s->lookahead = (uInt)(s->strstart - max_start); s->strstart = (uInt)max_start; FLUSH_BLOCK(s, 0); } /* Flush if we may have to slide, otherwise block_start may become * negative and the data will be gone: */ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { FLUSH_BLOCK(s, 0); } } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if ((long)s->strstart > s->block_start) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ local block_state deflate_fast(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ local block_state deflate_slow(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED #if TOO_FAR <= 32767 || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) #endif )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart-1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length-1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ local block_state deflate_rle(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest run, plus one for the unrolled loop. */ if (s->lookahead <= MAX_MATCH) { fill_window(s); if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* See how many times the previous byte repeats */ s->match_length = 0; if (s->lookahead >= MIN_MATCH && s->strstart > 0) { scan = s->window + s->strstart - 1; prev = *scan; if (prev == *++scan && prev == *++scan && prev == *++scan) { strend = s->window + s->strstart + MAX_MATCH; do { } while (prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (int)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ local block_state deflate_huff(s, flush) deflate_state *s; int flush; { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } golly-2.7-src/gui-web/zlib/inffast.h0000644000175000017500000000065312536111364014326 00000000000000/* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); golly-2.7-src/gui-web/zlib/inffast.c0000644000175000017500000003221712536111364014322 00000000000000/* inffast.c -- fast decoding * Copyright (C) 1995-2008, 2010, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifndef ASMINF /* Allow machine dependent optimization for post-increment or pre-increment. Based on testing to date, Pre-increment preferred for: - PowerPC G3 (Adler) - MIPS R5000 (Randers-Pehrson) Post-increment preferred for: - none No measurable difference: - Pentium III (Anderson) - M68060 (Nikl) */ #ifdef POSTINC # define OFF 0 # define PUP(a) *(a)++ #else # define OFF 1 # define PUP(a) *++(a) #endif /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in - OFF; last = in + (strm->avail_in - 5); out = strm->next_out - OFF; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op == 0) { /* literal */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); PUP(out) = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; hold += (unsigned long)(PUP(in)) << bits; bits += 8; } here = dcode[hold & dmask]; dodist: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op & 16) { /* distance base */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(PUP(in)) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { PUP(out) = 0; } while (--len); continue; } len -= op - whave; do { PUP(out) = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { PUP(out) = PUP(from); } while (--len); continue; } #endif } from = window - OFF; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = window - OFF; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { PUP(out) = PUP(from); } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ PUP(out) = PUP(from); PUP(out) = PUP(from); PUP(out) = PUP(from); len -= 3; } while (len > 2); if (len) { PUP(out) = PUP(from); if (len > 1) PUP(out) = PUP(from); } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode[here.val + (hold & ((1U << op) - 1))]; goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode[here.val + (hold & ((1U << op) - 1))]; goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in + OFF; strm->next_out = out + OFF; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ #endif /* !ASMINF */ golly-2.7-src/gui-web/zlib/zutil.h0000644000175000017500000001515612536111364014047 00000000000000/* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef ZUTIL_H #define ZUTIL_H #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include "zlib.h" #if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include # endif # include # include #endif #ifdef Z_SOLO typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ #ifndef DEF_WBITS # define DEF_WBITS MAX_WBITS #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default memLevel */ #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 /* The three kinds of block type */ #define MIN_MATCH 3 #define MAX_MATCH 258 /* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ /* target dependencies */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 # ifndef Z_SOLO # if defined(__TURBOC__) || defined(__BORLANDC__) # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) /* Allow compilation with ANSI keywords only enabled */ void _Cdecl farfree( void *block ); void *_Cdecl farmalloc( unsigned long nbytes ); # else # include # endif # else /* MSC or DJGPP */ # include # endif # endif #endif #ifdef AMIGA # define OS_CODE 0x01 #endif #if defined(VAXC) || defined(VMS) # define OS_CODE 0x02 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif #if defined(ATARI) || defined(atarist) # define OS_CODE 0x05 #endif #ifdef OS2 # define OS_CODE 0x06 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 0x07 # ifndef Z_SOLO # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fdopen */ # else # ifndef fdopen # define fdopen(fd,mode) NULL /* No fdopen() */ # endif # endif # endif #endif #ifdef TOPS20 # define OS_CODE 0x0a #endif #ifdef WIN32 # ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ # define OS_CODE 0x0b # endif #endif #ifdef __50SERIES /* Prime/PRIMOS */ # define OS_CODE 0x0f #endif #if defined(_BEOS_) || defined(RISCOS) # define fdopen(fd,mode) NULL /* No fdopen() */ #endif #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ # ifndef _PTRDIFF_T_DEFINED typedef int ptrdiff_t; # define _PTRDIFF_T_DEFINED # endif # else # define fdopen(fd,type) _fdopen(fd,type) # endif #endif #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif /* common defaults */ #ifndef OS_CODE # define OS_CODE 0x03 /* assume Unix */ #endif #ifndef F_OPEN # define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ #if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) /* Use our own functions for small and medium model with MSC <= 5.0. * You may have to use the same strategy for Borland C (untested). * The __SC__ check is for Symantec. */ # define NO_MEMCPY #endif #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) # define HAVE_MEMCPY #endif #ifdef HAVE_MEMCPY # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ # define zmemcpy _fmemcpy # define zmemcmp _fmemcmp # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); #endif /* Diagnostic functions */ #ifdef DEBUG # include extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif #ifndef Z_SOLO voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} /* Reverse the bytes in a 32-bit value */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */ golly-2.7-src/gui-web/zlib/gzlib.c0000644000175000017500000004003712536111364013776 00000000000000/* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" #if defined(_WIN32) && !defined(__BORLANDC__) # define LSEEK _lseeki64 #else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif #endif /* Local functions */ local void gz_reset OF((gz_statep)); local gzFile gz_open OF((const void *, int, const char *)); #if defined UNDER_CE /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to gz_strwinerror The gz_strwinerror function does not change the current setting of GetLastError. */ char ZLIB_INTERNAL *gz_strwinerror (error) DWORD error; { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, 0, /* Default language */ (LPVOID)&msgbuf, 0, NULL); if (chars != 0) { /* If there is an \r\n appended, zap it. */ if (chars >= 2 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { chars -= 2; msgbuf[chars] = 0; } if (chars > sizeof (buf) - 1) { chars = sizeof (buf) - 1; msgbuf[chars] = 0; } wcstombs(buf, msgbuf, chars + 1); LocalFree(msgbuf); } else { sprintf(buf, "unknown win32 error (%ld)", error); } SetLastError(lasterr); return buf; } #endif /* UNDER_CE */ /* Reset gzip file state */ local void gz_reset(state) gz_statep state; { state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ } state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ local gzFile gz_open(path, fd, mode) const void *path; int fd; const char *mode; { gz_statep state; size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; #endif #ifdef O_EXCL int exclusive = 0; #endif /* check input */ if (path == NULL) return NULL; /* allocate gzFile structure to return */ state = (gz_statep)malloc(sizeof(gz_state)); if (state == NULL) return NULL; state->size = 0; /* no buffers allocated yet */ state->want = GZBUFSIZE; /* requested buffer size */ state->msg = NULL; /* no error message yet */ /* interpret mode */ state->mode = GZ_NONE; state->level = Z_DEFAULT_COMPRESSION; state->strategy = Z_DEFAULT_STRATEGY; state->direct = 0; while (*mode) { if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; else switch (*mode) { case 'r': state->mode = GZ_READ; break; #ifndef NO_GZCOMPRESS case 'w': state->mode = GZ_WRITE; break; case 'a': state->mode = GZ_APPEND; break; #endif case '+': /* can't read and write at the same time */ free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; #ifdef O_CLOEXEC case 'e': cloexec = 1; break; #endif #ifdef O_EXCL case 'x': exclusive = 1; break; #endif case 'f': state->strategy = Z_FILTERED; break; case 'h': state->strategy = Z_HUFFMAN_ONLY; break; case 'R': state->strategy = Z_RLE; break; case 'F': state->strategy = Z_FIXED; break; case 'T': state->direct = 1; break; default: /* could consider as an error, but just ignore */ ; } mode++; } /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { free(state); return NULL; } /* can't force transparent read */ if (state->mode == GZ_READ) { if (state->direct) { free(state); return NULL; } state->direct = 1; /* for empty file */ } /* save the path name for error messages */ #ifdef _WIN32 if (fd == -2) { len = wcstombs(NULL, path, 0); if (len == (size_t)-1) len = 0; } else #endif len = strlen((const char *)path); state->path = (char *)malloc(len + 1); if (state->path == NULL) { free(state); return NULL; } #ifdef _WIN32 if (fd == -2) if (len) wcstombs(state->path, path, len + 1); else *(state->path) = 0; else #endif #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(state->path, len + 1, "%s", (const char *)path); #else strcpy(state->path, path); #endif /* compute the flags for open() */ oflag = #ifdef O_LARGEFILE O_LARGEFILE | #endif #ifdef O_BINARY O_BINARY | #endif #ifdef O_CLOEXEC (cloexec ? O_CLOEXEC : 0) | #endif (state->mode == GZ_READ ? O_RDONLY : (O_WRONLY | O_CREAT | #ifdef O_EXCL (exclusive ? O_EXCL : 0) | #endif (state->mode == GZ_WRITE ? O_TRUNC : O_APPEND))); /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( #ifdef _WIN32 fd == -2 ? _wopen(path, oflag, 0666) : #endif open((const char *)path, oflag, 0666)); if (state->fd == -1) { free(state->path); free(state); return NULL; } if (state->mode == GZ_APPEND) state->mode = GZ_WRITE; /* simplify later checks */ /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { state->start = LSEEK(state->fd, 0, SEEK_CUR); if (state->start == -1) state->start = 0; } /* initialize stream */ gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen64(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzdopen(fd, mode) int fd; const char *mode; { char *path; /* identifier for error messages */ gzFile gz; if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ #else sprintf(path, "", fd); /* for debugging */ #endif gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ #ifdef _WIN32 gzFile ZEXPORT gzopen_w(path, mode) const wchar_t *path; const char *mode; { return gz_open(path, -2, mode); } #endif /* -- see zlib.h -- */ int ZEXPORT gzbuffer(file, size) gzFile file; unsigned size; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* make sure we haven't already allocated memory */ if (state->size != 0) return -1; /* check and set requested size */ if (size < 2) size = 2; /* need two bytes to check magic header */ state->want = size; return 0; } /* -- see zlib.h -- */ int ZEXPORT gzrewind(file) gzFile file; { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ if (LSEEK(state->fd, state->start, SEEK_SET) == -1) return -1; gz_reset(state); return 0; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzseek64(file, offset, whence) gzFile file; z_off64_t offset; int whence; { unsigned n; z_off64_t ret; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* check that there's no error */ if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* can only seek from start or relative to current position */ if (whence != SEEK_SET && whence != SEEK_CUR) return -1; /* normalize offset to a SEEK_CUR specification */ if (whence == SEEK_SET) offset -= state->x.pos; else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; state->eof = 0; state->past = 0; state->seek = 0; gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; state->x.pos += offset; return state->x.pos; } /* calculate skip amount, rewinding if needed for back seek when reading */ if (offset < 0) { if (state->mode != GZ_READ) /* writing -- can't go backwards */ return -1; offset += state->x.pos; if (offset < 0) /* before start of file! */ return -1; if (gzrewind(file) == -1) /* rewind, then skip to offset */ return -1; } /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; offset -= n; } /* request skip (if not zero) */ if (offset) { state->seek = 1; state->skip = offset; } return state->x.pos + offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzseek(file, offset, whence) gzFile file; z_off_t offset; int whence; { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gztell64(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* return position */ return state->x.pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ z_off_t ZEXPORT gztell(file) gzFile file; { z_off64_t ret; ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzoffset64(file) gzFile file; { z_off64_t offset; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* compute and return effective offset in file */ offset = LSEEK(state->fd, 0, SEEK_CUR); if (offset == -1) return -1; if (state->mode == GZ_READ) /* reading */ offset -= state->strm.avail_in; /* don't count buffered input */ return offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzoffset(file) gzFile file; { z_off64_t ret; ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ int ZEXPORT gzeof(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; /* return end-of-file state */ return state->mode == GZ_READ ? state->past : 0; } /* -- see zlib.h -- */ const char * ZEXPORT gzerror(file, errnum) gzFile file; int *errnum; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); } /* -- see zlib.h -- */ void ZEXPORT gzclearerr(file) gzFile file; { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return; /* clear error and end-of-file */ if (state->mode == GZ_READ) { state->eof = 0; state->past = 0; } gz_error(state, Z_OK, NULL); } /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ void ZLIB_INTERNAL gz_error(state, err, msg) gz_statep state; int err; const char *msg; { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) free(state->msg); state->msg = NULL; } /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ if (err != Z_OK && err != Z_BUF_ERROR) state->x.have = 0; /* set error code, and if no message, then done */ state->err = err; if (msg == NULL) return; /* for an out of memory error, return literal string when requested */ if (err == Z_MEM_ERROR) return; /* construct error message with path */ if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { state->err = Z_MEM_ERROR; return; } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif return; } #ifndef INT_MAX /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ unsigned ZLIB_INTERNAL gz_intmax() { unsigned p, q; p = 1; do { q = p; p <<= 1; p++; } while (p > q); return q >> 1; } #endif golly-2.7-src/gui-web/zlib/zutil.c0000644000175000017500000001636612536111364014046 00000000000000/* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #ifndef Z_SOLO # include "gzguts.h" #endif #ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ #endif z_const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ "file error", /* Z_ERRNO (-1) */ "stream error", /* Z_STREAM_ERROR (-2) */ "data error", /* Z_DATA_ERROR (-3) */ "insufficient memory", /* Z_MEM_ERROR (-4) */ "buffer error", /* Z_BUF_ERROR (-5) */ "incompatible version",/* Z_VERSION_ERROR (-6) */ ""}; const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; } uLong ZEXPORT zlibCompileFlags() { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef DEBUG flags += 1 << 8; #endif #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif #ifdef ZLIB_WINAPI flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif #ifdef NO_GZIP flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; #endif #ifdef FASTEST flags += 1L << 21; #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifdef NO_vsnprintf flags += 1L << 25; # ifdef HAS_vsprintf_void flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void flags += 1L << 26; # endif # endif #else flags += 1L << 24; # ifdef NO_snprintf flags += 1L << 25; # ifdef HAS_sprintf_void flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void flags += 1L << 26; # endif # endif #endif return flags; } #ifdef DEBUG # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; void ZLIB_INTERNAL z_error (m) char *m; { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char * ZEXPORT zError(err) int err; { return ERR_MSG(err); } #if defined(_WIN32_WCE) /* The Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ int errno = 0; #endif #ifndef HAVE_MEMCPY void ZLIB_INTERNAL zmemcpy(dest, source, len) Bytef* dest; const Bytef* source; uInt len; { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } int ZLIB_INTERNAL zmemcmp(s1, s2, len) const Bytef* s1; const Bytef* s2; uInt len; { uInt j; for (j = 0; j < len; j++) { if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; } return 0; } void ZLIB_INTERNAL zmemzero(dest, len) Bytef* dest; uInt len; { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } #endif #ifndef Z_SOLO #ifdef SYS16BIT #ifdef __TURBOC__ /* Turbo C in 16-bit mode */ # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes * and farmalloc(64K) returns a pointer with an offset of 8, so we * must fix the pointer. Warning: the pointer must be put back to its * original form in order to free it, use zcfree(). */ #define MAX_PTR 10 /* 10*64K = 640K */ local int next_ptr = 0; typedef struct ptr_table_s { voidpf org_ptr; voidpf new_ptr; } ptr_table; local ptr_table table[MAX_PTR]; /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) { voidpf buf = opaque; /* just to make some compilers happy */ ulg bsize = (ulg)items*size; /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ if (bsize < 65520L) { buf = farmalloc(bsize); if (*(ush*)&buf != 0) return buf; } else { buf = farmalloc(bsize + 16L); } if (buf == NULL || next_ptr >= MAX_PTR) return NULL; table[next_ptr].org_ptr = buf; /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { int n; if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; } /* Find the original pointer */ for (n = 0; n < next_ptr; n++) { if (ptr != table[n].new_ptr) continue; farfree(table[n].org_ptr); while (++n < next_ptr) { table[n-1] = table[n]; } next_ptr--; return; } ptr = opaque; /* just to make some compilers happy */ Assert(0, "zcfree: ptr not found"); } #endif /* __TURBOC__ */ #ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) { if (opaque) opaque = 0; /* to make compiler happy */ return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { if (opaque) opaque = 0; /* to make compiler happy */ _hfree(ptr); } #endif /* M_I86 */ #endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC extern voidp malloc OF((uInt size)); extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) voidpf opaque; unsigned items; unsigned size; { if (opaque) items += size - size; /* make compiler happy */ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree (opaque, ptr) voidpf opaque; voidpf ptr; { free(ptr); if (opaque) return; /* make compiler happy */ } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ golly-2.7-src/gui-web/Makefile0000755000175000017500000004424412536111364013232 00000000000000# Makefile for creating web app version of Golly using Emscripten. # Type "emmake make" to build golly.html and golly.js. SOURCES = main.cpp webcalls.cpp \ ../gollybase/bigint.cpp \ ../gollybase/generationsalgo.cpp \ ../gollybase/ghashbase.cpp \ ../gollybase/ghashdraw.cpp \ ../gollybase/hlifealgo.cpp \ ../gollybase/hlifedraw.cpp \ ../gollybase/jvnalgo.cpp \ ../gollybase/lifealgo.cpp \ ../gollybase/lifepoll.cpp \ ../gollybase/liferender.cpp \ ../gollybase/liferules.cpp \ ../gollybase/qlifealgo.cpp \ ../gollybase/qlifedraw.cpp \ ../gollybase/readpattern.cpp \ ../gollybase/ruleloaderalgo.cpp \ ../gollybase/ruletable_algo.cpp \ ../gollybase/ruletreealgo.cpp \ ../gollybase/util.cpp \ ../gollybase/viewport.cpp \ ../gollybase/writepattern.cpp \ ../gui-common/algos.cpp \ ../gui-common/control.cpp \ ../gui-common/file.cpp \ ../gui-common/layer.cpp \ ../gui-common/prefs.cpp \ ../gui-common/render.cpp \ ../gui-common/select.cpp \ ../gui-common/status.cpp \ ../gui-common/undo.cpp \ ../gui-common/utils.cpp \ ../gui-common/view.cpp \ ../gui-common/MiniZip/ioapi.c \ ../gui-common/MiniZip/unzip.c \ ../gui-common/MiniZip/zip.c \ zlib/adler32.c \ zlib/compress.c \ zlib/crc32.c \ zlib/deflate.c \ zlib/gzclose.c \ zlib/gzlib.c \ zlib/gzread.c \ zlib/gzwrite.c \ zlib/infback.c \ zlib/inffast.c \ zlib/inflate.c \ zlib/inftrees.c \ zlib/trees.c \ zlib/uncompr.c \ zlib/zutil.c OBJECTS = main.o webcalls.o \ ../gollybase/bigint.o \ ../gollybase/generationsalgo.o \ ../gollybase/ghashbase.o \ ../gollybase/ghashdraw.o \ ../gollybase/hlifealgo.o \ ../gollybase/hlifedraw.o \ ../gollybase/jvnalgo.o \ ../gollybase/lifealgo.o \ ../gollybase/lifepoll.o \ ../gollybase/liferender.o \ ../gollybase/liferules.o \ ../gollybase/qlifealgo.o \ ../gollybase/qlifedraw.o \ ../gollybase/readpattern.o \ ../gollybase/ruleloaderalgo.o \ ../gollybase/ruletable_algo.o \ ../gollybase/ruletreealgo.o \ ../gollybase/util.o \ ../gollybase/viewport.o \ ../gollybase/writepattern.o \ ../gui-common/algos.o \ ../gui-common/control.o \ ../gui-common/file.o \ ../gui-common/layer.o \ ../gui-common/prefs.o \ ../gui-common/render.o \ ../gui-common/select.o \ ../gui-common/status.o \ ../gui-common/undo.o \ ../gui-common/utils.o \ ../gui-common/view.o \ ../gui-common/MiniZip/ioapi.o \ ../gui-common/MiniZip/unzip.o \ ../gui-common/MiniZip/zip.o \ zlib/adler32.o \ zlib/compress.o \ zlib/crc32.o \ zlib/deflate.o \ zlib/gzclose.o \ zlib/gzlib.o \ zlib/gzread.o \ zlib/gzwrite.o \ zlib/infback.o \ zlib/inffast.o \ zlib/inflate.o \ zlib/inftrees.o \ zlib/trees.o \ zlib/uncompr.o \ zlib/zutil.o CFLAGS = -Izlib -Wall -Wextra -Wno-unused-parameter -Wno-implicit-function-declaration -O2 CXXFLAGS = -Izlib -I. -I../gollybase -I../gui-common -I../gui-common/MiniZip \ -DVERSION=0.8 -DZLIB -DWEB_GUI -Wall -Wextra -Wno-unused-parameter -O2 # note that using -O2 results in a much smaller golly.js and no .map file TARGET = golly.html all: $(TARGET) $(TARGET): $(OBJECTS) jslib.js shell.html $(CXX) $(CXXFLAGS) --js-library jslib.js --shell-file shell.html \ --preload-file ../Patterns@/Patterns \ --preload-file ../Rules@/Rules \ --preload-file Help \ --preload-file ../gui-common/Help/intro.html@/Help/intro.html \ --preload-file ../gui-common/Help/tips.html@/Help/tips.html \ --preload-file ../gui-common/Help/archives.html@/Help/archives.html \ --preload-file ../gui-common/Help/refs.html@/Help/refs.html \ --preload-file ../gui-common/Help/formats.html@/Help/formats.html \ --preload-file ../gui-common/Help/bounded.html@/Help/bounded.html \ --preload-file ../gui-common/Help/credits.html@/Help/credits.html \ --preload-file ../gui-common/Help/algos.html@/Help/algos.html \ --preload-file ../gui-common/Help/Algorithms@/Help/Algorithms \ --preload-file ../gui-common/Help/Lexicon@/Help/Lexicon \ -s TOTAL_MEMORY=300000000 \ -s EXPORTED_FUNCTIONS="[ '_ClearStatus', '_NewUniverse', '_ResizeCanvas', \ '_SetViewport', '_StartStop', '_Next', '_Step', '_GoSlower', '_GoFaster', '_StepBy1', \ '_Undo', '_Redo', '_Fit', '_ZoomOut', '_ZoomIn', '_Scale1to1', '_Reset', \ '_ToggleIcons', '_ModeChanged', '_StateChanged', '_DoMenuItem', '_UpdateMenuItems', \ '_Paste', '_PasteAction', '_SelectionAction', '_OpenClickedFile', '_OpenClipboard', \ '_ToggleAutoFit', '_OverCanvas', '_OnKeyChanged', '_OnMouseWheel', '_Info', '_CloseInfo', \ '_Help', '_DoHelpClick', '_HelpBack', '_HelpNext', '_HelpContents', '_CloseHelp', \ '_FileCreated', '_CancelProgress', '_CancelOpen', '_SaveFile', '_CancelSave', \ '_StorePrefs', '_CancelPrefs', '_SaveLocalPrefs', '_FullScreen', '_ExitFullScreen', \ '_UnsavedChanges' ]" \ -o $@ $(LDFLAGS) $(OBJECTS) # better to use -s ALLOW_MEMORY_GROWTH=1 instead of setting TOTAL_MEMORY??? clean: $(RM) $(OBJECTS) $(TARGET) golly.js golly.data depend: @$(CXX) $(CXXFLAGS) -MM $(SOURCES) # type "emmake make depend" to generate these dependencies: main.o: main.cpp ../gollybase/bigint.h ../gollybase/lifealgo.h \ ../gollybase/viewport.h ../gollybase/liferender.h \ ../gollybase/lifepoll.h ../gollybase/readpattern.h \ ../gollybase/platform.h ../gollybase/qlifealgo.h \ ../gollybase/liferules.h ../gollybase/hlifealgo.h \ ../gollybase/jvnalgo.h ../gollybase/ghashbase.h \ ../gollybase/generationsalgo.h ../gollybase/ruleloaderalgo.h \ ../gollybase/ruletable_algo.h ../gollybase/ruletreealgo.h \ ../gui-common/algos.h ../gui-common/utils.h ../gui-common/prefs.h \ ../gui-common/layer.h ../gui-common/select.h ../gui-common/control.h \ ../gui-common/file.h ../gollybase/writepattern.h ../gui-common/view.h \ ../gui-common/status.h ../gui-common/undo.h ../gui-common/render.h \ webcalls.h webcalls.o: webcalls.cpp ../gollybase/util.h ../gui-common/utils.h \ ../gui-common/algos.h ../gollybase/lifealgo.h ../gollybase/bigint.h \ ../gollybase/viewport.h ../gollybase/liferender.h \ ../gollybase/lifepoll.h ../gollybase/readpattern.h \ ../gollybase/platform.h ../gui-common/prefs.h ../gui-common/layer.h \ ../gui-common/select.h ../gui-common/control.h ../gui-common/file.h \ ../gollybase/writepattern.h ../gui-common/view.h \ ../gui-common/status.h ../gui-common/undo.h webcalls.h bigint.o: ../gollybase/bigint.cpp ../gollybase/bigint.h \ ../gollybase/util.h generationsalgo.o: ../gollybase/generationsalgo.cpp \ ../gollybase/generationsalgo.h ../gollybase/ghashbase.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h ghashbase.o: ../gollybase/ghashbase.cpp ../gollybase/ghashbase.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h ../gollybase/util.h ghashdraw.o: ../gollybase/ghashdraw.cpp ../gollybase/ghashbase.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h ../gollybase/util.h hlifealgo.o: ../gollybase/hlifealgo.cpp ../gollybase/hlifealgo.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h ../gollybase/util.h hlifedraw.o: ../gollybase/hlifedraw.cpp ../gollybase/hlifealgo.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h jvnalgo.o: ../gollybase/jvnalgo.cpp ../gollybase/jvnalgo.h \ ../gollybase/ghashbase.h ../gollybase/lifealgo.h ../gollybase/bigint.h \ ../gollybase/viewport.h ../gollybase/liferender.h \ ../gollybase/lifepoll.h ../gollybase/readpattern.h \ ../gollybase/platform.h ../gollybase/liferules.h lifealgo.o: ../gollybase/lifealgo.cpp ../gollybase/lifealgo.h \ ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h lifepoll.o: ../gollybase/lifepoll.cpp ../gollybase/lifepoll.h \ ../gollybase/util.h liferender.o: ../gollybase/liferender.cpp ../gollybase/liferender.h liferules.o: ../gollybase/liferules.cpp ../gollybase/liferules.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h ../gollybase/util.h qlifealgo.o: ../gollybase/qlifealgo.cpp ../gollybase/qlifealgo.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h ../gollybase/util.h qlifedraw.o: ../gollybase/qlifedraw.cpp ../gollybase/qlifealgo.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h ../gollybase/util.h readpattern.o: ../gollybase/readpattern.cpp ../gollybase/readpattern.h \ ../gollybase/bigint.h ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/platform.h ../gollybase/liferules.h ../gollybase/util.h \ zlib/zlib.h zlib/zconf.h ruleloaderalgo.o: ../gollybase/ruleloaderalgo.cpp \ ../gollybase/ruleloaderalgo.h ../gollybase/ghashbase.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h ../gollybase/ruletable_algo.h \ ../gollybase/ruletreealgo.h ../gollybase/util.h ruletable_algo.o: ../gollybase/ruletable_algo.cpp \ ../gollybase/ruletable_algo.h ../gollybase/ghashbase.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/liferules.h ../gollybase/util.h ruletreealgo.o: ../gollybase/ruletreealgo.cpp ../gollybase/ruletreealgo.h \ ../gollybase/ghashbase.h ../gollybase/lifealgo.h ../gollybase/bigint.h \ ../gollybase/viewport.h ../gollybase/liferender.h \ ../gollybase/lifepoll.h ../gollybase/readpattern.h \ ../gollybase/platform.h ../gollybase/liferules.h ../gollybase/util.h util.o: ../gollybase/util.cpp ../gollybase/util.h viewport.o: ../gollybase/viewport.cpp ../gollybase/viewport.h \ ../gollybase/bigint.h ../gollybase/lifealgo.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h writepattern.o: ../gollybase/writepattern.cpp ../gollybase/writepattern.h \ ../gollybase/lifealgo.h ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h ../gollybase/util.h \ zlib/zlib.h zlib/zconf.h algos.o: ../gui-common/algos.cpp ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/qlifealgo.h ../gollybase/liferules.h \ ../gollybase/hlifealgo.h ../gollybase/jvnalgo.h \ ../gollybase/ghashbase.h ../gollybase/generationsalgo.h \ ../gollybase/ruleloaderalgo.h ../gollybase/ruletable_algo.h \ ../gollybase/ruletreealgo.h ../gui-common/utils.h \ ../gui-common/prefs.h ../gui-common/layer.h ../gui-common/algos.h \ ../gui-common/select.h control.o: ../gui-common/control.cpp ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/qlifealgo.h ../gollybase/liferules.h \ ../gollybase/hlifealgo.h ../gollybase/writepattern.h \ ../gollybase/util.h ../gui-common/utils.h ../gui-common/prefs.h \ ../gui-common/status.h ../gui-common/file.h ../gui-common/algos.h \ ../gui-common/layer.h ../gui-common/select.h ../gui-common/view.h \ ../gui-common/undo.h ../gui-common/control.h webcalls.h file.o: ../gui-common/file.cpp webcalls.h ../gui-common/MiniZip/zip.h \ zlib/zlib.h zlib/zconf.h ../gui-common/MiniZip/ioapi.h \ ../gui-common/MiniZip/unzip.h ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/qlifealgo.h ../gollybase/liferules.h \ ../gollybase/hlifealgo.h ../gollybase/writepattern.h \ ../gui-common/utils.h ../gui-common/prefs.h ../gui-common/status.h \ ../gui-common/algos.h ../gui-common/layer.h ../gui-common/select.h \ ../gui-common/control.h ../gui-common/view.h ../gui-common/undo.h \ ../gui-common/file.h layer.o: ../gui-common/layer.cpp ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/qlifealgo.h ../gollybase/liferules.h \ ../gollybase/hlifealgo.h ../gollybase/util.h ../gui-common/utils.h \ ../gui-common/prefs.h ../gui-common/algos.h ../gui-common/control.h \ ../gui-common/select.h ../gui-common/file.h \ ../gollybase/writepattern.h ../gui-common/view.h ../gui-common/undo.h \ ../gui-common/layer.h prefs.o: ../gui-common/prefs.cpp ../gollybase/lifealgo.h \ ../gollybase/bigint.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h ../gollybase/util.h \ ../gui-common/utils.h ../gui-common/status.h ../gui-common/algos.h \ ../gui-common/layer.h ../gui-common/select.h ../gui-common/prefs.h \ webcalls.h render.o: ../gui-common/render.cpp ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gui-common/utils.h ../gui-common/prefs.h ../gui-common/algos.h \ ../gui-common/layer.h ../gui-common/select.h ../gui-common/view.h \ ../gui-common/render.h select.o: ../gui-common/select.cpp ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gui-common/utils.h ../gui-common/prefs.h ../gui-common/status.h \ ../gui-common/undo.h ../gui-common/select.h ../gui-common/algos.h \ ../gui-common/layer.h ../gui-common/view.h ../gui-common/control.h \ ../gui-common/file.h ../gollybase/writepattern.h webcalls.h status.o: ../gui-common/status.cpp ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gui-common/utils.h ../gui-common/prefs.h ../gui-common/algos.h \ ../gui-common/layer.h ../gui-common/select.h ../gui-common/view.h \ ../gui-common/status.h webcalls.h undo.o: ../gui-common/undo.cpp ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/writepattern.h ../gui-common/select.h \ ../gui-common/utils.h ../gui-common/view.h ../gui-common/algos.h \ ../gui-common/layer.h ../gui-common/prefs.h ../gui-common/control.h \ ../gui-common/file.h ../gui-common/undo.h utils.o: ../gui-common/utils.cpp ../gollybase/lifepoll.h \ ../gollybase/util.h ../gui-common/prefs.h ../gui-common/utils.h \ webcalls.h view.o: ../gui-common/view.cpp ../gollybase/bigint.h \ ../gollybase/lifealgo.h ../gollybase/viewport.h \ ../gollybase/liferender.h ../gollybase/lifepoll.h \ ../gollybase/readpattern.h ../gollybase/platform.h \ ../gollybase/qlifealgo.h ../gollybase/liferules.h \ ../gollybase/hlifealgo.h ../gui-common/utils.h ../gui-common/prefs.h \ ../gui-common/status.h ../gui-common/render.h ../gui-common/undo.h \ ../gui-common/select.h ../gui-common/algos.h ../gui-common/layer.h \ ../gui-common/control.h ../gui-common/file.h \ ../gollybase/writepattern.h ../gui-common/view.h webcalls.h ioapi.o: ../gui-common/MiniZip/ioapi.c zlib/zlib.h zlib/zconf.h \ ../gui-common/MiniZip/ioapi.h unzip.o: ../gui-common/MiniZip/unzip.c zlib/zlib.h zlib/zconf.h \ ../gui-common/MiniZip/unzip.h ../gui-common/MiniZip/ioapi.h \ ../gui-common/MiniZip/crypt.h zip.o: ../gui-common/MiniZip/zip.c zlib/zlib.h zlib/zconf.h \ ../gui-common/MiniZip/zip.h ../gui-common/MiniZip/ioapi.h \ ../gui-common/MiniZip/crypt.h adler32.o: zlib/adler32.c zlib/zutil.h zlib/zlib.h zlib/zconf.h compress.o: zlib/compress.c zlib/zlib.h zlib/zconf.h crc32.o: zlib/crc32.c zlib/zutil.h zlib/zlib.h zlib/zconf.h zlib/crc32.h deflate.o: zlib/deflate.c zlib/deflate.h zlib/zutil.h zlib/zlib.h \ zlib/zconf.h gzclose.o: zlib/gzclose.c zlib/gzguts.h zlib/zlib.h zlib/zconf.h gzlib.o: zlib/gzlib.c zlib/gzguts.h zlib/zlib.h zlib/zconf.h gzread.o: zlib/gzread.c zlib/gzguts.h zlib/zlib.h zlib/zconf.h gzwrite.o: zlib/gzwrite.c zlib/gzguts.h zlib/zlib.h zlib/zconf.h infback.o: zlib/infback.c zlib/zutil.h zlib/zlib.h zlib/zconf.h \ zlib/inftrees.h zlib/inflate.h zlib/inffast.h zlib/inffixed.h inffast.o: zlib/inffast.c zlib/zutil.h zlib/zlib.h zlib/zconf.h \ zlib/inftrees.h zlib/inflate.h zlib/inffast.h inflate.o: zlib/inflate.c zlib/zutil.h zlib/zlib.h zlib/zconf.h \ zlib/inftrees.h zlib/inflate.h zlib/inffast.h zlib/inffixed.h inftrees.o: zlib/inftrees.c zlib/zutil.h zlib/zlib.h zlib/zconf.h \ zlib/inftrees.h trees.o: zlib/trees.c zlib/deflate.h zlib/zutil.h zlib/zlib.h \ zlib/zconf.h zlib/trees.h uncompr.o: zlib/uncompr.c zlib/zlib.h zlib/zconf.h zutil.o: zlib/zutil.c zlib/zutil.h zlib/zlib.h zlib/zconf.h zlib/gzguts.h golly-2.7-src/gui-web/beep.wav0000644000175000017500000001243012536111364013211 00000000000000RIFFWAVEfmt +"Vdataë5ÿOþÄý9ýZüú2öäô‚õ˜÷¯øÅùÜúóûŽý0ÿ*”"ã kûðdyO!ô Æ è/ûÌöBôYóëð0íëòé0ë†ï³ñËôøuúùü¯Bo¯ µm[BÓ!W ì\ÛüÑøêõóPî4êMçfä‚åièPë7î‡ò}÷5úý ‡ n +ù# Õz@{r ‹ £íòý¯úà÷ÂôôîSëlè…åäJå1èë~ðæôÈ÷úvÿA(< €ë)E^w¡Ó  Ûiœý'ú@÷;ô'ï‹ëmèÌä€äæré@ï~ò.õ,ø(þ"ýµÝ ÿæÍèd}–ßÈá ú½mÿ†üÁùöŸðªíÃê`çLâóãÚæúélïó÷õÞø‰þ«’yt Ç®•zœµ€™ dËãþÍû ÷Jò¿ïáìtèeã«â¼äÅè‰îñØóq÷ýL3o ¨v;€ÔíŒK¸ Ð Óþ5ûœözñðîìäçŽâHã‡çkìRï‹ñÀõûîýÔ÷¢ ‰ p/ý&¹—É={à @az”ýCøôñ8î!éjäƒáóâç3ìïò:ö”ûªþˆV RÊÀŽî*C\uÙ ÅÀÙeÿ—ù%ö>ó-ð_ê‰æ¢ã»àÚåêüìãïõžùXü?ÿì̳ G‚è϶D{”­ > :Õþù]õ¸ò‹ðÎêÀæªädåöçÝêÿípó÷ùùàü­” { yɰ—€š³Ì}u `oQ¤úì÷õtñìßèøåÔãæ¾è¥ë–îô½÷úhýu\ C ‘y`¸Ñêל µ ÎÏýú3÷Îòåíþêè„å¸ãŸæ†éí3ò;õ=øÒû êÊ ˜sZAÔð "?Ô î5~yü’ùö6òí6êå â€ãhæëñ6óöUúÒÿ¸ŸŒ ZŸªÅ“(4ö Œ ¥Ð˜þºûùÄó;ïTìméŒäbáIä0ç­ëþðåóÌöÒúY@ ƒ ôU#G@y‘ª  9õþÐúõäñsïŒìæŸâ*âåpê³îFñ-ô(ùûýáõ„„ å™ ~¯áÉâ  ßm‡ý‚úâôPñ«îÄë9æãdã2éÀìƒïòê÷ÝûÄþª"x SÝÚ”{€íÏèQ4 ³Ìæÿýû/ö1ó€ðEíwçäÕâõãÃé‰íRðÜòOøeüLÿ2MÀ §Žk\C€î ; Òë;ý6øOõhò2îé3æLãpãƒèjëQîÂñÖöúíü'õ¡ ˆ o-=$ š&>W£ `{ýî÷õ òòíRèkå€ädåKè2ë²ïõç÷©ú½þ›‚i í €€µ]o[ ¨ ÁÚhþ ú&÷?ô/ïqêŠç£äcä,æéúëBðÄõ}øWû;ÿÞ² çuJc|ªÜÇ ú²åÿFüEùDö/ñí©êÂç1ääõæÜé½î*óöøø½ýŬ“Å áȯ–}›´0¿ 'ˆÿãûüøö¶ðÇì@érããÖäùçÇíJñòóÙö€üŒVkk r©oÓW#ö 6 Eê2þ[ûµ÷òïÿì°éáã)äžæ‰éúî™ò#õ­÷ýWɃ és{@Õ•OÅ: Ÿ^¦ý[ùlô…ñêî?ëPæiãäLèî‡ðólö¯ûìþ£v¹ . ¸CÂD)”¤t %‹Óÿýù/ô¥ñðì³è†æåçZìûïònõFúÿü–ÿïÔs ý ü´éÔ zΡ äRÈ>ÿÎú÷àôVò”î¦ê¿ç+èØêèîrñ´óÕöPû«ýøC » Êø%g€R%p pyüËù¼÷Žõ÷ñ4ïíÙêñìWï0ñ]óÒö7úeü’þâ¢¡Æ m ¡Îûž·|O Û ¬­œ üñù˜÷Tô òðfî¬í+ïXñ‰ó*÷ˆùBûAý¬f7ë Ê ÷É€Óõ u X¶ó†æýüNúWøõó„ñ€ð€ðÁñuóèôøiú ü­ýÁp´M  Õ ¦ë¸è @ Ú8–Sÿ±ý8üúQ÷Ýõ$ôTòƒð•ñó1õøÀùJûý& €ôu[ Î B Vâ o  ÈTáµ;ÿÇýTühúí÷yöJô€ò€ò€ó’õ.øDù¤ú›üKÿ½°:y¿Y ã € ò } ó4ïªKIÜþ—ýAûùø•özô•òòò:ô/öøâù'ûçü ÿõ:Éäž  Š € 8 ® 'æˆÏ=ùÿ¦þîû*úåø ÷‰õ½ó©òÀóôõí÷ùJú]ü”þÙÿg¬Ïm ÷ n  i ß’evÖ’ÿMþÏûúzøðõšôƒó¯ò9õ÷Jø2ù¢ûvýÄþ6ŠŠÍãÓë _ ) ò T ='Ž8ó® ÿÄü`ûú·øŠöéôÞóó ö­÷ÄøÚù1üþ#ÿg™¡¸ ¥ Ð C – € a îøÑ¸Ïÿƒý=üøú:ùñöÚõÄôTôkõö±÷$ù€ûýFþ“ÿî”Ù  ´ ' d ñ ~–Ä®iM–ÿ[ýü&úLø÷ïõõ¿ôÖõ;÷ðøÞú#üGýÊþ%v»&%±û  b À © “M¥‡BLþ3ýîûú1ø÷°õ2õªõÁöØ÷JùFû‹ü²ýÿxµX]E•M z k U ò–Q:§7ÿ!þ ýºú8ùFø0÷1õô•õ¬ö¥ø™ú°ûÇü”þ³Êàn¤» Ø ê ŸDæÏ²„ ÿ«ý}ûHúIù6øö:õjõ€öøîùûü#þÈÿÞõ×¢¹¢L  q • þèÑ»Iøÿáþ•ýgûúùß÷²õõUõlö„øú0ûFü9þóÿ@¶Íä¡ ò • Õ&=U ÅÝÍÿ,þ%ü=û2ú¶ø‰öÊõ¹õuötø†ù„úµûâý'ÿ4VƸÏü ó 9 ¿('Š–®¢ÿþôûÞúKù°÷šöƒõ)ö$ø ùôùKûFý\þUÿ†„¶µ»‹Ðç þ Ö½§ÈPcLŽþðüüóúnùÅ÷¯öæõöøIùDú¥û¤ýœþžÿßÞû\L4< ä ‡ €‚e8 ò#ÿêýõüÞû!úÉøÚ÷Äö÷Ù÷ÁøØùcûúüâýÊþ: e5#ïV ¼Ó×ÛãÍÿ»ýœüú‚ù¯øï÷Øö?÷9øóø°úü(ýþÖÿ`H0²Ne'°ä*M =TlHyÿuþŒýˆü¸ú”ù½øø¥÷ò÷¶øžùMû¯ü—ýþ w>‡oX ¬ ëÕ^ö&¼.ÿFþûü6ûMúeùGø¥ö*÷ý÷ ùÙúõûÝüÊýlÿ•}eò6z u ˆŸßŸèÿÿý/üGûŒúHùØ÷÷œ÷ÖøúIû$üWý(ÿ騍–dWù¾È~Aa§ »ÿÿ‘ýüûZú@ùó÷—÷2øaùû»û’ü©ýKÿ!NÚÈ–8#€!€¢èxZr‹ÿñýÕüübûéù®øøø ùzú4ûíû(ý©þ‘ÿTo ñ»¶X(NÁ0v¹ rþýãüüŸú“ù¼øøùúìú¦ûÿüþØþÀÿ O8óf ì®Æþ –¥×üÿˆþ…ý±üîûzúdù˜ø ø*ù=úû¢ûý^þJÿ¼¸q+a_Ò¹FÒ_Jìþ2þyý}ü ûKú’ù ù9ùÝù–ú`ûÓüÄý}þ7ÿ ªco‘K‡Íô æštÿºþþÍüûÓúúGù©ø¿ùú~ûÂü|ý6þÿW"ܦëɃ=öÏ[+(n´—‚ÿÈþþýÛû!ûgúÂùMùúÁú¦ûëü®ýµþâÿšTIˆAûÝ"ÇSpÈ9ô\ÿÑþ¡ý¢üïûcûMú£ùú‹ú‰û¢ü-ýàýÝþÌe0u­…Ê‹f!=“Í×ÿÿ¾ýýpü¯ûjú¢ùjùõù+û%ü×übýþŒÿCϵ¥1æÏÓ^Dÿtè/êF¼ÿÿ×ýýüüðú-úêù£ú¬ûüýËýÆþ¯ÿ9uPÛfŠ}1• SfhÜ,Mÿ;þ°ý%ýeü ûƒú(ú0úuûOü÷ü„ý›þYÿäÿotEÐ\O2¾À” ;2§¸ÿÑþFþºýÞüäûXûÍúÔú‹ûü¡üXýoþÿŽÿ2Iï{ ó5ï,uê^gˆüq«ÿÛþPþÅý ý.ü£ûûûü‹üúü„ýšþÿÇÿÎZÃaxwÊø‹m„ÞRÇåÿ1ÿ¦þþDý„üûûžû€ûœûùûü?ýþ£þ.ÿàÿÄO¼?(¼0€€œ>V¨°ÿ<ÿ¦þ½ý<ýÎüCüŠû•ûürüEýþ‰þæþ¦ÿnùXÛgÌRökxþŒ/‘ÿÿ·þÏý$ý¦üIüÂû²ûü¡ütý7þÃþ}ÿ˜ô£.‘Ê@@ã1j °'rçÿ}ÿñþþ§ýJýÚü üü+ü’üzýþ^þ»þ›ÿ4‘î»gÄ!ÜrCêCqJš=áÿHÿ¨þKþîýaý´üWüdüÇü€ýÝý:þ®þhÿÑÿ-”Nà }5·õÇüUüÍ<¡DèÿVÿ¯þRþõýoý»ü^ü€üùü³ýþ¦þPÿ­ÿ ŒC üs-“Øå+¸J¾3Åh ‡ÿÿµþYþÙý_ýýÓü1ýËýúýOþØþ…ÿ³ÿ~8lµ%ß&Ts¹_Lé¦^¦ÿ6ÿíþ¸þÿýƒý3ýý+ýrýÏý,þ¬þ%ÿ‚ÿßÿYÌúRÆEtÅÝ€QžØ“1§ÿ_ÿ ÿÃþ:þåý­ýPýŽýëýKþ×þ!ÿ^ÿ»ÿCšÑ.°D¡À²ƒ*´8 ·G¿ÿ‘ÿDÿôþÅþmþ)þþþ$þRþþ ÿ^ÿŒÿºÿ9–ÅófÐþ-@5ØûÍ~!Åÿ”ÿ0ÿ·þ‰þZþþÃýòý þkþöþ,ÿZÿ˜ÿ#d“ÅPžÍûSg9 ”-þ¡EõÿÆÿ˜ÿRÿûþÌþžþpþAþnþþÖþ3ÿhÿ­ÿ2aŸü,[“ðë¹\ñÂh&øÿÊÿvÿ-ÿþþÐþ‚þ@þ@þkþ²þÿ6ÿeÿ¦ÿ/]ŒºéFt€n@ã´†W)üÿÍÿŸÿpÿBÿÿåþÀþÀþÿ@ÿDÿsÿÂÿ+tÀÀå(€€€dæ°S@,þÿ¡ÿ€ÿtÿEÿ@ÿ@ÿ@ÿ@ÿdÿ€ÿÿ¯ÿÞÿ(V€€¢ÐÿãÀÀ˜j@@ñÿÃÿÀÿ¦ÿ€ÿ€ÿZÿ@ÿDÿrÿ€ÿÿ½ÿìÿ6e€°ÞçÀÀœm@@"éÿÀÿÀÿÀÿÀÿÀÿÀÿÀÿËÿúÿ3@@@l€€€€€€€_@@@%íÿÀÿÀÿÀÿÀÿÀÿÀÿÙÿ@@@3Œgolly-2.7-src/gui-web/Help/0000755000175000017500000000000012536111546012531 500000000000000golly-2.7-src/gui-web/Help/keyboard.html0000644000175000017500000000545412536111364015145 00000000000000

Keyboard Commands

return start/stop generating
space advance 1 generation
- or _ go slower
+ or = go faster
0 set step exponent to 0
1 set scale to 1:1
5 randomly fill selection
[ zoom out
] zoom in
a select all
A remove selection
f fit entire pattern in view
F fit entire selection in view
h show help
i toggle icon mode
l toggle grid lines
m put cell at 0,0 in middle
o open a file on your computer
O open clipboard pattern or rule
p change preferences
r set rule
s save pattern to your computer
t toggle auto fit
v paste
V cancel paste
x flip paste image or selection left-right
y flip paste image or selection top-bottom
> rotate paste image or selection clockwise
< rotate paste image or selection anticlockwise
z undo
Z redo
arrow keys scroll up/down/left/right
shift-arrow scroll NE/SW/NW/SE
golly-2.7-src/gui-web/Help/about.html0000644000175000017500000000121312536111364014444 00000000000000
This is Golly version 0.8 for the Web

© 2014 The Golly Gang:
Andrew Trevorrow, Tom Rokicki, Tim Hutton,
Dave Greene, Jason Summers, Maks Verver, Robert Munafo.



Golly is an open source, cross-platform application for
exploring the Game of Life and other cellular automata.

http://golly.sourceforge.net/
golly-2.7-src/gui-web/Help/help.html0000644000175000017500000000300212536111364014260 00000000000000

Help Dialog

The Help dialog is used to display information on a variety of topics.

Special links

A number of Golly-specific links are used for various purposes:

  • edit:file
    Display the given file in a separate dialog.
  • get:url
    Download the specified file and process it according to its type:
    • A HTML file (.htm or .html) is displayed in the Help dialog. Note that this HTML file can contain get links with partial URLs. For a good example of their use, see the LifeWiki Pattern Archive.
    • A text file (.txt or .doc or a name containing "readme") is displayed in a separate dialog.
    • A zip file's contents are displayed in the Help dialog.
    • A rule file (.rule) is installed and Golly then switches to that rule.
    • A pattern file is loaded and displayed.
  • lexpatt:pattern
    Load the given Life Lexicon pattern and display it.
  • open:file
    Load the given pattern file and display it.
  • rule:rulename
    Load the given rule.
  • unzip:zip:file
    Extract a file from the given zip file and process it in the same manner as a get link (see above). Golly creates unzip links when it opens a zip file and displays its contents in the Help dialog.
golly-2.7-src/gui-web/Help/index.html0000644000175000017500000000164512536111364014452 00000000000000

Table of Contents

golly-2.7-src/gui-web/Help/changes.html0000644000175000017500000000015312536111364014744 00000000000000

Changes

Version 1.0 released !!! 2014

golly-2.7-src/gui-web/Help/problems.html0000644000175000017500000000175112536111364015164 00000000000000

Known Problems

This section lists all known bugs and limitations. If you come across any problems not mentioned below then please report them to Andrew Trevorrow (andrew@trevorrow.com).

  • All editing operations are restricted to cells whose coordinates are within +/- 1 billion. Not much of a limitation really!
  • The QuickLife algorithm has a minor bug that can cause selecting a large pattern to appear to be incorrect. The selection is actually correct but the rectangle is slightly offset (by one pixel).

Note that this version of Golly has a number of significant limitations when compared with the desktop version:

  • No scripting.
  • No multiple layers.
  • No timelines.
  • No auto fit mode.
  • No hyperspeed mode.
  • You can't change the colors, base step, nor origin.
Some of these capabilities might be added in future versions. golly-2.7-src/gui-web/images/0000755000175000017500000000000012536111546013106 500000000000000golly-2.7-src/gui-web/images/favicon.ico0000755000175000017500000000706612536111364015161 00000000000000h& ¨Ž( @ÿÿÿÿD3ÿÿ( @€ÿÿÿÿJÿÿ“§k娿j>?ôðÿ#–ìfÐÃ*ÿÿ£™}òX(ÿ:Ÿµœ<ÿÿä]1nñäñBkÚÍòO› †§°”—»£’¯˜ÿ/ÿÿÿA5ûù>ùøåd7ž®”üOš™~÷T"óH"ÿÿBïë3ÿÿ™À§÷KŸœÿÿÿ)ÿ5”«“ñQ"<öôœ³˜£²—˜ƒ;üû˜¢‰ûH•¾§/þþ:ù÷Bòž&ÿÿ•®•3ýüòLæ[/çb5èh<¡´™ž±–‘©‘ž„œµ›ÿÿ=þüoïâiæÚiÛϘª š˜š€šœ˜ †—½¥òG-ÿÿòIöM:ûùóR!òS#<øö>õóAñ야¤šž„’¬”ÿB5ýý4ûû:÷ö@òïž³™œ°–ñH1ÿÿòAüGýNóM<ÿýøS!òP!=÷õóW'=÷óå\0æc6çi=eÑÄ™Á©—Á©¤±–š¡‡ÿI/ÿÿ1þþ3þþ4þýñL;ûú;ø÷;øõ?ù÷=õò@óðAóï@óîAòíBñíCïìnðãjæÙjÛ΃—«˜À¨–½¦—¼¤ž¶œ’¨‘”ª’”®–“¯—ÿ*ÿ4÷LÿÿöLÿÿÿÿÿÿ!ÿÿ#ÿÿ+ÿÿ,ÿÿå\1.ÿÿ0ÿÿ/ÿþçb60þþæc73þýåd83ýý4ýý;ÿÿçj==þû<üû:ø÷;ù÷:øö;øö;÷õ<øõ<÷õ<÷ô<öó=öó?ôñ@óïAòï@òîAòîBóîAñíBñìoðãjåÙŸ„fÐÄgÐá³™“¨“§Ÿµ›‘¨‘“¬”—Áª—»¢•¼¥>Ã&Å&¶~ª~¶Â&ÅŠŠŠŠŠŠŠŠŠŠŠÅ&ÄWŒ‘ D “<°ÇR e”””””””””””e (J†u$l$©=²Ÿm˜«$XqqqqqqqqqqqX$BwdŠy™ ½ºN`ššššššššššš{‹Â#-›È»œZ6,--,k2‹Â; ššoz»œºN`ššššššššššš{‹Â; ššoz»ž´E€///////////€tÂÂ; ššoz¾bvEOQ55555555555QOÐŽ¶Â; ššoz¡¨9¾Ád¿¿¿¿¿¿‡†[¸··¸‚4¯Â; ššoz‰¢T£¢%%%%%%%%¢¡žHHH+<}Â; ššozÂ%¦§¦¦¦¦¦¦¦¦TT|a·¼00p³¯Â; ššozÂ%¦'''''''''§ 9ÉÍ"P"–cÂ; ššozÂ%¦'''''''''¦¢ÏsiSiAÒÂÂ; ššozÂ%¦'''''''''¦¡ÂN`™{‹Â; ššozÂ%¦'''''''''¦%¿V-nCŠÂ; ššozÂ%¦'''''''''¦%¿5/ššq”ŠÂÎ#-)FÂ%¦'''''''''¦%¿5/ššq”ŠŠy™ Š¡¦'''''''''¦%¿5/ššq”Š¿Óg¥Ì¿¢¦'''''''''¦%¿5/ššq”Š´L_O3O• 9£h'''''''''¦%¿5/ššq”Ь4µ¸¸¸9¦¤T¦¦¦¦¦¦¦¦§¦%¿5/ššq”Šª<+HHHž ¡¢%%%%%%%%¢ T¢ˆ5/ššq”Š®4¹0»º0¾À:ÂÂÂÂÂÂÂÄ¿´8¡¿5/ššq”жŽ."^zzzzzzzzzzz^"Ê …5/ššq”Š¿]ti?ooooooooooo?i@ƒž·5/ššq”ŠŠyššššššššššš ½œ‚5/ššq”ŠŠË!,--,j*rœ·-nCŠŠyššššššššššš ½ºN`™{‹† UY YU«—IŸm­UU±MdWÑfG;;;;;;;;;;;Gf’<°K7f1fxƇ\‰Â‰\¿¶¬ª~¶¿\Ä\‡aÿÿÿÿgolly-2.7-src/gui-web/images/about.gif0000644000175000017500000013617112536111364014636 00000000000000GIF89ayað1ÿÿÿ333!ÿ NETSCAPE2.0}!þGifBuilder 1.1!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷¾xÃý†Ä¢ñØ ‘̦óù»5”ЪõŠÚ"K„´› ‹ÇÌ­JhfHÉì¶ÛØM×`úúÏë=ñ©á^¸7HXø!˜@ågÈØèøW9‡øhyé3©ò€&è‰*Ê¢éP¸4ºÊz±ª’kGÛz‹›Hq:ÇË›,ü×2Ù9Œ|kKÌœºœMXê¬Û[]-­}I½íý­–!.A~fŽÎ®žÒÝï¸._?LMo¯¿Ï‘ÏÿïÎÔ8N š€öb<ƒ gó×ÁĆ +%zÕkFŠÿm‚ôŽÏÆŽ$+¨šf!„‘%[æPB–JY.kºR„ÊÂ9®ÚüirÅ12ùÛ 4i3f‘2õ"Ž¥Ò©ã^y:ÉtM$„N­˜XN(3°{p˜}*Ê—Z¯[ŽšfUYª¸®ú²#É–™­FñJ aUÛ±:¹@Íû±¯¦¶uÎ^û Ùq¸•qaIy²e´> ]œRJÏ^òÆÜ x.]p Ð ®%ö §ÖZ(#™ókŸ“éè\xsæà±I[>µ¬ÏðE‹?'^Jú/ã³s:¿Èó6RÕ¢«OÞøWaßË5n·ñð¶‘_þ°pÅ„¥_÷:>– äŸ¹ÿþ MWØì"Uuaav {=e0 J.•`9»°uTrtÂvÞsÖçÝy<)š€¿á—ÛJ'j‡^ˆš¸SÇiNW«ÝÈ ­)'>»Y04¦è¢f­ˆ—ò}XZ“ð5÷ã{Ðip™ƒÙã;‚‘’8~)áà})^&\ob"ItÎacæz‡]Z“RªØ!vê¸ÜYA‚Dçäù–ežµ˜æ¥š`.ZL¢²mè$—iŠh }é½Éç…„]xä¥-bF"‘SFúg”lަߓ£šÉ`™ZÖW ²Í7*¤¸¨inœRGi¤x†Ze‘›ÆÙ©°¥j)N­ÿú˜‘_aáhrT­3»FHеqÅj¥svE·žúq-AŽ’pk¦½rkª\±>:(•2Ê‘]ïZÈݘ,î)ª´íykŸ–Åq™dT˜ž)ðƒVzûÝFrG&—˫‚Ǫ¢¬i(¢ à¼ô¢3løR6¯¾Kl¤ùùúfe°Îº¿Á.©ò¤¶Ì2–ìÅô²¿<>¸”?öñO·9èvç>KƒŸâæ‚óÒ…”šÕ\5#ÙÐ28Ý.Ôûj}Å^X/Õ²~òØE³#önŒù'ô‚€®}ãI÷'¯GtÓS±AÌYjïÍÓs[`?„×=3¢Pž­øâ_†œŠä–ª o×&q¹Ñ)ñ¦ùkùÞy+3*l1é¥—Þ ƒ«/šáC‰¿®”Ô±LKûäåλa½ÿŽ‚í¸ûKÄ<ð÷æ|ç±WÞüT* ­zô “.¼õe3{vÙk¿ý@‚O·DWŸJ~E›ÿ«Sõé׺Ɇ"ý¾ÑybØ~ý{‰œtúïßùýOz3ù„ûx=”¬/×8ô=^œàï2fÁ Ê !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±õ[ÔhǦó %&É`ôŠÍjCÌG—Ê´nÇäòsÚø‚Íì¶«N„ÅrôûŽÏoâq%±¤'8Hè ö'ˆhÐÕWøɶ¨¤8y`w¹ÉéäHé¥ÈPÕYjªcIe¸æ5©y ;ô÷):”*«» ”™S „É;,{H’úØšKÜì|ùÁœ&ý\mJ­êq(lÝ+ ¬í=NŒaNž®Þ»ÞNžì/ŽR?g<‚œï¯w/Ø¿ÕÂ!!ˆ°DÀ1 :œc_‰+j0È.ÛD+ÿ¹Züˆ¥€¡<‰¢FJBè‡2&WSV¦œ&3gHnùñirÔ9Dúb„Œ¨Œ\Š:m©R$7žK›"}ŠU(Ò>Ê2äS5¤U¯pu3ËÎ¥ •j¸Ò¤¨Ñ‚ÚžYr…Ö–îO½G[e:Øœ´@oEØÆ(³W†¡aí㽆;.¼ pÄ„[*ö)øðHÄ›o%sÈÇܺíh™å#˜ccÙ\ .û™U(œ&G®Ìy2NÜ„w™H3¨ÑÁ1Ï9zXü_åhŽª6㉠¿úxoÑÊ}].¿Ù;h¶/‘§Fÿžùyß_K[=¬[¼ÆbÛÿãîY€½7`Z8 aÃ\ RƒÑ_á˜\_æýáE¶Ý§ƒÖQÖ™_òÙŸyÈebfãM8âräµèFtpè`%ëU²k:¦ÀÒyîÁŠéâw?Á˜}BŠB~Ffƒd|/^ô¡nö"c•ÔmÍ’;~ Q\Ú=È^^õÙR!ˆ>™Þ‹Ò1H£dzù¨¦slJÙ^wZ™dw¤¥i¥„4Ö¨dn]‚‰è s}2ØŠ“Ñ9‰…æyÛƒs~Ö‰"JzØž&¦HiŸ‚hcBeYâu†–$̨g2él.†Jé›–šišWÊ e§©ú ªˆ¢Æ©)p¶qÖ+­eÿ± `˜¤ú*„—ÏâWAŽÛáŸyF”Ÿ´¥­¬‹yê‚«†–i§Þó›\íò:í‘Ön¹m¼ôÌ›(H®éšÉºÓ”ië«öþXç™®ª§œ¹n¾J¬Šâ ¬£7‚{/ÃLnyonü/¿o„o¾­-'TøRUi°LÂE¯Ä·+'¸$Ál(Ÿ»œëÁÐ÷.=;‡;#´ßZxi8]©&²S¹èÕ˜GóÃ-–ƒ6ñ¿„ܶŸÔu0ʘ±yä²$ÀZ=Ö¨a†r†d')yñ´D³{° ¦T[oÈò¯5fL7JS÷ÛóÇÔÊEtßEM*†?e´Rƒë­à͋뫶ä}µå¸öäî$ž&8–kz¬Cü9è;»7á©Cez]IÎtì­n´X³ßïNVé¼ÿ^­ïÀ'öð®³k<îØE“üï05ýNÑO?t©»o=õY…½MæÚ§ó<äSü÷9©]¾ù#ß›­úˆî[Ùqé»¶ª|5&ýMÕ¯iúÓÞ8®îD)V-~à=:ä€ÛÊü(ò ‚" ø(˜/š`°uùÛ ŸæÁº !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf°Ö@:§ÔªU…$Ðíõ /irÔ,N«×L´"éEãìºýî±¹å†ìâ‡(8è°7aÈçG¸È¸¶…xyØx‰9$YÈ7C)•*Z÷Hé99šªúaJAwzÖº:K˲éùŠÚWÛëË{¡Û!Iü{LhœW¨ü׌ ñl++}}IA¬íÝØlý=.ÍM~Ž~Ó œÞ.(þF²îNß–_ŸŸ:‚«ÿÿ…Ÿ žùskÁ(Þâ°AD‡Æñ‚!'ÿ;–04‘™«HKÞòjN'¥LºüHÒÙ®™Åb²ë÷ äKŠ–$¶¢£³ÒΡÓôÔìÃͨHšƒmTÑcfüA´ù4ëÆIRAùˆ‹Â•Ã,îBYÚhz.¢\Ë•iN·WY9ÕZË«8m—l¹a”}× ³Ö\°`ÞԢ԰߃5?–x9°e¹%›R†F1ÆDèÞ š¯AY~z:KzWìÔ¸*ÏfFF¦F-gãw^úB¡hjV™Tj)Ófƒ²Yž›¢õ&˜âAig‹yž2Zsdž^ú¾v'ºñý .yßã²ï–?>þÉ®pH€Ÿ½ñ“¹Ìî€PÑßþˆ:¶-‚•ûW÷À ÚŽ[ì  !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~xà~Ä¢ñˆtUB[ò JËšS8Íj·ÜÙÕºvÇärôÛ¨ZÍì¶ÛD'nâ·ýŽ©ç89‚ž(88QWsà÷甈HèøHXg¨Ây‰I5ĸ±‡x5™):Ê"Úxöv Hú «qzˆ*Âi›«+cª×´ l2AlÀ)œ¬LaÌ@ܼ-}D-}=ÖƒŒÝí=¢ý-.´:Žþ ýÅîmÿN8ŸZŸ¯ó|oÑñOŸÀå| <˜%TÀ9x!|ø¢„…… ZŒ(g’ÂUÿv¼²jÖ>Ò ‰r7‰ž‘0™òâ¢4íî±<– f̃ž>©rv“IK :w>”´©ç1¥ …v(h4*GE¦”º¢¹æ)T©\ùl–ÓZ|&šò³9œXÚ.Së–ª¢¬”ú¹$Ë!h×q‘6ËT"»j¥e ´ØÜDp§Î2,´äá¶dYqÜ5Œk†‹9Èʼn?ÑÓCï^ˆ†.ó©¼Y. P˜gRöl`Km`&î›Ò/Ð8[~Ì08-ØÀ{ß¾ ùäî¡Tû´ö»Ô÷뢨!Û&~Z4VTΙkÄý{²Zã©“ÿ<½ùhðµÏ·ßhpÙ¹ù[ÿÕšY²Õx£áw WTÒtÞ— fâ%ZR^õ’u¿ˆ× rû±U^|ö•‡\P¹"|XÉמyÌlxÎ_`÷Ùq·ZŽÙ˜…²x÷Ot~øœc"fÖbÚØÔ{ºy8܈óÉ‚žpÒa!X•¦±çÓÿ馗§}I`}M·”SVyâŠóÕÆL€ÏÉ \iÉ9#‰ENyf”<úØc“ÅÍå–)ªf¢;ÀDŒszVç‘Ëñéœ:JœkW¦‡džoîÙbrf hYeYhšhnšÓ¨‡žéŠR†šäpqbš¢¦wJ*ªŠ•‚jdŸB:Z*iL b‘UÿQG‡iH„j¤îê& ’TÕ¥©1IæT~rø§‚8^Kì§f«›´ˆÚ´¤©èò ÃM—1;®¢)!µžFmèçw‡>« ·½bI§zU;‘¥™¾«&“ïÙ'tú¦*}ßÜpÀ A<ÒÁßùWT·öît]2B‰¡®ù‹2:骭r¦äÌÌQk§°1[̃¯–q±€ÖW2rÖ5®º#dÝ-b¼[½Z‚3(ÐÀ˜©´#o’UÊ)w9uír‘¯Õ»`-u[C-óÊ41üaÚK TX/NsÞÜz_Ëð×`LåÞs]rã\AÖ‚ËTIa*þäâ{­”‘SÀ ¹äQ} «˜þX¨¹QœjÒBr‡~µM˜ J5ê1©¾zì®Ïvà¶Ð&Ž!ãžûK¼ÿ®±š,ñ<ê+cñÊ'®Äò³Cþ¢óšÇ;ÅÒ'zù‚×ã.õéÛóåý÷Ó'_Šø‚‡½ùïü“é«o‘³/¾: :ÇQøõ_}«„5‰¼?ž ..V¡_I&’SY W— È@™¼Íl~‹ààüS; O!¶Ñ ðÇ:Ò€"ä+ôWÂJ !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf°Ö@:§ÔªÕ—\³(÷ ‹•´H™ñ«×ì& °}åyûŽÏwäóú[û§'8HÈqgg UÈØ8x¨•e·èx‰i”¨ˆ(™–* 39± eæ9ÊÚZq*™K—héz‹›:³Rç› l2Yª°*œ¬üʻ쮸NŽ.z.’´žþ^ElÌ_âîþ oßÿ‹“¿wÌ­H0!cóÞS‘T$SûR4ü1#¾/ÿ\æ™ HO£Èl°¶‰ÌEDfЬL ó„—/á8ÜC'¦NSÈhí éÔÁDUQsÈfŸŠ:u0 (@VÍù4«Ír'§bôz¬d%¨YbõPG YA[Ô>kë«”§v|ÈþìQS+9¹GYVý;\‰7~~ÁE3«l]™ídÉ[ZÃ7Ãî²8`âÊÔr†ê6.Ó»>c)º’سXô:UŠðçž!Ò†kÚçL»XËqÜç³åɸ!÷¥º‹pÍÀ'ú¦L¹0cÒ[9åÈQwÒµdoÿ†¾´%òÞF{nŒœ¸Û¤—u‘ß¾sðø¨Š‹6®¼}õûº©Ûÿú”—,´M$Í eQàU<%×”7·uú‰Wàrræ•bô}ãS’YØtw™7ßsW("ƒ¡U´a9ø½7bsÕÔÑ‹6ñÝi\¡èZ:\§\TIw‘긢c22w§=7]’ºè\y䆨…ü±H¥\5rÈb†ÈÚ€¯t˜Ÿ}.FiY›Rfib]’e~çeÉ&–U6ùÝœèµeä¨äiãž1¦HæNŽÉ¨!ÜÙv`‰¶ød‰Vòé‚t$›pZ _œˆJ^ ó‘ º¨æ Š¢ùži‚¦*ª´fº`Pëièi}µ&'ªžé1gª–p¡*¥¥ÿIÉë«(6K!^ùŒVä‹®iÔ¤xî൱Ñ’ÀJ[èˆuZ‘·$Lv&¥Åš{ƒTJ®šm£ön«^(k¤¸¶ª „±ú¥¡}á9y[h›R{d©rFÊéÁEö¹« GhÝÃvfV«¬†ÉÕ½zÍ*•™ˆ{å Zi~+Lð“07­¤æ¡ÖpÅÂÌž>—Ël´AâèåÇ´˜l²€"EWŽ‘ È8¯Ë±ºŒhl5!ÞYÜæÂ²é'5 €‚+ Öa¯±5ºd>­ÚÔG/ 7„Fv/¶¨·=s勘`Çõ‹wÞ{õmw8g-xd«xÖ‡‰?õÉ_N°¦¬ÃAŽÒJ*Ÿô { b>l8讜39¥›ÎJÖŽ×v9ëc¾þìO…½ºí:]ܹ«ºÃ-ÔçÿΨŸîåN|èkù|ó ] òÎë}BêÓÛøÓ×ç-ýövï}V•[~ø¸”T½Ëæ‹I{äâ®â¾÷-?üÖOùûT•o뱫2è §âK-’F@¦ý pßI`ñèÒú90# ÙÂ%8A ^ƒdšjØÁ{5ÐX!LáJø»ÿ p…0(!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5@ë ‡Ä¢±õ[ؒǦó 2I[ôŠÍjYK UQ nÇärTì˜RÑæ¶û]þ²©^¸ýŽ'©â9Ÿ(8ØðÅ`èw–HØèøÈƸfø×õx‰G9Ãø#™ Ú³IA fêõ)ºÊ‚º!'éÙJ[û ªòúg€k뛉x»¢ËKü{ìhÌ›¢«Œü $|á¼}¶›ÍÝR]ªè=n>JŽÞÔœ›fnOæ±oß6¯Ä“ï¯× ' ÿd7¡Þ‰^.<”0œ6j+Æ`¸ÍBA‹ÿwô’3cÇ‘JDJÔ$É•!˜ì·QË™¥Ö!Ú‹ZL4{œ&íe;}:œƒQq'¾3 µÐÍIRû "²hÔ­Å*bZç–1•8 bµ¦õŽ•µO‘±•öiVX¯%Éf<é#-×ZHAF+´mW:kðdéí¡±»)ntñÜ}‘é%F Ylã«‚e¾Âʹ²KÌp?[nÂ’ã±òåÈNëQ>ᙣ°¸˜Tš*NÔ«¨£lª«iÜŽV-@×Öy¥´÷éP…,‰mÔ®£\õX®¼cŠ'+ª”è~ÜŽ—¤µ•"<s㚚隘½éÎnÓkío‰‡®~ûÖok‡å«oC8Åb§erA p³óÒjàÅ[LZÚº7l²©ŒÇôñzž–gÜ–Æ8F,²§;Òùì» –ìžH ŒmZŒMò HgˆÏú'f\ ­|ÖÞâ#¨Â¬xÝ›¯fÛ»ÝAMwÒ ÃÕ$puï­Ó¤Sµ3Ygó=c‡m]Ⱦ/‚Mëé«¡Œ3®Ô–¦Â >yÔO ¹sæžëô¨u×¹Òùç&ÔbJ‘›.Û·Ù²ÞèÒä‹9ìäØU¶Ôn{: 9Ý{ÝEæ¼ç1É®{îÅÓ´“’ª/ß“¦NéÅ;ô|åV½õÂs¡=áÙgß=ªz5(¥4˼úÁµ¬EÃÜ´Ih‰ÜŸÜÞ¢Rk‡šHEs¤ÎMÛbêWpáíí“Dî°aaj‘ò·ž35H•MFüÐÏߘ#—âDù.Ù[6ƒ¬<ú›ç?¯…^|š´:ÉÿÂj5!xpÄÖW%—ÎÝÔí-ÓxKÆy™tlÍt3w¶«¹a½ÔךKb®<³]Ö¨×>œtjMèëc¶žJøêg¸¾oÿý:ãøËŸm>xäÕé«ÿÅžÜjHa§_Káù–jaÄ‚\`4PSÞZ{œY¸9+gà…*¢ufçWOZ ÷xª‰hÔ{Ÿù køE’ qº¨â‹ó¨c„³ôô£ˆªt¡ Zº)GlÅq'[:S-Xa‹÷UãŽ2æ†"‡ÞÙ‹·ÅH¥†É)sOþ}Y¢QÝÁ„’nFI]V;™µÝx£%¦$Žx8 „4ÝU—îmé%;|Ny¡‰Ú9a~wê5Y¡ÿé™'"¾‰)Q\jÊ¢3JЦ ÅÙŸétt]P¬ÇØóò‹®¬rþ™cüw®þŽ{]ž o_Æ Â~M￲-)^ÿ æ¡×/‘Á… ½U×0b†„í.P,¥J¢F}ÿÝýÁøm£H€Ilíëi¤Êrò4¡¬÷°ÚÊ™°XíÈG3§.w-§¼Ô 4¿*&kåøt#"/¥™4ê k§¦U*é´¢Ô­–“ÔT¡Ã±$c¦²‚ÚŒiá¬õ6 UJ0ÑlW[®ËªÊ±6BQ¡FëŠõ(—¨Ó¯JVÙÄÈ­ñÙŒXÏý},ÐðbÇŠ!á|‹™¬O_¤èLšK‹\Ë>qgìå Ž5ت‚-KÖÜ4e_µ‰Aþ8Øånß…u»6ôwïàx‡cÕ 74îÃYUYMM½³öçPùw¾=çÌŒ§+nžî÷ÉÇ›|ö¼úæéC¿ƒÞ2¹RMoÓÿíî߯ÉEß ;eæš0ï)¸_9àTÙ& &(L`juXh¨5 GðVyÀq†^yCµöblUÄÜfî™WK>ý3#Œ²áWk°í¨ŽñyÇLŒ/®¡œ~-zBF |GŸ‰:ÉÛXÒ! ¥‹DþçA‡<~ÉÇ–r$YŠáQÙžˆ/šˆßN€±wYub6Yßdk–鿇BrÙ]vÃ]ù¤‘+*ø’Ž`ª‡vÆùT–X zçynþµâ†}ŽV"‹IÚ™à)Ö=–‰›Ô(%§š^ÔÅ ‰5ú\”#FZX§”ÂYå¥DfºÜ¦f®©'¨Šú©¯îJ Z^êò+ŠqÿL´ ƒBʧ~ÑŽ·Žœ¢ê)LÂò°ç¤ª1ÊÓ€Í,ùj«µšË-ç’舾«â˜Óv†Tª¦&'í“øÅy¦æÙ¯¥¬Ž†$À³‡¹¼.z¸Ö>]ÃÛ!¬W­{âÂŽlÔy¦Þ:k¾ÊíKÚ  ŸÉ`¿Ä‰6§ˆŸü)¦S2œ\¶ñ 43`ß«°'Lɲ1ÇÁ0uh`õ€ÒZÝ&ƒrÆŒôäœ^áÖ.v0ãàtÖËH,õ"T3™ôYüæ5äÐF#ê#X‹†DBE¯NÛ£ôªtï]¡kiîÌwàâ­ÆÊ*Ì-¸2Ðþj+Ä'žSÞò®+!…¸sŒÜ…Q{9æèìxç`R„¶è¦'ê˨Ÿþn³TÖ™⬫Sú!”Ï›ë¶kŽûŽÔûè*ʼF…ò^<äÇ¿îlò35Ý8óÎK™!M¯¾¡‰}ç2qA|÷ð†-þ;sƒ~ù¡d\}¸é«¿þÍ&ûD>üð\¼5磾oÿ+’«K?þõï~Û VýH“cuA€ŒM×À½Å ŒàB&2 z¯v\;<Ó€p„;(!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇRµŒçúÎ÷!m¸ù†Ä¢ñÈ¢ J ò J‰JFÕ6Íj·Ü‘SQý2Ë®ùŒ†^™ñ8 ËÕírû`ǯçü¾Ÿãæ¶ ¨Gøwˆ˜ˆ§‘Ö¨)é±WWó8©¹©“™9X×àôÉYjšcF)jóHv ‹²ôiG(dŠ%ËÛ»‘ú¼ê ìk|¬;KZŒÜÌKê’뚭Ѹ#‡å; S ´+©‹‰óÂL=Œæü™…1 Dáìl•*¶šE›2zó.éÑ Ijtе-1BµLÆ2«X@—\îBê)eÕ÷0Q=Ûì†Ü·Îæb i‹k^Q_wôëM)TªxÓ²ÄÅóÃÃ6yÞ¢KÌ-ßVÙÚî²Ë8r¨Çpµæ|ïí܇75h«W+S×*f Ø ½ƒYKµ…qçwa'—L)™5eU»SSÆL8O1ÒwŠÿ¬òdäw1E×:ôŽ0É#ˤýka±tÞ…ÿ. ½2z×6ïúrïôÏÑ·¯î¾yÅ싘ÉÿÝ –u|½B‚%¡]³‚ ^…ƒâ<qjFÎM:W•Je½‡K%€3^vÀ57"}l`¸Y:_ÙõÒy™H¢}Ó…æ5¢HF ´^l>ª œjkÁÖÚqË#v0º¸_Ç•F“"jšŒ¡˜Ø‰ý©…£€õåG^T¯Áöc™Yê‡Ô˜÷…‰¦Yl²HåzO*ÈU{;j)!žò½('œJž(àm¾'—/•¸æ|D’if£Pz"\œ5y¢JªŽ¡{j:)••Î×gˆÓj$X%5y—–úyè©=QǦ«3ª÷ç¥sVX§|‚Ê*\•|ÚÊjœ1æhª¨ohxãªÆÿ÷MËH 1wåN¶´+…Ö·JE*d«=+ަªd Š“—i—ù-g.*¢…KI³(9Šï€.ÝÂh!‰R«m’ªF’[ð»íW "Ç/–½Þ70´¼fsnŹޯi^ôŽÁh‘ùÆ4)§`Ú&qx¨Íz±››–êÅÌNËÞžšç°»È1³BÌ‘w½e\êÆâ·¥VýÆ:rFžÙŸ~]œòƒdá§.$/‡Ã'S=œ¹GH)=g­ÈÖÓx ð×t}\o…7íãuâÅ´ÛáÑ]¦ÝH¦– žò=V¼þ:wãà„Çv›Å@.Îx-ÏF yå*¾/…ó„YrmùB‰ŸÕ]yhwþÑèÑrNzN¨»·zêM/l•…®ó½°éh¶>;?>…œyî€á.·ïfÂ>‹ðî~ðÆŸ³RÕV/¯:ºE ½£Kó^ýOÄ3Œcöù6ŸTïy‘í‚ç¦<ù±¤Ÿ)ûêŸb>Øú¾Tëþ±K?N&× üù¿~¤Zý+SC·H;x©„l¤[ãâ×@“HEoŒà÷\, vÎÒ ðÜçÁúA0„Ç« Oˆƒ!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇQ@Óòçú·uÝ ‡Ä¢ËÆøŒÌ¦ó9D.~€%ôŠÍjYÖj7¡ÜŠÇä«TÑ=#¨å¶û]<«§_°ŽÏë?õê¬À¶7HXØöð5fèøˆ·(ˆF险)d ÑY™Ô¸9Jº‡9è XÊÚzò‰†!Iëj{K![²¤‹û;X;!l ¨º«ê ¼LÚ©|ÈKÌ<%ˆ˜cM½Íô<œ¢Í-^&ý>³v>¾^œúÍ÷ÊNOX¾VŸ¯=™Í¸6ê„S§à±ƒ ¡xëWL!>y +ò’E1ÆC‰ÿ;ÒÆ‘ƒ”{Kòñ&ñ!:“,oôºv!ä™-k 7NF›<³){é®Xb4{7S¥<¥E:M—.Í*Œ3ŸZ!G‘(|?›^ýª!kB w"žJµ¬X6¬¸åöÖ\jq{«•ÑY;9ÿ…õáì-5„ EúñO{¡z‚º(.LgvQÍU\÷0âÄÿ"k^HYíD’™}ÕÊz™kŸ9¨õ¦NeNéÐÀ‚é­3öu®¶;; „2èáÓduzÖ Š·Ü·‘Ù:³ƒzèãÄ—¿s&?ØÄG®®+U4䉀‹ûM$ܺ'ó¸Å__ý}ePÚ^9øçÄ™ý´ÿÕßvBwÙwÐÁÝå%ˆŒb½qæ }“<‡V…mÖ`€®tá~èýány™ÕØI‚¶¡dîägYu¦¹‡âc÷ÉÈâ..®xÜá‡#yfùx ƒµ IÄY¬…x’%ÿièØ{“õh#fê(W*òS£t˜ý%$Œ Á%ØÞ’I‰& dyæˆ Ò×Þ;7·d9óÉ'Zv:ex¥}.egjÌÝéezŠå–êA$•L²¥ )AŒ©¨§˜-*:YeÊq]koÎCtº› Z)¨‹8gŸ1"(•…Žz)RÆwSžº $¨cŠšé¢˜îš'€O¢Âª¢®ÿbéÝ£•ÇTSR˜VÎF”ëyLòpš€`Vð[“¯ê`f©/zz̵Ñt™”ØË­‡è–‰¨,´EÊ^½¾Û¼fˆ!žåâÚ½Ô)ð¿Ÿî©e†•{Ê;ªëW˜ÂJô«.¾&­©1YK«’o›p±ê¹:0¸¤ Ûî¾pÞçðŒƒÇ%ÄãvI‰¦Bë|¤‚ÿu{bX÷Š,N³7«s‡kU8ô6C‡lHÎêè–VÔ‚ÆXgñ·¶h]¸Ø¬#Ëì2}a|ÅÊ%ÜpÙ(z±Õ´Ýq¯××»Úö“ßDN5£n©ª}°áµu¥™±à:Ny,±À­iYåšc%aÀ›þtãÞšó`æ ç›µÊxzë öëzìÞÊN»Ô׎»íäýaîh²UzÝKû^éðÌFüï2–¼UÌ#öuµÍ;¸•ÓØð×¼PáÛkš÷&hÿý#À Þûºå3ôâño9ùëõLÔó‹œöG¼ßßSýÎíÏ¿}ü/h%  ò‚78ÕÈÏ€)à%ÈÀÃ1KeŒ Kf± ‚ƒÔàݺf(Rq"¬]XÂ. !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰*Aʶî Çò¼öJçúÎ÷~xà~Ä¢ñˆtk·aò JK•Íàœj·Üîçú[WY¯ùŒ~VN±5 Ë¡íò›Ñœë÷üïl—à&¸Ögxˆ¨¢(t5xð˜(99ŨIdIéùI“9ÑÙ¸ F šªZ‚ê‘yʘ·:KY×ÀY»»Ûá‹ÅF!êÌ{¼Ú)*(\±ŒeŒ,Ûl-Q9Ímø<ªíìüÝ]®¬nήê«| Ô>O_¿¡^¯¯GŽÒ*ÖoŸ@5Ã0äÃ60¡™wBº§0â–€þ8´'1ãÄ/ÿ ÿiüØâ"Ç ð‚4`Žº¢[ºíFdJ¸„(zÅ@h~)Š·b é_†?Θ”e×PŒw\y>R7ÌT.v$Y‘jbHÞˆ$ù&c“Abù$ŽÛ•™Þ|p²)§IðUäå”f¢c&|KjueŸ¨…™%ŽNŠ™(>i®I醭'.¢Øbsw®ch{FšÚ–J¹Ü xÆ]žQ¶'[uüÑ é‹­ñ_ŠQrÙÞ§†úÖ¨–ŠÝ©žÒ*™‡ÿÖçg²öô8+§ºVJ¸ÂX•Óu™íOïi%jZ •ˆ2à¤ãœ©¥5º«îªo¢º,»6Æk![Ñš‹n¥þžŠ ¸“ñ{Û¹|’Kf«pΧ\½¿ª*ªÀÙÌvŒ2̨óbìŸÄ¤’jqÇãð£Õ&xáaøþ[Ï«õ56XÆ—F—g¸†¬ñs4k ±´97›rÄ"ßLòÎsél/ŠÆ)²d½z>ÂØ‹£’ÛÊ,w¬Ë†W0ÐÖ’T´½½ˆLð!MË,ŽmcÙµu½ÅvÙf“mõD!Ϧ¨°=ÄõÕ~<'ÚSœv y­`]Oxxã¬!è ýî8âÅÑ…ÊdˆVžØÞ¬vóMœå¦zAŽúƒŒCù¸©[ÅoI¬¼Nú_4þqî´ûÝ¡»ÿ~4îÀo»×Ä0ã#!ÿ7pƒë.9ó•bKܰÒÃnýäãyýn¡COW÷jR/ºøµ¯¼ù‡§¶ú´ËÞúyî³ä¼ëhy<D¾'¯¡˜uço6q¯]¬R¤#·:倎I [¦(áHå©{ÍÚ†* bC›×4È}Ѐ±ðÙ+Xž žsPY!ðJçBâ5á1¬! !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó ›KªôŠÍjAJHWnÇä2ô[ƒÕæ¶ûíD«Ø&ŽÏë1ì;  ·GXhx1øôàwøy¤(áXçgW©¹9“Ù¸6É9Júé5á9áÈXêúšñ•j1+È ›[Êû&j©+L Ì#Æ´<¼ YËKQ»èpÍl5[);Ý }ý .ø×ˆn~NY}RŒÞþȾ ¾êN¿Û TŸ,ϯðÊ6BD ˆ0г :ŒSμòZü·£âÅÿ5ÒâV‡£H…ž“üXEè9kŠõ6Öòh{sìÃ5·æÃ¡t36¬2Þ1ÙUfKë\²0]¸µžÎL4òU6—KíŒZõ8x‘¯½ËÛXcÒªn&7þ˜NdÍF¡V¼[»yÇÒÕ§ìþºýÍÁMÓÿï¿VèÉG;D¡tY‚ò— F4TÞ‚Ù1˜R…÷¸Û6‚ x.¿EGJçÕ·Ø€ÇñÒÓz ÎbqÓñGb9Ü%6£‰®-¶a\zùe[8éßj´5f zÙ˜š‹ûXQ{"96¾'Úˆ¨!”þµHÙ’O†Gå'µùHæG¾µ"¦‡ ‰¥pHòvã¿dÆ¡hY¢Õ&^!:)g•ú‡–oZ†Ù •¥¥¤&cYf£ü†{^¸§rЄi]ZvYbIòÅ祣1‡é~’ÝA¨v†æ©*ŠšF‰§Nzj¥×‰:'fšêæ‹R2yèž~Þ˜Ô¦½ªV㪟ÿ¶ºˆk>ˆ¦cCŒéƒâÅ’ Y ªÔ‚‹¦÷ŸÄ⊢¶ä| „MÐN sBêÀjR϶+¦£ö>[‡Â–fµ²¨gùZMœùíjg|"þ™k¦F¾ylišðŠ®2|$©ï;ÈrF΋-÷"ô]±Ñ¢/DùïÁ¥J|ḴTeļ2JçÄÇÔÄ…æüYÅò¶ã¢.é ø<·˜¥ ï r‚f~x1‰×,-lx3n›š*Â-¥Ö”'„ª”“wûùæ}«¹èN£ë¯éª¿äùê®SEÞS¾®·¿ZK{îøÂ®ûÜ¢â]zïJm%«ðÆïþ%>ÇÆrä-Ï<ñLCVó9Oý5Öm·WÝg?„† ¾>M‹üZù|ˆêNÂÛ¾Ïy쩤:Òôo„y¾ ³†½ý 7åÙãبIH YýC Lw@öè¸ÛN%ȹÁ]ƒLC9øn„á! —‚‰ª°!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±EkԒǦó 2?`ôŠÍj_¶ibÜŠÇd¨WVTËì¶»ÝM×ïºý>’3Έ%þè çñÃ'ˆ˜ÈF83xp”ĨHY‰2i B×Ç„i z’ö™Ñ¡é'ºÊêèŠÚG’*ÙZ[«ÙSš¹kë{÷I 3Ź×û‹ 7qlUûš-­ôõÀL!w=½M‰û<ªÍ-.ÈŒ>®œÞ쳈ëm,ow~ÙÛŽïŸÕZ¹±Ð£°ª„rÁæ0b¨tÇ„5úÀP¢Æÿ=Z¶1äbT.u‚(2%—ƒ%1¢³¦2¦oždÚEË1=„:æ²Àò¦P„“Hvâ Ê¡Lf3ŒNO“›Z]FÊ‹*5FÅùv5ìÊ£\Fš·+¡Ow¹‚¸åö¶ÙÚ|™êÅšµ¬NkS“š+ö×™*_?¢å«FobŒ’Òž<1¦Æ-Ë’[ ­…:f[ræ‹q;·Dì´áÏŠÏz•waˆ»UòtË©ëO4—KxbðYÚÞÁE«.~¹ô÷x†u<µñá˜1S^Üü´ÝÏHyÝž#·ÅÙ×aj®J}²iô²s*‡\jÞóÍ£‘WnŸùmy°çÇÿ:Q­-·YàL†Íx²q¤TvØ]ÐÏ@ýi·YE^T† fèx©yÝ_æQÇ^…!¶ÕWzÞ 5ÂA§Þr%J6HŽX Ž'îÇÞS±yG[mB Q“Ž}E|/šãtíµ““ƒõU7b2懟)SÖó :6™"t­éV™Cžé’‡guDRŒcnYÜ“m%H –œQ¨&-ú§"•Yöhšq\šµŒYîéJ6(’‡f£9øIŸ‹¥'g”r–h_’…I߉Ò%G§¢^fŠgœ%}y(œ.*J™™ ij¥“LVJ“é÷#õÈZ¥­~Îúâ~‚ÆêªÀ"ºjŽ~ÿle ‹Dù¡/I¥…Ìm¨‹–ƒv¨KÈÆÀã¥ÅæJ ´&XŠÕޤnš­§ÑvåCæ:Ц…¸‰|&NZèÊ®¯ÿ®+­•ü¶z«=ÕÊàÀ‹F[j—«-ª•ÂWþºĆÉ2/½¶ X1€¸‘‡¤‚bú0/Õ!pÃXª ‰Ï!¼$®¦Nû‚1‹©,Å ºÛw×]#1Œz\¹[Bå×¹†¶ìKÉG-uÇxr–UQAña5„ýöFÕ`Ã!v·yªŒÓZït²»H )•0 ƒh°É<¿íè`L‡h&¬Mã}¦t+©/à†£©«në*æØ‡¯C“‘Ž/þ¸Md»B;¹¨•3Õ·‹ûú¶ySVë£jš¡ ¥–y§¯¾êö°:éwÃN{ƒ¶|{íõ­—ì]ë>$?„OüëÅ_ðäÈŸ^1¶y,7‡‚½XvÿŽÆÕ[?’ôÛ‡u¡éS?Tøy(O~%`kcYú!ɾÔLî¿o̼Í/’ïnZË×ïø#CFd-cÿ‹ƒNE¹‚wdñŸ-ç¼£ ï)72 ƒµ+a§¸vpƒ",! !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰6Aʶî ÇòŒöJçúÎ÷¾xÃý†Ä¢ñ販7¤ó ›*ªôŠÍjAÖ*#(ÜŠÇd¨rqf†ݲû w¦½ßvüŽÏ‡ÖµÃ<¤'8(È÷ñè`HØè¨Å¸ô`ç§ùˆ™Ùry99Aéª9JÊÕÙ™±†˜¸(Zú Û×Z™ãª‹›Ë´(+Šáj°ªK¬û+Ü;ò;\ÜLÊ,í<Ýx¼qjÝ—MÍÝÆû™ì=þȼ-$M¶MÞ.†í›zÌî^—m½®nϯ™–Þ/ @4ôì§/ÞÁ…ä î’„Œ¡ÄÙ8ütJ\‹ÿ;b´¢ ŽK^[¦Qä ’&[Ê#¨ÜH–.]J«¨PÊ4kÚdI)£²>‹úJ-„žF›R…nÎ:¦ÒrеBR¥KÙ…ŒÀ4«Ç9mʆ’ÊiZOWy*Á×[܇añÌEë¡,Ÿ¨Á¶ÂËÔªX„PY5¯k ¥ëð²‰8Iê¬UsÒÈ YÇ:²Í¬æ›g°˜‘%¼q´6lqýi,8‘¡°±›ÜkX˜-Ö‹QÒ)­4eÈ“%_ÞEY3§Î¾…Ï&îå®iÎDS«¤.)R0¹¯ ®«[ó,ZËŒS®ú¼qéÉ_‡þ~jôå·Æ.ߢÌé¤ÓÏÿ·ã—rùq :_¹‡ZNãÅ—Šø,(šeÆÔ_[KX_²uf ô%\dþ…Úc#²rÚT•íwÜgʼnVŸsû¤J‰.F÷Üh¯eV›m>N±™~ÕtËoÖ…8Ù‹&ÆèÐ[ гbvJ2‡ÚEQReb%4Ú‡"‡’öøc™ vÇÕQè@H"yUV‰>Ô±×X„q(&ƒL¶ø¦,qÖ™åPÚNŒyªwÜåž™Ž:hʺêfppv‰!Y¥(Ž0ö·ç•IúÙ% xFß–'Îw¨”«•ÚæIk—£¡´bú‘¦—qzªzŸ~*—úÕ&¡è‰¸–ª¶ÿŠêª–hQ‘fdâÑãigQm>¦"øƒ•”J Ìr«Æð–Wø½+/d*c^¦S~;l£gšË–†ûh¾×†wäFëfØ©½¤¤tþ•K$®tö° n"¬ëÂÃVµÞ¦sŠËÖcÏi1¼Ìvèo¯‹îñ¯¾%íUØa]É;ò¸“.É_ÁÀÍv®e ׫Ã#\é}0yk¼•Þkç«ü§E)Ÿ·CÉ&ôkaÂ*"ÃJÉ37I;­ÇÑ\wÍ7•7µ‡1ËûÆÖh—á5PK§«c´Ò>M7·Još[uÓm¿cz7°{‹Õò†£*(¸Žƒ?Zä—†8Ñ‹g5öÛBÂOŽù r'~Hæ„+GÏÚžÿø5ƒ%8zK%c|Ó5©{þàà¾nê`#N{îYš£{ïCù< ¶ãÞpð°GE¡ÝÆùòΛ^¡Ë =_·èŽS¯ï¾>]¡ÛÀÍ>ïúõMŸ¿G»¯ï¯|ÆÚ»‰ X0ᨃØ*|øŒƒ/‡µàA¼L8ÿÐ6büè­ß¹_srx‰Ò µ2›A h¨dÊ™_œ˜&Í™+e’¤ GçΡ>Ðñ9iÑœK¢LMg) ŸšüšZ…ƒ«R0E}ªZZñªØ^¸˜AhÖåF¯²–¸ÕöV¦Ð@qYÍ%›U2V*/Üòwl²7„å%-»Ê죿È,zA·/:»R}•k²Í¬]WÖÜÙòËÌ©îm>$ZoZŸtrŒjê˜ ¶‚1z])5ê^AGôŒgX±nÔ¡…»&Ýõ˜QSÃÑx&ùy)ÇÄ.öêÉTn?Ý < oÓ]‚_½9g¾˜K&?}Öv²ÅÏ“voÝ9üʪ§ªÿ Va±ýtŠx„†U‚ñ]5„ Nè_?ÒI¸`¹m8ÉY´)x__òÙÜW†gÔI‘¸bƒÿåÇœqôANo5^à‰š˜TcµýHÆH£UÓÍ{#n†Þgç9”‹ˆúYK’:"éà…à1×ßRê7_„&ñ%b¥a‡a–õ"˜1’(e ÁHnוùdˆ¿ ØV½áÇcŸ`åU'ŸZ’Øb”ÎhcÉhHDZÙ¡Ÿv–ˆg“K®)h¤s–'ižw^Z(}\~%g œ.Öé”’Mj¨v¤Ê#xª**’n:ÕgœBšªf}ƒÚê)•kæ¨)¯¢z£zÄÿ±ú©« y=|(­3Q0)Юîð –t¦êªÊj£ž)jÛà™!Xz`š¥Rºè¡ÚÄRb€:o£Lywïn‹R"Ü”nŽDnĶ{fïnª¦Žˆš§0dì…ÛÞ[W» ³cº1­¸^i¦º€å«ï?üÞ›-ÉSxdÇ‘,1¸Â|ª±ërÅÕõZ¥Î¦í–Ưr<´'/ew*“\ò:õv”H²§(y0@C‹ŒÇÃ2“r³€ÈÂqt —;ØÕL¡5Ö¢µ¦­ád»cÓ ¨o"¾s¶Ü Ñ­ N²e€®Þ?®V«‹ßž·àóÀ†˜“€[«xmE2œŽ£îÂD.ØÄå…Í0æžø·_'Tþù¾gCXºç‰nsê@Ý0Æ»Þ4éŸN;æ«çλej÷<»ïºíI|îcùæñÉïðÏóäÃôzKo}éáž}æþ öÝ[Ííïãûád‚-þùÂ,÷=§£™ï>>4²î-§_+m-±jÏêŽé‡^¿Žö¹:H‡ Â{ì: óO¤3 =D|ˆŠ|ÿ\ˆeü8ÂÔ! -f¨2¥!OÎã‚R¥Ì^«ÌL23ç‘’*¸ñ¥ODÁñu¬T/¡“n}ª‡K{ÜQ'šþ‰j6 räj¥j•igªV¦ZcžRšzÙx¾~¹—­ÿò×b¬Æöªª¶Fz ¥žWqª¹D„¶Þ@报¹yù(šJk­v˜k‡2r®cg†ûão欫Cº3R ¤Ä‹én†› ¥j,µØq7g»œÎç®ÃàK­¨;ùj² ^ÇÓÞI'€®êÚÀˆ½)®µ“õ&˜¶œ#.ps)òžÿ5ì-Äõú{%~ ã§ÆìÜ,±Ÿù5ö³Å…й´‚­ýŠPœ1¯¼Á)ÞFQeS+¶´Ã¸Üêµ,Io=$¢fyâÌÈšT3Ùc€ 0]pìtšàFäËUTï}\ÙøÂ‰°SqóQ&èEUîN„ür‰d†¸xä;V”6 ƒÉKn6*[\œ™˜G˜‡›ýùL÷V%–k—^¸6V 9ë„ë–Õ nËŽ{>Ãí»¿ÃyÏ!ýNuåG§N|›¸òÙNò˜_¾’ó «+ýôQ«^ýïÿ š=îâøÞ½ìà‡¿Õò‰;8>ùÓø’è¿e«?˜èž ù¤ÿ‹¶€õÇß”ˆDîÏ&ƒÀ&vKI £ªPJeÔ >8c®Ñ5Ðtô"ô&¨Jä‚Ì`¿4ØAÉuå`!ÜÉ$XÂÅ‘0…ák _èƒ!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷>x»ý†Ä¢ñ³5‚8¤ó …‹  )Íj·\ö¡¬Z»ä²YvPã³û §}ÁsÄ*;Öãü¾_µ·W³öwˆØXEAhǤ–(9é´˜¶È†i`øÈIù gÙ ØzŠ ¥iW#¸é˜*;ûÓ´z«§tKÛëÛby{§÷[lÌŠËÛ¨|µt—{}j „]È,­-š}¢|½®hÝ-n~®2QŽÎÞ¾Yλî>O)ߨFM¯¿Ÿ‰œÎ/à™Q÷.`²'0!p¸:,v-Ÿ¿AäZ$Î?ÿ]ü¤£³†:D‚üȰ™Á &Oº 1 ßÊð^ÚD±Kb’€6Þü©îà+žBĴʈ„,ö‡ýú¥4\»Ö;×Íá,]ödÏŒ¶¢„A"ã·´±lµCе"˜ƒqõM¸qÄÒ\ Å_ò]8:]9x¦§EV'Ð ÓäºÅùÄrj¾Û™0Žï}¤ƒ^—T{[c6§£Þ‹¥sý±Ù°Ÿ¤íë·ß®;¸»_÷ïÂ<ÅðI2KaðÊõn<;[gN{ó^1¯·ôn*o½ôÔgßòì¹zÎýäoI~ãä¯^~ùÈC}ú/mOö>–µ7*ÿüÎÛn|ðëï ¡TÏn¥øÁ¾þYö È@ÍAækÏ0`c—'àäï‚KéÖbA:/2x¡ð V9JÐ]@Sá 7èÂã,†4ôA!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä" Øø!̦óÙ«%ЪõŠIÈ%BêÍŠÇä"BslËì¶V§ÑS@üÏë“Û\´(¸Whxò·à§ˆèø)·¡YiiIøuvÉÙyt’Y‘êizÚWJ±Ô(9ÕŠ+»ø š`{À kàg7û L‚K ¸Œœl7q|{ˬ,M­£è<]V[Û­ ŽíÁÌ~Þfn1þ…îÙå¢þ^_ÅnŸ¯ï›;L¿hß¾VÊÉ›ñ Â,^TýSÓn¡ÄD›ù{61£™yÿ«ú`¨¨1ä¸]¥jˆ2¤Êƒ€\™ìèq¥Ì ØZ9Lïå̶FÆKÈ!åΡhDõ»yÂ+¢LSAëÇ‹K/WO›ZBIª3›‰€^ýJëhÕˆËNª©ƒP~Á¡]«Ç­/ÃpåubtÁf» ï29%qý«é£°†óÜ’­E~r M K®<Ë™Ñ"¤uëd¨wÓ‘<(sÃvû®CìW\ÏÃFñšLõXЗ9ÇÑ,‰ÔÛпgëýfØ3@ÈóvKê÷h.ÏØÜy®]»¤‹ÁNmùdߌÇO­Ìûø©Û~mâò¦Q"µÝ}½Î õúÍñm·ý<ðµ„Ë{Ø„‹?a¶;ö ù):¯õýå•›BÓ0:¾ù—?imè‡þ«¦¯ÞÂ謿Þì²ã4»è‘ƒ];X®Ÿ†{î±iî;Ús|ñ&U¼— ‚þpòL¡þ¹äzîüD°|õà {û‰ÔkÿK£ôD7ø+!…÷^7šRò®7ûÏsˆý+ÙË/Žž¾¾R.þ9£„ûù5¹‘¾÷iå€Ô¢± o[’ áÒgAÙu+ƒ”A!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú·uÝ ‡Äb ÈøÙŒÌ¦óü%•ЪõŠõÑ"Û5 ‹¶®×°œšÇì¶;–† “€u¢ë÷|QÞkwðÕGXhØ(8xØèøøð§07)y‰yI‰ $™ù ʢȱ è`šªZaæ):Ú¹*;{”QÊYçJ»Ë;¹9ñçªÛ[lÌJ’H|̼º,ù\çÛ\M(MmÍ}ˆŒöýÝMîÖš3^®.–¾îþŽ~ 3 Õ>=“Œïo¤o"}ÿd7OÛÁ…& rç‡É7³wLJÿ;b”H޼„AÊ鈅"]=´™2¦…/ï¤á(3狚іàô¡3è ž €d)4é‰5s¶5²èP“J«Vâ¤ÌiÑ‹’~Fµ ö×¢ºå­šÝ©žyZ¨¿¾ŽèjÑŽ{Ú¹ïÎ{ï³GØûÒØžxðp_…Š5„TbI¯±J™5lê–ÚÔk3 è‹%®’q'Ím¸æô½F—ä×¥ïŠ5 hJªf…i¼†R°S1yèªA¢IãÃ(ÍYv¬´2áÉ–éuÎ<s·¸Ÿ¾æRYÔàÑŸ ¯i´.¦ØTaÉý{Î×k1^{M8gëÞÃ…†¦LiÙ™ó¼œ ¹qÎÁ”Cg~\³µµ8¥oV}½ö`á«‹n»umqב˫¯.ù:ÜÐj½¾~ZvøòKÇÿgsÚsÿy6Ò€÷¦-dÐÕkÌ4ÒƒÏU0DíÙÇV†áW‡bèápç‘w[p:W {ßðgš>¢m·"~)îàŒvÇ]uÞéGŒ ÅÜ*váF¤»åØM Çb{4V6$aî86‚×d/6G¥ö] `~'Jˆ˜zŠDYdšq¶J;0YcñAd`^îeG\˜1²Æbjt¶6_lri¦>B¹Ü2áQ'Œ*n€¦š’úu&£XÆ åœ:Ý‘z:Ù#ŸrV‰è}–îô)EÃHopu—çgxˆø øå5HØÈ˜8I'Ù8ȘwYù zFøjzú´XñÈf7Š+»¥êæ9‹››qÛJÁJª,ÌÂûe ñ;¬\™üÑŒg7ö¼LXŒ¼»Z½­|]ìÍŽ:ÝíÃv-®>ù­Èë¸?—žùRG/Ÿ/„¯ÿ¯‹Ü~ ÆðwœÁ…MVAGB!É%+'C EŠÿWÑ#HOÈŽ$ÿÜ)Bâ±’,UlÄØ¢”-k^ÔéÕŒz)múÔð’Á=_<b ù³$,À‚&}:Ðѽw’œB½ºBÌRŠ\‰Ä 6È ±[kýš6ôè\Hz!5ÔÖ˜Õ™dݪ²¨'-²·_ò¬‹­qûÝt„kΓKt²*ܯñ1Ȇq"~ Shfi˜ ­Œ9¹U3ÆœÂöù+Ù7jZK• ú"ßÊ~ò¾iiçÍs}I­GºêéÅ‘1ÅmûØÓh⨅ï^ü¸èᇅV…DŽrÓ¼åÊöí$3Ç`ÁsOmݸÛéU”_‡ÞܼÑò¡åR÷êΜ«ì›!bÿFžLÔµ¶WŒWSÅ­1ÁrÙ<¸“eFÍðJ¨áÛ‚š5X`œÑo^Ñ—ÞÁ]·‘v®Ÿ&&F'_ƒÏ1¸ßIwž6…4³Õ¤=S±¦•Iµ°˜Ÿs/8z6"hJæヤAÉ^‹%R©¥2c½I&Q¸IÊ‘õ%]!Þ ¸žwXÒ“Šž¸f•QºöaNéÍy߆ôÙ)(vn:Tn Yf£ðÅçzÊç$…ÏI'§Ÿ12×€ªIöfjÈ x›ñçiSHJi(Ž ¦Ê(’2Ù¦z^§ˆšºÈe§xÚž¨ìeúªª§ê8è³ÿÖè*†<•…’¢Ä€ôžZûP{+ˆ ö’s4B é…É$ŠºFèI©:¶)¹Ûq«l¡¼¶¨€ñjèh¾z¨mn?ÊÊÜ¡¥±˜W½I‚škŸ+J¸§ÀQ†–ܺ.Ü,bß^Ì,Ÿ[%¼¤6õ¬ð&•:“®¾ØkˆŠ|¯GKaJêǼL«Ì2ÇpÊq·;Xä…­jLÞ°½>ùaÌøÌV²Éù+òjúj‚¸rÜ4D» ×gFì^V«ƒõØplµo¸YÌvg41a¶Ó5°·K,wÞîèêÚ%*F¬wành*m˜· Žxdhå7gO‰ƒõ Ø÷ãO»é¥¶Œ–o~“JídÈùOi»0uèsWžó8›Îzë®›1úëúTþê²;úÑíA®¼ö¾fê^f2¨Û¼å¼Ÿñ #ϼ—«7ïSµi}ò¶ü;ÞÕ·¤Ü´Ûcå KÊÐõ‹fN¾MÔ³]a…éƒÏ |Û¾2þû³£å^ìö3Ô¼ÂÕ¿¿q ¯pŠO­§9®ù뀸Ûp„§@B®w) &ëî‚ÓwgÁF/",á !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡ÄâÊ2~H£ó êšµSŠÍj·œæAùð"ªb®ùŒŠÁ /»]MËçôVyö^Zãõ¾ÿïA•t·Çˆ˜¨’7ö³)©gðÖ8x8¹É9…GáæpÕIZZFX)ˆéh˜j ›óê–:*‹›»ñ*J[Á«+l\²Ì:¬¼,”Ìüœèü5« mí'MQOÿº®N¿µö9 ¿P¼ÂmÁ…§ìÉcñ\Â6gF¼Ø a7„ÿ1zd! •ÁÃ|<Ù¡Ú¯’ñ–Xd‰¥³œ‰ÓB†×ïê—%Oƒ<ƒn:¯Û2ëÉæø¨f¿‰AîåõçßÂk“®ÉUÒ¾>¥ÎØY³ëÈ@,þŠ9ßçb¿ûêe;\µèçÂ{Z¡ˆz³Ðç¼£o\*ÒÙŽøzw~^·pæÔ§{Öm})dæÚѯ/=Ÿnñ¯ø¯«ÿËžžB÷=¶wîE^^æýÓŸ|ñAgU„Ûd䃆¶‘bÀ€"†ŸÁWE]¡`T~Ç_€…݆S}ò5G ŠÐ±à~ìX}58Ù„;>…WW¹ÕF¤Û­uœˆøæâ‘2vG£M…ÐØÝr>>)b”75‰^•In¸ã{&r¶%xH¦$e‘jrábKš§å‰íç— jø‹’¢‘)ç˜øù3Õée Wþ¹ç¡ÿQJ›].¹f¤vÁxM\Nù真Ôi(mz—¢ŽQVÆáppÙè)žNž&*¢~‚é ~šÖ.]Úʨ–Ê© )ö4 ŸÀ’Jg–žù!p¬ÿ* l¢°bǨªçik‚V@ÚXC¤™êƒq;Ζ‘]Ø¥^0k«˜Ã®ƒÛ„è’P\¥­9I-¨=Pú¬½©²rkÖJz’™Ý.ö—Yúùj"¥¨òJì©õZk²6jk*J—ð±KKk’÷hh°ñTÌãˆ/ÌÈ»c´ž(o¿KoÆöuT³qÄuü¨ÄÑZ™ŸÅ%é\²±K-Ê$‹‰ïµ<-üòvBº²mg}–O³$LÒÿVäõ¶áͬ ¿Cš|ôBa3ó±Ê÷t\³kTmìÒ×Uë$’ºwêáÝ~;èÓã&»÷߆Ӊà¼Èšj÷áL•GÞp—êxå…ÇGU²r5nù3ˆuáÇçz§=º`Ûdzêà¸m†®K:´Ø³ßÞsè¸ÓNùî¾›ðµx¿On…­¿ŒÝ:âŠ/][zñõÓC™èå§•ðí¯-’6r¹âMv—3LzÈ ÀøõÎl Œ`‘S7 ЂïHÜ9ÈLÜ„·CàI8 ¢px#\¡ oP!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó ú„JGPŠÍj·! i­*‚^®ùŒ–¿ëX%NËçôV[…x/ïìxý¸ÀAxà—§'¸ÈØ8x¡8™çXiyyhȶԇéùi楙IxzŠ 3º9!Šèöš:K"+™ÙZ:YÛë;&ãªyû[l <²6J|ÜŒÉ|h í\Ý»úEÂdÍ]mòÝ-žEÍn5ž®np¹þþgø-úPŸ¶ÊÜž/à–~æ¨ðq%0¡‚7”S1GÃ'&F¼gЇÿ;ÒàÈŽR2mKz v¯P‹xLº¬ˆC È—4¹ðÛ¦cfÍtJjÃ2d+žD§»‡I€E›Ú+#s«Œþ„:½ªj´*@c2mi«Ø•PËB%5V µÈb%'Ô«·¸iwøAd—.°/|޵v·l"½7 ½pÎŒ¯äJP"×ñ a‡åTur]ºCýy=j8QfJ(/à üYYäÁ*÷µuø¯:¼Ñ’êíäÚïã{ŠGŸ~í[3dÎLºB-r™iÑ–ƒãZ 2ð§C–vήø#ì\#ÑÎÞãä=Ø75ï=ܳuãÔ1'n½k³úã8WKßÞžotååï#ÿSŽW|òèf<„ÜnÕYÐЋÖêrΣOí zéT·fz䕲àyê&}R×®Ïîí¡O»í³—3¥î’Ÿ^Ýæ¾s#OOÊ>öÅí€c’…AvÄÀèÄTÜ'WÁùh¤;è¶ât„$4@!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇRµŒçúÎ÷!m¸ù†Ä¢ñÈ¢ J ò J‰JFÕ6Íj·Ü‘SQý2Ë®ùŒ¦ŽË ñ8 Ëa쉛l4çü¾ßQGqhsõ‡˜(W–1ˆPó¨8IyÄ"t¸†Uéù‰tÙ±ùÖ zŠÊ#ªñVH–+ë² (*éT;»ËkŠ+tëȸ×[lŒñ5 l‘©yü -ø¡KH}}j ÈÚŒý .ÍNî©í%^®ŽX뜾–¬“ |.ŸŸ6¬ßïŸg' @€ÿ ¢º7Í B-ø \rg*â‰?.4¬p±”DŠÿé€!cÇ‘IV!$‰2)nïRºä²²”®“8D¾¼Yí!›8{î´S›™èù<*¢L² †– ÄïcQ¤Tí8C,çÀqzªz 鎛{°Úxã‰ÉÀhÿ°Í²…X¬C[lØ6îWr+•:Ýf¶¨É¶zr…ŒdËP‚‡;½ÝÖáUÅ WVFe+káFjf–˜Ÿ2†\vnaÂÝöRUe,PÁ¬Ÿ¶‚¸ðh©›Cç~©ÎÙÏÞö½¸÷ÇßÉoÜu›»Ç¸wͶ!ÜX½–ÜÛyòÁŠ{¶8:o“Ç—[wÜØ|ìàÉA«?o<<ýË`×ÿÕ8ßjµ…EÍ]ÄwW-ÍgV=¸U~¼1¡ƒ w{B è^{o”öœrÎØó^t®×ˆãÅ—X\ûM%†*ò—ŸŠ¤lBS®í˜†‘I8Êwص"yz…f(ÖHäŠà]D]ƒ€I5‡å™"+§Á&Ô4Gòf’€5ÖFÆG_/Â`‡J¢7åu¤¡Éæ ¹¡(ž›qnW•2²Xg–1^¹ç„p~©[˜ŠÊ•×2OÒY–£™GW}MÒ£‘Ì=¨Ôy•öÙ"gUŠXžœLšg{ZiU”ºiZ*§Á÷雯by*v›JÚi€µ˜h£žh®ž®)Ú£%ÿb„¨ExˆQÍø£˜=@)e…|v¹A³‚¬É+?¿vå­w¤n7£3ºúàê…—n9YuÙ¹h½«ñ ®ºÞQŠì¦íÊl¬üVki¢š¥‰lqùư| j‚~Ú­ ÿ{ê[⥺Üo¯”k‡öªc~ž5#¤—Wêp°Ï²‰ñˆ¶VÇ߯³Œ®–0/[ì‰xØNùÝl»Ó£¤•+Zv›~Žš{›ý9èÂL^zêg.¹êaâ¡Ä®Ï^ÑÓ´·¹³ÞÎ÷Ôˆó>Òï<Ï#>z Oü?°G›üQ»ÓÌ|ôÍ¿öŠGÓ_/YçØƒ2 öömèè¬~™÷૵Õg(“Ï òç÷AÔèo­'ôïë#þ¹õ[žóýýØ1§1Å|þSH†Ld—;°nìkÊðøÎ}”Ç/WA{%PÔ`‰¹–ŽL",! !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf樒ΪõŠý@I*BêÍŠÇdåVq>/¤å¶ûÝ OÔ‰.×&‡ë÷ü¯†ŽxðÓWh—'"hÅvø锈ö79õ€©¹ùbÉU²8EÈIZŠãé:ƒgÚꪈz©Õ•˜ùz‹«è7SÊ›\«f ¼á(¼ÌŒILuL¡ÚL]­…m½ÝfL-Í-Îù b77žþ¨íS®þ~Ë?Ï<ý´KŸŸ -¯ï_è #Láþ;Ø \*|~ë7b{ZDA±Ž•Œÿ;^ ¨ÐB@$ßÐú(qaÉ•¦5J‘’¥Ìv¼î bHPàÌ ”šä“£¬1yµùåä"ŸkØ; Õ…-¢MEŒŠU§(/A#Éó©Õ›×Öüº í%¡RÃte”-Y”¢³²’ÄܨŸs‡2`‹iU q)ùMÆJ–Ú¿žŠÖxøoÅÁrSUOz>\ºÇß‘ûæÿ?cKÛ¿+e}ü `Æj/Òn Ô\˜¸ûAp] œ eP!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰*Aʶî Çò¼öJçúÎ÷~xà~Ä¢ñˆtk·aò JK•Íàœj·Üîçú[WY¯ùŒ~VN±5 Ë¡íòçN4çü¾ÿ›•džeG(ø‡˜ˆVÁˆ¥×t(ä¨hyIS iÈ ‰  £I*tÇt7¹d*êújÑÚª2A¦9I‰ »Ë;›áKYÃÆøÉk|\|1‹‹§Œ Í’wX'}ýèðœ¦Ç¾8è9¤{ºL±'ÎîZy®ŠOØ^ßi¯¿ïIÂÏ/ »w "ØoBƒ -¤Õ0¢1ór<”ˆñÌÅŒÿ-¢hãM³Ž$ùœÛˆ*eÉ•›½xg %Ë™Dþª¥.ŒLš,OâYFP¥KžD[\!¶FØË¢LS$FÝ·2;›ZöMU³5vª&¼ Vd :«X• ‹¶ÈسÚrµÍ:4˜¯sµýdw×–™b‚¶ÊÊénZcÔÖ¢Òµ.9¸Rsx:ÌqÖjoEEw—í6k”%+ut´kåyå~ݹޡ WçSv”ÞÔrÖdTÌ“ª³Âž !lúlëà)I…Æl—¸lÔœÈZtïÉÉO‡¨s¤y™Su~Ž9j5ù~ƒ9Þð¶Þõè×í¡«—nüréëù²7ÿ? ÞzøÕ‡|º1_)Î6œXÚÕ2ßMÚTʃ^Ha†öf™…jVY_hõLÓÃ^‡ˆ)÷ xÅ(àgí]&ÜHÜm j)’¦#1³%¨p¸ y®©'ÔcˆÑèÝ€*þÃd…ØUÇc…;ê¨AwRö÷È'òçŒYnˆ%‹¿ÜFdšXéÑ“ŠQfçÆ~µqùÆ”VI§~êDù˜˜ä‘ÍÅù…#ºwžž&Ù’š’z©p3Êyâu&W§t}ÊÈÚ¥±eJ]˜‚zZ&-^"J¥˜ƒ0ºž ŇЛ(Šª3GÚ™£M‚Êg{ŠJß©JÑÙϪÄÿ꫹6*+°æ ©` ÔöÊa7jA !¶ª5æ–±˜#e]‹ë¸fvy§vèš0j2sFçmTy¨°Ne(‚¶b8iÀºÏ2I²«ŸÌ Œ{Õ%졸/Âú"rã‘êÝØœí±8bº©Åý.ìj ÏÆ:F½*wð¯À`¡ÜÈ?*D1œkÊí{ëE›g±'WlrÆòš/Ê'Xs?Ó74»lr ¤‚U½ë2GAXQR( yoÒØÀJu]p%æmb1É5"'‡m Øi‡ õr1Ï[Ó¥øV­&W -éÏ~ã-©ÞÏüŸÑ€.Œ_}G¼ï‡ˆã–Ùo3þøU>Ëè+ÆpWnùmÐ*ÆyèÝÆõ¨áè‰Û#zêé4~ôæ­WžõŸÏŽû[[çÎ{¬»ÃÞ;â°M|ZÓV|ò§ý¥<êºE|óµ«ôÖ_?éNlÛŽ½DÏW/w‹Ý[<餻¸îøû0/ûšS¯~@ß§¿¦,ÑÇ/ÇêŽË[ßöø¯_¾ð®Zÿ³ 8àÀ–&-‹œÿØ[™Ël÷ƒ 4P¥¸ZHYÙ6Xµ­Ü „ÂSM¼Hˆ;¢pv \a ?èÂÊ !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"@—̦SXkآϪõŠ)@E´› ‹ÇͭÜø‘×ìvœ„3ä$ÝÏë3Ý齇¶GXh˜¸x¦vèøX†1ˆÐø“¹É©•¢ ˆÙØIZê¡ù‘ˆ6Iagú ë5z:«J›KJ{${–¤,œV—ã7WÇ:¼üÊ«l±¥ŠÈL ú)m0ZÍíè vÝ->®õýIŽž>-¥Þ.Í%éN?_Á[¯Oô¼ïÿ0 À~ì^äˆÏAÏòI1•Ãx³Šýª1c‚ÿ/ÉÓÖê£Æ‘+:2 )¥RA’,‚šådË™ó¸À¹Î×Jš½ÚK*UpÉ^BhZR±8«‘Ö§œ/g-¥Uª­í o±’„tQC¹ZÁÁ‰V×´[–|t,1a›}­&þHx_È8“"ûê÷1±Ž“+*{1'h?Dã õQÚ…ã"† T§Ä”šáJMñYËZïTì±ö`Ç´tWvëØ÷åbœqÿ,únAxo–µógiê”Ù£'kMɹ¢cÓÑ2EÅ:¼wbë‘K¿ts:vèÊéƒlÞ~¾áàòyÓÿv­Œ`$øÝ ÙÚ©&ÓrðÙ‚Ò\êIˆào"gŸpr…B€Öax[{ß±Vg²÷•x#÷`d âÇ\q*š¢Œùù'nÑL¥ZNì¸Ö_t±òˆ,b>þÇžE6ºø’ ÎØ[“÷=yRüi`b•½u©`]>ŽY!{8rIä’s§f–’¥]†9êH¥“-Æ×Ê’pòâšž¹Ÿ”Ça$ä|K9[“¢If£0ˆé§ŸÅ±)âsvšçåi¹I™”xB($¦qž()2øMŠ"ƒµQz¨œQZºÁ¢nÝ9+¨o^™i4rzªÆj¦{Z™›©X Š¢„…ÿRªi³¯^)«’ÛEf‚iS£>ÓCLB“™ÓB*©Cú›ëgä¢V)ˆn¦ «`¥³¶µ9¬®Ü:ÊoƒùV-šçÖZ^¼þº'¼újiè­ÀI†/cå1kš…®ŠJqªÂKQ¯ªT¨} ¸n¿ý G%sÇç§ ¬¤Æ7‚Œä~ «ç±m\ è ö£{­&¬¥·{¸WÀùn4­Éõ„¢óÏ@5m­!¬R½ÇÍ+Ç ²T{•©=Ws£5Öçä•P݉;šÓn ó:f¿M÷†KcXß„tï  (_ç-5ßüòx­·… >S?Sýµˆ s#nW¤êÝîµ¾Cnz …yO…ûhç4•¬êF¢ó}Ïã—ŸžQz•W|!묇-{ítQî‰íˆµµîžç {p¾¯i>«|ÍɯFrð>,Ða«}B¥§ˆQ„IVïŽñÚ_cÏÜ‹#ýÙy?þ!¥U‘IJ§èïËÎûðG«æ˜õ~ÿH0Û¿§LÊoè  >Ç›DÌ€viÜxÇÀ1)NŒàjXA ’$MöÓ ÛäAȉ/„¢‹ OØ‚!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±EkԒǦó 2?`ôŠÍjcÓÄ2¸ ‹ÇÐ.£J5“×ìöZ}Xºçô: ­„äö¾ÿ¯„¡·—4xˆ(±hˆ ÷³˜8IÉãèu÷È$YéùÉÑé!:Aêeʪºú(bê ¹iËjëWûK»K¥Kë{;Ì&ܘ#›F¼ü'¬á¬Ë,==sÕM­Í›W½ý Z‹½÷~Þç{Ùj>2Žÿd¸ô¿aŸÏßÌÞ±¯Ÿ@\1eˆpUÁ„ a,¤` bÉ7èmÊä,b,ŠÿÝ­{¸1ÈŽ$#$3­] o,KºÔçÈâ™”>þ½¼ ‘Vžk D¤7gÉ“õÀøT´TR¡ÍLùræ£J¦TwtÁ“êTÌ}ЖVExuÑ8[ š=å°Mµä²±µ"³I$n³¢Šó*ï×[N9Õ³Ù­-ZF¤~†µÒ ÎÛ:/Vì¢bÁ!aòI™Q[¶óLò,üW3⨡ f$MÖ(ѬJCÄÝÛ±ÓẉG×Õ[š—å`¿l'nü–wÏ\Ùíz<¹ŸŽä]§¥H™q! %d™î$wà(HžÈ[FÈ–hžåX—ç5ך$œ½)˜Fz¸Ò’õñè[›o®¦M%ªif£V½¢gcw>Ç`u i\¶Èfyš¸(tçÍtc“žz£çs‡bXYŒcùY§èåyÌ¥qÒ©iŽœR‰'…©j—›¨[’  ©0Љ€µÿÊ)áQUÉØ˜öçŠÓ*XdtR<ÃF®'LÚi ˜š d¥ÞJÉ䇯pl”[.;ï­s¶;¡£úV©½Wz«§GáëªÀYþËj„Æ©lz/Jª®Á¡.(~Ê6lë‹_v¹'ÃFã¯}w¼»ïPsú´‚¬i0}×¶,#®‰ºw1‹ÓÇ­ÄÿJS²†bÜñ¦Õýj¶ oE²“%Ãruª / ?'}ÈÅT÷ Û5Zï”/?S§»…Õ`».]áRjW×K¯=œ½:V@l/=¢\le…s›Iîón<öÞLô¢Z(xHoè%ã‰37êÈüøP—¾ RÞ•“tµ8™†òùæ±Þ`M¢ŸŽoà¨ î¹æ«¿~~ªÃ.dÓWºI{îPo¬{ïà6»ïˆxõîÕÂ'„»ƒ­óÎìñ ÖÒò“;Ïùî_¿»ñÔ“<¿ÀoÏôŽ#>Uâß‘fù8I~ùZÁ«ßhßð¯8È„½?¿*¶›a/ÚçžÑ ÿàठ¸pnû‹þˆT,J+„`%¨2 >Ž€Ô`â¨åÁÕu0„°ƒ Oȃ!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~x³ý†Ä¢ñé‚Ȧó - AeôŠÍjASΊ¸ÀÛ²ùÜì:Ô &ú ?ÅÔù ¼Ë÷üþ‡ÝF·$èWhxÈ¥7Vµ†èø¨¥ضè噩I$Y‰!ɸ):*ÓÕ9–A‰gy©JúJzJÕhàºá «ûÉõ‰‹*»;,'Ìj¼ä…—Lì\fÜùè÷˜³3¥ =¶iù€ãKÿ§_žv¸áWÔ*Y9üYvÚjçÁ×_ÃYàW41ita/éôD ‚‘aè“@Ûí÷a~$Þg"bTwQq¯!÷ŸsÞùô]tû½èß$ôQ—Ò•ø¸ ƒ Öˆ#†ìHVÙR¼-ùÆW­ø‡d;Î7¤Ž2bãg6F¤yUbIX¹h—EjId˜YŽÛFì1 '_ª¥{bZååe:5褖›‘‰ yV.GД˜y9æ€Ïz¥~`Ö'¢qî9ç`¸åéæ^qnJR¦€ ºX¡­ø[¥<¢y#¨Ê ¢´‘©Ü2@ƈ]¤Caª(›¨&˜(qvÒ*ˆ”¢Ö™©Tî°«ÿ>ªŸ«ÍÑ*kšêÚ¦•+²¥öéQ>ö kˆ?|ûªj‘{Q˜Rx›Žó ‹§4Î~Æm#ðŽ0Y§] èÛ½Géš,„ØòHéºwZÉiÂÄYª¢¡TXµóªŠ¿úƒ*®Ž;Ú„jqw&>9©` ? pµ';Û.‹ŠšÒ› /‰Ü˜‹…Äë1€ R6”jÍ^û3ÇÇ©Éç…A‡FoÉ[½¥†×[n’¶Ò’¦3£bàb!N{ƒ«¿r¡Wjp-c|ÐØÝ”­5¾áæk2ÛBŽuo.®m)—yÿÍÙÒH¶Â÷†€+|³[ºZtä1ÎdXœÑçݘÌf×xy™ÓÅaçpú汆~§,ºR\,÷ã©Óä/å®ÿñ:WU{î-¤¦{ï–Ïþ*Þ¾ÿͺðÃo •¨ÇOBUËYé"GzðóÉF=‰@Z/D¡óŽzøÜO=…¡Ï)ö'¶ˆþè!š=¢äíÛ~v¶ó£ Ì÷/¯¿^Æï?ŒòU Eƒø‰±“}ÍQ×9 ç€±@µÐûhœWòEÁËEúË òa'ÂyPwÂéàs§ %‹à {'¿îO…2¬! !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋uÝ ‡Äb ¸øÙŒÌ¦ó)D*K¨õŠÍ®€4F·« ‹ÇPpò`N|Éì¶ûmK«ò·ýŽU§Ë:Zš(8¨·§¦D˜¨8hшÐçG÷³Xiéô˜”i°‰x* Ói²7Ù·9Úê:3Q:"9‰úz‹ë@{&õ› ìÆª1¬Z<ç¼xÌëQå ËÉ\m'm*ÛщmíM$Íý=NmÕ]žžˆNý®/øK1ߎ_ùþî•ïÏæ,Ͱhôþ¼f—ÀX:„„ì¡Düîé‚hn¢Æÿõ>Tœ‚áãÆ‘%›F2%O|žE©2&EG«,)Sæ/[œ±ÛWgΑ #~âùÒf¿?‡:Ý ÇL=CÎzŠ5ƒ@ª´(éªú¥½¬dÃþ9m'ÚÊ<†éÓNh¸tRÍ¥»RM.È-»,*Á…4Lý›lï!»È°­© Yo±­Œ1®…|ÒÝix+ƒ,Ì4SM“˜ùjK:’Oqg/NVѰÊÕ­?¶z1ßÒ-OóÎl«³æÉz'ýmÛ7ÚàqSù¾ÝôÞTÔ‹•^PÁL‘×ÒÛ{OÏÍ ?ƾÛìR‹—%“ü’9ü/`A¯§6]¼óúí›Óÿ'O›mÒIá ‚!S1ÑÅ—`ƒbé÷Ù wR„=m\Z,PXÖ™W\lð‘ÆÞu"ò¡{&ŽfØù¹Èbj+FøXr¨"[ZP†â69šV#t&Va…åŨߟ-G!“P*Y׌7>©¢VÔ¥WÒbÝAs¤bjéå† éàŽÁx"›Ïq©Ô‰R¶(Ÿ…¼ÁåäxT–Ùe•ý™·d–î×gœ|*•§ž`ŽÉhr…H¢sô¸ékF¥YdSPž7éø¹YŸ‘ýX ¨œ‚~J¨¡[bÙÛ)B*F¤¤8Ê‚§¥…ÆÊ꜑nÖ¢q‰¾™æ¨Šjª©©Í¥KÿU5P…ù¥E‘´ŠÚ÷^†Õ2è [ i›mP?±igQκV ·ã6 j¤<ðú-·¶ÊgWÙÁdm£cxmwˆqQ³ábÚ&ªÑî g¥©l0’ÒÊWkeÓ2 ²+MÖîT$íÑo© >w÷•Ê)ܾ6Öê…½ƒyª-–©$6’ŒáÔxPÞ›ìBÅ—‘äË _B¦º ¡e½s/ÒôÜhïäÏ›QŸÃµ©™­ÝºxeؾŒ×„Û™vqη£;Ï;Ü:羫Ðb~ü†)èæØS'ý9`öѯÕ{o¼[kùÌ«oÿ®Ùuÿ§_ràhÕ_¤”"’tóa×=³puËVÔ¬#5xhxჯa6ØJY5aƒ#·}¦‘”bgÿ±Wߊ‚ `¹Á·–vßÉHÜŽ®ä&^bw9C¢nFF!›]•äEd3¶ÇÎtüm£‹|T¬9zL1ÐÇ;4u"ã¹2UOC60Î.÷GX…>EØ%† ÃÇV'òóØjœèX@‚í‡Øl7äö?¯·qÊ’y5¥~(nÏæ xÔ/™˜Þ”!~õÔh–iÓˆOZ$ÕoQÉöÛÑ߃oL–Àïå^Öb2{ãùç™u‹wéª ~Ö˜«»o©¨¿®w-ŽûDûã–Ï{TÜ4Õjë½ÿ${ê?ý!9„-e»ëÏÉɯXüJ;ܤ¹êg¬ØÜΘ–eA,iDµüUpMµaÞaW›¹ïƒR ÍHػΠ…×£ ¹7Â^.]2¬á !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷>x»ý†Ä¢ñ³5‚8¤ó …‹  )Íj·Ü$ÁìŠÇä¬rVXËì¶û˜¦:Òêë÷Ïë5_ºÊ&·7HX¨rpW¸¶døiXEi'(™©©eù€‰Ø¸):Š÷Y5gGªºÊ‘˜Ñäú÷§Ëj{KÒ7W[׉û»‰å[rÇ;i œlˆ<¹#̬ý6¬ØìU-Ý]Ë «-Îõ‹4žNÎRGÁ[®.ŸŸ:Q?¯_f?£»°P8|2ú<(Æ` fÿ:Œâk` …+Z°'±Oÿ;&T!E$'"sEmDÆ#Kº¼s×)Tà-z‰ÓGJšZæüùΦ±‘>±=”箢v"} *·aÔ(Ú„Šõâ3©±Ö0Š™5¬:ŸúL­ÊÑš¦!ZÃÁ¶ÔÛ{yüŠcê\ÄDWUÆkËn_™2Ý-Të·Ø Jp“6ŽÙnèVƈÕHù2š¹0#²œ|(åcY™¹=^ŒÙgy{:ãT+àÙÅ/2ˆ).cÔ3Oò>Ýl7švÕNV>\ú3ä¹´ø*·¬×¸fäΧ÷fþÛ¬75¬£.–˜;ݶ¾SïÌW²Òå›­GM>œ}ãæ3_¯çÝ>òøsî‹cÿ7_Ýqv)ÒUC!䵟QñAWïv>õ˜ö`[k%Å`{²`›v7]‚‚pðÙçYl£ÝwÜu_XXaŠF tú±hÙŒ&¨Ù]ÝÍÆã6°•e`+ªáç_|±!÷œ‚'Ö袊$:Øß‡'c“uDÉn)Šwå1CÎ_=Ž9å1ü…¹âoŽ·ÜjõiÔ%gi•GË–¤ùGŸw Ú¦$ŽWÒ)'K•e7JN™'#>If£"µ˜¦)_¡ZYäœÊÕ‰%’ä©g™wžc§æš_Œ nY¥x0Õ }œ®E)pnÆ™¦“4Ñéš©ïáYë¥+†Öê“ì]˜£¤lÿâaz~âÅ(w7rHÜ+EDk&­RÚG„–_Qkm„¡¾Â«l%nµ¶ÄôÚ »˜¡‹)K"k£¨ïr›-œùò!¦£?yx&Ÿrê,£²rìz»j¥èaVS¯¶&œ¡¸ªÊÊæ|”fÙ`¥Û;î¶:Jû‚þf¥˜ÀŠ)ļ ·ëðŒ{êûéÇ·Y0”ï:3³T*ûéÃ4vóŸgq™°z,÷{²6·Š¼Ñv†;¡ê>òñÕf¸º¯ŸÁÑên2V3MFÖd›$°™pÁš„ˆÝ4@nDÜJ]KwÜ#{ÉQ¤Tçío99+Œ7àdzErÀzÂmxZ[Èx々--—ÊKŽùENÚB䙯¢uµŠ?úùQ‘{^:P%c”zÞœ«4zÅ­«^¡ M]&곋’ȸû®”î»kòº¯¿o üð™Pˆ{òÊÓ¶mÏM=ò²¶ƒC½ëµgÏý¡„›V÷Žch¼Ûâýñüžo8ó^ƒÏ>R‰~w—ǯ¶úñ=§óø“â-|ÍÂÿ ¸’¤(ð¾A‰É¨7ÆH”G¬UÁöAç‚÷Ë üˆ8*Ï¡áìZ¶?î.„*d_jZC#!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±õ[ÔhǦó %&É`ôŠÍjCÌG—Ê´nÇäòsÊ@'¾æ¶û}fSⵎÏë5_›\Y‡°´GXhè8ñwеxøi–˜fqgð3¹ÉùxI¤Ù9JŠä%Úà‡J—êWú ë¤j©Ù{‹Káx±ÚšŠÙ›+<œ \yjL¼¬§¼öáŒÌ<½ilµ{"6HÍmˆ=gíÛM^&¡­¨{ZÞ®u®‹š>ãånòÈïßdMк…åSçÞÁ‚ ]\ ¶°XÉc”E<†Ž¢F‡ÿä常1$‰‡ãè…«R¤JŒõ”°Cw-ÞÊ™÷u™’¦Îpò¢)ìÇk§PŸ¢gs¨R0¢¾%M¸4j6iN!J½*E›mL?býŠRM’É,Q‚‘³D(Ll©­ªÚÖ@ŸŠ‚kûkdZ°¹þÔÙ “«X˜ŒÔÎû ®"WŠß¦Yux‘ã~Mg³Øv-¶^‘)Å ±QÌYmÖ ¦UÒyúöòµGµØÊ´§•&Ñd_a2³• ¹ibΠSK.þ¸téÜ.kç-üYqòãÒ)ûf¼6ÙŬ[£¦ÎyÖ[ͺƒõm¶ºqÝÈCÿm9ñ˳Љ«¯>£rññúÿgôW:§•Ýs„x’D%‡à|Ιa{ ""Ü‚¡a`Ë`Ò€öT1ŠVØ}î ×ánô¡×mùiG!ˆõDWŸ~*²'âe->Å܉ hL‡¯ý(ÄawIˆad4†çâb5nbˆöÍØ’ù˜x¡|ðÉxã‘X*ˆä9nhJ>IfP— ¶Á%Ø16Cï iejC*—"a½-éÞp¦É'“Åõ——”(nã—5Òæ% :väZ™ŽZÈètâÉØr|þÇ›–éIɘEl^ç&ìL¢h”vºé3kbÚ¤uëÉ‘šüáùª“WØÜ¨šÖ©]§”êi(u£zöä©tze°‹ÿšZë/¡Ä:–Bb˜•‡JâÚ¦|´Xdš%%É“®án&Úgcfó©’Pb›eT¦š)«#H/¸b>Š/¤å–w.-Tšío^:'ƒÀÎj«¥yŽ‹Â,åzž@«VJ^’ïòZ±²ß¶I0Þå[¦¨nÚ `£UÌÛí{xÞÙêÆ î9ÚËÆm»É»Ù7ÇÄód¼«™<»znöÔo½ KUqÁÛ%Ó(‘gÀ\´'³FEl·–¬šºò–2uÓ’tMȇsjU™51öŽìÂuÚ.Ew—6hÛUËN§÷£¥>Ìà´yÿØcE xá2q+ïÙ†/x„2¹œ-I^pä–»Sí®å4)â^{­ù-žšI¸~¡Ešéªã|ºPék U­»~8QÔήRê+³:îÝÀí¥[û®ðHôNü=˜'ï»îP1ÿšñ<Þ†<ôn­måè·[¯÷ðw7ÎýN?Mˆ·Úá‹¿Waz|¾ø¼˜mvûÅKTUpÕË?Ñ>ú¯¿Nû“º¼þ-å‚£•Q1·ì€ørßfs?Dß“`Ü‘ ž®Ô`HøçÁÈ-¡ƒ!,á !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú·uÝ ‡Ä¢‹ÖøÙŒÌ¦ó).”K¨õŠÍ‚IW¡ÔŠÇdë·›”–×ìöó À¶¹ûŽÏoÑòj"¬(88bçH˜¨èöåá8eا¶XiÙYhHuÙé)S%)§‘—&ú™ªŠµ‰¸ú ÛÑX‚Ú{‹KZê±{Л \ºçû+ŒÛë÷;Kqœ]ùìÀ,­ú°nŸ™±¾|Ï­/ ¼íLöï¹rø:$‘°žDϾ=¼h‚¯ÿô"büøZDMy‰RÅ»kýPhL ³K GƼ鲤1xâü9ãå >§=šâŒš—3/C u ³©Beò‹Š•Õ?Ž¡‚34HQˆ'ëÕ³$­-B”ʦ ÕÖi§Ïf½¶+6¥\'öíYêl;j¹Õq[–A-¥u2¶—¸áÈ=%rªßrçKvL²Y[C!!9Mõ+KÏv™Þ½hú¯±µ`š>švÁ̤-7¶š†ÜîG¡éü6Å»°ÚÜ&›*þ£¿è–E+'}ºÂ²'Í>f7QЛ?M¼E†"‹'ŸÜ7v£€…sn_þ=}ü×sOÿæ3[€ —\ö…t M¤4\sõÅ`edX‚¢)F’^;™¦Ù!áÕ6rbFpø±G\~Â7âLUuŒ*†¨.vÜs øÃk>fAIiÆI5Þ~#f8£€VgâFÖW’gÁ9˜]“ÁýgãUIn§ÝŠJrY"?®ýHf„ºÅ%¦þUt&bŒÑ‡!œLJwäyvuRŽ%NGe˜5¶hgŠxú‡œ 6§§thÎóa™ŽR¨ÕkVÈzv餈&wØ–’þ©çöt‡ŒñºiŒ¿Uêàså%êªÞx5_?Uöwé’W²˜*”Úê×r·’7j~UÒ åœÖÿ©J£±‚š˜W<-ê烮Î3Ę`û¥Žâ^¯×¾nÓ𿃲ñ8:e½¯|0t}õVÇž¼õ)3¿:õÝk”è—³-ø7ÉÚ;ßê››å"Èþö¯}üú¨TýöÃsx_‹Q»¿‡€~Ó_ÃÁ½æ•JxDI+LÖÀ2ñ¦€Œš$ XÁÅ탌TÓAÆõ/„®kŒIˆB!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~xà~Ä¢ñˆtUB[ò JËšS8Íj·Ü×ê;LÃݲù ½>ÔV´û ‡_ÙâjüŽÏȈ9ÿpó§7HXÈ 81†ˆeèøiÀˆc×çÄ™©£FçQ 8·9J ƒ rÚÔXÚꊑ*ÙGâúõŠ› »§ªû ,Q Á›H\œœË[Œ¬ü º6+|ñŸÐn|Y«µ>e™É“¤»ê¼=/éer„9õèô^»éÚ?eõ¥ßO~òzêÒljþã9ÑImûy“—¶ü=íæpåöß/ÐËMÔ¿?sK?ŠË^ÛqÂu†qT^äÕÀ€¡ÈnœßWA V΀ôÐ:ºÅ0s`ààO€!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Äb‹Ö°ÕŒÌ¦ó9\&¥ÐªõŠQ§Œ0 ‹ŸÈî¡ÜE×ì¶ð ئ“q¸ûŽÏ‹ìs³Z(øð‡ V¨ 7¸ÈØxÇ÷h€8Y鈙If8¡hè©*uy–@É9…:ÊÚê°êQº°úãj{k†!{Jú‰ ¼›Z×ÛG79ÌÜ|²¬ í<·‹&ýL­=]Ò½ kJHòŽ.nœÃ'ÉK—4‹½šÉ »š<5l¼¹™•=‹rGKÉÀ˜F›Ê8t ZReúœZ`êÏ>ë.à¼úðX¨1KÊ S—"…~­V ÙV6rÆJÚIç¹`ÃÙýeêÐ)kËøåÓ¶Û¸²BR:+®ÂÆIÆÊ¸R¾€…Z.˜8¤M^ž1/F’ïlçGÝò¾Ý·/âÁŸ¦½û2ri.¨3ËuÍùé—UŽ5åâߣ‰ÝÉ<`qÚˆB'k u^.–‹¤RæuEÖçô^~ðó\äˆï¦¾ý½hìšÓßæª;°{ÊÍÛ›ÿ¦¯]Ó…¤Z}¿(‡ŸõÒ˜OŽ” iŠM8CWBGHƒÂæa¬¡µZ4†%§[aöñòSyùù6PÕ]H‹K†â~2–øßŠÑÈUn=†`lBþCÖ`åtŒÒs^†+.×"oñ™(ßHTZÆ ü½X%r¨hÜŠFˆ–#‰æ†>®9Q-M’(Øi!:&–þI×å’P‰ܘlÞ§'â}VÖXLœvr蜟½çËQiNº—™‰Y(?ßÍ h˜\ژ鞅ö™—N^2(–TZánÙ•ÊÞ£ÀiÉÝ^$Ê`srªä]Sæ*˜æ‘ªk|§úê±¢ÿF©ß¥tvê%|ÀëxLj¨Ö×vÂk­$=!·±‡S€s9úY·é’„éŽ:þ9Ÿx_öšË–Gš—Q‘° ›+¥þ¶ÊZ ¾uë¹ÙùV*¶ë¥òª® ˆ«¤†6Üã¢h®¦ÿÊÑÃ?+p¬3*â™iÈû/<Þ}XÛ½–@l«›ÛN좄 û÷ñ›Î÷லÚ|1s9{<(¿xFG•4á…`rÊýèËòËð u GÈÇ\ß3[ KDi#[£ ¶³_I[ÛlÞŠ$ÚR$Öy>]çÜz£bxÖ ¸öÞiÖrÞ÷É-¸QµÄ|µ9‰ƒõ¦´vLùã²ÂñG/´Oš–¹å ažç¢ «éyO‘;Yzêmj.ú䪿žȲkû܈‹[ûÞçÎû³÷®øï£œð±I%¼ñÊsÎüíˇå8ëÒ?ÏÓîkºã<õÂ$öN¹Œu,ÞˆƒºãÓdý—ÙŸËRÇ~õÜk^&…ñ×ÔQ«f5nÜú÷£$øÝ$}ÿ ”’â¿Ú¾PJ¨2Ê” ‚BºRdHA‹ ðÔ *0ØÁ¢€0„ä ñgµªð!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5@ë ‡Ä¢±õ[ؒǦó 2I[ôŠÍjaAeͺ ‹ÇЮcJ5“×ìv—±‡pòk!Í ÉVž{9?Lñž]n,kÉE†ª—TÉå­Êø°f*¥ý†›§ˆ*åìÌÐ)cÁòÈå’,Ø×M|l6&h‡bsç~a¬>iK}ÀÉ%;0ÝzÏïO /½wà«Î„[\ Žø#oÁEàµZ'žÕØ‚^ š€ÃCþQµ_V>NǘµîÕ:Ìý¹(|9ˆz¥¥Ó]ïã2­.5Ð/D {O¤×Ž» ·ç®ÂŠ‚Äû¿;!|¤]Ž|çÅGŽí‹Ê/Ÿí g ½™_ï^ý=f„}öÆt?øÞßâ:ðã3¿ƒôç{ã{Ï6‡¼>KÉ”ÿ>r'ÇÑñì5‰øø³¢“W±Ksÿ£‰Šªæ¿Ú%’SŠê$Y‚ÖãŸâHÁlHP}Œ 9ØÁèa0„ª! U¦–žp…(!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó •Ë ôŠÍjÔ³[³nÇä²ìmV…æ¶ûýD§×l¸ýŽBÔiyþXsÁ§R¨P'¨¸•Há‡p ÉhyYæh¨I)†ù ŠÔ¹ù@Úyªº’zàjèàÉJ[ÁiÀ†»‘Ziû ühª±‹|¼:ZœË‹ül§+¼³ mí&´[}²}í}ç\ÒMù].¨=Î<nÞ^›î/Ÿ!íQ?ÏÚÍþ ŸÿÃ_«I b[GÍ BüreÓ–£á‰¨†Åÿ#”@äðÑBHŽ$VáöðÃÅ’,Ãàò8feË’³IœFh¦N‘¾¾¼ùJ%ÁD×ÕQ¦ÎË-Go}ŠáTÍ9äÉÄ5«4\ =drò§ŠWé©ÃQöZf@£MôÕ•X¥Ój Ö5L¤žL ª7£š}×Våwo_DIe5¶ºxÐa§U×J]ªXÓÊbýÞz¶¯Ô¼?Û#«­Ñ»wåd‹Œê§ìÀ `N[8´çb— .3 ÙóãX†-of¼çå XÀõ ¿=¶2ÛÍÏý‚q ·ŸHb~SMnwrǾ9§† Ø»té™b^²ü÷ðÌî¡Ó-.ú¸äÄ´µ‡ÿÅj_|F^TÄàDUt[mÃÎ>ûQ¶`&ÈSEhéçÓ~A¨v^ss\Öà|È¥gn÷aÖ™ƒÌÅW"qõÉ Cèu£Œíõg_¬í(Š2p XÛ`( d®‡QŠ'Žw‘‡8]‹¾(åv1*å¨až=ò&j´éhaƒâw]}ˆé¤dêÙFàQQ¦IךCE)æ›]VIÝ™ R˜0f×]_†‰(=†þáuºé¢&K&9$’(º™–G7ÖŠWj‡B·õ ›fU zªRd&gf©jz§‰È Zi›bª¥ŒPþ§*­Lî™'‹¹è«sÅ>¹!H7ÿõf @…Cg„ÎxRTv§ †ŠV"¤Nª£ˆœ·‰kˆ”ʪ.}AšK•­«%J/h{Á{ïªãŽsc¨g*7Þ¬™:ºž¶6ÚTðœøîúç$ýúÉžÁ–ŠŠ&©Ú°1ÉÞ»i‘­ [ï?? ©\qáœÀ:·)ÆgJâËÁQ[1yrŠÉØÃ®¾ü\“¯ö¶0Æ'Ïle¸!gå#ÑI9#ɵצ«ó3:ƒŒ ¡k´» Õj ü4Swi°N64/ÕhÙùÎfÕh‡ÙÄk>A;2Ö¿½ã†šõ"®Öé€7>W‹Ø=u"8kqo‚ÔØv'y¶9>Þà‘¯Ce²¼-×ëå$5dy…žïä6 ¡Ž¹¨¿M 8§¯.rçÃN»€â\{í`Ãózîñ4®¬ï¾÷^´ðZŽ{GÆ£¾ûòÎßþ|ôˆKtó³ÏK½NÈS«(ñÙ3¿¢~´‘¦JþLüp’«é ™™{ÿ>^1—ýõ Î7ûáퟸÑè €­á ûHÀæO ÜÈØÀzIìzô+¹/0ƒd@!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡Ä¢ ȰՌ̦ó9\.~ôŠÍjYK¤âgÝŠÇä§÷{8#¨å¶ûýV†Ñj¸ýŽÍ“õ´4(è³·6ˆ˜ˆW8ÃøÕWŦ8Iä9 vYéù×Ö)jzúA:ש±Ù…  â¥ZR*‹››Y•vÂjð§;Œ ¼ö`L¬¼ì@›•Ì=¶ MRÝ+ 8ŠŒQÍ{­-®>n~®émÎÞî]îÏ /:Á‹ÏEýb¯ŸÀôô¥¨70!Ápûvù"Ø, Â‰¢º] 'ÑÅÿ” ˈi]0Ž$Õ]jØ ä”c%[6vlH•h\ÚÄäq%F0+ ¼ ÔÚZ=²4j‚fЄgÔ öÔg—ZÅ¹ËØ(IN6³ÃŠØ‘ËÆöBiêU$©OsŠâíÕqN›®zøuƒÜ”n#1k–V¶p±Y¬Õ'°_²cÁùýçèÖáˆkk~c¼Ö±à¬ýªüö‘¥sÍ":X߬C’ý˜óYžª?³Ôú:]âÜ¡ü[vU_(‹Þm8¯oà R~ݳ®ç“ÂHC]-ø¯lÉŸ'1Š;ùñÂZs.çŽ×ûʘá“_Œ­q)äÂ×wçݹøTÚõÙÿV×µ ÷˜¨ŸEä5ƒz>•#Ivy¶ß,Æe÷Ù^Ú'Ûd½½‡•{牶^{”ÉÅ\H(¦É]†DUZBTžjÁ¶gåq|"ZV`@ŠVq*~˜¢­ð¶R™-9^sõhc–qv…д¸]sô¥“d‡Êiž€«É'fpdJ9›“!šébkÌ5õ]he‚y&NJa©e üù wçÝ#†MÖ‰f¶ç„eöö‰?ú¶¥óÉ8iž´Yé©“3±h(f’©(‘Œ†˜æ£àM‰(”ºUJåŠtz¨$¬‰Êªªµj"/MõßEQØCj¬zÿZòä²Ä¶à…Wª *{ÊÒa^ùÍɤTï»÷KËŠ“ØàØH$ß2¤Ü¦%w¨ÀM•A©Í’åÿþSœíõZAV‹GZþÊ£ÐT¿ê¤)ÅFD«zÀËlsr3îÿ߈¯§ëŸB_ë@r©¢|3¢r—DC¤¦WhA|ŠKÛÉepCeöÁPWÛYPvä-¨Y,.þÀ÷ï‹èê›ôøÖi¬Ø°ÏŠðœ^ðä$¿g^£l‡îÜ(¢Tf$•Ùðùë" ÿ)»ë ÖÙ Ò¾a¾C#)Oˆ¢Û‡`fØ{šÆÝà¯Èy4nv~Âc¦k®Á–ÞiÖ`vvÙUˆ‹GX L%)’I»ëÜW3Âv_š7*ß¡f‚½V„å[¡>ëd-i[Å(øÚV"í0Âöô¶✇È84äíº‡†ÿ.Ö’Ä• Ã5ù™…¼pC¨ź2«ørÂsŸQÄò!³u L‚5Y¯á›5@•Fë /Í¿ùØ{Dv!æè8+Éiøê—)oCJ)U;û°2½«å&p”ƒÐÕy£ç]ù€Ø“ˆ¯šÂ–šO¬uSˆÐôSsa­›4F¬H{…U™¯á§0³Ý«š&¼q ¼•λ‘tiiW™ߘ‚ Ðl ‚Òî‘‘ŠnÉûà+`f§ÁÍ‚XoÇæê^m¿àÆŽksH¯ŸGqÇ<$gœˆÔòÙ[Î|`ŠPá'c r,VÛPÝ<éM ½åFòe2çQôèôsˆÚ?Üê½DnfŸ'íôpåýàüÇ õâ4R¯zPؾ€Šžl<ä4 Kì>3OÖÁçew9ƒÈ—àåÛ 0Œ!ö€ §Æ!¯ûˆÂ;nÈj' .·›„úwÿ+dW—OÈîîÊPågDžbó€Êmˆa— ˆ6Eê†ÈåÌOÿÿM:ŸØPIEND®B`‚golly-2.7-src/gui-web/images/item_blank.png0000755000175000017500000000020412536111364015636 00000000000000‰PNG  IHDR Ðá.I!tEXtSoftwareGraphicConverter (Intel)w‡úIDATxœbhhh` “¤xTè†Õÿÿ9›€~zŽIEND®B`‚golly-2.7-src/gui-web/images/next.png0000644000175000017500000000035512536111364014513 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡úrIDATxœbøÿÿ?:f`hø cU‹Ë€K÷¿üßqæ ¯8ð‚t`A¸såýÁl®ÃfvŒ`ȇŽÑåáàÒ€#\E `È›dœ=å:ŠqàÓÍ @8X€‘d±Ùÿÿ<›¿t³:IEND®B`‚golly-2.7-src/gui-web/images/redo.png0000644000175000017500000000036112536111364014463 00000000000000‰PNG  IHDRóÿa!tEXtSoftwareGraphicConverter (Intel)w‡ú‹IDATxœb`@ )@üŸxŒ@ ¹tÿËÿgÞ`Å+¼ÀgÂBl¸så}Bà7„@4ƒ’anÍ01<`ל=å:<ê@lÔœSƒC5€€fT‹€]3º!x À­Ù™P0L;›à!Œäÿ:² AÃxÂÿÿêŠNm—ÄŠãIEND®B`‚golly-2.7-src/gui-web/images/triangle_down.png0000755000175000017500000000030112536111364016363 00000000000000‰PNG  IHDRëŠZ!tEXtSoftwareGraphicConverter (Intel)w‡ú[IDATxœìÒ1 CÑÝãõV*¸Û$ƒƒv­Ÿ§ õƒ±¿»{Ã3·B&±¾6Â7¶Ž®ßŒðÌÂ8ãåG¼dYqt€Å G¬ˆN¶÷þöÿÿM¨Z±fé„;IEND®B`‚golly-2.7-src/gui-web/images/fit.png0000644000175000017500000000030512536111364014312 00000000000000‰PNG  IHDR‘h6 pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡úJIDATxœb``h 14ÜyöH„Ѐl† „8 8LÅ­0íASŠ¢ÙHü\rC‰| Ä:‰dOˆ#-”HBÿÿTd¤ð••–IEND®B`‚golly-2.7-src/gui-web/images/cursor_zoomout.png0000644000175000017500000000034612536111364016646 00000000000000‰PNG  IHDRóÿa pHYsÄÄ•+!tEXtSoftwareGraphicConverter (Intel)w‡úkIDATxœ¼Òm À €áî*oÖ¶…{ókMó¡Ì&"M¯3º^Ì/çYÈÈ Yœ…‡¼*ÅrØ@öå{`ë ¿þ‚{ƒÊ ë_—Q&¬‘pÎ [HðG‘-@÷éÚÿÿœ2ƒf`!(«IEND®B`‚golly-2.7-src/gui-web/images/step.png0000644000175000017500000000033712536111364014510 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡údIDATxœbøÿÿ?1˜¡á?VLŠ—îù¿ãÌ0^qàéÀ4‚pçÊûƒÙ\F’ȆŒ‰6Y16<ˆ &À@(À@H1í € ‚³§\LjÄbÿÿè‰Ç¶óMIEND®B`‚golly-2.7-src/gui-web/images/cursor_move.png0000644000175000017500000000035112536111364016074 00000000000000‰PNG  IHDRóÿa pHYsÄÄ•+!tEXtSoftwareGraphicConverter (Intel)w‡únIDATxœ¬“‹EýÿWõg^Kîõˆ¶VÌ=!‚ˆæÙbñå&(±Y›G°Alz¬ó/€í˜Ákî °Õå!»ágßÙ°vâ~‰7U!ÀyèÇDÛ蜶‘~¦Èw@ÿÿTÕÏ;ƒÖ IEND®B`‚golly-2.7-src/gui-web/images/zoomout.png0000644000175000017500000000042212536111364015244 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú—IDATxœ´’Á € E;ºW7Ñ›#8˜x3NÀµ¦&ŸÔRB<ü@(ÿÑ–3“h?óÁDÃKr&1ܳŠf–-<‘ìqžƒD³6ZäAiçÌÊI_¯Û,\€~Å“Žÿè*¡»‰-ßè}eõ ! ‰¤Ò(cÖ+¸óm¥{`!U€¤àAš¶á²¿ÿÿ¾¶åÕ+lÿîIEND®B`‚golly-2.7-src/gui-web/images/cursor_draw.png0000644000175000017500000000032712536111364016066 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú\IDATxœ´‘[ ½ÿ©¼Y@Œt ö+f6TTU²¬'×íxQ©ÝJ k/ |{( pŸ€Â=‚ìlHàÏö-ÈÚÑ"88\"Ÿ ïLÿÿ\ˆOß÷0>IEND®B`‚golly-2.7-src/gui-web/images/step1.png0000644000175000017500000000032112536111364014562 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡úVIDATxœbøÿÿ?±øÎ³oÿà$F²æÎ•÷Á˜d`šWxAž0C¨or `ÃDƉ6€"Œ†Á`HH¤@vf‚€>ÿÿʸ”¤V2IEND®B`‚golly-2.7-src/gui-web/images/triangle_right.png0000755000175000017500000000025412536111364016540 00000000000000‰PNG  IHDRëŠZ!tEXtSoftwareGraphicConverter (Intel)w‡úFIDATxœbøO`Õ<°šOœ8A¾æ0 Æœš‰1‚€füF¥—$h†úÚL¦ŸÉ m2㙢F< H3ÿÿÚTZ±•j9IEND®B`‚golly-2.7-src/gui-web/images/info.png0000755000175000017500000000134012536111364014466 00000000000000‰PNG  IHDRóÿa§IDAT8]“=o\U†Ÿwι÷îõz7Np„XB‹AÙbiR¥°%*ˆRäD¢¥°¥å&•×ÿ€)EŠÔ(Âe2l@JŒ’;“ØëýðÝì]ßC±ÖuÌHÓŒæ}Î;G3âѸqwQÒ*²åùKõV‡½¬#iÙÖîý[{oö«~þýÒú{ ókW—®0)"ކ^ç'ÃaÆ‹ÃÃ,k#m<»w³[NÅ?]¿¶ÔªÖæxòü˜,Ôf ú£g:eCzÃÒÊÓ>ëÚÔ‡Ö¯_[jY\çÑÓ!YñàÎÇ<¸ó2dƒ´NZ»Ü’¹ukܸ»øþÂüÚlmŽ'gSO˜ÊÍò†yÞUëD•êZóöÃE/iõêÒ»üúüøL,!'>ýæÏéëfe âêNz¯V=²åIðdãü\ÓãïšåO7¿ÜÅyaN¡‰KsËvù­zëh8A Fý /þ(qâ‰+ž$õ$3žx&b¶Q©¤-_çãIàp0AfD‰Ã{+QÅáãiMfH0›†}wòÉ /sBsœá"wÎARñ$3•ê4/ÎEd㓎IÚ~u0À9é œ+w Ÿ8¢Š'I§âZ=ÆYœß6d[Gƒ—f„4M3!w6‚Qâ‰SO¥óᕈöGÈÜ–íÞ¿µ7Î_·)2RG él6JÀ_¿s†…ˆ~oÌ¿/ÇíÍæž?ÝÄü¤¿ìÌ·³|òÕ_$iTÎ]«Å|0Ýý?ïtd¶`ÏîÝì"­H½¶]TäĪ¸Þ©.(ã÷ßöyôøE›V~ù¶qvLoFóöÃE™­Êùå$I[>vŒò¢#ç·enkg³yîœÿÞ ¯rIEND®B`‚golly-2.7-src/gui-web/images/zoomin.png0000644000175000017500000000042412536111364015045 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú™IDATxœ´’1 €0 EstWo¢·ptvñ®‘¿Äo”–âðiIû_Ò4¢ªbš·CÛ~Q‘æ&‹Ùî±’†qZ/ƒÉöˆ¿A’ÙYEAÙÞà³ú˜Ý}¢ìU„6²üù?€ª'T7±ä£¯Ì$TÀDúe¬Ý°? á|³|’ø‚d"H1€nûÿÿ ’Ôu„WŒ0IEND®B`‚golly-2.7-src/gui-web/images/reset.png0000644000175000017500000000040012536111364014646 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú…IDATxœb``hø >|çÙ7¨Z qéþ—ÿ;μã^4¡jL#w®¼×˜f¥$€¬¦Žh5#«#ÊtÍ$€M3ÑàÒL? ‰“e.CÈŽF˜!$€nY 7¦„³§\'=3Q’ÿÿí¼zÉ(«ãIEND®B`‚golly-2.7-src/gui-web/images/cursor_pick.png0000644000175000017500000000035012536111364016053 00000000000000‰PNG  IHDRóÿa pHYsÄÄ•+!tEXtSoftwareGraphicConverter (Intel)w‡úmIDATxœ¤Òa€ †aî*n¦éÀLAùȵž×l32Ï*:ýÅmÍ‘ÔÎPÀ…Èx8ô Ìs ¾ëZñ1`a½ xØ|öÞýŒ ñ'0c âÈb±y¼@üŒ$:ÿÿÒ1Å |Ú\IEND®B`‚golly-2.7-src/gui-web/images/menu_down.png0000755000175000017500000000024612536111364015532 00000000000000‰PNG  IHDR b û!tEXtSoftwareGraphicConverter (Intel)w‡ú@IDATxœbhhh` &¦ªaX üO Ú…ä†×ËäF0 I5Œ è†’)¸ %FÑ’‚G ÿÿBÁ€í[wêIEND®B`‚golly-2.7-src/gui-web/images/scale1to1.png0000644000175000017500000000033412536111364015326 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡úaIDATxœbøÿÿ?Ãgßþ304À1H FW è\yŒñ€M-L`Å À¦.AŒØÔâ5[¸lHœ"(rÅa0ˆôDb26µ~%Æd ÿÿ|Š,|†ÛIEND®B`‚golly-2.7-src/gui-web/images/slower.png0000644000175000017500000000040312536111364015042 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡úˆIDATxœ¬Ó1€ ÐÝÕ›è-<ƒ3 ›ñƵ†¤”ÿKŒ,¼æJU´Òq«È¤#‘X§¸ç x§8¯¹ @qÙÎ.€9D9D[0rAØŒük@=bÙˆ®À¼i¢-BMDÞ=c-bÏèRÁh¬ÓQFÈÿÿLo¿óÿÿ$”Ð%,¿IEND®B`‚golly-2.7-src/gui-web/images/full.png0000644000175000017500000000025712536111364014500 00000000000000‰PNG  IHDR‘h6 pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú4IDATxœb``h@Cwž}ƒ#LY25 +Â…¯b”¢h„a°’©†©ÿÿë§Ÿœ]ÅIEND®B`‚golly-2.7-src/gui-web/images/start.png0000644000175000017500000000056312536111364014673 00000000000000‰PNG  IHDRóÿa!tEXtSoftwareGraphicConverter (Intel)w‡ú IDATxœbhÛßÿß!ÙñÛÑþÿ` 3˜%YügØ#ÿ_;Iï¿`§ødä7@®J Å ù"UˆA¼†b€v§úí™ÆÿfHa„ÃE 'ƒ>QŒeç+ ㉒pƒX°7ì,À0<Œ¢PÃÆù` 7ˆA`N‘œõ¸ aFA@ÉB±ý$—ÿrþË5©±C#È DÌÐD1@`†"Ã4laÏo˜bj1á(æ†ij’Eh¬öÆØ `ÉÄi#†`…@@6€0!1 Ù@ŽF¸ ´NŒSqaÿÿ”¢üÒX¨­IEND®B`‚golly-2.7-src/gui-web/images/undo.png0000644000175000017500000000035312536111364014500 00000000000000‰PNG  IHDRóÿa!tEXtSoftwareGraphicConverter (Intel)w‡ú…IDATxœb`ƒ†ÿ$àLÐðÿÒý/ÿwœyƒãÑ 1¤hÅX1Íø B3 è\yŸ2/iÂXt‘hHZT1X‘†`K$„ Á4‹Ó0 Áež†BÀBá Š ÈžrTê@@š ¦L¸æBÙÿÿï´SE²tÏIEND®B`‚golly-2.7-src/gui-web/main.cpp0000755000175000017500000020227712536111364013224 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ // gollybase #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "jvnalgo.h" #include "generationsalgo.h" #include "ruleloaderalgo.h" // gui-common #include "algos.h" // for InitAlgorithms, NumAlgos, etc #include "prefs.h" // for GetPrefs, MAX_MAG, tempdir, etc #include "layer.h" // for ResizeLayers, currlayer #include "control.h" // for SetMinimumStepExponent, NextGeneration, etc #include "file.h" // for NewPattern #include "view.h" // for fullscreen, TouchBegan, etc #include "status.h" // for SetMessage, CheckMouseLocation, etc #include "utils.h" // for Beep, etc #include "undo.h" // for currlayer->undoredo->... #include "render.h" // for InitOGLES2, DrawPattern #include "webcalls.h" // for refresh_pattern, UpdateStatus, PatternSaved, etc #include #include #include #include // ----------------------------------------------------------------------------- // the following JavaScript functions are implemented in jslib.js: extern "C" { extern void jsSetMode(int index); extern const char* jsSetRule(const char* oldrule); extern void jsShowMenu(const char* id, int x, int y); extern int jsTextAreaIsActive(); extern int jsElementIsVisible(const char* id); extern void jsEnableImgButton(const char* id, bool enable); extern void jsTickMenuItem(const char* id, bool tick); extern void jsSetInputValue(const char* id, int num); extern int jsGetInputValue(const char* id); extern void jsSetCheckBox(const char* id, bool flag); extern bool jsGetCheckBox(const char* id); extern void jsSetInnerHTML(const char* id, const char* text); extern void jsShowSaveDialog(const char* filename, const char* extensions); extern void jsSaveFile(const char* filename); } // ----------------------------------------------------------------------------- static int currwd, currht; // current size of viewport (in pixels) static double last_time; // time when NextGeneration was last called static bool alt_down = false; // alt/option key is currently pressed? static bool ctrl_down = false; // ctrl key is currently pressed? static bool shift_down = false; // shift key is currently pressed? static bool meta_down = false; // cmd/start/menu key is currently pressed? static bool ok_to_check_mouse = false; // ok to call glfwGetMousePos? static bool mouse_down = false; // is mouse button down? static bool over_canvas = false; // is mouse over canvas? static bool over_paste = false; // is mouse over paste image? static bool paste_menu_visible = false; static bool selection_menu_visible = false; // ----------------------------------------------------------------------------- static void InitPaths() { userdir = ""; // webGolly doesn't use this // webGolly doesn't use savedir (jsSaveFile will download saved files to the user's computer // in a directory specified by the browser) savedir = ""; // webGolly doesn't need to set downloaddir (browser will cache downloaded files) downloaddir = ""; // create a directory for user's rules EM_ASM( FS.mkdir('/LocalRules'); ); userrules = "/LocalRules/"; // WARNING: GetLocalPrefs() assumes this string // !!! we'll need to provide a way for users to delete .rule files in localStorage // to avoid exceeding the localStorage disk quota (implement special "DELETE" links // in Set Rule dialog, like we do in iGolly and aGolly) // supplied patterns, rules, help are stored in golly.data via --preload-file option in Makefile supplieddir = "/"; patternsdir = supplieddir + "Patterns/"; rulesdir = supplieddir + "Rules/"; helpdir = supplieddir + "Help/"; // create a directory for all our temporary files (can't use /tmp as it already exists!) EM_ASM( FS.mkdir('/gollytmp'); ); tempdir = "/gollytmp/"; clipfile = tempdir + "golly_clipboard"; // WARNING: GetLocalPrefs() and SaveLocalPrefs() assume the user's preferences are // temporarily stored in a file with this name prefsfile = "GollyPrefs"; } // ----------------------------------------------------------------------------- static void GetLocalPrefs() { EM_ASM( // get GollyPrefs string from local storage (key name must match setItem call) var contents = localStorage.getItem('GollyPrefs'); if (contents) { // write contents to virtual file system so GetPrefs() can read it // and initialize various global settings FS.writeFile('GollyPrefs', contents, {encoding:'utf8'}); } ); GetPrefs(); // read prefsfile from virtual file system EM_ASM( // re-create any .rule files that were saved in localStorage for (var i=0; idirty && asktosave); } } // extern "C" // ----------------------------------------------------------------------------- static void InitEventHandlers() { EM_ASM( // the following code fixes bugs in emscripten/src/library_glfw.js: // - onMouseWheel fails to use wheelDelta // - the onmousewheel handler is assigned to the entire window rather than just the canvas var wheelpos = 0; function on_mouse_wheel(event) { // Firefox sets event.detail, other browsers set event.wheelDelta with opposite sign, // so set delta to a value between -1 and 1 var delta = Math.max(-1, Math.min(1, (event.detail || -event.wheelDelta))); wheelpos += delta; _OnMouseWheel(wheelpos); return false; }; // for Firefox: Module['canvas'].addEventListener('DOMMouseScroll', on_mouse_wheel, false); // for Chrome, Safari, etc: Module['canvas'].onmousewheel = on_mouse_wheel; ); EM_ASM( // we do our own keyboard event handling because glfw's onKeyChanged always calls // event.preventDefault() so browser shortcuts like ctrl-Q/X/C/V don't work and // text can't be typed into our clipboard textarea function on_key_changed(event, status) { var key = event.keyCode; // DEBUG: Module.printErr('keycode='+key+' status='+status); // DEBUG: Module.printErr('activeElement='+document.activeElement.tagName); var prevent = _OnKeyChanged(key, status); // we allow default handler in these 2 cases: // 1. if ctrl/meta key is down (allows cmd/ctrl-Q/X/C/V/A/etc to work) // 2. if a textarea is active (document.activeElement.tagName == 'TEXTAREA') // on Firefox it seems we NEED to call preventDefault to stop cursor disappearing, // but on Safari/Chrome if we call it then cursor disappears (and arrow keys ALWAYS // cause disappearance regardless of whether we call it or not)... sheesh!!! if (prevent) { event.preventDefault(); return false; } }; function on_key_down(event) { on_key_changed(event, 1); // GLFW_PRESS }; function on_key_up(event) { on_key_changed(event, 0); // GLFW_RELEASE }; window.addEventListener('keydown', on_key_down, false); window.addEventListener('keyup', on_key_up, false); ); EM_ASM( // detect exit from full screen mode document.addEventListener('fullscreenchange', function() { if (!document.fullscreenElement) _ExitFullScreen(); }, false); document.addEventListener('msfullscreenchange', function() { if (!document.msFullscreenElement) _ExitFullScreen(); }, false); document.addEventListener('mozfullscreenchange', function() { if (!document.mozFullScreen) _ExitFullScreen(); }, false); document.addEventListener('webkitfullscreenchange', function() { if (!document.webkitIsFullScreen) _ExitFullScreen(); }, false); ); EM_ASM( // give user the option to save any changes window.onbeforeunload = function() { if (_UnsavedChanges()) return 'You have unsaved changes.'; }; // save current settings when window is unloaded window.addEventListener('unload', function() { _SaveLocalPrefs(); }); ); } // ----------------------------------------------------------------------------- static int InitGL() { if (glfwInit() != GL_TRUE) { Warning("glfwInit failed!"); return GL_FALSE; } InitEventHandlers(); // initial size doesn't matter -- ResizeCanvas will soon change it if (glfwOpenWindow(100, 100, 8, 8, 8, 8, 0, 0, GLFW_WINDOW) != GL_TRUE) { Warning("glfwOpenWindow failed!"); return GL_FALSE; } glfwSetWindowTitle("Golly"); if (!InitOGLES2()) { Warning("InitOGLES2 failed!"); return GL_FALSE; } // we only do 2D drawing glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glDisable(GL_STENCIL_TEST); // following 2 cause WebGL warnings on Chrome and Firefox: // glDisable(GL_FOG); // glDisable(GL_MULTISAMPLE); glEnable(GL_BLEND); // this blending function seems similar to the one used in desktop Golly // (ie. selected patterns look much the same) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(1.0, 1.0, 1.0, 1.0); last_time = glfwGetTime(); return GL_TRUE; } // ----------------------------------------------------------------------------- // many of the following routines are declared as C functions to avoid // C++ name mangling and make it easy to call them from JavaScript code // (the routine names, along with a leading underscore, must be listed in // -s EXPORTED_FUNCTIONS in Makefile) extern "C" { void ResizeCanvas() { // resize canvas based on current window dimensions and fullscreen flag if (fullscreen) { EM_ASM( var wd = window.innerWidth; var ht = window.innerHeight; var canvas = Module['canvas']; canvas.style.top = '0px'; canvas.style.left = '0px'; canvas.style.width = wd + 'px'; canvas.style.height = ht + 'px'; canvas.width = wd; canvas.height = ht; _SetViewport(wd, ht); // call C routine (see below) ); } else { EM_ASM( var trect = document.getElementById('toolbar').getBoundingClientRect(); // place canvas immediately under toolbar var top = trect.top + trect.height; var left = trect.left; var wd = window.innerWidth - left - 10; var ht = window.innerHeight - top - 10; if (wd < 0) wd = 0; if (ht < 0) ht = 0; var canvas = Module['canvas']; canvas.style.top = top + 'px'; canvas.style.left = left + 'px'; canvas.style.width = wd + 'px'; canvas.style.height = ht + 'px'; canvas.width = wd; canvas.height = ht; _SetViewport(wd, ht); // call C routine (see below) ); } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void SetViewport(int width, int height) { // do NOT call glfwSetWindowSize as it cancels full screen mode // glfwSetWindowSize(width, height); // ResizeCanvas has changed canvas size so we need to change OpenGL's viewport size glViewport(0, 0, width, height); currwd = width; currht = height; if (currwd != currlayer->view->getwidth() || currht != currlayer->view->getheight()) { // also change size of Golly's viewport ResizeLayers(currwd, currht); // to avoid seeing lots of black, draw now rather than call UpdatePattern DrawPattern(currindex); } } } // extern "C" // ----------------------------------------------------------------------------- static void InitClipboard() { // initialize clipboard data to a simple RLE pattern EM_ASM( document.getElementById('cliptext').value = '# To open the following RLE pattern,\n'+ '# select File > Open Clipboard.\n' + '# Or to paste in the pattern, click on\n'+ '# the Paste button, drag the floating\n' + '# image to the desired location, then\n' + '# right-click on the image.\n' + 'x = 9, y = 5, rule = B3/S23\n' + '$bo3b3o$b3o2bo$2bo!'; ); } // ----------------------------------------------------------------------------- static void UpdateCursorImage() { // note that the 2 numbers after the cursor url are the x and y offsets of the // cursor's hotspot relative to the top left corner if (over_paste) { // user can drag paste image so show hand cursor EM_ASM( Module['canvas'].style.cursor = 'url(images/cursor_move.png) 7 7, auto'; ); return; } if (!currlayer) return; // in case this routine is called very early if (currlayer->touchmode == drawmode) { EM_ASM( Module['canvas'].style.cursor = 'url(images/cursor_draw.png) 4 15, auto'; ); } else if (currlayer->touchmode == pickmode) { EM_ASM( Module['canvas'].style.cursor = 'url(images/cursor_pick.png) 0 15, auto'; ); } else if (currlayer->touchmode == selectmode) { EM_ASM( Module['canvas'].style.cursor = 'crosshair'; ); // all browsers support this??? } else if (currlayer->touchmode == movemode) { EM_ASM( Module['canvas'].style.cursor = 'url(images/cursor_move.png) 7 7, auto'; ); } else if (currlayer->touchmode == zoominmode) { EM_ASM( Module['canvas'].style.cursor = 'url(images/cursor_zoomin.png) 6 6, auto'; ); } else if (currlayer->touchmode == zoomoutmode) { EM_ASM( Module['canvas'].style.cursor = 'url(images/cursor_zoomout.png) 6 6, auto'; ); } else { Warning("Bug detected in UpdateCursorImage!"); } } // ----------------------------------------------------------------------------- static void CheckCursor(int x, int y) { if (mouse_down) { // don't check for cursor change if mouse button is pressed // (eg. we don't want cursor to change if user drags pencil/crosshair // cursor over the paste image) } else if (waitingforpaste && PointInPasteImage(x, y) && !over_paste) { // change cursor to hand to indicate that paste image can be dragged over_paste = true; UpdateCursorImage(); } else if (over_paste && (!waitingforpaste || !PointInPasteImage(x, y))) { // change cursor from hand to match currlayer->touchmode over_paste = false; UpdateCursorImage(); } } // ----------------------------------------------------------------------------- static void StopIfGenerating() { if (generating) { StopGenerating(); // generating flag is now false so change button image EM_ASM( document.getElementById('imgstartStop').src = 'images/start.png'; ); } } // ----------------------------------------------------------------------------- extern "C" { void NewUniverse() { // undo/redo history is about to be cleared so no point calling RememberGenFinish // if we're generating a (possibly large) pattern bool saveundo = allowundo; allowundo = false; StopIfGenerating(); allowundo = saveundo; if (event_checker > 0) { // try again after a short delay EM_ASM( window.setTimeout('_NewUniverse()', 10); ); return; } NewPattern(); UpdateEverything(); } } // extern "C" // ----------------------------------------------------------------------------- static void Open() { StopIfGenerating(); // display the open file dialog and start listening for change to selected file // (the on_file_change function is in shell.html) EM_ASM( document.getElementById('open_overlay').style.visibility = 'visible'; document.getElementById('upload_file').addEventListener('change', on_file_change, false); ); } // ----------------------------------------------------------------------------- extern "C" { void CancelOpen() { // close the open file dialog and remove the change event handler EM_ASM( document.getElementById('open_overlay').style.visibility = 'hidden'; document.getElementById('upload_file').removeEventListener('change', on_file_change, false); ); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void OpenClipboard() { StopIfGenerating(); if (event_checker > 0) { // try again after a short delay EM_ASM( window.setTimeout('_OpenClipboard()', 10); ); return; } // if clipboard text starts with "@RULE rulename" then install rulename.rule and switch to that rule if (ClipboardContainsRule()) return; // load and view pattern data stored in clipboard std::string data; if (GetTextFromClipboard(data)) { // copy clipboard data to tempstart so we can handle all formats supported by readpattern FILE* outfile = fopen(currlayer->tempstart.c_str(), "w"); if (outfile) { if (fputs(data.c_str(), outfile) == EOF) { ErrorMessage("Could not write clipboard text to tempstart file!"); fclose(outfile); return; } } else { ErrorMessage("Could not open tempstart file for writing!"); fclose(outfile); return; } fclose(outfile); LoadPattern(currlayer->tempstart.c_str(), "clipboard"); } } } // extern "C" // ----------------------------------------------------------------------------- static void Save() { StopIfGenerating(); // display the save pattern dialog if (currlayer->algo->hyperCapable()) { jsShowSaveDialog(currlayer->currname.c_str(), ".mc (default), .mc.gz, .rle, .rle.gz"); } else { jsShowSaveDialog(currlayer->currname.c_str(), ".rle (default), .rle.gz"); } } // ----------------------------------------------------------------------------- extern "C" { void CancelSave() { // close the save pattern dialog EM_ASM( document.getElementById('save_overlay').style.visibility = 'hidden'; ); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void SaveFile(const char* filename) { std::string fname = filename; // PatternSaved will append default extension if not supplied if (PatternSaved(fname)) { CancelSave(); // close dialog UpdateStatus(); // fname successfully created, so download it to user's computer jsSaveFile(fname.c_str()); } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void StartStop() { if (generating) { StopGenerating(); // generating flag is now false so change button image EM_ASM( document.getElementById('imgstartStop').src = 'images/start.png'; ); // don't call UpdateButtons here because if event_checker is > 0 // then StopGenerating hasn't called RememberGenFinish, and so CanUndo/CanRedo // might not return correct results bool canreset = currlayer->algo->getGeneration() > currlayer->startgen; jsEnableImgButton("reset", canreset); jsEnableImgButton("undo", allowundo && (canreset || currlayer->undoredo->CanUndo())); jsEnableImgButton("redo", false); } else if (StartGenerating()) { // generating flag is now true so change button image EM_ASM( document.getElementById('imgstartStop').src = 'images/stop.png'; ); // don't call UpdateButtons here because we want user to // be able to stop generating by hitting reset/undo buttons jsEnableImgButton("reset", true); jsEnableImgButton("undo", allowundo); jsEnableImgButton("redo", false); } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void Next() { StopIfGenerating(); if (event_checker > 0) { // previous NextGeneration() hasn't finished so try again after a short delay EM_ASM( window.setTimeout('_Next()', 10); ); return; } NextGeneration(false); // advance by 1 UpdateEverything(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void Step() { StopIfGenerating(); if (event_checker > 0) { // previous NextGeneration() hasn't finished so try again after a short delay EM_ASM( window.setTimeout('_Step()', 10); ); return; } NextGeneration(true); // advance by current step size UpdateEverything(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void GoSlower() { if (currlayer->currexpo > minexpo) { currlayer->currexpo--; SetGenIncrement(); UpdateStatus(); } else { Beep(); } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void GoFaster() { currlayer->currexpo++; SetGenIncrement(); UpdateStatus(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void StepBy1() { // reset step exponent to 0 currlayer->currexpo = 0; SetGenIncrement(); UpdateStatus(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void Reset() { if (currlayer->algo->getGeneration() == currlayer->startgen) return; StopIfGenerating(); if (event_checker > 0) { // try again after a short delay EM_ASM( window.setTimeout('_Reset()', 10); ); return; } ResetPattern(); UpdateEverything(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void Fit() { // no need to call TestAutoFit() FitInView(1); UpdatePatternAndStatus(); } } // extern "C" // ----------------------------------------------------------------------------- void Middle() { TestAutoFit(); if (currlayer->originx == bigint::zero && currlayer->originy == bigint::zero) { currlayer->view->center(); } else { // put cell saved by ChangeOrigin (not yet implemented!!!) in middle currlayer->view->setpositionmag(currlayer->originx, currlayer->originy, currlayer->view->getmag()); } UpdateEverything(); } // ----------------------------------------------------------------------------- extern "C" { void ZoomOut() { TestAutoFit(); currlayer->view->unzoom(); UpdateEverything(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void ZoomIn() { if (currlayer->view->getmag() < MAX_MAG) { TestAutoFit(); currlayer->view->zoom(); UpdateEverything(); } else { Beep(); } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void Scale1to1() { if (currlayer->view->getmag() != 0) { TestAutoFit(); currlayer->view->setmag(0); UpdateEverything(); } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void FullScreen() { fullscreen = true; EM_ASM( var canvas = Module['canvas']; if (canvas.requestFullscreen) { canvas.requestFullscreen(); } else if (canvas.msRequestFullscreen) { canvas.msRequestFullscreen(); } else if (canvas.mozRequestFullScreen) { canvas.mozRequestFullScreen(); } else if (canvas.webkitRequestFullScreen) { canvas.webkitRequestFullScreen(); // following only works on Chrome??? (but prevents Safari going full screen!!!) // canvas.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); } ); // no need to call ResizeCanvas here (the resize event handler calls it) } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void ExitFullScreen() { fullscreen = false; ResizeCanvas(); } } // extern "C" // ----------------------------------------------------------------------------- static void SetScale(int mag) { if (currlayer->view->getmag() != mag) { TestAutoFit(); currlayer->view->setmag(mag); UpdateEverything(); } } // ----------------------------------------------------------------------------- extern "C" { void Info() { if (currlayer->currname != "untitled") { // display comments in current pattern file char *commptr = NULL; // readcomments will allocate commptr const char *err = readcomments(currlayer->currfile.c_str(), &commptr); if (err) { if (commptr) free(commptr); ErrorMessage(err); return; } const char* commfile = "comments"; FILE* outfile = fopen(commfile, "w"); if (outfile) { int result; if (commptr[0] == 0) { result = fputs("No comments found.", outfile); } else { result = fputs(commptr, outfile); } if (result == EOF) { ErrorMessage("Could not write comments to file!"); fclose(outfile); return; } } else { ErrorMessage("Could not open file for comments!"); fclose(outfile); return; } fclose(outfile); if (commptr) free(commptr); ShowTextFile(commfile); } } } // extern "C" // ----------------------------------------------------------------------------- void StopAndHelp(const char* helpfile) { StopIfGenerating(); ShowHelp(helpfile); } // ----------------------------------------------------------------------------- extern "C" { void Help() { // show most recently loaded help file (or contents page if no such file) StopAndHelp(""); } } // extern "C" // ----------------------------------------------------------------------------- static void OpenPrefs() { // show a modal dialog that lets user change various settings EM_ASM( document.getElementById('prefs_overlay').style.visibility = 'visible'; ); // show current settings jsSetInputValue("random_fill", randomfill); jsSetInputValue("max_hash", maxhashmem); jsSetCheckBox("ask_to_save", asktosave); jsSetCheckBox("toggle_beep", allowbeep); // select random fill percentage (the most likely setting to change) EM_ASM( var randfill = document.getElementById('random_fill'); randfill.select(); randfill.focus(); ); } // ----------------------------------------------------------------------------- extern "C" { void CancelPrefs() { // ignore any changes to the current settings and close the prefs dialog EM_ASM( document.getElementById('prefs_overlay').style.visibility = 'hidden'; ); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void StorePrefs() { // get and validate settings int newrandfill = jsGetInputValue("random_fill"); if (newrandfill < 1 || newrandfill > 100) { Warning("Random fill percentage must be an integer from 1 to 100."); return; } int newmaxhash = jsGetInputValue("max_hash"); if (newmaxhash < MIN_MEM_MB || newmaxhash > MAX_MEM_MB) { char msg[128]; sprintf(msg, "Maximum hash memory must be an integer from %d to %d.", MIN_MEM_MB, MAX_MEM_MB); Warning(msg); return; } // all settings are valid randomfill = newrandfill; if (maxhashmem != newmaxhash) { // need to call setMaxMemory if maxhashmem changed maxhashmem = newmaxhash; for (int i = 0; i < numlayers; i++) { Layer* layer = GetLayer(i); if (algoinfo[layer->algtype]->canhash) { layer->algo->setMaxMemory(maxhashmem); } // non-hashing algos (QuickLife) use their default memory setting } } asktosave = jsGetCheckBox("ask_to_save"); allowbeep = jsGetCheckBox("toggle_beep"); CancelPrefs(); // close the prefs dialog SaveLocalPrefs(); // remember settings in local storage } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void Paste() { StopIfGenerating(); if (event_checker > 0) { // try again after a short delay EM_ASM( window.setTimeout('_Paste()', 10); ); return; } // remove any existing paste image if (waitingforpaste) AbortPaste(); PasteClipboard(); UpdatePatternAndStatus(); } } // extern "C" // ----------------------------------------------------------------------------- static void CancelPaste() { if (waitingforpaste) { AbortPaste(); UpdatePattern(); } } // ----------------------------------------------------------------------------- extern "C" { void Undo() { StopIfGenerating(); if (event_checker > 0) { // try again after a short delay EM_ASM( window.setTimeout('_Undo()', 10); ); return; } currlayer->undoredo->UndoChange(); UpdateEverything(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void Redo() { StopIfGenerating(); if (event_checker > 0) { // try again after a short delay EM_ASM( window.setTimeout('_Redo()', 10); ); return; } currlayer->undoredo->RedoChange(); UpdateEverything(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void ToggleIcons() { showicons = !showicons; UpdateEditBar(); // updates check box UpdatePattern(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void ToggleAutoFit() { currlayer->autofit = !currlayer->autofit; UpdateEditBar(); // updates check box // we only use autofit when generating if (generating && currlayer->autofit) { FitInView(0); UpdateEverything(); } } } // extern "C" // ----------------------------------------------------------------------------- static void ToggleGrid() { showgridlines = !showgridlines; UpdatePattern(); } // ----------------------------------------------------------------------------- static void ToggleHashInfo() { currlayer->showhashinfo = !currlayer->showhashinfo; // only show hashing info while generating if (generating) lifealgo::setVerbose( currlayer->showhashinfo ); } // ----------------------------------------------------------------------------- static void ToggleTiming() { showtiming = !showtiming; } // ----------------------------------------------------------------------------- static void SetAlgo(int index) { if (index >= 0 && index < NumAlgos()) { if (index != currlayer->algtype) ChangeAlgorithm(index, currlayer->algo->getrule()); } else { Warning("Bug detected in SetAlgo!"); } } // ----------------------------------------------------------------------------- extern "C" { void ModeChanged(int index) { switch (index) { case 0: currlayer->touchmode = drawmode; break; case 1: currlayer->touchmode = pickmode; break; case 2: currlayer->touchmode = selectmode; break; case 3: currlayer->touchmode = movemode; break; case 4: currlayer->touchmode = zoominmode; break; case 5: currlayer->touchmode = zoomoutmode; break; default: Warning("Bug detected in ModeChanged!"); return; } UpdateCursorImage(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void StateChanged(int index) { if (index >= 0 && index < currlayer->algo->NumCellStates()) { currlayer->drawingstate = index; } else { Warning("Bug detected in StateChanged!"); } } } // extern "C" // ----------------------------------------------------------------------------- /* enable next 2 routines if we provide keyboard shortcuts for them!!! static void DecState() { if (currlayer->drawingstate > 0) { currlayer->drawingstate--; jsSetState(currlayer->drawingstate); } } // ----------------------------------------------------------------------------- static void IncState() { if (currlayer->drawingstate < currlayer->algo->NumCellStates() - 1) { currlayer->drawingstate++; jsSetState(currlayer->drawingstate); } } */ // ----------------------------------------------------------------------------- static void ToggleCursorMode() { // state of shift key has changed so may need to toggle cursor mode if (currlayer->touchmode == drawmode) { currlayer->touchmode = pickmode; jsSetMode(currlayer->touchmode); UpdateCursorImage(); } else if (currlayer->touchmode == pickmode) { currlayer->touchmode = drawmode; jsSetMode(currlayer->touchmode); UpdateCursorImage(); } else if (currlayer->touchmode == zoominmode) { currlayer->touchmode = zoomoutmode; jsSetMode(currlayer->touchmode); UpdateCursorImage(); } else if (currlayer->touchmode == zoomoutmode) { currlayer->touchmode = zoominmode; jsSetMode(currlayer->touchmode); UpdateCursorImage(); } } // ----------------------------------------------------------------------------- static void SetRule() { StopIfGenerating(); std::string newrule = jsSetRule(currlayer->algo->getrule()); // newrule is empty if user hit Cancel if (newrule.length() > 0) ChangeRule(newrule); } // ----------------------------------------------------------------------------- static void FlipPasteOrSelection(bool direction) { if (waitingforpaste) { FlipPastePattern(direction); } else if (SelectionExists()) { FlipSelection(direction); } } // ----------------------------------------------------------------------------- static void RotatePasteOrSelection(bool direction) { if (waitingforpaste) { RotatePastePattern(direction); } else if (SelectionExists()) { RotateSelection(direction); } } // ----------------------------------------------------------------------------- extern "C" { void PasteAction(int item) { if (item == 2 && !SelectionExists()) { // pastesel item is grayed, so ignore click return; } // remove menu EM_ASM( document.getElementById('pastemenu').style.visibility = 'hidden'; ); paste_menu_visible = false; switch (item) { case 0: AbortPaste(); break; case 1: DoPaste(false); break; case 2: DoPaste(true); break; case 3: FlipPastePattern(true); break; case 4: FlipPastePattern(false); break; case 5: RotatePastePattern(true); break; case 6: RotatePastePattern(false); break; default: Warning("Bug detected in PasteAction!"); } UpdateEverything(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void SelectionAction(int item) { // remove menu first EM_ASM( document.getElementById('selectionmenu').style.visibility = 'hidden'; ); selection_menu_visible = false; if (generating && item >= 1 && item <= 13 && item != 2 && item != 5 && item != 6) { // temporarily stop generating for all actions except Remove, Copy, Shrink, Fit PauseGenerating(); } switch (item) { case 0: RemoveSelection(); break; // WARNING: above test assumes Remove is item 0 case 1: CutSelection(); break; case 2: CopySelection(); break; // WARNING: above test assumes Copy is item 2 case 3: ClearSelection(); break; case 4: ClearOutsideSelection(); break; case 5: ShrinkSelection(false); break; // WARNING: above test assumes Shrink is item 5 case 6: FitSelection(); break; // WARNING: above test assumes Fit is item 6 case 7: RandomFill(); break; case 8: FlipSelection(true); break; case 9: FlipSelection(false); break; case 10: RotateSelection(true); break; case 11: RotateSelection(false); break; case 12: currlayer->currsel.Advance(); break; case 13: currlayer->currsel.AdvanceOutside(); break; // WARNING: above test assumes 13 is last item default: Warning("Bug detected in SelectionAction!"); } ResumeGenerating(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void ClearStatus() { ClearMessage(); } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void OpenClickedFile(const char* filepath) { ClearMessage(); StopIfGenerating(); OpenFile(filepath); } } // extern "C" // ----------------------------------------------------------------------------- static void ChangePasteMode(paste_mode newmode) { if (pmode != newmode) pmode = newmode; } // ----------------------------------------------------------------------------- static void ToggleDisableUndoRedo() { allowundo = !allowundo; if (allowundo) { if (currlayer->algo->getGeneration() > currlayer->startgen) { // undo list is empty but user can Reset, so add a generating change // to undo list so user can Undo or Reset (and then Redo if they wish) currlayer->undoredo->AddGenChange(); } } else { currlayer->undoredo->ClearUndoRedo(); } UpdateEditBar(); } // ----------------------------------------------------------------------------- extern "C" { void UpdateMenuItems(const char* id) { // this routine is called just before the given menu is made visible std::string menu = id; if (menu == "File_menu") { // items in this menu don't change } else if (menu == "Edit_menu") { if (currlayer->undoredo->CanUndo()) { EM_ASM( document.getElementById('edit_undo').className = 'item_normal'; ); } else { EM_ASM( document.getElementById('edit_undo').className = 'item_disabled'; ); } if (currlayer->undoredo->CanRedo()) { EM_ASM( document.getElementById('edit_redo').className = 'item_normal'; ); } else { EM_ASM( document.getElementById('edit_redo').className = 'item_disabled'; ); } if (allowundo) { EM_ASM( document.getElementById('edit_disable').innerHTML = 'Disable Undo/Redo'; ); } else { EM_ASM( document.getElementById('edit_disable').innerHTML = 'Enable Undo/Redo'; ); } if (SelectionExists()) { EM_ASM( document.getElementById('edit_cut').className = 'item_normal'; ); EM_ASM( document.getElementById('edit_copy').className = 'item_normal'; ); EM_ASM( document.getElementById('edit_clear').className = 'item_normal'; ); EM_ASM( document.getElementById('edit_clearo').className = 'item_normal'; ); EM_ASM( document.getElementById('edit_remove').className = 'item_normal'; ); } else { EM_ASM( document.getElementById('edit_cut').className = 'item_disabled'; ); EM_ASM( document.getElementById('edit_copy').className = 'item_disabled'; ); EM_ASM( document.getElementById('edit_clear').className = 'item_disabled'; ); EM_ASM( document.getElementById('edit_clearo').className = 'item_disabled'; ); EM_ASM( document.getElementById('edit_remove').className = 'item_disabled'; ); } } else if (menu == "PasteMode_menu") { jsTickMenuItem("paste_mode_and", pmode == And); jsTickMenuItem("paste_mode_copy", pmode == Copy); jsTickMenuItem("paste_mode_or", pmode == Or); jsTickMenuItem("paste_mode_xor", pmode == Xor); } else if (menu == "Control_menu") { if (generating) { EM_ASM( document.getElementById('control_startstop').innerHTML = 'Stop Generating'; ); } else { EM_ASM( document.getElementById('control_startstop').innerHTML = 'Start Generating'; ); } if (currlayer->algo->getGeneration() > currlayer->startgen) { EM_ASM( document.getElementById('control_reset').className = 'item_normal'; ); } else { EM_ASM( document.getElementById('control_reset').className = 'item_disabled'; ); } jsTickMenuItem("control_autofit", currlayer->autofit); jsTickMenuItem("control_hash", currlayer->showhashinfo); jsTickMenuItem("control_timing", showtiming); } else if (menu == "Algo_menu") { jsTickMenuItem("algo0", currlayer->algtype == 0); jsTickMenuItem("algo1", currlayer->algtype == 1); jsTickMenuItem("algo2", currlayer->algtype == 2); jsTickMenuItem("algo3", currlayer->algtype == 3); jsTickMenuItem("algo4", currlayer->algtype == 4); } else if (menu == "View_menu") { if (SelectionExists()) { EM_ASM( document.getElementById('view_fits').className = 'item_normal'; ); } else { EM_ASM( document.getElementById('view_fits').className = 'item_disabled'; ); } jsTickMenuItem("view_grid", showgridlines); jsTickMenuItem("view_icons", showicons); if (currlayer->currname != "untitled") { EM_ASM( document.getElementById('view_info').className = 'item_normal'; ); } else { EM_ASM( document.getElementById('view_info').className = 'item_disabled'; ); } } else if (menu == "Scale_menu") { jsTickMenuItem("scale0", currlayer->view->getmag() == 0); jsTickMenuItem("scale1", currlayer->view->getmag() == 1); jsTickMenuItem("scale2", currlayer->view->getmag() == 2); jsTickMenuItem("scale3", currlayer->view->getmag() == 3); jsTickMenuItem("scale4", currlayer->view->getmag() == 4); jsTickMenuItem("scale5", currlayer->view->getmag() == 5); } else if (menu == "Help_menu") { // items in this menu don't change } else if (menu == "pastemenu") { char text[32]; sprintf(text, "Paste Here (%s)", GetPasteMode()); jsSetInnerHTML("pastehere", text); if (SelectionExists()) { EM_ASM( document.getElementById('pastesel').className = 'normal'; ); } else { EM_ASM( document.getElementById('pastesel').className = 'grayed'; ); } } else if (menu == "selectionmenu") { char text[32]; sprintf(text, "Random Fill (%d%%)", randomfill); jsSetInnerHTML("randfill", text); } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void DoMenuItem(const char* id) { std::string item = id; // items in File menu: if (item == "file_new") NewUniverse(); else if (item == "file_open") Open(); else if (item == "file_openclip") OpenClipboard(); else if (item == "file_save") Save(); else if (item == "file_prefs") OpenPrefs(); else // items in Edit menu: if (item == "edit_undo") Undo(); else if (item == "edit_redo") Redo(); else if (item == "edit_disable") ToggleDisableUndoRedo(); else if (item == "edit_cut") CutSelection(); else if (item == "edit_copy") CopySelection(); else if (item == "edit_clear") ClearSelection(); else if (item == "edit_clearo") ClearOutsideSelection(); else if (item == "edit_paste") Paste(); else if (item == "paste_mode_and") ChangePasteMode(And); else if (item == "paste_mode_copy") ChangePasteMode(Copy); else if (item == "paste_mode_or") ChangePasteMode(Or); else if (item == "paste_mode_xor") ChangePasteMode(Xor); else if (item == "edit_all") SelectAll(); else if (item == "edit_remove") RemoveSelection(); else // items in Control menu: if (item == "control_startstop") StartStop(); else if (item == "control_next") Next(); else if (item == "control_step") Step(); else if (item == "control_step1") StepBy1(); else if (item == "control_slower") GoSlower(); else if (item == "control_faster") GoFaster(); else if (item == "control_reset") Reset(); else if (item == "control_autofit") ToggleAutoFit(); else if (item == "control_hash") ToggleHashInfo(); else if (item == "control_timing") ToggleTiming(); else if (item == "algo0") SetAlgo(0); else if (item == "algo1") SetAlgo(1); else if (item == "algo2") SetAlgo(2); else if (item == "algo3") SetAlgo(3); else if (item == "algo4") SetAlgo(4); else if (item == "control_setrule") SetRule(); else // items in View menu: if (item == "view_fitp") Fit(); else if (item == "view_fits") FitSelection(); else if (item == "view_middle") Middle(); else if (item == "view_zoomin") ZoomIn(); else if (item == "view_zoomout") ZoomOut(); else if (item == "scale0") SetScale(0); else if (item == "scale1") SetScale(1); else if (item == "scale2") SetScale(2); else if (item == "scale3") SetScale(3); else if (item == "scale4") SetScale(4); else if (item == "scale5") SetScale(5); else if (item == "view_grid") ToggleGrid(); else if (item == "view_icons") ToggleIcons(); else if (item == "view_info") Info(); else // items in Help menu: if (item == "help_index") StopAndHelp("/Help/index.html"); else if (item == "help_intro") StopAndHelp("/Help/intro.html"); else if (item == "help_tips") StopAndHelp("/Help/tips.html"); else if (item == "help_algos") StopAndHelp("/Help/algos.html"); else if (item == "help_lexicon") StopAndHelp("/Help/Lexicon/lex.htm"); else if (item == "help_archives") StopAndHelp("/Help/archives.html"); else if (item == "help_keyboard") StopAndHelp("/Help/keyboard.html"); else if (item == "help_refs") StopAndHelp("/Help/refs.html"); else if (item == "help_formats") StopAndHelp("/Help/formats.html"); else if (item == "help_bounded") StopAndHelp("/Help/bounded.html"); else if (item == "help_problems") StopAndHelp("/Help/problems.html"); else if (item == "help_changes") StopAndHelp("/Help/changes.html"); else if (item == "help_credits") StopAndHelp("/Help/credits.html"); else if (item == "help_about") StopAndHelp("/Help/about.html"); else Warning("Not yet implemented!!!"); } } // extern "C" // ----------------------------------------------------------------------------- static const int META_KEY = 666; // cmd key on Mac, start/menu key on Windows (latter untested!!!) static int TranslateKey(int keycode) { // this is a modified version of DOMToGLFWKeyCode in emscripten/src/library_glfw.js switch (keycode) { // my changes (based on testing and info at http://unixpapa.com/js/key.html) case 224 : return META_KEY; // cmd key on Firefox (Mac) case 91 : return META_KEY; // left cmd key on Safari, Chrome (Mac) case 93 : return META_KEY; // right cmd key on Safari, Chrome (Mac) case 92 : return META_KEY; // right start key on Firefox, IE (Windows) case 219 : return '['; // Firefox, Chrome and Safari (Mac) case 220 : return '\\'; // Firefox, Chrome and Safari (Mac) case 221 : return ']'; // Firefox, Chrome and Safari (Mac) case 173 : return '-'; // Firefox (Mac) case 189 : return '-'; // Chrome and Safari (Mac) case 187 : return '='; // Chrome and Safari (Mac) case 188 : return '<'; // Firefox, Chrome and Safari (Mac) case 190 : return '>'; // Firefox, Chrome and Safari (Mac) case 0x09: return 295 ; //DOM_VK_TAB -> GLFW_KEY_TAB // GLFW_KEY_ESC is not 255???!!! case 0x1B: return 255 ; //DOM_VK_ESCAPE -> GLFW_KEY_ESC case 0x6A: return 313 ; //DOM_VK_MULTIPLY -> GLFW_KEY_KP_MULTIPLY case 0x6B: return 315 ; //DOM_VK_ADD -> GLFW_KEY_KP_ADD case 0x6D: return 314 ; //DOM_VK_SUBTRACT -> GLFW_KEY_KP_SUBTRACT case 0x6E: return 316 ; //DOM_VK_DECIMAL -> GLFW_KEY_KP_DECIMAL case 0x6F: return 312 ; //DOM_VK_DIVIDE -> GLFW_KEY_KP_DIVIDE case 0x70: return 258 ; //DOM_VK_F1 -> GLFW_KEY_F1 case 0x71: return 259 ; //DOM_VK_F2 -> GLFW_KEY_F2 case 0x72: return 260 ; //DOM_VK_F3 -> GLFW_KEY_F3 case 0x73: return 261 ; //DOM_VK_F4 -> GLFW_KEY_F4 case 0x74: return 262 ; //DOM_VK_F5 -> GLFW_KEY_F5 case 0x75: return 263 ; //DOM_VK_F6 -> GLFW_KEY_F6 case 0x76: return 264 ; //DOM_VK_F7 -> GLFW_KEY_F7 case 0x77: return 265 ; //DOM_VK_F8 -> GLFW_KEY_F8 case 0x78: return 266 ; //DOM_VK_F9 -> GLFW_KEY_F9 case 0x79: return 267 ; //DOM_VK_F10 -> GLFW_KEY_F10 case 0x7a: return 268 ; //DOM_VK_F11 -> GLFW_KEY_F11 case 0x7b: return 269 ; //DOM_VK_F12 -> GLFW_KEY_F12 case 0x25: return 285 ; //DOM_VK_LEFT -> GLFW_KEY_LEFT case 0x26: return 283 ; //DOM_VK_UP -> GLFW_KEY_UP case 0x27: return 286 ; //DOM_VK_RIGHT -> GLFW_KEY_RIGHT case 0x28: return 284 ; //DOM_VK_DOWN -> GLFW_KEY_DOWN case 0x21: return 298 ; //DOM_VK_PAGE_UP -> GLFW_KEY_PAGEUP case 0x22: return 299 ; //DOM_VK_PAGE_DOWN -> GLFW_KEY_PAGEDOWN case 0x24: return 300 ; //DOM_VK_HOME -> GLFW_KEY_HOME case 0x23: return 301 ; //DOM_VK_END -> GLFW_KEY_END case 0x2d: return 296 ; //DOM_VK_INSERT -> GLFW_KEY_INSERT case 16 : return 287 ; //DOM_VK_SHIFT -> GLFW_KEY_LSHIFT case 0x05: return 287 ; //DOM_VK_LEFT_SHIFT -> GLFW_KEY_LSHIFT case 0x06: return 288 ; //DOM_VK_RIGHT_SHIFT -> GLFW_KEY_RSHIFT case 17 : return 289 ; //DOM_VK_CONTROL -> GLFW_KEY_LCTRL case 0x03: return 289 ; //DOM_VK_LEFT_CONTROL -> GLFW_KEY_LCTRL case 0x04: return 290 ; //DOM_VK_RIGHT_CONTROL -> GLFW_KEY_RCTRL case 18 : return 291 ; //DOM_VK_ALT -> GLFW_KEY_LALT case 0x02: return 291 ; //DOM_VK_LEFT_ALT -> GLFW_KEY_LALT case 0x01: return 292 ; //DOM_VK_RIGHT_ALT -> GLFW_KEY_RALT case 96 : return 302 ; //GLFW_KEY_KP_0 case 97 : return 303 ; //GLFW_KEY_KP_1 case 98 : return 304 ; //GLFW_KEY_KP_2 case 99 : return 305 ; //GLFW_KEY_KP_3 case 100 : return 306 ; //GLFW_KEY_KP_4 case 101 : return 307 ; //GLFW_KEY_KP_5 case 102 : return 308 ; //GLFW_KEY_KP_6 case 103 : return 309 ; //GLFW_KEY_KP_7 case 104 : return 310 ; //GLFW_KEY_KP_8 case 105 : return 311 ; //GLFW_KEY_KP_9 default : return keycode; }; } // ----------------------------------------------------------------------------- extern "C" { int OnKeyChanged(int keycode, int action) { int key = TranslateKey(keycode); // first check for modifier keys (meta/ctrl/alt/shift); // note that we need to set flags for these keys BEFORE testing // jsTextAreaIsActive so users can do things like ctrl-click in canvas while // a textarea has focus and OnMouseClick will be able to test ctrl_down flag if (key == META_KEY) { meta_down = action == GLFW_PRESS; return 0; // don't call preventDefault } else if (key == GLFW_KEY_LCTRL || key == GLFW_KEY_RCTRL) { ctrl_down = action == GLFW_PRESS; return 0; // don't call preventDefault } else if (key == GLFW_KEY_LALT || key == GLFW_KEY_RALT) { alt_down = action == GLFW_PRESS; return 1; } else if (key == GLFW_KEY_LSHIFT || key == GLFW_KEY_RSHIFT) { bool oldshift = shift_down; shift_down = action == GLFW_PRESS; if (oldshift != shift_down) ToggleCursorMode(); return 1; } if (meta_down || ctrl_down) { // could be a browser shortcut like ctrl/cmd-Q/X/C/V, // so don't handle the key here and don't call preventDefault return 0; } // check if a modal dialog is visible if (jsElementIsVisible("open_overlay") || jsElementIsVisible("save_overlay") || jsElementIsVisible("prefs_overlay") || jsElementIsVisible("info_overlay") || jsElementIsVisible("help_overlay") ) { if (action == GLFW_PRESS && (key == 13 || key == 27)) { // return key or escape key closes dialog if (jsElementIsVisible("open_overlay")) { CancelOpen(); } else if (jsElementIsVisible("save_overlay")) { if (key == 13) { EM_ASM( save_pattern(); ); // see shell.html for save_pattern() } else { CancelSave(); } } else if (jsElementIsVisible("prefs_overlay")) { if (key == 13) { StorePrefs(); } else { CancelPrefs(); } } else if (jsElementIsVisible("info_overlay")) { EM_ASM( _CloseInfo(); ); } else if (jsElementIsVisible("help_overlay")) { // some of the above dialogs can be on top of help dialog, so test this last EM_ASM( _CloseHelp(); ); } return 1; // call preventDefault } return 0; } if (jsTextAreaIsActive()) { // a textarea is active (and probably has focus), // so don't handle the key here and don't call preventDefault return 0; } if (action == GLFW_PRESS) ClearMessage(); if (action == GLFW_RELEASE) return 1; // non-modifier key was released // a non-modifer key is down (and meta/ctrl key is NOT currently down) // check for arrow keys and do panning if (key == GLFW_KEY_UP) { if (shift_down) PanNE(); else PanUp( SmallScroll(currlayer->view->getheight()) ); return 1; } else if (key == GLFW_KEY_DOWN) { if (shift_down) PanSW(); else PanDown( SmallScroll(currlayer->view->getheight()) ); return 1; } else if (key == GLFW_KEY_LEFT) { if (shift_down) PanNW(); else PanLeft( SmallScroll(currlayer->view->getwidth()) ); return 1; } else if (key == GLFW_KEY_RIGHT) { if (shift_down) PanSE(); else PanRight( SmallScroll(currlayer->view->getwidth()) ); return 1; } int ch = key; if (key >= 'A' && key <= 'Z' && !shift_down) { // convert to lowercase ch = ch + 32; } switch (ch) { case 13 : StartStop(); break; case ' ' : Next(); break; case '_' : GoSlower(); break; case '-' : GoSlower(); break; case '+' : GoFaster(); break; case '=' : GoFaster(); break; case '0' : StepBy1(); break; case '1' : Scale1to1(); break; case '5' : RandomFill(); break; case '[' : ZoomOut(); break; case ']' : ZoomIn(); break; case 'a' : SelectAll(); break; case 'A' : RemoveSelection(); break; case 'f' : Fit(); break; case 'F' : FitSelection(); break; case 'h' : Help(); break; case 'i' : ToggleIcons(); break; case 'l' : ToggleGrid(); break; case 'm' : Middle(); break; case 'o' : Open(); break; case 'O' : OpenClipboard(); break; case 'p' : OpenPrefs(); break; case 'r' : SetRule(); break; case 's' : Save(); break; case 't' : ToggleAutoFit(); break; case 'v' : Paste(); break; case 'V' : CancelPaste(); break; case 'x' : FlipPasteOrSelection(false); break; case 'y' : FlipPasteOrSelection(true); break; case '<' : RotatePasteOrSelection(false); break; case '>' : RotatePasteOrSelection(true); break; case 'z' : Undo(); break; case 'Z' : Redo(); break; } return 1; // call preventDefault } } // extern "C" // ----------------------------------------------------------------------------- static void OnMouseClick(int button, int action) { ok_to_check_mouse = true; if (action == GLFW_PRESS) { // make sure a textarea element no longer has focus (for testing in on_key_changed); // note that 'patterns' is a div with a tabindex, and an outline style that prevents // a focus ring appearing EM_ASM( document.getElementById('patterns').focus(); ); int x, y; glfwGetMousePos(&x, &y); ClearMessage(); if (paste_menu_visible) { EM_ASM( document.getElementById('pastemenu').style.visibility = 'hidden'; ); paste_menu_visible = false; return; } if (selection_menu_visible) { EM_ASM( document.getElementById('selectionmenu').style.visibility = 'hidden'; ); selection_menu_visible = false; return; } // test for ctrl/right click in paste image or selection; // button test should be for GLFW_MOUSE_BUTTON_RIGHT which is defined to be 1 in glfw.h // but I actually get 2 when right button is pressed in all my browsers (report bug!!!) if (button == 2 || ctrl_down) { if (waitingforpaste && PointInPasteImage(x, y)) { UpdateMenuItems("pastemenu"); jsShowMenu("pastemenu", x, y); paste_menu_visible = true; } else if (SelectionExists() && PointInSelection(x, y)) { UpdateMenuItems("selectionmenu"); jsShowMenu("selectionmenu", x, y); selection_menu_visible = true; } return; } // check for click outside viewport if (x < 0 || x >= currwd || y < 0 || y >= currht) { if (mouse_down) TouchEnded(); mouse_down = false; return; } bool was_auto_fit = currlayer->autofit; TouchBegan(x, y); mouse_down = true; // TouchBegan might have called TestAutoFit and turned off currlayer->autofit, // in which case we need to update the check box if (was_auto_fit && !currlayer->autofit) UpdateEditBar(); } else if (action == GLFW_RELEASE) { if (mouse_down) TouchEnded(); mouse_down = false; } } // ----------------------------------------------------------------------------- static void OnMouseMove(int x, int y) { ok_to_check_mouse = true; int mousestate = glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT); if (mousestate == GLFW_PRESS) { // play safe and ignore move outside viewport if (x < 0 || x >= currwd || y < 0 || y >= currht) return; TouchMoved(x, y); } } // ----------------------------------------------------------------------------- static int prevwheel = 0; extern "C" { void OnMouseWheel(int pos) { int x, y; glfwGetMousePos(&x, &y); // we use a threshold of 2 in below tests to reduce sensitivity if (pos + 2 < prevwheel) { ZoomInPos(x, y); prevwheel = pos; } else if (pos - 2 > prevwheel) { ZoomOutPos(x, y); prevwheel = pos; } } } // extern "C" // ----------------------------------------------------------------------------- extern "C" { void OverCanvas(int entered) { if (entered) { // mouse entered canvas so change cursor image depending on currlayer->touchmode UpdateCursorImage(); // call CheckMouseLocation in DoFrame over_canvas = true; // remove focus from select element to avoid problem if an arrow key is pressed // (doesn't quite work!!! if selection is NOT changed and arrow key is hit immediately // then it can cause the selection to change) EM_ASM( if (document.activeElement.tagName == 'SELECT') { document.getElementById('patterns').focus(); }; ); } else { // mouse exited canvas; cursor is automatically restored to standard arrow // so no need to do this: // EM_ASM( Module['canvas'].style.cursor = 'auto'; ); // force XY location to be cleared CheckMouseLocation(-1, -1); // we also need to prevent CheckMouseLocation being called in DoFrame because // it might detect a valid XY location if right/bottom cells are clipped over_canvas = false; } } } // extern "C" // ----------------------------------------------------------------------------- static void DoFrame() { if (generating && event_checker == 0) { if (currlayer->currexpo < 0) { // get current delay (in secs) float delay = GetCurrentDelay() / 1000.0; double current_time = glfwGetTime(); // check if it's time to call NextGeneration if (current_time - last_time >= delay) { NextGeneration(true); UpdatePatternAndStatus(); last_time = current_time; } } else { NextGeneration(true); UpdatePatternAndStatus(); } } if (refresh_pattern) { refresh_pattern = false; DrawPattern(currindex); } glfwSwapBuffers(); // check the current mouse location continuously, but only after the 1st mouse-click or // mouse-move event, because until then glfwGetMousePos returns 0,0 (report bug???!!!) if (ok_to_check_mouse && over_canvas) { int x, y; glfwGetMousePos(&x, &y); CheckMouseLocation(x, y); // also check if cursor image needs to be changed (this can only be done AFTER // DrawPattern has set pasterect, which is tested by PointInPasteImage) CheckCursor(x, y); } } // ----------------------------------------------------------------------------- // we need the EMSCRIPTEN_KEEPALIVE flag to avoid our main() routine disappearing // (a somewhat strange consequence of using -s EXPORTED_FUNCTIONS in Makefile) int EMSCRIPTEN_KEEPALIVE main() { SetMessage("This is Golly 0.8 for the web. Copyright 2014 The Golly Gang."); InitPaths(); // init tempdir, prefsfile, etc MAX_MAG = 5; // maximum cell size = 32x32 maxhashmem = 300; // enough for caterpillar InitAlgorithms(); // must initialize algoinfo first GetLocalPrefs(); // load user's preferences from local storage SetMinimumStepExponent(); // for slowest speed AddLayer(); // create initial layer (sets currlayer) NewPattern(); // create new, empty universe UpdateStatus(); // show initial message InitClipboard(); // initialize clipboard data UpdateEditBar(); // initialize buttons, drawing state, and check boxes if (InitGL() == GL_TRUE) { ResizeCanvas(); // we do our own keyboard event handling (see InitEventHandlers) // glfwSetKeyCallback(OnKeyChanged); glfwSetMouseButtonCallback(OnMouseClick); glfwSetMousePosCallback(OnMouseMove); // we do our own mouse wheel handling (see InitEventHandlers) // glfwSetMouseWheelCallback(OnMouseWheel); emscripten_set_main_loop(DoFrame, 0, 1); } glfwTerminate(); return 0; } golly-2.7-src/gui-web/webcalls.h0000644000175000017500000000757612536111364013543 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _WEBCALLS_H_ #define _WEBCALLS_H_ #include // for std::string // Web-specific routines (called mainly from gui-common code): extern bool refresh_pattern; // DoFrame in main.cpp should call DrawPattern? void UpdatePattern(); // Redraw the current pattern (actually just sets refresh_pattern to true). void UpdateStatus(); // Redraw the status bar info. void PauseGenerating(); // If pattern is generating then temporarily pause. void ResumeGenerating(); // Resume generating pattern if it was paused. std::string GetRuleName(const std::string& rule); // Return name of given rule (empty string if rule is unnamed). void UpdateButtons(); // Some buttons might need to be enabled/disabled. void UpdateEditBar(); // Update buttons, show current drawing state and cursor mode. void BeginProgress(const char* title); bool AbortProgress(double fraction_done, const char* message); void EndProgress(); // These calls display a progress bar while a lengthy task is carried out. void SwitchToPatternTab(); // Switch to main screen for displaying/editing/generating patterns. void ShowTextFile(const char* filepath); // Display contents of given text file in a modal view. void ShowHelp(const char* filepath); // Display given HTML file in Help screen. void WebWarning(const char* msg); // Beep and display message in a modal dialog. bool WebYesNo(const char* msg); // Similar to Warning, but there are 2 buttons: Yes and No. // Returns true if Yes button is hit. void WebFatal(const char* msg); // Beep, display message in a modal dialog, then exit app. void WebBeep(); // Play beep sound, depending on allowbeep setting. void WebRemoveFile(const std::string& filepath); // Delete given file. bool WebMoveFile(const std::string& inpath, const std::string& outpath); // Return true if input file is successfully moved to output file. // If the output file existed it is replaced. void WebFixURLPath(std::string& path); // Replace "%..." with suitable chars for a file path (eg. %20 is changed to space). bool WebCopyTextToClipboard(const char* text); // Copy given text to the clipboard. bool WebGetTextFromClipboard(std::string& text); // Get text from the clipboard. bool PatternSaved(std::string& filename); // Return true if current pattern is saved in virtual file system using given // filename (which will have default extension appended if none supplied). bool WebSaveChanges(); // Show a modal dialog that lets user save their changes. // Return true if it's ok to continue. bool WebDownloadFile(const std::string& url, const std::string& filepath); // Download given url and create given file. void WebCheckEvents(); // Run main UI thread for a short time so app remains responsive while doing a // lengthy computation. Note that event_checker is > 0 while in this routine. void CopyRuleToLocalStorage(const char* rulepath); // Copy contents of given .rule file to HTML5's localStorage (using rulepath as // the key) so that the file can be re-created in the next webGolly session. #endif golly-2.7-src/gui-web/jslib.js0000755000175000017500000003760412536111364013235 00000000000000// The following JavaScript routines can be called from C++ code (eg. webcalls.cpp). // Makefile merges these routines into golly.js via the --js-library option. var LibraryGOLLY = { $GOLLY: { cancel_progress: false, // cancel progress dialog? progstart: 0.0, // time when jsBeginProgress is called }, // ----------------------------------------------------------------------------- jsAlert: function(msg) { alert(Pointer_stringify(msg)); }, // ----------------------------------------------------------------------------- jsConfirm: function(query) { return confirm(Pointer_stringify(query)); }, // ----------------------------------------------------------------------------- jsSetBackgroundColor: function(id, color) { document.getElementById(Pointer_stringify(id)).style.backgroundColor = Pointer_stringify(color); }, // ----------------------------------------------------------------------------- jsSetMode: function(index) { document.getElementById('mode').selectedIndex = index; }, // ----------------------------------------------------------------------------- jsSetState: function(state, numstates) { var list = document.getElementById('state'); // may need to update number of options in list while (list.length < numstates) { // append another option var option = document.createElement('option'); option.text = list.length.toString(); list.add(option); }; while (list.length > numstates) { // remove last option list.remove(list.length - 1); } list.selectedIndex = state; }, // ----------------------------------------------------------------------------- jsSetRule: function(oldrule) { var newrule = prompt('Type in a new rule:', Pointer_stringify(oldrule)); if (newrule == null) { return allocate(intArrayFromString('\0'), 'i8', ALLOC_STACK); } else { return allocate(intArrayFromString(newrule), 'i8', ALLOC_STACK); } }, // ----------------------------------------------------------------------------- jsGetSaveName: function(currname) { var newname = prompt('Save current pattern in given file:', Pointer_stringify(currname)); if (newname == null) { return allocate(intArrayFromString('\0'), 'i8', ALLOC_STACK); } else { return allocate(intArrayFromString(newname), 'i8', ALLOC_STACK); } }, // ----------------------------------------------------------------------------- jsShowMenu: function(id, x, y) { var menu = document.getElementById(Pointer_stringify(id)); var mrect = menu.getBoundingClientRect(); // x,y coords are relative to canvas, so convert to window coords var crect = Module['canvas'].getBoundingClientRect(); // note that scrolling is disabled so window.scrollX and window.scrollY are 0 x += crect.left + 1; y += crect.top + 1; // if menu would be outside right/bottom window edge then move it if (x + mrect.width > window.innerWidth) x -= mrect.width + 2; if (y + mrect.height > window.innerHeight) y -= y + mrect.height - window.innerHeight; menu.style.top = y.toString() + 'px'; menu.style.left = x.toString() + 'px'; menu.style.visibility = 'visible'; }, // ----------------------------------------------------------------------------- jsSetClipboard: function(text) { document.getElementById('cliptext').value = Pointer_stringify(text); }, // ----------------------------------------------------------------------------- jsGetClipboard: function() { var text = document.getElementById('cliptext').value; if (text == null) { return allocate(intArrayFromString('\0'), 'i8', ALLOC_STACK); } else { return allocate(intArrayFromString(text), 'i8', ALLOC_STACK); } }, // ----------------------------------------------------------------------------- jsTextAreaIsActive: function() { if (document.activeElement.tagName == 'TEXTAREA') { return 1; } else { return 0; } }, // ----------------------------------------------------------------------------- jsElementIsVisible: function(id) { if (document.getElementById(Pointer_stringify(id)).style.visibility == 'visible') { return true; } else { return false; } }, // ----------------------------------------------------------------------------- jsEnableButton: function(id, enable) { var button = document.getElementById(Pointer_stringify(id)); if (enable) { button.disabled = false; button.style.color = '#000'; } else { button.disabled = true; button.style.color = '#888'; } }, // ----------------------------------------------------------------------------- jsEnableImgButton: function(id, enable) { var button = document.getElementById(Pointer_stringify(id)); var img = document.getElementById('img' + Pointer_stringify(id)); if (enable) { button.disabled = false; img.style.opacity = 1.0; // following is needed on IE???!!! // img.style.filter = 'alpha(opacity:100)'; } else { button.disabled = true; img.style.opacity = 0.25; // following is needed on IE???!!! // img.style.filter = 'alpha(opacity:25)'; } }, // ----------------------------------------------------------------------------- jsTickMenuItem: function(id, tick) { var menuitem = document.getElementById(Pointer_stringify(id)); if (tick) { menuitem.style.backgroundImage = 'url(images/item_tick.png)'; } else { menuitem.style.backgroundImage = 'url(images/item_blank.png)'; } }, // ----------------------------------------------------------------------------- jsSetInputValue: function(id, num) { document.getElementById(Pointer_stringify(id)).value = num.toString(); }, // ----------------------------------------------------------------------------- jsGetInputValue: function(id) { var num = parseInt(document.getElementById(Pointer_stringify(id)).value, 10); if (isNaN(num)) return -1; return num; }, // ----------------------------------------------------------------------------- jsSetCheckBox: function(id, flag) { document.getElementById(Pointer_stringify(id)).checked = flag; }, // ----------------------------------------------------------------------------- jsGetCheckBox: function(id) { return document.getElementById(Pointer_stringify(id)).checked; }, // ----------------------------------------------------------------------------- jsSetInnerHTML: function(id, text) { document.getElementById(Pointer_stringify(id)).innerHTML = Pointer_stringify(text); }, // ----------------------------------------------------------------------------- jsMoveToAnchor: function(anchor) { window.location.hash = Pointer_stringify(anchor); }, // ----------------------------------------------------------------------------- jsSetScrollTop: function(id, pos) { document.getElementById(Pointer_stringify(id)).scrollTop = pos; }, // ----------------------------------------------------------------------------- jsGetScrollTop: function(id) { return document.getElementById(Pointer_stringify(id)).scrollTop; }, // ----------------------------------------------------------------------------- jsBeep: function() { var beep = new Audio("beep.wav"); beep.play(); }, // ----------------------------------------------------------------------------- jsDeleteFile: function(filepath) { FS.unlink(Pointer_stringify(filepath)); }, // ----------------------------------------------------------------------------- jsMoveFile: function(inpath, outpath) { try { FS.rename(Pointer_stringify(inpath), Pointer_stringify(outpath)); return true; } catch (e) { alert('FS.rename failed!'); return false; } }, // ----------------------------------------------------------------------------- jsShowSaveDialog: function(filename, extensions) { document.getElementById('save_overlay').style.visibility = 'visible'; document.getElementById('save_extensions').innerHTML = 'Valid extensions: ' + Pointer_stringify(extensions); var namebox = document.getElementById('save_name'); namebox.value = Pointer_stringify(filename); namebox.select(); namebox.focus(); }, // ----------------------------------------------------------------------------- jsSaveFile: function(filenameptr) { var filename = Pointer_stringify(filenameptr); var contents, blob; var gzext = '.gz'; if (filename.length >= gzext.length && filename.substr(filename.length - gzext.length) == gzext) { // treat .gz file as uninterpreted binary data contents = FS.readFile(filename, {encoding:'binary'}); blob = new Blob([contents], {type:'application/octet-stream'}); } else { // assume it's a text file (.rle or .mc) contents = FS.readFile(filename, {encoding:'utf8'}); blob = new Blob([contents], {type:'text/plain'}); } var alink = document.createElement('a'); alink.download = filename; alink.innerHTML = 'Download File'; if (window.webkitURL != null) { // Safari/Chrome allows the link to be clicked without actually adding it to the DOM alink.href = window.webkitURL.createObjectURL(blob); } else { // Firefox requires the link to be added to the DOM before it can be clicked alink.href = window.URL.createObjectURL(blob); alink.onclick = function(event) { document.body.removeChild(event.target); }; alink.style.display = 'none'; document.body.appendChild(alink); } alink.click(); }, // ----------------------------------------------------------------------------- jsStoreRule: function(rulepath) { // read contents of .rule file and save to local storage using rulepath as the key var filepath = Pointer_stringify(rulepath); try { var contents = FS.readFile(filepath, {encoding:'utf8'}); localStorage.setItem(filepath, contents); } catch(e) { alert('Failed to store rule file:\n' + filepath); } }, // ----------------------------------------------------------------------------- jsCancelProgress: function() { // user hit Cancel button in progress dialog GOLLY.cancel_progress = true; // best to hide the progress dialog immediately document.getElementById('progress_overlay').style.visibility = 'hidden'; }, // ----------------------------------------------------------------------------- jsBeginProgress: function(title) { // DEBUG: Module.printErr('jsBeginProgress'); document.getElementById('progress_title').innerHTML = Pointer_stringify(title); document.getElementById('progress_percent').innerHTML = ' '; // don't show the progress dialog immediately // document.getElementById('progress_overlay').style.visibility = 'visible'; GOLLY.cancel_progress = false; GOLLY.progstart = Date.now()/1000; }, // ----------------------------------------------------------------------------- jsAbortProgress: function(percentage) { // DEBUG: Module.printErr('jsAbortProgress: ' + percentage); var secs = Date.now()/1000 - GOLLY.progstart; if (document.getElementById('progress_overlay').style.visibility == 'visible') { if (percentage < 0) { // -ve percentage is # of bytes downloaded so far (file size is unknown) percentage *= -1; document.getElementById('progress_percent').innerHTML = 'Bytes downloaded: '+percentage; } else { document.getElementById('progress_percent').innerHTML = 'Completed: '+percentage+'%'; } return GOLLY.cancel_progress; } else { // note that percentage is not always an accurate estimator for how long // the task will take, especially when we use nextcell for cut/copy if ( (secs > 1.0 && percentage < 30) || secs > 2.0 ) { // task is probably going to take a while so show progress dialog document.getElementById('progress_overlay').style.visibility = 'visible'; } return false; } }, // ----------------------------------------------------------------------------- jsEndProgress: function() { // DEBUG: Module.printErr('jsEndProgress'); // hide the progress dialog document.getElementById('progress_overlay').style.visibility = 'hidden'; }, // ----------------------------------------------------------------------------- jsDownloadFile: function(urlptr, filepathptr) { // download file from given url and store its contents in filepath var url = Pointer_stringify(urlptr); var filepath = Pointer_stringify(filepathptr); // DEBUG: Module.printErr('URL: '+url+' FILE: '+filepath); // prefix url with http://www.corsproxy.com/ so we can get file from another domain // (note that we assume url starts with "http://") url = 'http://www.corsproxy.com/' + url.substring(7); var xhr = new XMLHttpRequest(); if (xhr) { // first send a request to get the file's size /* doesn't work!!! -- get error 400 (bad request) probably because corsproxy.com only supports GET requests xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200) { Module.printErr('response: '+xhr.getResponseHeader('Content-Length')); } else { // some sort of error occurred Module.printErr('status error: ' + xhr.status + ' ' + xhr.statusText); } } } xhr.open('HEAD', url, true); // get only the header info xhr.send(); */ // note that we need to prefix jsBeginProgress/jsAbortProgress/jsEndProgress calls // with an underscore because webcalls.cpp declares them as extern C routines _jsBeginProgress(allocate(intArrayFromString('Downloading file...'), 'i8', ALLOC_STACK)); xhr.onprogress = function updateProgress(evt) { var percent_complete = 0; if (evt.lengthComputable) { percent_complete = Math.floor((evt.loaded / evt.total) * 100); // DEBUG: Module.printErr('Percentage downloaded: ' + percent_complete); } else { // file size is unknown (this seems to happen for .mc/rle files) // so we pass -ve bytes loaded to indicate it's not a percentage percent_complete = -evt.loaded; // DEBUG: Module.printErr('Bytes downloaded: ' + evt.loaded); } if (_jsAbortProgress(percent_complete)) { // GOLLY.cancel_progress is true _jsEndProgress(); xhr.abort(); } } xhr.onreadystatechange = function() { // DEBUG: Module.printErr('readyState=' + xhr.readyState); if (xhr.readyState == 4) { _jsEndProgress(); // DEBUG: Module.printErr('status=' + xhr.status); if (xhr.status == 200) { // success, so save binary data to filepath var uInt8Array = new Uint8Array(xhr.response); FS.writeFile(filepath, uInt8Array, {encoding:'binary'}); filecreated = Module.cwrap('FileCreated', 'void', ['string']); filecreated(filepath); } else if (!GOLLY.cancel_progress) { // some sort of error occurred alert('XMLHttpRequest error: ' + xhr.status); } } } xhr.open('GET', url, true); // setting the following responseType will treat all files as binary // (note that this is only allowed for async requests) xhr.responseType = 'arraybuffer'; xhr.send(null); } else { alert('XMLHttpRequest failed!'); } }, // ----------------------------------------------------------------------------- }; // LibraryGOLLY autoAddDeps(LibraryGOLLY, '$GOLLY'); mergeInto(LibraryManager.library, LibraryGOLLY); golly-2.7-src/gui-common/0000755000175000017500000000000012536111364012352 500000000000000golly-2.7-src/gui-common/utils.cpp0000644000175000017500000003516512536111364014150 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include // for gettimeofday #include // for std::transform #include // for tolower #include "lifepoll.h" // for lifepoll #include "util.h" // for linereader #include "prefs.h" // for allowbeep, tempdir #include "utils.h" #ifdef ANDROID_GUI #include "jnicalls.h" // for AndroidWarning, AndroidBeep, UpdateStatus, etc #endif #ifdef WEB_GUI #include "webcalls.h" // for WebWarning, WebBeep, UpdateStatus, etc #endif #ifdef IOS_GUI #import // for AudioServicesPlaySystemSound, etc #import "PatternViewController.h" // for UpdateStatus, etc #endif // ----------------------------------------------------------------------------- int event_checker = 0; // if > 0 then we're in gollypoller.checkevents() // ----------------------------------------------------------------------------- void SetColor(gColor& color, unsigned char red, unsigned char green, unsigned char blue) { color.r = red; color.g = green; color.b = blue; } // ----------------------------------------------------------------------------- void SetRect(gRect& rect, int x, int y, int width, int height) { rect.x = x; rect.y = y; rect.width = width; rect.height = height; } // ----------------------------------------------------------------------------- #ifdef IOS_GUI // need the following to make YesNo/Warning/Fatal dialogs modal: @interface ModalAlertDelegate : NSObject { NSInteger returnButt; } @property () NSInteger returnButt; - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex; @end @implementation ModalAlertDelegate @synthesize returnButt; - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { returnButt = buttonIndex; } @end #endif // IOS_GUI // ----------------------------------------------------------------------------- bool YesNo(const char* msg) { Beep(); #ifdef ANDROID_GUI return AndroidYesNo(msg); #endif #ifdef WEB_GUI return WebYesNo(msg); #endif #ifdef IOS_GUI ModalAlertDelegate *md = [[ModalAlertDelegate alloc] init]; md.returnButt = -1; UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"Warning" message:[NSString stringWithCString:msg encoding:NSUTF8StringEncoding] delegate:md cancelButtonTitle:@"No" otherButtonTitles:@"Yes", nil]; [a show]; // wait for user to hit button while (md.returnButt == -1) { event_checker++; [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; event_checker--; } return md.returnButt != 0; #endif // IOS_GUI } // ----------------------------------------------------------------------------- void Warning(const char* msg) { Beep(); #ifdef ANDROID_GUI AndroidWarning(msg); #endif #ifdef WEB_GUI WebWarning(msg); #endif #ifdef IOS_GUI ModalAlertDelegate *md = [[ModalAlertDelegate alloc] init]; md.returnButt = -1; UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"Warning" message:[NSString stringWithCString:msg encoding:NSUTF8StringEncoding] delegate:md cancelButtonTitle:@"OK" otherButtonTitles:nil]; [a show]; // wait for user to hit button while (md.returnButt == -1) { event_checker++; [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; event_checker--; } #endif // IOS_GUI } // ----------------------------------------------------------------------------- void Fatal(const char* msg) { Beep(); #ifdef ANDROID_GUI AndroidFatal(msg); #endif #ifdef WEB_GUI WebFatal(msg); #endif #ifdef IOS_GUI ModalAlertDelegate *md = [[ModalAlertDelegate alloc] init]; md.returnButt = -1; UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"Fatal Error" message:[NSString stringWithCString:msg encoding:NSUTF8StringEncoding] delegate:md cancelButtonTitle:@"Quit" otherButtonTitles:nil]; [a show]; // wait for user to hit button while (md.returnButt == -1) { event_checker++; [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; event_checker--; } exit(1); #endif // IOS_GUI } // ----------------------------------------------------------------------------- void Beep() { if (!allowbeep) return; #ifdef ANDROID_GUI AndroidBeep(); #endif #ifdef WEB_GUI WebBeep(); #endif #ifdef IOS_GUI static SystemSoundID beepID = 0; if (beepID == 0) { // get the path to the sound file NSString* path = [[NSBundle mainBundle] pathForResource:@"beep" ofType:@"aiff"]; if (path) { NSURL* url = [NSURL fileURLWithPath:path]; OSStatus err = AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, &beepID); if (err == kAudioServicesNoError && beepID > 0) { // play the sound AudioServicesPlaySystemSound(beepID); } } } else { // assume we got the sound AudioServicesPlaySystemSound(beepID); } #endif // IOS_GUI } // ----------------------------------------------------------------------------- double TimeInSeconds() { struct timeval trec; gettimeofday(&trec, 0); return double(trec.tv_sec) + double(trec.tv_usec) / 1.0e6; } // ----------------------------------------------------------------------------- std::string CreateTempFileName(const char* prefix) { /* std::string tmplate = tempdir; tmplate += prefix; tmplate += ".XXXXXX"; std::string path = mktemp((char*)tmplate.c_str()); */ // simpler to ignore prefix and create /tmp/0, /tmp/1, /tmp/2, etc char n[32]; static int nextname = 0; sprintf(n, "%d", nextname++); std::string path = tempdir + n; return path; } // ----------------------------------------------------------------------------- bool FileExists(const std::string& filepath) { FILE* f = fopen(filepath.c_str(), "r"); if (f) { fclose(f); return true; } else { return false; } } // ----------------------------------------------------------------------------- void RemoveFile(const std::string& filepath) { #ifdef ANDROID_GUI AndroidRemoveFile(filepath); #endif #ifdef WEB_GUI WebRemoveFile(filepath); #endif #ifdef IOS_GUI if ([[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithCString:filepath.c_str() encoding:NSUTF8StringEncoding] error:NULL] == NO) { // should never happen Warning("RemoveFile failed!"); }; #endif } // ----------------------------------------------------------------------------- bool CopyFile(const std::string& inpath, const std::string& outpath) { #if defined(ANDROID_GUI) || defined(WEB_GUI) FILE* infile = fopen(inpath.c_str(), "r"); if (infile) { // read entire file into contents std::string contents; const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; linereader reader(infile); while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; contents += linebuf; contents += "\n"; } reader.close(); // fclose(infile) has been called // write contents to outpath FILE* outfile = fopen(outpath.c_str(), "w"); if (outfile) { if (fputs(contents.c_str(), outfile) == EOF) { fclose(outfile); Warning("CopyFile failed to copy contents to output file!"); return false; } fclose(outfile); } else { Warning("CopyFile failed to open output file!"); return false; } return true; } else { Warning("CopyFile failed to open input file!"); return false; } #endif // ANDROID_GUI or WEB_GUI #ifdef IOS_GUI if (FileExists(outpath)) { RemoveFile(outpath); } return [[NSFileManager defaultManager] copyItemAtPath:[NSString stringWithCString:inpath.c_str() encoding:NSUTF8StringEncoding] toPath:[NSString stringWithCString:outpath.c_str() encoding:NSUTF8StringEncoding] error:NULL]; #endif // IOS_GUI } // ----------------------------------------------------------------------------- bool MoveFile(const std::string& inpath, const std::string& outpath) { #ifdef ANDROID_GUI return AndroidMoveFile(inpath, outpath); #endif #ifdef WEB_GUI return WebMoveFile(inpath, outpath); #endif #ifdef IOS_GUI if (FileExists(outpath)) { RemoveFile(outpath); } return [[NSFileManager defaultManager] moveItemAtPath:[NSString stringWithCString:inpath.c_str() encoding:NSUTF8StringEncoding] toPath:[NSString stringWithCString:outpath.c_str() encoding:NSUTF8StringEncoding] error:NULL]; #endif } // ----------------------------------------------------------------------------- void FixURLPath(std::string& path) { // replace "%..." with suitable chars for a file path (eg. %20 is changed to space) #ifdef ANDROID_GUI AndroidFixURLPath(path); #endif #ifdef WEB_GUI WebFixURLPath(path); #endif #ifdef IOS_GUI NSString* newpath = [[NSString stringWithCString:path.c_str() encoding:NSUTF8StringEncoding] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; if (newpath) path = [newpath cStringUsingEncoding:NSUTF8StringEncoding]; #endif } // ----------------------------------------------------------------------------- bool IsHTMLFile(const std::string& filename) { size_t dotpos = filename.rfind('.'); if (dotpos == std::string::npos) return false; std::string ext = filename.substr(dotpos+1); return ( strcasecmp(ext.c_str(),"htm") == 0 || strcasecmp(ext.c_str(),"html") == 0 ); } // ----------------------------------------------------------------------------- bool IsTextFile(const std::string& filename) { if (!IsHTMLFile(filename)) { // if non-html file name contains "readme" then assume it's a text file std::string basename = filename; size_t lastsep = basename.rfind('/'); if (lastsep != std::string::npos) { basename = basename.substr(lastsep+1); } std::transform(basename.begin(), basename.end(), basename.begin(), tolower); if (basename.find("readme") != std::string::npos) return true; } size_t dotpos = filename.rfind('.'); if (dotpos == std::string::npos) return false; std::string ext = filename.substr(dotpos+1); return ( strcasecmp(ext.c_str(),"txt") == 0 || strcasecmp(ext.c_str(),"doc") == 0 ); } // ----------------------------------------------------------------------------- bool IsZipFile(const std::string& filename) { size_t dotpos = filename.rfind('.'); if (dotpos == std::string::npos) return false; std::string ext = filename.substr(dotpos+1); return ( strcasecmp(ext.c_str(),"zip") == 0 || strcasecmp(ext.c_str(),"gar") == 0 ); } // ----------------------------------------------------------------------------- bool IsRuleFile(const std::string& filename) { size_t dotpos = filename.rfind('.'); if (dotpos == std::string::npos) return false; std::string ext = filename.substr(dotpos+1); return ( strcasecmp(ext.c_str(),"rule") == 0 || strcasecmp(ext.c_str(),"table") == 0 || strcasecmp(ext.c_str(),"tree") == 0 || strcasecmp(ext.c_str(),"colors") == 0 || strcasecmp(ext.c_str(),"icons") == 0 ); } // ----------------------------------------------------------------------------- bool IsScriptFile(const std::string& filename) { size_t dotpos = filename.rfind('.'); if (dotpos == std::string::npos) return false; std::string ext = filename.substr(dotpos+1); return ( strcasecmp(ext.c_str(),"pl") == 0 || strcasecmp(ext.c_str(),"py") == 0 ); } // ----------------------------------------------------------------------------- bool EndsWith(const std::string& str, const std::string& suffix) { // return true if str ends with suffix size_t strlen = str.length(); size_t sufflen = suffix.length(); return (strlen >= sufflen) && (str.rfind(suffix) == strlen - sufflen); } // ----------------------------------------------------------------------------- // let gollybase modules process events class golly_poll : public lifepoll { public: virtual int checkevents(); virtual void updatePop(); }; int golly_poll::checkevents() { if (event_checker > 0) return isInterrupted(); event_checker++; #ifdef ANDROID_GUI AndroidCheckEvents(); #endif #ifdef WEB_GUI WebCheckEvents(); #endif #ifdef IOS_GUI [[NSRunLoop currentRunLoop] runUntilDate:[NSDate date]]; #endif event_checker--; return isInterrupted(); } void golly_poll::updatePop() { UpdateStatus(); } // ----------------------------------------------------------------------------- golly_poll gollypoller; // create instance lifepoll* Poller() { return &gollypoller; } void PollerReset() { gollypoller.resetInterrupted(); } void PollerInterrupt() { gollypoller.setInterrupted(); } golly-2.7-src/gui-common/view.cpp0000644000175000017500000014662512536111364013766 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "viewport.h" #include "utils.h" // for Warning, Fatal, YesNo, Beep, etc #include "prefs.h" // for showgridlines, etc #include "status.h" // for DisplayMessage, etc #include "render.h" // for CreatePasteImage, DestroyPasteImage #include "undo.h" // for currlayer->undoredo->... #include "select.h" // for Selection #include "algos.h" // for algo_type, *_ALGO, CreateNewUniverse, etc #include "layer.h" // for currlayer, ResizeLayers, etc #include "control.h" // for generating, ChangeRule #include "file.h" // for GetTextFromClipboard #include "view.h" #ifdef ANDROID_GUI #include "jnicalls.h" // for UpdatePattern, BeginProgress, etc #endif #ifdef WEB_GUI #include "webcalls.h" // for UpdatePattern, BeginProgress, etc #endif #ifdef IOS_GUI #import "PatternViewController.h" // for UpdatePattern, BeginProgress, etc #endif // ----------------------------------------------------------------------------- // exported data: const char* empty_selection = "There are no live cells in the selection."; const char* empty_outside = "There are no live cells outside the selection."; const char* no_selection = "There is no selection."; const char* selection_too_big = "Selection is outside +/- 10^9 boundary."; const char* pattern_too_big = "Pattern is outside +/- 10^9 boundary."; const char* origin_restored = "Origin restored."; bool widescreen = true; // is screen wide enough to show all info? (assume a tablet device; eg. iPad) bool fullscreen = false; // in full screen mode? bool nopattupdate = false; // disable pattern updates? bool waitingforpaste = false; // waiting for user to decide what to do with paste image? gRect pasterect; // bounding box of paste image int pastex, pastey; // where user wants to paste clipboard pattern bool draw_pending = false; // delay drawing? int pendingx, pendingy; // start of delayed drawing // ----------------------------------------------------------------------------- // local data: static int cellx, celly; // current cell's 32-bit position static bigint bigcellx, bigcelly; // current cell's position static int initselx, initsely; // location of initial selection click static bool forceh; // resize selection horizontally? static bool forcev; // resize selection vertically? static bigint anchorx, anchory; // anchor cell of current selection static Selection prevsel; // previous selection static int drawstate; // new cell state (0..255) static lifealgo* pastealgo = NULL; // temporary universe with pattern to be pasted static gRect pastebox; // bounding box (in cells) for paste pattern static std::string oldrule; // rule before readclipboard is called static std::string newrule; // rule after readclipboard is called static int pastetype; // algo type for pastealgo static bool drawingcells = false; // drawing cells by dragging finger? static bool pickingcells = false; // picking cell states by dragging finger? static bool selectingcells = false; // selecting cells by dragging finger? static bool movingview = false; // moving view by dragging finger? static bool movingpaste = false; // moving paste image by dragging finger? // ----------------------------------------------------------------------------- void UpdatePatternAndStatus() { if (inscript || currlayer->undoredo->doingscriptchanges) return; UpdatePattern(); UpdateStatus(); } // ----------------------------------------------------------------------------- void UpdateEverything() { UpdatePattern(); UpdateStatus(); UpdateEditBar(); } // ----------------------------------------------------------------------------- // most editing operations are limited to absolute coordinates <= 10^9 because // getcell and setcell only take int parameters (the limits must be smaller // than INT_MIN and INT_MAX to avoid boundary conditions) static bigint min_coord = -1000000000; static bigint max_coord = +1000000000; bool OutsideLimits(bigint& t, bigint& l, bigint& b, bigint& r) { return ( t < min_coord || l < min_coord || b > max_coord || r > max_coord ); } // ----------------------------------------------------------------------------- void TestAutoFit() { if (currlayer->autofit && generating) { // assume user no longer wants us to do autofitting currlayer->autofit = false; } } // ----------------------------------------------------------------------------- void FitInView(int force) { if (waitingforpaste && currlayer->algo->isEmpty()) { // fit paste image in viewport if there is no pattern // (note that pastealgo->fit() won't work because paste image // might be bigger than paste pattern) int vwd = currlayer->view->getxmax(); int vht = currlayer->view->getymax(); int pwd, pht; int mag = MAX_MAG; while (true) { pwd = mag >= 0 ? (pastebox.width << mag) - 1 : (pastebox.width >> -mag); pht = mag >= 0 ? (pastebox.height << mag) - 1 : (pastebox.height >> -mag); if (vwd >= pwd && vht >= pht) { // all of paste image can fit within viewport at this mag break; } mag--; } // set mag and move viewport to origin currlayer->view->setpositionmag(bigint::zero, bigint::zero, mag); // move paste image to middle of viewport pastex = (vwd - pwd) / 2; pastey = (vht - pht) / 2; } else { // fit current pattern in viewport // (if no pattern this will set mag to MAX_MAG and move to origin) currlayer->algo->fit(*currlayer->view, force); } } // ----------------------------------------------------------------------------- bool PointInView(int x, int y) { return ( x >= 0 && x <= currlayer->view->getxmax() && y >= 0 && y <= currlayer->view->getymax() ); } // ----------------------------------------------------------------------------- bool PointInPasteImage(int x, int y) { return (x >= pasterect.x && x <= pasterect.x + pasterect.width-1 && y >= pasterect.y && y <= pasterect.y + pasterect.height-1); } // ----------------------------------------------------------------------------- bool PointInSelection(int x, int y) { pair cellpos = currlayer->view->at(x, y); int cx = cellpos.first.toint(); int cy = cellpos.second.toint(); return currlayer->currsel.ContainsCell(cx, cy); } // ----------------------------------------------------------------------------- bool CellInGrid(const bigint& x, const bigint& y) { // return true if cell at x,y is within bounded grid if (currlayer->algo->gridwd > 0 && (x < currlayer->algo->gridleft || x > currlayer->algo->gridright)) return false; if (currlayer->algo->gridht > 0 && (y < currlayer->algo->gridtop || y > currlayer->algo->gridbottom)) return false; return true; } // ----------------------------------------------------------------------------- bool PointInGrid(int x, int y) { // is given viewport location also in grid? if (currlayer->algo->gridwd == 0 && currlayer->algo->gridht == 0) { // unbounded grid return true; } pair cellpos = currlayer->view->at(x, y); return CellInGrid(cellpos.first, cellpos.second); } // ----------------------------------------------------------------------------- void RememberOneCellChange(int cx, int cy, int oldstate, int newstate) { if (allowundo) { // remember this cell change for later undo/redo currlayer->undoredo->SaveCellChange(cx, cy, oldstate, newstate); } } // ----------------------------------------------------------------------------- void DrawCells(int x, int y) { // make sure x,y is within viewport if (x < 0) x = 0; if (y < 0) y = 0; if (x > currlayer->view->getxmax()) x = currlayer->view->getxmax(); if (y > currlayer->view->getymax()) y = currlayer->view->getymax(); // make sure x,y is within bounded grid pair cellpos = currlayer->view->at(x, y); if (currlayer->algo->gridwd > 0) { if (cellpos.first < currlayer->algo->gridleft) cellpos.first = currlayer->algo->gridleft; if (cellpos.first > currlayer->algo->gridright) cellpos.first = currlayer->algo->gridright; } if (currlayer->algo->gridht > 0) { if (cellpos.second < currlayer->algo->gridtop) cellpos.second = currlayer->algo->gridtop; if (cellpos.second > currlayer->algo->gridbottom) cellpos.second = currlayer->algo->gridbottom; } if ( currlayer->view->getmag() < 0 || OutsideLimits(cellpos.second, cellpos.first, cellpos.second, cellpos.first) ) { return; } int currstate; int numchanged = 0; int newx = cellpos.first.toint(); int newy = cellpos.second.toint(); if ( newx != cellx || newy != celly ) { // draw a line of cells using Bresenham's algorithm int d, ii, jj, di, ai, si, dj, aj, sj; di = newx - cellx; ai = abs(di) << 1; si = (di < 0)? -1 : 1; dj = newy - celly; aj = abs(dj) << 1; sj = (dj < 0)? -1 : 1; ii = cellx; jj = celly; lifealgo* curralgo = currlayer->algo; if (ai > aj) { d = aj - (ai >> 1); while (ii != newx) { currstate = curralgo->getcell(ii, jj); if (currstate != drawstate) { curralgo->setcell(ii, jj, drawstate); RememberOneCellChange(ii, jj, currstate, drawstate); numchanged++; } if (d >= 0) { jj += sj; d -= ai; } ii += si; d += aj; } } else { d = ai - (aj >> 1); while (jj != newy) { currstate = curralgo->getcell(ii, jj); if (currstate != drawstate) { curralgo->setcell(ii, jj, drawstate); RememberOneCellChange(ii, jj, currstate, drawstate); numchanged++; } if (d >= 0) { ii += si; d -= aj; } jj += sj; d += ai; } } cellx = newx; celly = newy; currstate = curralgo->getcell(cellx, celly); if (currstate != drawstate) { curralgo->setcell(cellx, celly, drawstate); RememberOneCellChange(cellx, celly, currstate, drawstate); numchanged++; } } if (numchanged > 0) { currlayer->algo->endofpattern(); MarkLayerDirty(); UpdatePattern(); UpdateStatus(); } } // ----------------------------------------------------------------------------- void StartDrawingCells(int x, int y) { if (generating) { // temporarily stop generating when drawing cells (necessary for undo/redo) PauseGenerating(); if (event_checker > 0) { // delay drawing until after step() finishes in NextGeneration() draw_pending = true; pendingx = x; pendingy = y; return; } // NOTE: ResumeGenerating() is called in TouchEnded() } if (!PointInGrid(x, y)) { ErrorMessage("Drawing is not allowed outside grid."); return; } if (currlayer->view->getmag() < 0) { ErrorMessage("Drawing is not allowed at scales greater than 1 cell per pixel."); return; } // check that x,y is within getcell/setcell limits pair cellpos = currlayer->view->at(x, y); if ( OutsideLimits(cellpos.second, cellpos.first, cellpos.second, cellpos.first) ) { ErrorMessage("Drawing is not allowed outside +/- 10^9 boundary."); return; } drawingcells = true; // save dirty state now for later use by RememberCellChanges if (allowundo) currlayer->savedirty = currlayer->dirty; cellx = cellpos.first.toint(); celly = cellpos.second.toint(); int currstate = currlayer->algo->getcell(cellx, celly); // reset drawing state in case it's no longer valid (due to algo/rule change) if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) { currlayer->drawingstate = 1; } if (currstate == currlayer->drawingstate) { drawstate = 0; } else { drawstate = currlayer->drawingstate; } if (currstate != drawstate) { currlayer->algo->setcell(cellx, celly, drawstate); currlayer->algo->endofpattern(); // remember this cell change for later undo/redo RememberOneCellChange(cellx, celly, currstate, drawstate); MarkLayerDirty(); UpdatePattern(); UpdateStatus(); // update population count } } // ----------------------------------------------------------------------------- void PickCell(int x, int y) { if (!PointInGrid(x, y)) return; pair cellpos = currlayer->view->at(x, y); if ( currlayer->view->getmag() < 0 || OutsideLimits(cellpos.second, cellpos.first, cellpos.second, cellpos.first) ) { return; } int newx = cellpos.first.toint(); int newy = cellpos.second.toint(); if ( newx != cellx || newy != celly ) { cellx = newx; celly = newy; currlayer->drawingstate = currlayer->algo->getcell(cellx, celly); UpdateEditBar(); } } // ----------------------------------------------------------------------------- void StartPickingCells(int x, int y) { if (!PointInGrid(x, y)) { ErrorMessage("Picking is not allowed outside grid."); return; } if (currlayer->view->getmag() < 0) { ErrorMessage("Picking is not allowed at scales greater than 1 cell per pixel."); return; } cellx = INT_MAX; celly = INT_MAX; PickCell(x, y); pickingcells = true; } // ----------------------------------------------------------------------------- void SelectCells(int x, int y) { // only select cells within view if (x < 0) x = 0; if (y < 0) y = 0; if (x > currlayer->view->getxmax()) x = currlayer->view->getxmax(); if (y > currlayer->view->getymax()) y = currlayer->view->getymax(); if ( abs(initselx - x) < 2 && abs(initsely - y) < 2 && !SelectionExists() ) { // avoid 1x1 selection if finger hasn't moved much return; } // make sure x,y is within bounded grid pair cellpos = currlayer->view->at(x, y); if (currlayer->algo->gridwd > 0) { if (cellpos.first < currlayer->algo->gridleft) cellpos.first = currlayer->algo->gridleft; if (cellpos.first > currlayer->algo->gridright) cellpos.first = currlayer->algo->gridright; } if (currlayer->algo->gridht > 0) { if (cellpos.second < currlayer->algo->gridtop) cellpos.second = currlayer->algo->gridtop; if (cellpos.second > currlayer->algo->gridbottom) cellpos.second = currlayer->algo->gridbottom; } if (forceh && forcev) { // move selection bigint xdelta = cellpos.first; bigint ydelta = cellpos.second; xdelta -= bigcellx; ydelta -= bigcelly; if ( xdelta != bigint::zero || ydelta != bigint::zero ) { currlayer->currsel.Move(xdelta, ydelta); bigcellx = cellpos.first; bigcelly = cellpos.second; } } else { // change selection size if (!forcev) currlayer->currsel.SetLeftRight(cellpos.first, anchorx); if (!forceh) currlayer->currsel.SetTopBottom(cellpos.second, anchory); } if (currlayer->currsel != prevsel) { // selection has changed DisplaySelectionSize(); prevsel = currlayer->currsel; UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- void StartSelectingCells(int x, int y) { TestAutoFit(); // make sure anchor cell is within bounded grid (x,y can be outside grid) pair cellpos = currlayer->view->at(x, y); if (currlayer->algo->gridwd > 0) { if (cellpos.first < currlayer->algo->gridleft) cellpos.first = currlayer->algo->gridleft; if (cellpos.first > currlayer->algo->gridright) cellpos.first = currlayer->algo->gridright; } if (currlayer->algo->gridht > 0) { if (cellpos.second < currlayer->algo->gridtop) cellpos.second = currlayer->algo->gridtop; if (cellpos.second > currlayer->algo->gridbottom) cellpos.second = currlayer->algo->gridbottom; } anchorx = cellpos.first; anchory = cellpos.second; bigcellx = anchorx; bigcelly = anchory; // save original selection for RememberNewSelection currlayer->savesel = currlayer->currsel; // reset previous selection prevsel.Deselect(); // for avoiding 1x1 selection if finger doesn't move much initselx = x; initsely = y; // allow changing size in any direction forceh = false; forcev = false; if (SelectionExists()) { if (PointInSelection(x, y)) { // modify current selection currlayer->currsel.Modify(x, y, anchorx, anchory, &forceh, &forcev); DisplaySelectionSize(); } else { // remove current selection currlayer->currsel.Deselect(); } UpdatePatternAndStatus(); } selectingcells = true; } // ----------------------------------------------------------------------------- void MoveView(int x, int y) { pair cellpos = currlayer->view->at(x, y); bigint xdelta = bigcellx; bigint ydelta = bigcelly; xdelta -= cellpos.first; ydelta -= cellpos.second; int xamount, yamount; int mag = currlayer->view->getmag(); if (mag >= 0) { // move an integral number of cells xamount = xdelta.toint() << mag; yamount = ydelta.toint() << mag; } else { // convert cell deltas to screen pixels xdelta >>= -mag; ydelta >>= -mag; xamount = xdelta.toint(); yamount = ydelta.toint(); } if ( xamount != 0 || yamount != 0 ) { currlayer->view->move(xamount, yamount); cellpos = currlayer->view->at(x, y); bigcellx = cellpos.first; bigcelly = cellpos.second; UpdatePattern(); UpdateStatus(); } } // ----------------------------------------------------------------------------- void StartMovingView(int x, int y) { TestAutoFit(); pair cellpos = currlayer->view->at(x, y); bigcellx = cellpos.first; bigcelly = cellpos.second; movingview = true; } // ----------------------------------------------------------------------------- void MovePaste(int x, int y) { pair cellpos = currlayer->view->at(x, y); bigint xdelta = bigcellx; bigint ydelta = bigcelly; xdelta -= cellpos.first; ydelta -= cellpos.second; int xamount, yamount; int mag = currlayer->view->getmag(); if (mag >= 0) { // move an integral number of cells xamount = xdelta.toint() << mag; yamount = ydelta.toint() << mag; } else { // convert cell deltas to screen pixels xdelta >>= -mag; ydelta >>= -mag; xamount = xdelta.toint(); yamount = ydelta.toint(); } if ( xamount != 0 || yamount != 0 ) { // shift location of pasterect pastex -= xamount; pastey -= yamount; cellpos = currlayer->view->at(x, y); bigcellx = cellpos.first; bigcelly = cellpos.second; UpdatePattern(); } } // ----------------------------------------------------------------------------- void StartMovingPaste(int x, int y) { pair cellpos = currlayer->view->at(x, y); bigcellx = cellpos.first; bigcelly = cellpos.second; movingpaste = true; } // ----------------------------------------------------------------------------- void TouchBegan(int x, int y) { if (waitingforpaste && PointInPasteImage(x, y)) { StartMovingPaste(x, y); } else if (currlayer->touchmode == drawmode) { StartDrawingCells(x, y); } else if (currlayer->touchmode == pickmode) { StartPickingCells(x, y); } else if (currlayer->touchmode == selectmode) { StartSelectingCells(x, y); } else if (currlayer->touchmode == movemode) { StartMovingView(x, y); } else if (currlayer->touchmode == zoominmode) { ZoomInPos(x, y); } else if (currlayer->touchmode == zoomoutmode) { ZoomOutPos(x, y); } } // ----------------------------------------------------------------------------- void TouchMoved(int x, int y) { // make sure x,y is within viewport if (x < 0) x = 0; if (y < 0) y = 0; if (x > currlayer->view->getxmax()) x = currlayer->view->getxmax(); if (y > currlayer->view->getymax()) y = currlayer->view->getymax(); if ( drawingcells ) { DrawCells(x, y); } else if ( pickingcells ) { PickCell(x, y); } else if ( selectingcells ) { SelectCells(x, y); } else if ( movingview ) { MoveView(x, y); } else if ( movingpaste ) { MovePaste(x, y); } } // ----------------------------------------------------------------------------- void TouchEnded() { if (drawingcells && allowundo) { // MarkLayerDirty has set dirty flag, so we need to // pass in the flag state saved before drawing started currlayer->undoredo->RememberCellChanges("Drawing", currlayer->savedirty); UpdateEditBar(); // update various buttons } if (selectingcells) { if (allowundo) RememberNewSelection("Selection"); UpdateEditBar(); // update various buttons } drawingcells = false; pickingcells = false; selectingcells = false; movingview = false; movingpaste = false; ResumeGenerating(); } // ----------------------------------------------------------------------------- bool CopyRect(int itop, int ileft, int ibottom, int iright, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, const char* progmsg) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; double maxcount = (double)wd * (double)ht; int cntr = 0; int v = 0; bool abort = false; // copy (and erase if requested) live cells from given rect // in source universe to same rect in destination universe BeginProgress(progmsg); for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = srcalgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; destalgo->setcell(cx, cy, v); if (erasesrc) srcalgo->setcell(cx, cy, 0); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, ""); if (abort) break; } } if (abort) break; } if (erasesrc) srcalgo->endofpattern(); destalgo->endofpattern(); EndProgress(); return !abort; } // ----------------------------------------------------------------------------- void CopyAllRect(int itop, int ileft, int ibottom, int iright, lifealgo* srcalgo, lifealgo* destalgo, const char* progmsg) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; // copy all cells from given rect in srcalgo to same rect in destalgo BeginProgress(progmsg); for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { destalgo->setcell(cx, cy, srcalgo->getcell(cx, cy)); cntr++; if ((cntr % 4096) == 0) { abort = AbortProgress((double)cntr / maxcount, ""); if (abort) break; } } if (abort) break; } destalgo->endofpattern(); EndProgress(); } // ----------------------------------------------------------------------------- bool SelectionExists() { return currlayer->currsel.Exists(); } // ----------------------------------------------------------------------------- void SelectAll() { SaveCurrentSelection(); if (SelectionExists()) { currlayer->currsel.Deselect(); UpdatePatternAndStatus(); } if (currlayer->algo->isEmpty()) { ErrorMessage("All cells are dead."); RememberNewSelection("Deselection"); return; } bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); currlayer->currsel.SetEdges(top, left, bottom, right); RememberNewSelection("Select All"); DisplaySelectionSize(); UpdateEverything(); } // ----------------------------------------------------------------------------- void RemoveSelection() { if (SelectionExists()) { SaveCurrentSelection(); currlayer->currsel.Deselect(); RememberNewSelection("Deselection"); UpdateEverything(); } } // ----------------------------------------------------------------------------- void FitSelection() { if (!SelectionExists()) return; currlayer->currsel.Fit(); TestAutoFit(); UpdateEverything(); } // ----------------------------------------------------------------------------- void DisplaySelectionSize() { currlayer->currsel.DisplaySize(); } // ----------------------------------------------------------------------------- void SaveCurrentSelection() { if (allowundo && !currlayer->stayclean) { currlayer->savesel = currlayer->currsel; } } // ----------------------------------------------------------------------------- void RememberNewSelection(const char* action) { if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberSelection(action); } } // ----------------------------------------------------------------------------- void ClearSelection() { currlayer->currsel.Clear(); } // ----------------------------------------------------------------------------- void ClearOutsideSelection() { currlayer->currsel.ClearOutside(); } // ----------------------------------------------------------------------------- void CutSelection() { currlayer->currsel.CopyToClipboard(true); } // ----------------------------------------------------------------------------- void CopySelection() { currlayer->currsel.CopyToClipboard(false); } // ----------------------------------------------------------------------------- void ShrinkSelection(bool fit) { currlayer->currsel.Shrink(fit); } // ----------------------------------------------------------------------------- void RandomFill() { currlayer->currsel.RandomFill(); } // ----------------------------------------------------------------------------- bool FlipSelection(bool topbottom, bool inundoredo) { return currlayer->currsel.Flip(topbottom, inundoredo); } // ----------------------------------------------------------------------------- bool RotateSelection(bool clockwise, bool inundoredo) { return currlayer->currsel.Rotate(clockwise, inundoredo); } // ----------------------------------------------------------------------------- bool GetClipboardPattern(bigint* t, bigint* l, bigint* b, bigint* r) { std::string data; if ( !GetTextFromClipboard(data) ) return false; // copy clipboard data to temporary file so we can handle all formats supported by readclipboard FILE* tmpfile = fopen(clipfile.c_str(), "w"); if (tmpfile) { if (fputs(data.c_str(), tmpfile) == EOF) { fclose(tmpfile); Warning("Could not write clipboard text to temporary file!"); return false; } } else { Warning("Could not create temporary file for clipboard data!"); return false; } fclose(tmpfile); // remember current rule oldrule = currlayer->algo->getrule(); const char* err = readclipboard(clipfile.c_str(), *pastealgo, t, l, b, r); if (err) { // cycle thru all other algos until readclipboard succeeds for (int i = 0; i < NumAlgos(); i++) { if (i != currlayer->algtype) { delete pastealgo; pastealgo = CreateNewUniverse(i); err = readclipboard(clipfile.c_str(), *pastealgo, t, l, b, r); if (!err) { pastetype = i; // remember algo type for later use in PasteTemporaryToCurrent break; } } } } if (!err && canchangerule > 0) { // set newrule for later use in PasteTemporaryToCurrent if (canchangerule == 1 && !currlayer->algo->isEmpty()) { // don't change rule if universe isn't empty newrule = oldrule; } else { // remember rule set by readclipboard newrule = pastealgo->getrule(); } } RemoveFile(clipfile); if (err) { // error probably due to bad rule string in clipboard data Warning("Could not load clipboard pattern\n(probably due to unknown rule)."); return false; } return true; } // ----------------------------------------------------------------------------- bool ClipboardContainsRule() { std::string data; if (!GetTextFromClipboard(data)) return false; if (strncmp(data.c_str(), "@RULE ", 6) != 0) return false; // extract rule name std::string rulename; int i = 6; while (data[i] > ' ') { rulename += data[i]; i++; } // check if rulename.rule already exists in userrules std::string rulepath = userrules + rulename; rulepath += ".rule"; if (FileExists(rulepath)) { std::string question = "Do you want to replace the existing " + rulename; question += ".rule with the version in the clipboard?"; if (!YesNo(question.c_str())) { // don't overwrite existing .rule file return true; } } // create rulename.rule in userrules FILE* rulefile = fopen(rulepath.c_str(), "w"); if (rulefile) { if (fputs(data.c_str(), rulefile) == EOF) { fclose(rulefile); Warning("Could not write clipboard text to .rule file!"); return true; } } else { Warning("Could not open .rule file for writing!"); return true; } fclose(rulefile); #ifdef WEB_GUI // ensure the .rule file persists beyond the current session CopyRuleToLocalStorage(rulepath.c_str()); #endif // now switch to the newly created rule ChangeRule(rulename); std::string msg = "Created " + rulename + ".rule"; DisplayMessage(msg.c_str()); return true; } // ----------------------------------------------------------------------------- void PasteClipboard() { // if clipboard text starts with "@RULE rulename" then install rulename.rule // and switch to that rule if (ClipboardContainsRule()) return; // create a temporary universe for storing the clipboard pattern if (pastealgo) { Warning("Bug detected in PasteClipboard!"); delete pastealgo; // might as well continue } pastealgo = CreateNewUniverse(currlayer->algtype); pastetype = currlayer->algtype; // read clipboard pattern into temporary universe bigint top, left, bottom, right; if ( GetClipboardPattern(&top, &left, &bottom, &right) ) { // make sure given edges are within getcell/setcell limits if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Clipboard pattern is too big."); } else { #ifdef WEB_GUI DisplayMessage("Drag paste image to desired location then right-click on it."); #else // Android and iOS devices use a touch screen DisplayMessage("Drag paste image to desired location then tap Paste button."); #endif waitingforpaste = true; // set initial position of pasterect's top left corner to near top left corner // of viewport so all of paste image is likely to be visble and it isn't far // to move finger from Paste button pastex = 128; pastey = 64; // create image for drawing the pattern to be pasted; note that pastebox // is not necessarily the minimal bounding box because clipboard pattern // might have blank borders (in fact it could be empty) int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; SetRect(pastebox, ileft, itop, wd, ht); CreatePasteImage(pastealgo, pastebox); } } // waitingforpaste will only be false if an error occurred if (!waitingforpaste) { delete pastealgo; pastealgo = NULL; } } // ----------------------------------------------------------------------------- void PasteTemporaryToCurrent(bigint top, bigint left, bigint wd, bigint ht) { // reset waitingforpaste now to avoid paste image being displayed prematurely waitingforpaste = false; bigint bottom = top; bottom += ht; bottom -= 1; bigint right = left; right += wd; right -= 1; // check that paste rectangle is within edit limits if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Pasting is not allowed outside +/- 10^9 boundary."); return; } // set edges of pattern in pastealgo int itop = pastebox.y; int ileft = pastebox.x; int ibottom = pastebox.y + pastebox.height - 1; int iright = pastebox.x + pastebox.width - 1; // set pastex,pastey to top left cell of paste rectangle pastex = left.toint(); pastey = top.toint(); // selection might change if grid becomes smaller, // so save current selection for RememberRuleChange/RememberAlgoChange SaveCurrentSelection(); // pasting clipboard pattern can cause a rule change int oldmaxstate = currlayer->algo->NumCellStates() - 1; if (canchangerule > 0 && oldrule != newrule) { const char* err = currlayer->algo->setrule( newrule.c_str() ); // setrule can fail if readclipboard loaded clipboard pattern into // a different type of algo (pastetype) if (err) { // allow rule change to cause algo change ChangeAlgorithm(pastetype, newrule.c_str()); } else { // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { ClearOutsideGrid(); } // rule change might have changed the number of cell states; // if there are fewer states then pattern might change int newmaxstate = currlayer->algo->NumCellStates() - 1; if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { ReduceCellStates(newmaxstate); } // switch to default colors for new rule UpdateLayerColors(); if (allowundo && !currlayer->stayclean) currlayer->undoredo->RememberRuleChange(oldrule.c_str()); } } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; //!!! if (savecells && inscript) SavePendingChanges(); // don't paste cells outside bounded grid int gtop = currlayer->algo->gridtop.toint(); int gleft = currlayer->algo->gridleft.toint(); int gbottom = currlayer->algo->gridbottom.toint(); int gright = currlayer->algo->gridright.toint(); if (currlayer->algo->gridwd == 0) { // grid has infinite width gleft = INT_MIN; gright = INT_MAX; } if (currlayer->algo->gridht == 0) { // grid has infinite height gtop = INT_MIN; gbottom = INT_MAX; } // copy pattern from temporary universe to current universe int tx, ty, cx, cy; double maxcount = wd.todouble() * ht.todouble(); int cntr = 0; bool abort = false; bool pattchanged = false; bool reduced = false; lifealgo* curralgo = currlayer->algo; int maxstate = curralgo->NumCellStates() - 1; BeginProgress("Pasting pattern"); // we can speed up pasting sparse patterns by using nextcell in these cases: // - if using Or mode // - if current universe is empty // - if paste rect is outside current pattern edges bool usenextcell; if ( pmode == Or || curralgo->isEmpty() ) { usenextcell = true; } else { bigint ctop, cleft, cbottom, cright; curralgo->findedges(&ctop, &cleft, &cbottom, &cright); usenextcell = top > cbottom || bottom < ctop || left > cright || right < cleft; } if ( usenextcell && pmode == And ) { // current universe is empty or paste rect is outside current pattern edges // so don't change any cells } else if ( usenextcell ) { int newstate = 0; cy = pastey; for ( ty=itop; ty<=ibottom; ty++ ) { cx = pastex; for ( tx=ileft; tx<=iright; tx++ ) { int skip = pastealgo->nextcell(tx, ty, newstate); if (skip + tx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell so paste it into current universe tx += skip; cx += skip; if (cx >= gleft && cx <= gright && cy >= gtop && cy <= gbottom) { int currstate = curralgo->getcell(cx, cy); if (currstate != newstate) { if (newstate > maxstate) { newstate = maxstate; reduced = true; } curralgo->setcell(cx, cy, newstate); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, newstate); } } cx++; } else { tx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((ty - itop) * (double)(iright - ileft + 1) + (tx - ileft)) / maxcount; abort = AbortProgress(prog, ""); if (abort) break; } } if (abort) break; cy++; } } else { // have to use slower getcell/setcell calls int tempstate, currstate; int numstates = curralgo->NumCellStates(); cy = pastey; for ( ty=itop; ty<=ibottom; ty++ ) { cx = pastex; for ( tx=ileft; tx<=iright; tx++ ) { tempstate = pastealgo->getcell(tx, ty); currstate = curralgo->getcell(cx, cy); if (cx >= gleft && cx <= gright && cy >= gtop && cy <= gbottom) { switch (pmode) { case And: if (tempstate != currstate && currstate > 0) { curralgo->setcell(cx, cy, 0); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, 0); } break; case Copy: if (tempstate != currstate) { if (tempstate > maxstate) { tempstate = maxstate; reduced = true; } curralgo->setcell(cx, cy, tempstate); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, tempstate); } break; case Or: // Or mode is done using above nextcell loop; // we only include this case to avoid compiler warning break; case Xor: if (tempstate == currstate) { if (currstate != 0) { curralgo->setcell(cx, cy, 0); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, 0); } } else { // tempstate != currstate int newstate = tempstate ^ currstate; // if xor overflows then don't change current state if (newstate >= numstates) newstate = currstate; if (currstate != newstate) { curralgo->setcell(cx, cy, newstate); pattchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, currstate, newstate); } } break; } } cx++; cntr++; if ( (cntr % 4096) == 0 ) { abort = AbortProgress((double)cntr / maxcount, ""); if (abort) break; } } if (abort) break; cy++; } } if (pattchanged) curralgo->endofpattern(); EndProgress(); // tidy up and display result ClearMessage(); if (pattchanged) { if (savecells) currlayer->undoredo->RememberCellChanges("Paste", currlayer->dirty); MarkLayerDirty(); UpdatePatternAndStatus(); } if (reduced) ErrorMessage("Some cell states were reduced."); } // ----------------------------------------------------------------------------- void DoPaste(bool toselection) { bigint top, left; bigint wd = pastebox.width; bigint ht = pastebox.height; if (toselection) { // paste pattern into selection rectangle, if possible if (!SelectionExists()) { ErrorMessage("There is no selection."); return; } if (!currlayer->currsel.CanPaste(wd, ht, top, left)) { ErrorMessage("Clipboard pattern is bigger than selection."); return; } // top and left have been set to the selection's top left corner PasteTemporaryToCurrent(top, left, wd, ht); } else { // paste pattern into pasterect, if possible if ( // allow paste if any corner of pasterect is within grid !( PointInGrid(pastex, pastey) || PointInGrid(pastex+pasterect.width-1, pastey) || PointInGrid(pastex, pastey+pasterect.height-1) || PointInGrid(pastex+pasterect.width-1, pastey+pasterect.height-1) ) ) { ErrorMessage("Paste must be at least partially within grid."); return; } // get paste rectangle's top left cell coord pair cellpos = currlayer->view->at(pastex, pastey); top = cellpos.second; left = cellpos.first; PasteTemporaryToCurrent(top, left, wd, ht); } AbortPaste(); } // ----------------------------------------------------------------------------- void AbortPaste() { waitingforpaste = false; pastex = -1; pastey = -1; if (pastealgo) { delete pastealgo; pastealgo = NULL; } DestroyPasteImage(); } // ----------------------------------------------------------------------------- bool FlipPastePattern(bool topbottom) { bool result; Selection pastesel(pastebox.y, pastebox.x, pastebox.y + pastebox.height - 1, pastebox.x + pastebox.width - 1); // flip the pattern in pastealgo lifealgo* savealgo = currlayer->algo; int savetype = currlayer->algtype; currlayer->algo = pastealgo; currlayer->algtype = pastetype; // pass in true for inundoredo parameter so flip won't be remembered // and layer won't be marked as dirty; also set inscript temporarily // so that viewport won't be updated inscript = true; result = pastesel.Flip(topbottom, true); // currlayer->algo might point to a *different* universe pastealgo = currlayer->algo; currlayer->algo = savealgo; currlayer->algtype = savetype; inscript = false; if (result) { DestroyPasteImage(); CreatePasteImage(pastealgo, pastebox); } return result; } // ----------------------------------------------------------------------------- bool RotatePastePattern(bool clockwise) { bool result; Selection pastesel(pastebox.y, pastebox.x, pastebox.y + pastebox.height - 1, pastebox.x + pastebox.width - 1); // rotate the pattern in pastealgo lifealgo* savealgo = currlayer->algo; int savetype = currlayer->algtype; currlayer->algo = pastealgo; currlayer->algtype = pastetype; // pass in true for inundoredo parameter so rotate won't be remembered // and layer won't be marked as dirty; also set inscript temporarily // so that viewport won't be updated and selection size won't be displayed inscript = true; result = pastesel.Rotate(clockwise, true); // currlayer->algo might point to a *different* universe pastealgo = currlayer->algo; currlayer->algo = savealgo; currlayer->algtype = savetype; inscript = false; if (result) { // get rotated selection and update pastebox int x, y, wd, ht; pastesel.GetRect(&x, &y, &wd, &ht); SetRect(pastebox, x, y, wd, ht); DestroyPasteImage(); CreatePasteImage(pastealgo, pastebox); } return result; } // ----------------------------------------------------------------------------- void ZoomInPos(int x, int y) { // zoom in to given point if (currlayer->view->getmag() < MAX_MAG) { TestAutoFit(); currlayer->view->zoom(x, y); UpdateEverything(); } else { Beep(); // can't zoom in any further } } // ----------------------------------------------------------------------------- void ZoomOutPos(int x, int y) { // zoom out from given point TestAutoFit(); currlayer->view->unzoom(x, y); UpdateEverything(); } // ----------------------------------------------------------------------------- void PanUp(int amount) { TestAutoFit(); currlayer->view->move(0, -amount); UpdateEverything(); } // ----------------------------------------------------------------------------- void PanDown(int amount) { TestAutoFit(); currlayer->view->move(0, amount); UpdateEverything(); } // ----------------------------------------------------------------------------- void PanLeft(int amount) { TestAutoFit(); currlayer->view->move(-amount, 0); UpdateEverything(); } // ----------------------------------------------------------------------------- void PanRight(int amount) { TestAutoFit(); currlayer->view->move(amount, 0); UpdateEverything(); } // ----------------------------------------------------------------------------- void PanNE() { TestAutoFit(); int xamount = SmallScroll(currlayer->view->getwidth()); int yamount = SmallScroll(currlayer->view->getheight()); int amount = (xamount < yamount) ? xamount : yamount; currlayer->view->move(amount, -amount); UpdateEverything(); } // ----------------------------------------------------------------------------- void PanNW() { TestAutoFit(); int xamount = SmallScroll(currlayer->view->getwidth()); int yamount = SmallScroll(currlayer->view->getheight()); int amount = (xamount < yamount) ? xamount : yamount; currlayer->view->move(-amount, -amount); UpdateEverything(); } // ----------------------------------------------------------------------------- void PanSE() { TestAutoFit(); int xamount = SmallScroll(currlayer->view->getwidth()); int yamount = SmallScroll(currlayer->view->getheight()); int amount = (xamount < yamount) ? xamount : yamount; currlayer->view->move(amount, amount); UpdateEverything(); } // ----------------------------------------------------------------------------- void PanSW() { TestAutoFit(); int xamount = SmallScroll(currlayer->view->getwidth()); int yamount = SmallScroll(currlayer->view->getheight()); int amount = (xamount < yamount) ? xamount : yamount; currlayer->view->move(-amount, amount); UpdateEverything(); } // ----------------------------------------------------------------------------- int SmallScroll(int xysize) { int amount; int mag = currlayer->view->getmag(); if (mag > 0) { // scroll an integral number of cells (1 cell = 2^mag pixels) if (mag < 3) { amount = ((xysize >> mag) / 20) << mag; if (amount == 0) amount = 1 << mag; return amount; } else { // grid lines are visible so scroll by only 1 cell return 1 << mag; } } else { // scroll by approx 5% of current wd/ht amount = xysize / 20; if (amount == 0) amount = 1; return amount; } } // ----------------------------------------------------------------------------- int BigScroll(int xysize) { int amount; int mag = currlayer->view->getmag(); if (mag > 0) { // scroll an integral number of cells (1 cell = 2^mag pixels) amount = ((xysize >> mag) * 9 / 10) << mag; if (amount == 0) amount = 1 << mag; return amount; } else { // scroll by approx 90% of current wd/ht amount = xysize * 9 / 10; if (amount == 0) amount = 1; return amount; } } golly-2.7-src/gui-common/algos.cpp0000644000175000017500000010510412536111364014104 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "jvnalgo.h" #include "generationsalgo.h" #include "ruleloaderalgo.h" #include "utils.h" // for Fatal, Warning, SetColor, Poller #include "prefs.h" // for maxhashmem #include "layer.h" // for currlayer #include "algos.h" #include // for std::map // ----------------------------------------------------------------------------- // exported data: algo_type initalgo = QLIFE_ALGO; // initial algorithm AlgoData* algoinfo[MAX_ALGOS]; // static info for each algorithm gBitmapPtr* circles7x7; // circular icons for scale 1:8 gBitmapPtr* circles15x15; // circular icons for scale 1:16 gBitmapPtr* circles31x31; // circular icons for scale 1:32 gBitmapPtr* diamonds7x7; // diamond-shaped icons for scale 1:8 gBitmapPtr* diamonds15x15; // diamond-shaped icons for scale 1:16 gBitmapPtr* diamonds31x31; // diamond-shaped icons for scale 1:32 gBitmapPtr* hexagons7x7; // hexagonal icons for scale 1:8 gBitmapPtr* hexagons15x15; // hexagonal icons for scale 1:16 gBitmapPtr* hexagons31x31; // hexagonal icons for scale 1:32 gBitmapPtr* triangles7x7; // triangular icons for scale 1:8 gBitmapPtr* triangles15x15; // triangular icons for scale 1:16 gBitmapPtr* triangles31x31; // triangular icons for scale 1:32 // ----------------------------------------------------------------------------- // These default cell colors were generated by continuously finding the // color furthest in rgb space from the closest of the already selected // colors, black, and white. static unsigned char default_colors[] = { 48,48,48, // better if state 0 is dark gray (was 255,127,0) 0,255,127,127,0,255,148,148,148,128,255,0,255,0,128, 0,128,255,1,159,0,159,0,1,255,254,96,0,1,159,96,255,254, 254,96,255,126,125,21,21,126,125,125,21,126,255,116,116,116,255,116, 116,116,255,228,227,0,28,255,27,255,27,28,0,228,227,227,0,228, 27,28,255,59,59,59,234,195,176,175,196,255,171,194,68,194,68,171, 68,171,194,72,184,71,184,71,72,71,72,184,169,255,188,252,179,63, 63,252,179,179,63,252,80,9,0,0,80,9,9,0,80,255,175,250, 199,134,213,115,100,95,188,163,0,0,188,163,163,0,188,203,73,0, 0,203,73,73,0,203,94,189,0,189,0,94,0,94,189,187,243,119, 55,125,32,125,32,55,32,55,125,255,102,185,102,185,255,120,209,168, 208,166,119,135,96,192,182,255,41,83,153,130,247,88,55,89,247,55, 88,55,247,87,75,0,0,87,75,75,0,87,200,135,59,51,213,127, 255,255,162,255,37,182,37,182,255,228,57,117,142,163,210,57,117,228, 193,255,246,188,107,123,123,194,107,145,59,5,5,145,59,59,5,145, 119,39,198,40,197,23,197,23,40,23,40,197,178,199,158,255,201,121, 134,223,223,39,253,84,149,203,15,203,15,149,15,149,203,152,144,90, 143,75,139,71,97,132,224,65,219,65,219,224,255,255,40,218,223,69, 74,241,0,241,0,74,0,74,241,122,171,51,220,211,227,61,127,87, 90,124,176,36,39,13,165,142,255,255,38,255,38,255,255,83,50,107, 224,142,165,255,181,9,9,255,181,181,9,255,140,238,70,255,74,5, 74,5,255,138,84,51,31,172,101,177,115,17,221,0,0,0,221,0, 0,0,221,220,255,200,0,41,50,255,150,205,178,45,116,113,255,189, 47,0,44,40,119,171,205,107,255,177,115,172,133,73,236,109,0,168, 168,46,207,188,181,203,212,188,35,90,97,52,39,209,184,41,164,152, 227,46,70,46,70,227,211,156,255,98,146,222,136,56,95,102,54,152, 86,142,0,142,0,86,0,86,142,86,223,96,246,135,46,4,208,120, 212,233,158,177,92,214,104,147,88,149,240,147,227,93,148,72,255,133, 209,27,194,147,255,255,44,93,0,160,36,158,182,233,0,96,94,217, 218,103,88,163,154,38,118,114,139,94,0,43,113,164,174,168,188,114, 0,23,119,42,86,93,255,226,202,80,191,155,255,158,136,0,247,62, 234,146,88,0,183,229,110,212,36,0,143,161,105,191,210,133,164,0, 41,30,89,164,0,132,30,89,42,178,222,217,121,22,11,221,107,22, 69,151,255,45,158,3,158,3,45,3,45,158,86,42,29,9,122,22, 213,209,110,53,221,57,159,101,91,93,140,45,247,213,37,185,34,0, 0,185,34,34,0,185,236,0,172,210,180,78,231,107,221,162,49,43, 43,162,49,49,43,162,36,248,213,114,0,214,213,36,248,149,34,243, 185,158,167,144,122,224,34,245,149,255,31,98,31,98,255,152,200,193, 255,80,95,128,123,63,102,62,72,255,62,148,151,226,108,159,99,255, 226,255,126,98,223,136,80,95,255,225,153,15,73,41,211,212,71,41, 83,217,187,180,235,79,0,166,127,251,135,243,229,41,0,41,0,229, 82,255,216,141,174,249,249,215,255,167,31,79,31,79,167,213,102,185, 255,215,83,4,2,40,224,171,220,41,0,4,6,50,90,221,15,113, 15,113,221,33,0,115,108,23,90,182,215,36 }; // ----------------------------------------------------------------------------- // Note that all the default icons are grayscale bitmaps. // These icons are used for lots of different rules with different numbers // of states, and at rendering time we will replace the white pixels in each // icon with the cell's state color to avoid "color shock" when switching // between icon and non-icon view. Gray pixels are used to do anti-aliasing. // XPM data for default 7x7 icon static const char* default7x7[] = { // width height ncolors chars_per_pixel "7 7 4 1", // colors ". c #000000", // black will be transparent "D c #404040", "E c #E0E0E0", "W c #FFFFFF", // white // pixels ".DEWED.", "DWWWWWD", "EWWWWWE", "WWWWWWW", "EWWWWWE", "DWWWWWD", ".DEWED." }; // XPM data for default 15x15 icon static const char* default15x15[] = { // width height ncolors chars_per_pixel "15 15 5 1", // colors ". c #000000", // black will be transparent "D c #404040", "C c #808080", "B c #C0C0C0", "W c #FFFFFF", // white // pixels "...............", "....DBWWWBD....", "...BWWWWWWWB...", "..BWWWWWWWWWB..", ".DWWWWWWWWWWWD.", ".BWWWWWWWWWWWB.", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", ".WWWWWWWWWWWWW.", ".BWWWWWWWWWWWB.", ".DWWWWWWWWWWWD.", "..BWWWWWWWWWB..", "...BWWWWWWWB...", "....DBWWWBD....", "..............." }; // XPM data for default 31x31 icon static const char* default31x31[] = { // width height ncolors chars_per_pixel "31 31 5 1", // colors ". c #000000", // black will be transparent "D c #404040", "C c #808080", "B c #C0C0C0", "W c #FFFFFF", // white // pixels "...............................", "...............................", "..........DCBWWWWWBCD..........", ".........CWWWWWWWWWWWC.........", ".......DWWWWWWWWWWWWWWWD.......", "......BWWWWWWWWWWWWWWWWWB......", ".....BWWWWWWWWWWWWWWWWWWWB.....", "....DWWWWWWWWWWWWWWWWWWWWWD....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...CWWWWWWWWWWWWWWWWWWWWWWWC...", "..DWWWWWWWWWWWWWWWWWWWWWWWWWD..", "..CWWWWWWWWWWWWWWWWWWWWWWWWWC..", "..BWWWWWWWWWWWWWWWWWWWWWWWWWB..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "..BWWWWWWWWWWWWWWWWWWWWWWWWWB..", "..CWWWWWWWWWWWWWWWWWWWWWWWWWC..", "..DWWWWWWWWWWWWWWWWWWWWWWWWWD..", "...CWWWWWWWWWWWWWWWWWWWWWWWC...", "....WWWWWWWWWWWWWWWWWWWWWWW....", "....DWWWWWWWWWWWWWWWWWWWWWD....", ".....BWWWWWWWWWWWWWWWWWWWB.....", "......BWWWWWWWWWWWWWWWWWB......", ".......DWWWWWWWWWWWWWWWD.......", ".........CWWWWWWWWWWWC.........", "..........DCBWWWWWBCD..........", "...............................", "..............................." }; // XPM data for the 7x7 icon used for hexagonal CA static const char* hex7x7[] = { // width height ncolors chars_per_pixel "7 7 3 1", // colors ". c #000000", // black will be transparent "C c #808080", "W c #FFFFFF", // white // pixels ".WWC...", "WWWWW..", "WWWWWW.", "CWWWWWC", ".WWWWWW", "..WWWWW", "...CWW."}; // XPM data for the 15x15 icon used for hexagonal CA static const char* hex15x15[] = { // width height ncolors chars_per_pixel "15 15 3 1", // colors ". c #000000", // black will be transparent "C c #808080", "W c #FFFFFF", // white // pixels "...WWC.........", "..WWWWWC.......", ".WWWWWWWWC.....", "WWWWWWWWWWW....", "WWWWWWWWWWWW...", "CWWWWWWWWWWWC..", ".WWWWWWWWWWWW..", ".CWWWWWWWWWWWC.", "..WWWWWWWWWWWW.", "..CWWWWWWWWWWWC", "...WWWWWWWWWWWW", "....WWWWWWWWWWW", ".....CWWWWWWWW.", ".......CWWWWW..", ".........CWW..."}; // XPM data for 31x31 icon used for hexagonal CA static const char* hex31x31[] = { // width height ncolors chars_per_pixel "31 31 3 1", // colors ". c #000000", // black will be transparent "C c #808080", "W c #FFFFFF", // white // pixels ".....WWC.......................", "....WWWWWC.....................", "...WWWWWWWWC...................", "..WWWWWWWWWWWC.................", ".WWWWWWWWWWWWWWC...............", "WWWWWWWWWWWWWWWWWC.............", "WWWWWWWWWWWWWWWWWWWC...........", "CWWWWWWWWWWWWWWWWWWWWC.........", ".WWWWWWWWWWWWWWWWWWWWWW........", ".CWWWWWWWWWWWWWWWWWWWWWC.......", "..WWWWWWWWWWWWWWWWWWWWWW.......", "..CWWWWWWWWWWWWWWWWWWWWWC......", "...WWWWWWWWWWWWWWWWWWWWWW......", "...CWWWWWWWWWWWWWWWWWWWWWC.....", "....WWWWWWWWWWWWWWWWWWWWWW.....", "....CWWWWWWWWWWWWWWWWWWWWWC....", ".....WWWWWWWWWWWWWWWWWWWWWW....", ".....CWWWWWWWWWWWWWWWWWWWWWC...", "......WWWWWWWWWWWWWWWWWWWWWW...", "......CWWWWWWWWWWWWWWWWWWWWWC..", ".......WWWWWWWWWWWWWWWWWWWWWW..", ".......CWWWWWWWWWWWWWWWWWWWWWC.", "........WWWWWWWWWWWWWWWWWWWWWW.", ".........CWWWWWWWWWWWWWWWWWWWWC", "...........CWWWWWWWWWWWWWWWWWWW", ".............CWWWWWWWWWWWWWWWWW", "...............CWWWWWWWWWWWWWW.", ".................CWWWWWWWWWWW..", "...................CWWWWWWWW...", ".....................CWWWWW....", ".......................CWW....." }; // XPM data for the 7x7 icon used for von Neumann CA static const char* vn7x7[] = { // width height ncolors chars_per_pixel "7 7 2 1", // colors ". c #000000", // black will be transparent "W c #FFFFFF", // white // pixels "...W...", "..WWW..", ".WWWWW.", "WWWWWWW", ".WWWWW.", "..WWW..", "...W..." }; // XPM data for the 15x15 icon used for von Neumann CA static const char* vn15x15[] = { // width height ncolors chars_per_pixel "15 15 2 1", // colors ". c #000000", // black will be transparent "W c #FFFFFF", // white // pixels "...............", ".......W.......", "......WWW......", ".....WWWWW.....", "....WWWWWWW....", "...WWWWWWWWW...", "..WWWWWWWWWWW..", ".WWWWWWWWWWWWW.", "..WWWWWWWWWWW..", "...WWWWWWWWW...", "....WWWWWWW....", ".....WWWWW.....", "......WWW......", ".......W.......", "..............." }; // XPM data for 31x31 icon used for von Neumann CA static const char* vn31x31[] = { // width height ncolors chars_per_pixel "31 31 2 1", // colors ". c #000000", // black will be transparent "W c #FFFFFF", // white // pixels "...............................", "...............................", "...............W...............", "..............WWW..............", ".............WWWWW.............", "............WWWWWWW............", "...........WWWWWWWWW...........", "..........WWWWWWWWWWW..........", ".........WWWWWWWWWWWWW.........", "........WWWWWWWWWWWWWWW........", ".......WWWWWWWWWWWWWWWWW.......", "......WWWWWWWWWWWWWWWWWWW......", ".....WWWWWWWWWWWWWWWWWWWWW.....", "....WWWWWWWWWWWWWWWWWWWWWWW....", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "..WWWWWWWWWWWWWWWWWWWWWWWWWWW..", "...WWWWWWWWWWWWWWWWWWWWWWWWW...", "....WWWWWWWWWWWWWWWWWWWWWWW....", ".....WWWWWWWWWWWWWWWWWWWWW.....", "......WWWWWWWWWWWWWWWWWWW......", ".......WWWWWWWWWWWWWWWWW.......", "........WWWWWWWWWWWWWWW........", ".........WWWWWWWWWWWWW.........", "..........WWWWWWWWWWW..........", "...........WWWWWWWWW...........", "............WWWWWWW............", ".............WWWWW.............", "..............WWW..............", "...............W...............", "...............................", "..............................." }; // XPM data for the 7x7 icons used by 4-state rules emulating a triangular neighborhood static const char* tri7x7[] = { // width height ncolors chars_per_pixel "7 21 2 1", // colors ". c #000000", // black will be transparent "W c #FFFFFF", // white // pixels for state 1 ".......", "W......", "WW.....", "WWW....", "WWWW...", "WWWWW..", "WWWWWW.", // pixels for state 2 ".WWWWWW", "..WWWWW", "...WWWW", "....WWW", ".....WW", "......W", ".......", // pixels for state 3 ".WWWWWW", "W.WWWWW", "WW.WWWW", "WWW.WWW", "WWWW.WW", "WWWWW.W", "WWWWWW." }; // XPM data for the 15x15 icons used by 4-state rules emulating a triangular neighborhood static const char* tri15x15[] = { // width height ncolors chars_per_pixel "15 45 2 1", // colors ". c #000000", "W c #FFFFFF", // pixels for state 1 "...............", "W..............", "WW.............", "WWW............", "WWWW...........", "WWWWW..........", "WWWWWW.........", "WWWWWWW........", "WWWWWWWW.......", "WWWWWWWWW......", "WWWWWWWWWW.....", "WWWWWWWWWWW....", "WWWWWWWWWWWW...", "WWWWWWWWWWWWW..", "WWWWWWWWWWWWWW.", // pixels for state 2 ".WWWWWWWWWWWWWW", "..WWWWWWWWWWWWW", "...WWWWWWWWWWWW", "....WWWWWWWWWWW", ".....WWWWWWWWWW", "......WWWWWWWWW", ".......WWWWWWWW", "........WWWWWWW", ".........WWWWWW", "..........WWWWW", "...........WWWW", "............WWW", ".............WW", "..............W", "...............", // pixels for state 3 ".WWWWWWWWWWWWWW", "W.WWWWWWWWWWWWW", "WW.WWWWWWWWWWWW", "WWW.WWWWWWWWWWW", "WWWW.WWWWWWWWWW", "WWWWW.WWWWWWWWW", "WWWWWW.WWWWWWWW", "WWWWWWW.WWWWWWW", "WWWWWWWW.WWWWWW", "WWWWWWWWW.WWWWW", "WWWWWWWWWW.WWWW", "WWWWWWWWWWW.WWW", "WWWWWWWWWWWW.WW", "WWWWWWWWWWWWW.W", "WWWWWWWWWWWWWW." }; // XPM data for the 31x31 icons used by 4-state rules emulating a triangular neighborhood static const char* tri31x31[] = { // width height ncolors chars_per_pixel "31 93 2 1", // colors ". c #000000", "W c #FFFFFF", // pixels for state 1 "...............................", "W..............................", "WW.............................", "WWW............................", "WWWW...........................", "WWWWW..........................", "WWWWWW.........................", "WWWWWWW........................", "WWWWWWWW.......................", "WWWWWWWWW......................", "WWWWWWWWWW.....................", "WWWWWWWWWWW....................", "WWWWWWWWWWWW...................", "WWWWWWWWWWWWW..................", "WWWWWWWWWWWWWW.................", "WWWWWWWWWWWWWWW................", "WWWWWWWWWWWWWWWW...............", "WWWWWWWWWWWWWWWWW..............", "WWWWWWWWWWWWWWWWWW.............", "WWWWWWWWWWWWWWWWWWW............", "WWWWWWWWWWWWWWWWWWWW...........", "WWWWWWWWWWWWWWWWWWWWW..........", "WWWWWWWWWWWWWWWWWWWWWW.........", "WWWWWWWWWWWWWWWWWWWWWWW........", "WWWWWWWWWWWWWWWWWWWWWWWW.......", "WWWWWWWWWWWWWWWWWWWWWWWWW......", "WWWWWWWWWWWWWWWWWWWWWWWWWW.....", "WWWWWWWWWWWWWWWWWWWWWWWWWWW....", "WWWWWWWWWWWWWWWWWWWWWWWWWWWW...", "WWWWWWWWWWWWWWWWWWWWWWWWWWWWW..", "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW.", // pixels for state 2 ".WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "..WWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "...WWWWWWWWWWWWWWWWWWWWWWWWWWWW", "....WWWWWWWWWWWWWWWWWWWWWWWWWWW", ".....WWWWWWWWWWWWWWWWWWWWWWWWWW", "......WWWWWWWWWWWWWWWWWWWWWWWWW", ".......WWWWWWWWWWWWWWWWWWWWWWWW", "........WWWWWWWWWWWWWWWWWWWWWWW", ".........WWWWWWWWWWWWWWWWWWWWWW", "..........WWWWWWWWWWWWWWWWWWWWW", "...........WWWWWWWWWWWWWWWWWWWW", "............WWWWWWWWWWWWWWWWWWW", ".............WWWWWWWWWWWWWWWWWW", "..............WWWWWWWWWWWWWWWWW", "...............WWWWWWWWWWWWWWWW", "................WWWWWWWWWWWWWWW", ".................WWWWWWWWWWWWWW", "..................WWWWWWWWWWWWW", "...................WWWWWWWWWWWW", "....................WWWWWWWWWWW", ".....................WWWWWWWWWW", "......................WWWWWWWWW", ".......................WWWWWWWW", "........................WWWWWWW", ".........................WWWWWW", "..........................WWWWW", "...........................WWWW", "............................WWW", ".............................WW", "..............................W", "...............................", // pixels for state 3 ".WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "W.WWWWWWWWWWWWWWWWWWWWWWWWWWWWW", "WW.WWWWWWWWWWWWWWWWWWWWWWWWWWWW", "WWW.WWWWWWWWWWWWWWWWWWWWWWWWWWW", "WWWW.WWWWWWWWWWWWWWWWWWWWWWWWWW", "WWWWW.WWWWWWWWWWWWWWWWWWWWWWWWW", "WWWWWW.WWWWWWWWWWWWWWWWWWWWWWWW", "WWWWWWW.WWWWWWWWWWWWWWWWWWWWWWW", "WWWWWWWW.WWWWWWWWWWWWWWWWWWWWWW", "WWWWWWWWW.WWWWWWWWWWWWWWWWWWWWW", "WWWWWWWWWW.WWWWWWWWWWWWWWWWWWWW", "WWWWWWWWWWW.WWWWWWWWWWWWWWWWWWW", "WWWWWWWWWWWW.WWWWWWWWWWWWWWWWWW", "WWWWWWWWWWWWW.WWWWWWWWWWWWWWWWW", "WWWWWWWWWWWWWW.WWWWWWWWWWWWWWWW", "WWWWWWWWWWWWWWW.WWWWWWWWWWWWWWW", "WWWWWWWWWWWWWWWW.WWWWWWWWWWWWWW", "WWWWWWWWWWWWWWWWW.WWWWWWWWWWWWW", "WWWWWWWWWWWWWWWWWW.WWWWWWWWWWWW", "WWWWWWWWWWWWWWWWWWW.WWWWWWWWWWW", "WWWWWWWWWWWWWWWWWWWW.WWWWWWWWWW", "WWWWWWWWWWWWWWWWWWWWW.WWWWWWWWW", "WWWWWWWWWWWWWWWWWWWWWW.WWWWWWWW", "WWWWWWWWWWWWWWWWWWWWWWW.WWWWWWW", "WWWWWWWWWWWWWWWWWWWWWWWW.WWWWWW", "WWWWWWWWWWWWWWWWWWWWWWWWW.WWWWW", "WWWWWWWWWWWWWWWWWWWWWWWWWW.WWWW", "WWWWWWWWWWWWWWWWWWWWWWWWWWW.WWW", "WWWWWWWWWWWWWWWWWWWWWWWWWWWW.WW", "WWWWWWWWWWWWWWWWWWWWWWWWWWWWW.W", "WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW." }; // ----------------------------------------------------------------------------- gBitmapPtr* CreateIconBitmaps(const char** xpmdata, int maxstates) { if (xpmdata == NULL) return NULL; int wd, ht, numcolors, charsperpixel; sscanf(xpmdata[0], "%d %d %d %d", &wd, &ht, &numcolors, &charsperpixel); if (charsperpixel < 1 || charsperpixel > 2) { Warning("Error in XPM header data: chars_per_pixel must be 1 or 2"); return NULL; }; std::map colormap; std::map::iterator iterator; for (int i = 0; i < numcolors; i++) { std::string pixel; char ch1, ch2; int skip; if (charsperpixel == 1) { sscanf(xpmdata[i+1], "%c ", &ch1); pixel += ch1; skip = 2; } else { sscanf(xpmdata[i+1], "%c%c ", &ch1, &ch2); pixel += ch1; pixel += ch2; skip = 3; } if (strlen(xpmdata[i+1]) == (size_t)(skip+9)) { int rgb; sscanf(xpmdata[i+1]+skip, "c #%6x", &rgb); colormap[pixel] = rgb; } else { int r, g, b; sscanf(xpmdata[i+1]+skip, "c #%4x%4x%4x", &r, &g, &b); // only use top 8 bits of r,g,b colormap[pixel] = ((r>>8) << 16) | ((g>>8) << 8) | (b>>8); } } // allocate and clear memory for all icon bitmaps // (using calloc means black pixels will be transparent) unsigned char* rgba = (unsigned char*) calloc(wd * ht * 4, 1); if (rgba == NULL) return NULL; int pos = 0; for (int i = 0; i < ht; i++) { const char* rowstring = xpmdata[i+1+numcolors]; for (int j = 0; j < wd * charsperpixel; j = j + charsperpixel) { std::string pixel; pixel += rowstring[j]; if (charsperpixel == 2) pixel += rowstring[j+1]; // find the RGB color for this pixel iterator = colormap.find(pixel); int rgb = (iterator == colormap.end()) ? 0 : iterator->second; if (rgb == 0) { // pixel is black and alpha is 0 pos += 4; } else { rgba[pos] = (rgb & 0xFF0000) >> 16; pos++; // red rgba[pos] = (rgb & 0x00FF00) >> 8; pos++; // green rgba[pos] = (rgb & 0x0000FF); pos++; // blue rgba[pos] = 255; pos++; // alpha } } } int numicons = ht / wd; if (numicons > 255) numicons = 255; // play safe gBitmapPtr* iconptr = (gBitmapPtr*) malloc(256 * sizeof(gBitmapPtr)); if (iconptr) { for (int i = 0; i < 256; i++) iconptr[i] = NULL; unsigned char* nexticon = rgba; int iconbytes = wd * wd * 4; for (int i = 0; i < numicons; i++) { gBitmapPtr icon = (gBitmapPtr) malloc(sizeof(gBitmap)); if (icon) { icon->wd = wd; icon->ht = wd; icon->pxldata = (unsigned char*) malloc(iconbytes); if (icon->pxldata) { memcpy(icon->pxldata, nexticon, iconbytes); } } // add 1 to skip iconptr[0] (ie. dead state) iconptr[i+1] = icon; nexticon += iconbytes; } if (numicons < maxstates-1 && iconptr[numicons]) { // duplicate last icon nexticon -= iconbytes; for (int i = numicons; i < maxstates-1; i++) { gBitmapPtr icon = (gBitmapPtr) malloc(sizeof(gBitmap)); if (icon) { icon->wd = wd; icon->ht = wd; icon->pxldata = (unsigned char*) malloc(iconbytes); if (icon->pxldata) { memcpy(icon->pxldata, nexticon, iconbytes); } } iconptr[i+1] = icon; } } } free(rgba); return iconptr; } // ----------------------------------------------------------------------------- static gBitmapPtr CreateSmallerIcon(unsigned char* indata, int insize, int outsize) { gBitmapPtr icon = (gBitmapPtr) malloc(sizeof(gBitmap)); if (icon) { icon->wd = outsize; icon->ht = outsize; icon->pxldata = (unsigned char*) malloc(outsize * outsize * 4); if (icon->pxldata) { // use same algorithm as in create_smaller_icons in icon-importer.py int sample = insize / outsize; int offset = sample / 2; int outpos = 0; for (int row = 0; row < outsize; row++) { for (int col = 0; col < outsize; col++) { int x = offset + col * sample; int y = offset + row * sample; int inpos = (y * insize * 4) + (x * 4); icon->pxldata[outpos++] = indata[inpos++]; icon->pxldata[outpos++] = indata[inpos++]; icon->pxldata[outpos++] = indata[inpos++]; icon->pxldata[outpos++] = indata[inpos++]; } } } } return icon; } // ----------------------------------------------------------------------------- #define SETPIXEL(x, y) \ outpos = (y) * outsize * 4 + (x) * 4; \ icon->pxldata[outpos++] = r; \ icon->pxldata[outpos++] = g; \ icon->pxldata[outpos++] = b; \ icon->pxldata[outpos++] = a; static gBitmapPtr CreateBiggerIcon(unsigned char* indata, int insize, int outsize) { if (insize != 15 || outsize != 31) { // we currently don't support scaling up 7x7 icons as it's highly unlikely // that a .rule file won't have 15x15 icons return NULL; } gBitmapPtr icon = (gBitmapPtr) malloc(sizeof(gBitmap)); if (icon) { icon->wd = outsize; icon->ht = outsize; icon->pxldata = (unsigned char*) calloc(outsize * outsize * 4, 1); if (icon->pxldata) { // use same algorithm as in create31x31icons in icon-importer.py // to scale up a 15x15 bitmap into a 31x31 bitmap using a simple // method that conserves any vertical or horizontal symmetry int inpos = 0; for (int row = 0; row < insize; row++) { for (int col = 0; col < insize; col++) { unsigned char r = indata[inpos++]; unsigned char g = indata[inpos++]; unsigned char b = indata[inpos++]; unsigned char a = indata[inpos++]; if (r || g || b) { // non-black pixel int outpos; if (row == 7 && col == 7) { // expand middle pixel into 9 pixels int x = 15; int y = 15; SETPIXEL(x, y); SETPIXEL(x, y+1); SETPIXEL(x, y-1); SETPIXEL(x+1, y); SETPIXEL(x-1, y); SETPIXEL(x+1, y+1); SETPIXEL(x+1, y-1); SETPIXEL(x-1, y+1); SETPIXEL(x-1, y-1); } else if (row == 7) { // expand pixel in middle row into 6 pixels int x = col * 2; int y = row * 2; if (col > 7) x++; SETPIXEL(x, y); SETPIXEL(x, y+1); SETPIXEL(x+1, y); SETPIXEL(x+1, y+1); SETPIXEL(x, y+2); SETPIXEL(x+1, y+2); } else if (col == 7) { // expand pixel in middle column into 6 pixels int x = col * 2; int y = row * 2; if (row > 7) y++; SETPIXEL(x, y); SETPIXEL(x, y+1); SETPIXEL(x+1, y); SETPIXEL(x+1, y+1); SETPIXEL(x+2, y); SETPIXEL(x+2, y+1); } else { // expand all other pixels into 4 pixels int x = col * 2; int y = row * 2; if (col > 7) x++; if (row > 7) y++; SETPIXEL(x, y); SETPIXEL(x, y+1); SETPIXEL(x+1, y); SETPIXEL(x+1, y+1); } } } } } } return icon; } // ----------------------------------------------------------------------------- gBitmapPtr* ScaleIconBitmaps(gBitmapPtr* srcicons, int size) { if (srcicons == NULL) return NULL; gBitmapPtr* iconptr = (gBitmapPtr*) malloc(256 * sizeof(gBitmapPtr)); if (iconptr) { for (int i = 0; i < 256; i++) { if (srcicons[i] == NULL) { iconptr[i] = NULL; } else { int insize = srcicons[i]->wd; if (insize > size) { iconptr[i] = CreateSmallerIcon(srcicons[i]->pxldata, insize, size); } else { // assume insize < size iconptr[i] = CreateBiggerIcon(srcicons[i]->pxldata, insize, size); } } } } return iconptr; } // ----------------------------------------------------------------------------- static void CreateDefaultIcons(AlgoData* ad) { if (ad->defxpm7x7 || ad->defxpm15x15 || ad->defxpm31x31) { // create icons using given algo's default XPM data ad->icons7x7 = CreateIconBitmaps(ad->defxpm7x7, ad->maxstates); ad->icons15x15 = CreateIconBitmaps(ad->defxpm15x15, ad->maxstates); ad->icons31x31 = CreateIconBitmaps(ad->defxpm31x31, ad->maxstates); // create scaled bitmaps if size(s) not supplied if (!ad->icons7x7) { if (ad->icons15x15) // scale down 15x15 bitmaps ad->icons7x7 = ScaleIconBitmaps(ad->icons15x15, 7); else // scale down 31x31 bitmaps ad->icons7x7 = ScaleIconBitmaps(ad->icons31x31, 7); } if (!ad->icons15x15) { if (ad->icons31x31) // scale down 31x31 bitmaps ad->icons15x15 = ScaleIconBitmaps(ad->icons31x31, 15); else // scale up 7x7 bitmaps ad->icons15x15 = ScaleIconBitmaps(ad->icons7x7, 15); } if (!ad->icons31x31) { if (ad->icons15x15) // scale up 15x15 bitmaps ad->icons31x31 = ScaleIconBitmaps(ad->icons15x15, 31); else // scale up 7x7 bitmaps ad->icons31x31 = ScaleIconBitmaps(ad->icons7x7, 31); } } else { // algo didn't supply any icons so use static XPM data defined above ad->icons7x7 = CreateIconBitmaps(default7x7, ad->maxstates); ad->icons15x15 = CreateIconBitmaps(default15x15, ad->maxstates); ad->icons31x31 = CreateIconBitmaps(default31x31, ad->maxstates); } } // ----------------------------------------------------------------------------- AlgoData::AlgoData() { defbase = 0; icons7x7 = NULL; icons15x15 = NULL; icons31x31 = NULL; } // ----------------------------------------------------------------------------- AlgoData& AlgoData::tick() { AlgoData* r = new AlgoData(); algoinfo[r->id] = r; return *r; } // ----------------------------------------------------------------------------- void InitAlgorithms() { // qlife must be 1st and hlife must be 2nd qlifealgo::doInitializeAlgoInfo(AlgoData::tick()); hlifealgo::doInitializeAlgoInfo(AlgoData::tick()); // nicer if the rest are in alphabetical order generationsalgo::doInitializeAlgoInfo(AlgoData::tick()); jvnalgo::doInitializeAlgoInfo(AlgoData::tick()); ruleloaderalgo::doInitializeAlgoInfo(AlgoData::tick()); // init algoinfo array for (int i = 0; i < NumAlgos(); i++) { AlgoData* ad = algoinfo[i]; if (ad->algoName == 0 || ad->creator == 0) Fatal("Algorithm did not set name and/or creator"); // does algo use hashing? ad->canhash = ad->defbase == 8; // safer method needed??? // set status bar background by cycling thru a few pale colors switch (i % 9) { case 0: SetColor(ad->statusrgb, 255, 255, 206); break; // pale yellow case 1: SetColor(ad->statusrgb, 226, 250, 248); break; // pale blue case 2: SetColor(ad->statusrgb, 255, 233, 233); break; // pale pink case 3: SetColor(ad->statusrgb, 225, 255, 225); break; // pale green case 4: SetColor(ad->statusrgb, 243, 225, 255); break; // pale purple case 5: SetColor(ad->statusrgb, 255, 220, 180); break; // pale orange case 6: SetColor(ad->statusrgb, 200, 255, 255); break; // pale aqua case 7: SetColor(ad->statusrgb, 200, 200, 200); break; // pale gray case 8: SetColor(ad->statusrgb, 255, 255, 255); break; // white } // initialize default color scheme if (ad->defr[0] == ad->defr[1] && ad->defg[0] == ad->defg[1] && ad->defb[0] == ad->defb[1]) { // colors are nonsensical, probably unset, so use above defaults unsigned char* rgbptr = default_colors; for (int c = 0; c < ad->maxstates; c++) { ad->defr[c] = *rgbptr++; ad->defg[c] = *rgbptr++; ad->defb[c] = *rgbptr++; } } ad->gradient = ad->defgradient; SetColor(ad->fromrgb, ad->defr1, ad->defg1, ad->defb1); SetColor(ad->torgb, ad->defr2, ad->defg2, ad->defb2); for (int c = 0; c < ad->maxstates; c++) { ad->algor[c] = ad->defr[c]; ad->algog[c] = ad->defg[c]; ad->algob[c] = ad->defb[c]; } CreateDefaultIcons(ad); } circles7x7 = CreateIconBitmaps(default7x7,256); circles15x15 = CreateIconBitmaps(default15x15,256); circles31x31 = CreateIconBitmaps(default31x31,256); diamonds7x7 = CreateIconBitmaps(vn7x7,256); diamonds15x15 = CreateIconBitmaps(vn15x15,256); diamonds31x31 = CreateIconBitmaps(vn31x31,256); hexagons7x7 = CreateIconBitmaps(hex7x7,256); hexagons15x15 = CreateIconBitmaps(hex15x15,256); hexagons31x31 = CreateIconBitmaps(hex31x31,256); // these icons can only be used with 4-state rules triangles7x7 = CreateIconBitmaps(tri7x7,4); triangles15x15 = CreateIconBitmaps(tri15x15,4); triangles31x31 = CreateIconBitmaps(tri31x31,4); } // ----------------------------------------------------------------------------- void FreeIconBitmaps(gBitmapPtr* icons) { if (icons) { for (int i = 0; i < 256; i++) { if (icons[i]) { if (icons[i]->pxldata) free(icons[i]->pxldata); free(icons[i]); } } free(icons); } } // ----------------------------------------------------------------------------- void DeleteAlgorithms() { for (int i = 0; i < NumAlgos(); i++) { delete algoinfo[i]; } FreeIconBitmaps(circles7x7); FreeIconBitmaps(circles15x15); FreeIconBitmaps(circles31x31); FreeIconBitmaps(diamonds7x7); FreeIconBitmaps(diamonds15x15); FreeIconBitmaps(diamonds31x31); FreeIconBitmaps(hexagons7x7); FreeIconBitmaps(hexagons15x15); FreeIconBitmaps(hexagons31x31); FreeIconBitmaps(triangles7x7); FreeIconBitmaps(triangles15x15); FreeIconBitmaps(triangles31x31); } // ----------------------------------------------------------------------------- lifealgo* CreateNewUniverse(algo_type algotype, bool allowcheck) { lifealgo* newalgo = algoinfo[algotype]->creator(); if (newalgo == NULL) Fatal("Failed to create new universe!"); if (algoinfo[algotype]->canhash) { newalgo->setMaxMemory(maxhashmem); } // non-hashing algos (QuickLife) use their default memory setting if (allowcheck) newalgo->setpoll(Poller()); return newalgo; } // ----------------------------------------------------------------------------- const char* GetAlgoName(algo_type algotype) { return algoinfo[algotype]->algoName; } // ----------------------------------------------------------------------------- int NumAlgos() { return staticAlgoInfo::getNumAlgos(); } // ----------------------------------------------------------------------------- bool MultiColorImage(gBitmapPtr image) { // return true if image contains at least one color that isn't a shade of gray if (image == NULL) return false; unsigned char* pxldata = image->pxldata; if (pxldata == NULL) return false; // play safe int numpixels = image->wd * image->ht; int byte = 0; for (int i = 0; i < numpixels; i++) { unsigned char r = pxldata[byte]; unsigned char g = pxldata[byte+1]; unsigned char b = pxldata[byte+2]; if (r != g || g != b) return true; // multi-color byte += 4; } return false; // grayscale } golly-2.7-src/gui-common/MiniZip/0000755000175000017500000000000012536111364013731 500000000000000golly-2.7-src/gui-common/MiniZip/ioapi.c0000644000175000017500000000665512536111364015132 00000000000000/* ioapi.c -- IO base function header for compress/uncompress .zip files using zlib + zip or unzip API Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant */ #include #include #include #include "zlib.h" #include "ioapi.h" /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif voidpf ZCALLBACK fopen_file_func OF(( voidpf opaque, const char* filename, int mode)); uLong ZCALLBACK fread_file_func OF(( voidpf opaque, voidpf stream, void* buf, uLong size)); uLong ZCALLBACK fwrite_file_func OF(( voidpf opaque, voidpf stream, const void* buf, uLong size)); long ZCALLBACK ftell_file_func OF(( voidpf opaque, voidpf stream)); long ZCALLBACK fseek_file_func OF(( voidpf opaque, voidpf stream, uLong offset, int origin)); int ZCALLBACK fclose_file_func OF(( voidpf opaque, voidpf stream)); int ZCALLBACK ferror_file_func OF(( voidpf opaque, voidpf stream)); voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) { FILE* file = NULL; const char* mode_fopen = NULL; if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) mode_fopen = "rb"; else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) mode_fopen = "r+b"; else if (mode & ZLIB_FILEFUNC_MODE_CREATE) mode_fopen = "wb"; if ((filename!=NULL) && (mode_fopen != NULL)) file = fopen(filename, mode_fopen); return file; } uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) { uLong ret; ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); return ret; } uLong ZCALLBACK fwrite_file_func ( voidpf opaque, voidpf stream, const void* buf, uLong size) { uLong ret; ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); return ret; } long ZCALLBACK ftell_file_func ( voidpf opaque, voidpf stream) { long ret; ret = ftell((FILE *)stream); return ret; } long ZCALLBACK fseek_file_func ( voidpf opaque, voidpf stream, uLong offset, int origin) { int fseek_origin=0; long ret; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR : fseek_origin = SEEK_CUR; break; case ZLIB_FILEFUNC_SEEK_END : fseek_origin = SEEK_END; break; case ZLIB_FILEFUNC_SEEK_SET : fseek_origin = SEEK_SET; break; default: return -1; } ret = 0; fseek((FILE *)stream, offset, fseek_origin); return ret; } int ZCALLBACK fclose_file_func ( voidpf opaque, voidpf stream) { int ret; ret = fclose((FILE *)stream); return ret; } int ZCALLBACK ferror_file_func ( voidpf opaque, voidpf stream) { int ret; ret = ferror((FILE *)stream); return ret; } void fill_fopen_filefunc ( zlib_filefunc_def* pzlib_filefunc_def) { pzlib_filefunc_def->zopen_file = fopen_file_func; pzlib_filefunc_def->zread_file = fread_file_func; pzlib_filefunc_def->zwrite_file = fwrite_file_func; pzlib_filefunc_def->ztell_file = ftell_file_func; pzlib_filefunc_def->zseek_file = fseek_file_func; pzlib_filefunc_def->zclose_file = fclose_file_func; pzlib_filefunc_def->zerror_file = ferror_file_func; pzlib_filefunc_def->opaque = NULL; } golly-2.7-src/gui-common/MiniZip/unzip.c0000644000175000017500000013564112536111364015174 00000000000000/* unzip.c -- IO for uncompress .zip files using zlib Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant Read unzip.h for more info */ /* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of compatibility with older software. The following is from the original crypt.c. Code woven in by Terry Thorsen 1/2003. */ /* Copyright (c) 1990-2000 Info-ZIP. All rights reserved. See the accompanying file LICENSE, version 2000-Apr-09 or later (the contents of which are also included in zip.h) for terms of use. If, for some reason, all these files are missing, the Info-ZIP license also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html */ /* crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) */ /* This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). */ #include #include #include #include "zlib.h" #include "unzip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef CASESENSITIVITYDEFAULT_NO # if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) # define CASESENSITIVITYDEFAULT_NO # endif #endif #ifndef UNZ_BUFSIZE #define UNZ_BUFSIZE (16384) #endif #ifndef UNZ_MAXFILENAMEINZIP #define UNZ_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) const char unz_copyright[] = " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; /* unz_file_info_interntal contain internal info about a file in zipfile*/ typedef struct unz_file_info_internal_s { uLong offset_curfile;/* relative offset of local header 4 bytes */ } unz_file_info_internal; /* file_in_zip_read_info_s contain internal information about a file in zipfile, when reading and decompress it */ typedef struct { char *read_buffer; /* internal buffer for compressed data */ z_stream stream; /* zLib stream structure for inflate */ uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ uLong stream_initialised; /* flag set if stream structure is initialised*/ uLong offset_local_extrafield;/* offset of the local extra field */ uInt size_local_extrafield;/* size of the local extra field */ uLong pos_local_extrafield; /* position in the local extra field in read*/ uLong crc32; /* crc32 of all data uncompressed */ uLong crc32_wait; /* crc32 we must obtain after decompress all */ uLong rest_read_compressed; /* number of byte to be decompressed */ uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ zlib_filefunc_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ uLong compression_method; /* compression method (0==store) */ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ int raw; } file_in_zip_read_info_s; /* unz_s contain internal information about the zipfile */ typedef struct { zlib_filefunc_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ unz_global_info gi; /* public global information */ uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ uLong num_file; /* number of the current file in the zipfile*/ uLong pos_in_central_dir; /* pos of the current file in the central dir*/ uLong current_file_ok; /* flag about the usability of the current file*/ uLong central_pos; /* position of the beginning of the central dir*/ uLong size_central_dir; /* size of the central directory */ uLong offset_central_dir; /* offset of start of central directory with respect to the starting disk number */ unz_file_info cur_file_info; /* public info about the current file in zip*/ unz_file_info_internal cur_file_info_internal; /* private info about it*/ file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current file if we are decompressing it */ int encrypted; # ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const unsigned long* pcrc_32_tab; # endif } unz_s; #ifndef NOUNCRYPT #include "crypt.h" #endif /* =========================================================================== Read a byte from a gz_stream; update next_in and avail_in. Return EOF for end of file. IN assertion: the stream s has been sucessfully opened for reading. */ local int unzlocal_getByte OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int unzlocal_getByte( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, int *pi) { unsigned char c; int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return UNZ_OK; } else { if (ZERROR(*pzlib_filefunc_def,filestream)) return UNZ_ERRNO; else return UNZ_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int unzlocal_getShort OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unzlocal_getShort ( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i; int err; err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } local int unzlocal_getLong OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int unzlocal_getLong ( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i; int err; err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<16; if (err==UNZ_OK) err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==UNZ_OK) *pX = x; else *pX = 0; return err; } /* My own strcmpi / strcasecmp */ local int strcmpcasenosensitive_internal ( const char* fileName1, const char* fileName2) { for (;;) { char c1=*(fileName1++); char c2=*(fileName2++); if ((c1>='a') && (c1<='z')) c1 -= 0x20; if ((c2>='a') && (c2<='z')) c2 -= 0x20; if (c1=='\0') return ((c2=='\0') ? 0 : -1); if (c2=='\0') return 1; if (c1c2) return 1; } } #ifdef CASESENSITIVITYDEFAULT_NO #define CASESENSITIVITYDEFAULTVALUE 2 #else #define CASESENSITIVITYDEFAULTVALUE 1 #endif #ifndef STRCMPCASENOSENTIVEFUNCTION #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal #endif /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern int ZEXPORT unzStringFileNameCompare ( const char* fileName1, const char* fileName2, int iCaseSensitivity) { if (iCaseSensitivity==0) iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; if (iCaseSensitivity==1) return strcmp(fileName1,fileName2); return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local uLong unzlocal_SearchCentralDir OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream)); local uLong unzlocal_SearchCentralDir( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; uLong uSizeFile; uLong uBackRead; uLong uMaxBack=0xffff; /* maximum size of global comment */ uLong uPosFound=0; if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } /* Open a Zip file. path contain the full pathname (by example, on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer "zlib/zlib114.zip". If the zipfile cannot be opened (file doesn't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ extern unzFile ZEXPORT unzOpen2 ( const char *path, zlib_filefunc_def* pzlib_filefunc_def) { unz_s us; unz_s *s; uLong central_pos,uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ uLong number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ int err=UNZ_OK; if (unz_copyright[0]!=' ') return NULL; if (pzlib_filefunc_def==NULL) fill_fopen_filefunc(&us.z_filefunc); else us.z_filefunc = *pzlib_filefunc_def; us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, path, ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_EXISTING); if (us.filestream==NULL) return NULL; central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); if (central_pos==0) err=UNZ_ERRNO; if (ZSEEK(us.z_filefunc, us.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* the signature, already checked */ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) err=UNZ_ERRNO; /* number of this disk */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) err=UNZ_ERRNO; /* number of the disk with the start of the central directory */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir on this disk */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) err=UNZ_ERRNO; /* total number of entries in the central dir */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) err=UNZ_ERRNO; if ((number_entry_CD!=us.gi.number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=UNZ_BADZIPFILE; /* size of the central directory */ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) err=UNZ_ERRNO; /* zipfile comment length */ if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) err=UNZ_ERRNO; if ((central_pospfile_in_zip_read!=NULL) unzCloseCurrentFile(file); ZCLOSE(s->z_filefunc, s->filestream); TRYFREE(s); return UNZ_OK; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo ( unzFile file, unz_global_info *pglobal_info) { unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; *pglobal_info=s->gi; return UNZ_OK; } /* Translate date/time from Dos format to tm_unz (readable more easilty) */ local void unzlocal_DosDateToTmuDate ( uLong ulDosDate, tm_unz* ptm) { uLong uDate; uDate = (uLong)(ulDosDate>>16); ptm->tm_mday = (uInt)(uDate&0x1f) ; ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; } /* Get Info about the current file in the zipfile, with internal only info */ local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); local int unzlocal_GetCurrentFileInfoInternal ( unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { unz_s* s; unz_file_info file_info; unz_file_info_internal file_info_internal; int err=UNZ_OK; uLong uMagic; long lSeek=0; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (ZSEEK(s->z_filefunc, s->filestream, s->pos_in_central_dir+s->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) err=UNZ_ERRNO; /* we check the magic */ if (err==UNZ_OK) { if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x02014b50) err=UNZ_BADZIPFILE; } if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) err=UNZ_ERRNO; unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) err=UNZ_ERRNO; lSeek+=file_info.size_filename; if ((err==UNZ_OK) && (szFileName!=NULL)) { uLong uSizeRead ; if (file_info.size_filename0) && (fileNameBufferSize>0)) if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek -= uSizeRead; } if ((err==UNZ_OK) && (extraField!=NULL)) { uLong uSizeRead ; if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek += file_info.size_file_extra - uSizeRead; } else lSeek+=file_info.size_file_extra; if ((err==UNZ_OK) && (szComment!=NULL)) { uLong uSizeRead ; if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) lSeek=0; else err=UNZ_ERRNO; } if ((file_info.size_file_comment>0) && (commentBufferSize>0)) if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) err=UNZ_ERRNO; lSeek+=file_info.size_file_comment - uSizeRead; } else lSeek+=file_info.size_file_comment; if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) *pfile_info_internal=file_info_internal; return err; } /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize) { return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, szFileName,fileNameBufferSize, extraField,extraFieldBufferSize, szComment,commentBufferSize); } /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToFirstFile (unzFile file) { int err=UNZ_OK; unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; s->pos_in_central_dir=s->offset_central_dir; s->num_file=0; err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzGoToNextFile (unzFile file) { unz_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ if (s->num_file+1==s->gi.number_entry) return UNZ_END_OF_LIST_OF_FILE; s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; s->num_file++; err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzipStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ extern int ZEXPORT unzLocateFile ( unzFile file, const char *szFileName, int iCaseSensitivity) { unz_s* s; int err; /* We remember the 'current' position in the file so that we can jump * back there if we fail. */ unz_file_info cur_file_infoSaved; unz_file_info_internal cur_file_info_internalSaved; uLong num_fileSaved; uLong pos_in_central_dirSaved; if (file==NULL) return UNZ_PARAMERROR; if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; /* Save the current state */ num_fileSaved = s->num_file; pos_in_central_dirSaved = s->pos_in_central_dir; cur_file_infoSaved = s->cur_file_info; cur_file_info_internalSaved = s->cur_file_info_internal; err = unzGoToFirstFile(file); while (err == UNZ_OK) { char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; err = unzGetCurrentFileInfo(file,NULL, szCurrentFileName,sizeof(szCurrentFileName)-1, NULL,0,NULL,0); if (err == UNZ_OK) { if (unzStringFileNameCompare(szCurrentFileName, szFileName,iCaseSensitivity)==0) return UNZ_OK; err = unzGoToNextFile(file); } } /* We failed, so restore the state of the 'current file' to where we * were. */ s->num_file = num_fileSaved ; s->pos_in_central_dir = pos_in_central_dirSaved ; s->cur_file_info = cur_file_infoSaved; s->cur_file_info_internal = cur_file_info_internalSaved; return err; } /* /////////////////////////////////////////// // Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) // I need random access // // Further optimization could be realized by adding an ability // to cache the directory in memory. The goal being a single // comprehensive file read to put the file I need in a memory. */ /* typedef struct unz_file_pos_s { uLong pos_in_zip_directory; // offset in file uLong num_of_file; // # of file } unz_file_pos; */ extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos) { unz_s* s; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_END_OF_LIST_OF_FILE; file_pos->pos_in_zip_directory = s->pos_in_central_dir; file_pos->num_of_file = s->num_file; return UNZ_OK; } extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos) { unz_s* s; int err; if (file==NULL || file_pos==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; /* jump to the right spot */ s->pos_in_central_dir = file_pos->pos_in_zip_directory; s->num_file = file_pos->num_of_file; /* set the current file */ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); /* return results */ s->current_file_ok = (err == UNZ_OK); return err; } /* // Unzip Helper Functions - should be here? /////////////////////////////////////////// */ /* Read the local header of the current zipfile Check the coherency of the local header and info in the end of central directory about this file store in *piSizeVar the size of extra info in local header (filename and size of extra field data) */ local int unzlocal_CheckCurrentFileCoherencyHeader ( unz_s* s, uInt* piSizeVar, uLong *poffset_local_extrafield, uInt *psize_local_extrafield) { uLong uMagic,uData,uFlags; uLong size_filename; uLong size_extra_field; int err=UNZ_OK; *piSizeVar = 0; *poffset_local_extrafield = 0; *psize_local_extrafield = 0; if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (err==UNZ_OK) { if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) err=UNZ_ERRNO; else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; /* else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) err=UNZ_BADZIPFILE; */ if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) err=UNZ_ERRNO; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) err=UNZ_BADZIPFILE; if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ err=UNZ_ERRNO; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ err=UNZ_ERRNO; else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) err=UNZ_BADZIPFILE; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) err=UNZ_ERRNO; else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) err=UNZ_BADZIPFILE; *piSizeVar += (uInt)size_filename; if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) err=UNZ_ERRNO; *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + size_filename; *psize_local_extrafield = (uInt)size_extra_field; *piSizeVar += (uInt)size_extra_field; return err; } /* Open for reading data the current file in the zipfile. If there is no error and the file is opened, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile3 ( unzFile file, int* method, int* level, int raw, const char* password) { int err=UNZ_OK; uInt iSizeVar; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uLong offset_local_extrafield; /* offset of the local extra field */ uInt size_local_extrafield; /* size of the local extra field */ # ifndef NOUNCRYPT char source[12]; # else if (password != NULL) return UNZ_PARAMERROR; # endif if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return UNZ_PARAMERROR; if (s->pfile_in_zip_read != NULL) unzCloseCurrentFile(file); if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) return UNZ_BADZIPFILE; pfile_in_zip_read_info = (file_in_zip_read_info_s*) ALLOC(sizeof(file_in_zip_read_info_s)); if (pfile_in_zip_read_info==NULL) return UNZ_INTERNALERROR; pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; pfile_in_zip_read_info->pos_local_extrafield=0; pfile_in_zip_read_info->raw=raw; if (pfile_in_zip_read_info->read_buffer==NULL) { TRYFREE(pfile_in_zip_read_info); return UNZ_INTERNALERROR; } pfile_in_zip_read_info->stream_initialised=0; if (method!=NULL) *method = (int)s->cur_file_info.compression_method; if (level!=NULL) { *level = 6; switch (s->cur_file_info.flag & 0x06) { case 6 : *level = 1; break; case 4 : *level = 2; break; case 2 : *level = 9; break; } } if ((s->cur_file_info.compression_method!=0) && (s->cur_file_info.compression_method!=Z_DEFLATED)) err=UNZ_BADZIPFILE; pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; pfile_in_zip_read_info->crc32=0; pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; pfile_in_zip_read_info->filestream=s->filestream; pfile_in_zip_read_info->z_filefunc=s->z_filefunc; pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; pfile_in_zip_read_info->stream.total_out = 0; if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) { pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; pfile_in_zip_read_info->stream.zfree = (free_func)0; pfile_in_zip_read_info->stream.opaque = (voidpf)0; pfile_in_zip_read_info->stream.next_in = NULL; // AKT was (voidpf)0; pfile_in_zip_read_info->stream.avail_in = 0; err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); if (err == Z_OK) pfile_in_zip_read_info->stream_initialised=1; else { TRYFREE(pfile_in_zip_read_info); return err; } /* windowBits is passed < 0 to tell that there is no zlib header. * Note that in this case inflate *requires* an extra "dummy" byte * after the compressed stream in order to complete decompression and * return Z_STREAM_END. * In unzip, i don't wait absolutely Z_STREAM_END because I known the * size of both compressed and uncompressed data */ } pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size ; pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size ; pfile_in_zip_read_info->pos_in_zipfile = s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar; pfile_in_zip_read_info->stream.avail_in = (uInt)0; s->pfile_in_zip_read = pfile_in_zip_read_info; # ifndef NOUNCRYPT if (password != NULL) { int i; s->pcrc_32_tab = (const unsigned long *)get_crc_table(); init_keys(password,s->keys,s->pcrc_32_tab); if (ZSEEK(s->z_filefunc, s->filestream, s->pfile_in_zip_read->pos_in_zipfile + s->pfile_in_zip_read->byte_before_the_zipfile, SEEK_SET)!=0) return UNZ_INTERNALERROR; if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) return UNZ_INTERNALERROR; for (i = 0; i<12; i++) zdecode(s->keys,s->pcrc_32_tab,source[i]); s->pfile_in_zip_read->pos_in_zipfile+=12; s->encrypted=1; } # endif return UNZ_OK; } extern int ZEXPORT unzOpenCurrentFile (unzFile file) { return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); } extern int ZEXPORT unzOpenCurrentFilePassword ( unzFile file, const char* password) { return unzOpenCurrentFile3(file, NULL, NULL, 0, password); } extern int ZEXPORT unzOpenCurrentFile2 ( unzFile file, int* method, int* level, int raw) { return unzOpenCurrentFile3(file, method, level, raw, NULL); } /* Read bytes from the current file. buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern int ZEXPORT unzReadCurrentFile ( unzFile file, voidp buf, unsigned len) { int err=UNZ_OK; uInt iRead = 0; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; if (len==0) return 0; pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; pfile_in_zip_read_info->stream.avail_out = (uInt)len; if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && (!(pfile_in_zip_read_info->raw))) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_uncompressed; if ((len>pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in) && (pfile_in_zip_read_info->raw)) pfile_in_zip_read_info->stream.avail_out = (uInt)pfile_in_zip_read_info->rest_read_compressed+ pfile_in_zip_read_info->stream.avail_in; while (pfile_in_zip_read_info->stream.avail_out>0) { if ((pfile_in_zip_read_info->stream.avail_in==0) && (pfile_in_zip_read_info->rest_read_compressed>0)) { uInt uReadThis = UNZ_BUFSIZE; if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; if (uReadThis == 0) return UNZ_EOF; if (ZSEEK(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->pos_in_zipfile + pfile_in_zip_read_info->byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->read_buffer, uReadThis)!=uReadThis) return UNZ_ERRNO; # ifndef NOUNCRYPT if(s->encrypted) { uInt i; for(i=0;iread_buffer[i] = zdecode(s->keys,s->pcrc_32_tab, pfile_in_zip_read_info->read_buffer[i]); } # endif pfile_in_zip_read_info->pos_in_zipfile += uReadThis; pfile_in_zip_read_info->rest_read_compressed-=uReadThis; pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->read_buffer; pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; } if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) { uInt uDoCopy,i ; if ((pfile_in_zip_read_info->stream.avail_in == 0) && (pfile_in_zip_read_info->rest_read_compressed == 0)) return (iRead==0) ? UNZ_EOF : iRead; if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in) uDoCopy = pfile_in_zip_read_info->stream.avail_out ; else uDoCopy = pfile_in_zip_read_info->stream.avail_in ; for (i=0;istream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i); pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, pfile_in_zip_read_info->stream.next_out, uDoCopy); pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; pfile_in_zip_read_info->stream.avail_in -= uDoCopy; pfile_in_zip_read_info->stream.avail_out -= uDoCopy; pfile_in_zip_read_info->stream.next_out += uDoCopy; pfile_in_zip_read_info->stream.next_in += uDoCopy; pfile_in_zip_read_info->stream.total_out += uDoCopy; iRead += uDoCopy; } else { uLong uTotalOutBefore,uTotalOutAfter; const Bytef *bufBefore; uLong uOutThis; int flush=Z_SYNC_FLUSH; uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; bufBefore = pfile_in_zip_read_info->stream.next_out; /* if ((pfile_in_zip_read_info->rest_read_uncompressed == pfile_in_zip_read_info->stream.avail_out) && (pfile_in_zip_read_info->rest_read_compressed == 0)) flush = Z_FINISH; */ err=inflate(&pfile_in_zip_read_info->stream,flush); if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) err = Z_DATA_ERROR; uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; uOutThis = uTotalOutAfter-uTotalOutBefore; pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); if (err==Z_STREAM_END) return (iRead==0) ? UNZ_EOF : iRead; if (err!=Z_OK) break; } } if (err==Z_OK) return iRead; return err; } /* Give the current position in uncompressed data */ extern z_off_t ZEXPORT unztell (unzFile file) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; return (z_off_t)pfile_in_zip_read_info->stream.total_out; } /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzeof (unzFile file) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if (pfile_in_zip_read_info->rest_read_uncompressed == 0) return 1; else return 0; } /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field that can be read if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ extern int ZEXPORT unzGetLocalExtrafield ( unzFile file, voidp buf, unsigned len) { unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; uInt read_now; uLong size_to_read; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; size_to_read = (pfile_in_zip_read_info->size_local_extrafield - pfile_in_zip_read_info->pos_local_extrafield); if (buf==NULL) return (int)size_to_read; if (len>size_to_read) read_now = (uInt)size_to_read; else read_now = (uInt)len ; if (read_now==0) return 0; if (ZSEEK(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, pfile_in_zip_read_info->offset_local_extrafield + pfile_in_zip_read_info->pos_local_extrafield, ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (ZREAD(pfile_in_zip_read_info->z_filefunc, pfile_in_zip_read_info->filestream, buf,read_now)!=read_now) return UNZ_ERRNO; return (int)read_now; } /* Close the file in zip opened with unzipOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzCloseCurrentFile (unzFile file) { int err=UNZ_OK; unz_s* s; file_in_zip_read_info_s* pfile_in_zip_read_info; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; pfile_in_zip_read_info=s->pfile_in_zip_read; if (pfile_in_zip_read_info==NULL) return UNZ_PARAMERROR; if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && (!pfile_in_zip_read_info->raw)) { if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) err=UNZ_CRCERROR; } TRYFREE(pfile_in_zip_read_info->read_buffer); pfile_in_zip_read_info->read_buffer = NULL; if (pfile_in_zip_read_info->stream_initialised) inflateEnd(&pfile_in_zip_read_info->stream); pfile_in_zip_read_info->stream_initialised = 0; TRYFREE(pfile_in_zip_read_info); s->pfile_in_zip_read=NULL; return err; } /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ extern int ZEXPORT unzGetGlobalComment ( unzFile file, char *szComment, uLong uSizeBuf) { //AKT int err=UNZ_OK; unz_s* s; uLong uReadThis ; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; uReadThis = uSizeBuf; if (uReadThis>s->gi.size_comment) uReadThis = s->gi.size_comment; if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) return UNZ_ERRNO; if (uReadThis>0) { *szComment='\0'; if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) return UNZ_ERRNO; } if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) *(szComment+s->gi.size_comment)='\0'; return (int)uReadThis; } /* Additions by RX '2004 */ extern uLong ZEXPORT unzGetOffset (unzFile file) { unz_s* s; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; if (!s->current_file_ok) return 0; if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) if (s->num_file==s->gi.number_entry) return 0; return s->pos_in_central_dir; } extern int ZEXPORT unzSetOffset ( unzFile file, uLong pos) { unz_s* s; int err; if (file==NULL) return UNZ_PARAMERROR; s=(unz_s*)file; s->pos_in_central_dir = pos; s->num_file = s->gi.number_entry; /* hack */ err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, &s->cur_file_info_internal, NULL,0,NULL,0,NULL,0); s->current_file_ok = (err == UNZ_OK); return err; } golly-2.7-src/gui-common/MiniZip/zip.h0000644000175000017500000002121712536111364014627 00000000000000/* zip.h -- IO for compress .zip files using zlib Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This unzip package allow creates .ZIP file, compatible with PKZip 2.04g WinZip, InfoZip tools and compatible. Multi volume ZipFile (span) are not supported. Encryption compatible with pkzip 2.04g only supported Old compressions used by old PKZip 1.x are not supported For uncompress .zip file, look at unzip.h I WAIT FEEDBACK at mail info@winimage.com Visit also http://www.winimage.com/zLibDll/unzip.html for evolution Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* for more info about .ZIP format, see http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip http://www.info-zip.org/pub/infozip/doc/ PkWare has also a specification at : ftp://ftp.pkware.com/probdesc.zip */ #ifndef _zip_H #define _zip_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #if defined(STRICTZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagzipFile__ { int unused; } zipFile__; typedef zipFile__ *zipFile; #else typedef voidp zipFile; #endif #define ZIP_OK (0) #define ZIP_EOF (0) #define ZIP_ERRNO (Z_ERRNO) #define ZIP_PARAMERROR (-102) #define ZIP_BADZIPFILE (-103) #define ZIP_INTERNALERROR (-104) #ifndef DEF_MEM_LEVEL # if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 # else # define DEF_MEM_LEVEL MAX_MEM_LEVEL # endif #endif /* default memLevel */ /* tm_zip contain date/time info */ typedef struct tm_zip_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_zip; typedef struct { tm_zip tmz_date; /* date in understandable format */ uLong dosDate; /* if dos_date == 0, tmu_date is used */ /* uLong flag; */ /* general purpose bit flag 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ } zip_fileinfo; typedef const char* zipcharpc; #define APPEND_STATUS_CREATE (0) #define APPEND_STATUS_CREATEAFTER (1) #define APPEND_STATUS_ADDINZIP (2) extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); /* Create a zipfile. pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip will be created at the end of the file. (useful if the file contain a self extractor code) if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will add files in existing zip (be sure you don't add file that doesn't exist) If the zipfile cannot be opened, the return value is NULL. Else, the return value is a zipFile Handle, usable with other function of this zip package. */ /* Note : there is no delete function into a zipfile. If you want delete file into a zipfile, you must open a zipfile, and create another Of couse, you can use RAW reading and writing to copy the file you did not want delte */ extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def)); extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level)); /* Open a file in the ZIP for writing. filename : the filename in zip (if NULL, '-' without quote will be used *zipfi contain supplemental information if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local contains the extrafield data the the local header if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global contains the extrafield data the the local header if comment != NULL, comment contain the comment string method contain the compression method (0 for store, Z_DEFLATED for deflate) level contain the level of compression (can be Z_DEFAULT_COMPRESSION) */ extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw)); /* Same than zipOpenNewFileInZip, except if raw=1, we write raw file */ extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCtypting)); /* Same than zipOpenNewFileInZip2, except windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 password : crypting password (NULL for no crypting) crcForCtypting : crc of file to compress (needed for crypting) */ extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, const void* buf, unsigned len)); /* Write data in the zipfile */ extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); /* Close the current file in the zipfile */ extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, uLong uncompressed_size, uLong crc32)); /* Close the current file in the zipfile, for fiel opened with parameter raw=1 in zipOpenNewFileInZip2 uncompressed_size and crc32 are value for the uncompressed size */ extern int ZEXPORT zipClose OF((zipFile file, const char* global_comment)); /* Close the zipfile */ #ifdef __cplusplus } #endif #endif /* _zip_H */ golly-2.7-src/gui-common/MiniZip/zip.c0000644000175000017500000010655112536111364014627 00000000000000/* zip.c -- IO on .zip files using zlib Version 1.01e, February 12th, 2005 27 Dec 2004 Rolf Kalbermatter Modification to zipOpen2 to support globalComment retrieval. Copyright (C) 1998-2005 Gilles Vollant Read zip.h for more info */ #include #include #include #include #include "zlib.h" #include "zip.h" #ifdef STDC # include # include # include #endif #ifdef NO_ERRNO_H extern int errno; #else # include #endif #ifndef local # define local static #endif /* compile with -Dlocal if your debugger can't find static symbols */ #ifndef VERSIONMADEBY # define VERSIONMADEBY (0x0) /* platform depedent */ #endif #ifndef Z_BUFSIZE #define Z_BUFSIZE (16384) #endif #ifndef Z_MAXFILENAMEINZIP #define Z_MAXFILENAMEINZIP (256) #endif #ifndef ALLOC # define ALLOC(size) (malloc(size)) #endif #ifndef TRYFREE # define TRYFREE(p) {if (p) free(p);} #endif /* #define SIZECENTRALDIRITEM (0x2e) #define SIZEZIPLOCALHEADER (0x1e) */ /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ #ifndef SEEK_CUR #define SEEK_CUR 1 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef DEF_MEM_LEVEL #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif #endif const char zip_copyright[] = " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; #define SIZEDATA_INDATABLOCK (4096-(4*4)) #define LOCALHEADERMAGIC (0x04034b50) #define CENTRALHEADERMAGIC (0x02014b50) #define ENDHEADERMAGIC (0x06054b50) #define FLAG_LOCALHEADER_OFFSET (0x06) #define CRC_LOCALHEADER_OFFSET (0x0e) #define SIZECENTRALHEADER (0x2e) /* 46 */ typedef struct linkedlist_datablock_internal_s { struct linkedlist_datablock_internal_s* next_datablock; uLong avail_in_this_block; uLong filled_in_this_block; uLong unused; /* for future use and alignement */ unsigned char data[SIZEDATA_INDATABLOCK]; } linkedlist_datablock_internal; typedef struct linkedlist_data_s { linkedlist_datablock_internal* first_block; linkedlist_datablock_internal* last_block; } linkedlist_data; typedef struct { z_stream stream; /* zLib stream structure for inflate */ int stream_initialised; /* 1 is stream is initialised */ uInt pos_in_buffered_data; /* last written byte in buffered_data */ uLong pos_local_header; /* offset of the local header of the file currenty writing */ char* central_header; /* central header data for the current file */ uLong size_centralheader; /* size of the central header for cur file */ uLong flag; /* flag of the file currently writing */ int method; /* compression method of file currenty wr.*/ int raw; /* 1 for directly writing raw data */ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ uLong dosDate; uLong crc32; int encrypt; #ifndef NOCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ const unsigned long* pcrc_32_tab; int crypt_header_size; #endif } curfile_info; typedef struct { zlib_filefunc_def z_filefunc; voidpf filestream; /* io structore of the zipfile */ linkedlist_data central_dir;/* datablock with central dir in construction*/ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ curfile_info ci; /* info on the file curretly writing */ uLong begin_pos; /* position of the beginning of the zipfile */ uLong add_position_when_writting_offset; uLong number_entry; #ifndef NO_ADDFILEINEXISTINGZIP char *globalcomment; #endif } zip_internal; #ifndef NOCRYPT #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED #include "crypt.h" #endif local linkedlist_datablock_internal* allocate_new_datablock() { linkedlist_datablock_internal* ldi; ldi = (linkedlist_datablock_internal*) ALLOC(sizeof(linkedlist_datablock_internal)); if (ldi!=NULL) { ldi->next_datablock = NULL ; ldi->filled_in_this_block = 0 ; ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; } return ldi; } local void free_datablock(linkedlist_datablock_internal* ldi) { while (ldi!=NULL) { linkedlist_datablock_internal* ldinext = ldi->next_datablock; TRYFREE(ldi); ldi = ldinext; } } local void init_linkedlist(linkedlist_data* ll) { ll->first_block = ll->last_block = NULL; } /* AKT: not used local void free_linkedlist(linkedlist_data* ll) { free_datablock(ll->first_block); ll->first_block = ll->last_block = NULL; } */ local int add_data_in_datablock( linkedlist_data* ll, const void* buf, uLong len) { linkedlist_datablock_internal* ldi; const unsigned char* from_copy; if (ll==NULL) return ZIP_INTERNALERROR; if (ll->last_block == NULL) { ll->first_block = ll->last_block = allocate_new_datablock(); if (ll->first_block == NULL) return ZIP_INTERNALERROR; } ldi = ll->last_block; from_copy = (unsigned char*)buf; while (len>0) { uInt copy_this; uInt i; unsigned char* to_copy; if (ldi->avail_in_this_block==0) { ldi->next_datablock = allocate_new_datablock(); if (ldi->next_datablock == NULL) return ZIP_INTERNALERROR; ldi = ldi->next_datablock ; ll->last_block = ldi; } if (ldi->avail_in_this_block < len) copy_this = (uInt)ldi->avail_in_this_block; else copy_this = (uInt)len; to_copy = &(ldi->data[ldi->filled_in_this_block]); for (i=0;ifilled_in_this_block += copy_this; ldi->avail_in_this_block -= copy_this; from_copy += copy_this ; len -= copy_this; } return ZIP_OK; } /****************************************************************************/ #ifndef NO_ADDFILEINEXISTINGZIP /* =========================================================================== Inputs a long in LSB order to the given file nbByte == 1, 2 or 4 (byte, short or long) */ local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong x, int nbByte)); local int ziplocal_putValue ( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong x, int nbByte) { unsigned char buf[4]; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 (X Roche) */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) return ZIP_ERRNO; else return ZIP_OK; } local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte)); local void ziplocal_putValue_inmemory ( void* dest, uLong x, int nbByte) { unsigned char* buf=(unsigned char*)dest; int n; for (n = 0; n < nbByte; n++) { buf[n] = (unsigned char)(x & 0xff); x >>= 8; } if (x != 0) { /* data overflow - hack for ZIP64 */ for (n = 0; n < nbByte; n++) { buf[n] = 0xff; } } } /****************************************************************************/ local uLong ziplocal_TmzDateToDosDate( const tm_zip* ptm, uLong dosDate) { uLong year = (uLong)ptm->tm_year; if (year>1980) year-=1980; else if (year>80) year-=80; return (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); } /****************************************************************************/ local int ziplocal_getByte OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, int *pi)); local int ziplocal_getByte( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, int *pi) { unsigned char c; int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); if (err==1) { *pi = (int)c; return ZIP_OK; } else { if (ZERROR(*pzlib_filefunc_def,filestream)) return ZIP_ERRNO; else return ZIP_EOF; } } /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ local int ziplocal_getShort OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int ziplocal_getShort ( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i; int err; err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } local int ziplocal_getLong OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); local int ziplocal_getLong ( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, uLong *pX) { uLong x ; int i; int err; err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x = (uLong)i; if (err==ZIP_OK) err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<8; if (err==ZIP_OK) err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<16; if (err==ZIP_OK) err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i); x += ((uLong)i)<<24; if (err==ZIP_OK) *pX = x; else *pX = 0; return err; } #ifndef BUFREADCOMMENT #define BUFREADCOMMENT (0x400) #endif /* Locate the Central directory of a zipfile (at the end, just before the global comment) */ local uLong ziplocal_SearchCentralDir OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream)); local uLong ziplocal_SearchCentralDir( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream) { unsigned char* buf; uLong uSizeFile; uLong uBackRead; uLong uMaxBack=0xffff; /* maximum size of global comment */ uLong uPosFound=0; if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) return 0; uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); if (uMaxBack>uSizeFile) uMaxBack = uSizeFile; buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); if (buf==NULL) return 0; uBackRead = 4; while (uBackReaduMaxBack) uBackRead = uMaxBack; else uBackRead+=BUFREADCOMMENT; uReadPos = uSizeFile-uBackRead ; uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) break; if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) break; for (i=(int)uReadSize-3; (i--)>0;) if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) { uPosFound = uReadPos+i; break; } if (uPosFound!=0) break; } TRYFREE(buf); return uPosFound; } #endif /* !NO_ADDFILEINEXISTINGZIP*/ /************************************************************/ extern zipFile ZEXPORT zipOpen2 ( const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc_def) { zip_internal ziinit; zip_internal* zi; int err=ZIP_OK; if (pzlib_filefunc_def==NULL) fill_fopen_filefunc(&ziinit.z_filefunc); else ziinit.z_filefunc = *pzlib_filefunc_def; ziinit.filestream = (*(ziinit.z_filefunc.zopen_file)) (ziinit.z_filefunc.opaque, pathname, (append == APPEND_STATUS_CREATE) ? (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); if (ziinit.filestream == NULL) return NULL; ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream); ziinit.in_opened_file_inzip = 0; ziinit.ci.stream_initialised = 0; ziinit.number_entry = 0; ziinit.add_position_when_writting_offset = 0; init_linkedlist(&(ziinit.central_dir)); zi = (zip_internal*)ALLOC(sizeof(zip_internal)); if (zi==NULL) { ZCLOSE(ziinit.z_filefunc,ziinit.filestream); return NULL; } /* now we add file in a zipfile */ # ifndef NO_ADDFILEINEXISTINGZIP ziinit.globalcomment = NULL; if (append == APPEND_STATUS_ADDINZIP) { uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ uLong size_central_dir; /* size of the central directory */ uLong offset_central_dir; /* offset of start of central directory */ uLong central_pos,uL; uLong number_disk; /* number of the current dist, used for spaning ZIP, unsupported, always 0*/ uLong number_disk_with_CD; /* number the the disk with central dir, used for spaning ZIP, unsupported, always 0*/ uLong number_entry; uLong number_entry_CD; /* total number of entries in the central dir (same than number_entry on nospan) */ uLong size_comment; central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream); if (central_pos==0) err=ZIP_ERRNO; if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) err=ZIP_ERRNO; /* the signature, already checked */ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK) err=ZIP_ERRNO; /* number of this disk */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK) err=ZIP_ERRNO; /* number of the disk with the start of the central directory */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central dir on this disk */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK) err=ZIP_ERRNO; /* total number of entries in the central dir */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK) err=ZIP_ERRNO; if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) err=ZIP_BADZIPFILE; /* size of the central directory */ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK) err=ZIP_ERRNO; /* offset of start of central directory with respect to the starting disk number */ if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK) err=ZIP_ERRNO; /* zipfile global comment length */ if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK) err=ZIP_ERRNO; if ((central_pos0) { // AKT added (char*) ziinit.globalcomment = (char*) ALLOC(size_comment+1); if (ziinit.globalcomment) { size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment); ziinit.globalcomment[size_comment]=0; } } byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); ziinit.add_position_when_writting_offset = byte_before_the_zipfile; { uLong size_central_dir_to_read = size_central_dir; size_t buf_size = SIZEDATA_INDATABLOCK; void* buf_read = (void*)ALLOC(buf_size); if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) err=ZIP_ERRNO; while ((size_central_dir_to_read>0) && (err==ZIP_OK)) { uLong read_this = SIZEDATA_INDATABLOCK; if (read_this > size_central_dir_to_read) read_this = size_central_dir_to_read; if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this) err=ZIP_ERRNO; if (err==ZIP_OK) err = add_data_in_datablock(&ziinit.central_dir,buf_read, (uLong)read_this); size_central_dir_to_read-=read_this; } TRYFREE(buf_read); } ziinit.begin_pos = byte_before_the_zipfile; ziinit.number_entry = number_entry_CD; if (ZSEEK(ziinit.z_filefunc, ziinit.filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) err=ZIP_ERRNO; } if (globalcomment) { *globalcomment = ziinit.globalcomment; } # endif /* !NO_ADDFILEINEXISTINGZIP*/ if (err != ZIP_OK) { # ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(ziinit.globalcomment); # endif /* !NO_ADDFILEINEXISTINGZIP*/ TRYFREE(zi); return NULL; } else { *zi = ziinit; return (zipFile)zi; } } extern zipFile ZEXPORT zipOpen ( const char *pathname, int append) { return zipOpen2(pathname,append,NULL,NULL); } extern int ZEXPORT zipOpenNewFileInZip3 ( zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw, int windowBits, int memLevel, int strategy, const char* password, uLong crcForCrypting) { zip_internal* zi; uInt size_filename; uInt size_comment; uInt i; int err = ZIP_OK; # ifdef NOCRYPT if (password != NULL) return ZIP_PARAMERROR; # endif if (file == NULL) return ZIP_PARAMERROR; if ((method!=0) && (method!=Z_DEFLATED)) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); if (err != ZIP_OK) return err; } if (filename==NULL) filename="-"; if (comment==NULL) size_comment = 0; else size_comment = (uInt)strlen(comment); size_filename = (uInt)strlen(filename); if (zipfi == NULL) zi->ci.dosDate = 0; else { if (zipfi->dosDate != 0) zi->ci.dosDate = zipfi->dosDate; else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate); } zi->ci.flag = 0; if ((level==8) || (level==9)) zi->ci.flag |= 2; if (level==2) zi->ci.flag |= 4; if (level==1) zi->ci.flag |= 6; if (password != NULL) zi->ci.flag |= 1; zi->ci.crc32 = 0; zi->ci.method = method; zi->ci.encrypt = 0; zi->ci.stream_initialised = 0; zi->ci.pos_in_buffered_data = 0; zi->ci.raw = raw; zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ; zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader); ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); /* version info */ ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2); ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ if (zipfi==NULL) ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); else ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); if (zipfi==NULL) ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); else ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4); for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = *(((const char*)extrafield_global)+i); for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ size_extrafield_global+i) = *(comment+i); if (zi->ci.central_header == NULL) return ZIP_INTERNALERROR; /* write the local header */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2); if ((err==ZIP_OK) && (size_filename>0)) if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) err = ZIP_ERRNO; if ((err==ZIP_OK) && (size_extrafield_local>0)) if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local) !=size_extrafield_local) err = ZIP_ERRNO; zi->ci.stream.avail_in = (uInt)0; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; zi->ci.stream.total_in = 0; zi->ci.stream.total_out = 0; if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { zi->ci.stream.zalloc = (alloc_func)0; zi->ci.stream.zfree = (free_func)0; zi->ci.stream.opaque = (voidpf)0; if (windowBits>0) windowBits = -windowBits; err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); if (err==Z_OK) zi->ci.stream_initialised = 1; } # ifndef NOCRYPT zi->ci.crypt_header_size = 0; if ((err==Z_OK) && (password != NULL)) { unsigned char bufHead[RAND_HEAD_LEN]; unsigned int sizeHead; zi->ci.encrypt = 1; zi->ci.pcrc_32_tab = (const unsigned long *)get_crc_table(); /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); zi->ci.crypt_header_size = sizeHead; if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) err = ZIP_ERRNO; } # endif if (err==Z_OK) zi->in_opened_file_inzip = 1; return err; } extern int ZEXPORT zipOpenNewFileInZip2( zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level, int raw) { return zipOpenNewFileInZip3 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, raw, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, NULL, 0); } extern int ZEXPORT zipOpenNewFileInZip ( zipFile file, const char* filename, const zip_fileinfo* zipfi, const void* extrafield_local, uInt size_extrafield_local, const void* extrafield_global, uInt size_extrafield_global, const char* comment, int method, int level) { return zipOpenNewFileInZip2 (file, filename, zipfi, extrafield_local, size_extrafield_local, extrafield_global, size_extrafield_global, comment, method, level, 0); } local int zipFlushWriteBuffer(zip_internal* zi) { int err=ZIP_OK; if (zi->ci.encrypt != 0) { #ifndef NOCRYPT uInt i; int t; for (i=0;ici.pos_in_buffered_data;i++) zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); #endif } if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) !=zi->ci.pos_in_buffered_data) err = ZIP_ERRNO; zi->ci.pos_in_buffered_data = 0; return err; } extern int ZEXPORT zipWriteInFileInZip ( zipFile file, const void* buf, unsigned len) { zip_internal* zi; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.next_in = (Bytef*)buf; // AKT was (void*)buf; zi->ci.stream.avail_in = len; zi->ci.crc32 = crc32(zi->ci.crc32, (Bytef*)buf, len); // AKT added (Bytef*) while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) { if (zi->ci.stream.avail_out == 0) { if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } if(err != ZIP_OK) break; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { uLong uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_NO_FLUSH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } else { uInt copy_this,i; if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) copy_this = zi->ci.stream.avail_in; else copy_this = zi->ci.stream.avail_out; for (i=0;ici.stream.next_out)+i) = *(((const char*)zi->ci.stream.next_in)+i); { zi->ci.stream.avail_in -= copy_this; zi->ci.stream.avail_out-= copy_this; zi->ci.stream.next_in+= copy_this; zi->ci.stream.next_out+= copy_this; zi->ci.stream.total_in+= copy_this; zi->ci.stream.total_out+= copy_this; zi->ci.pos_in_buffered_data += copy_this; } } } return err; } extern int ZEXPORT zipCloseFileInZipRaw ( zipFile file, uLong uncompressed_size, uLong crc32) { zip_internal* zi; uLong compressed_size; int err=ZIP_OK; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 0) return ZIP_PARAMERROR; zi->ci.stream.avail_in = 0; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) while (err==ZIP_OK) { uLong uTotalOutBefore; if (zi->ci.stream.avail_out == 0) { if (zipFlushWriteBuffer(zi) == ZIP_ERRNO) err = ZIP_ERRNO; zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; zi->ci.stream.next_out = zi->ci.buffered_data; } uTotalOutBefore = zi->ci.stream.total_out; err=deflate(&zi->ci.stream, Z_FINISH); zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; } if (err==Z_STREAM_END) err=ZIP_OK; /* this is normal */ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) if (zipFlushWriteBuffer(zi)==ZIP_ERRNO) err = ZIP_ERRNO; if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) { err=deflateEnd(&zi->ci.stream); zi->ci.stream_initialised = 0; } if (!zi->ci.raw) { crc32 = (uLong)zi->ci.crc32; uncompressed_size = (uLong)zi->ci.stream.total_in; } compressed_size = (uLong)zi->ci.stream.total_out; # ifndef NOCRYPT compressed_size += zi->ci.crypt_header_size; # endif ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ ziplocal_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ if (zi->ci.stream.data_type == Z_ASCII) ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); ziplocal_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ if (err==ZIP_OK) err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header, (uLong)zi->ci.size_centralheader); free(zi->ci.central_header); if (err==ZIP_OK) { long cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); if (ZSEEK(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; if (err==ZIP_OK) err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ if (err==ZIP_OK) /* compressed size, unknown */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); if (err==ZIP_OK) /* uncompressed size, unknown */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); if (ZSEEK(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) err = ZIP_ERRNO; } zi->number_entry ++; zi->in_opened_file_inzip = 0; return err; } extern int ZEXPORT zipCloseFileInZip (zipFile file) { return zipCloseFileInZipRaw (file,0,0); } extern int ZEXPORT zipClose ( zipFile file, const char* global_comment) { zip_internal* zi; int err = 0; uLong size_centraldir = 0; uLong centraldir_pos_inzip; uInt size_global_comment; if (file == NULL) return ZIP_PARAMERROR; zi = (zip_internal*)file; if (zi->in_opened_file_inzip == 1) { err = zipCloseFileInZip (file); } #ifndef NO_ADDFILEINEXISTINGZIP if (global_comment==NULL) global_comment = zi->globalcomment; #endif if (global_comment==NULL) size_global_comment = 0; else size_global_comment = (uInt)strlen(global_comment); centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream); if (err==ZIP_OK) { linkedlist_datablock_internal* ldi = zi->central_dir.first_block ; while (ldi!=NULL) { if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) if (ZWRITE(zi->z_filefunc,zi->filestream, ldi->data,ldi->filled_in_this_block) !=ldi->filled_in_this_block ) err = ZIP_ERRNO; size_centraldir += ldi->filled_in_this_block; ldi = ldi->next_datablock; } } free_datablock(zi->central_dir.first_block); if (err==ZIP_OK) /* Magic End */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); if (err==ZIP_OK) /* number of this disk */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* number of the disk with the start of the central directory */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); if (err==ZIP_OK) /* total number of entries in the central dir */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); if (err==ZIP_OK) /* size of the central directory */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); if (err==ZIP_OK) /* zipfile comment length */ err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); if ((err==ZIP_OK) && (size_global_comment>0)) if (ZWRITE(zi->z_filefunc,zi->filestream, global_comment,size_global_comment) != size_global_comment) err = ZIP_ERRNO; if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0) if (err == ZIP_OK) err = ZIP_ERRNO; #ifndef NO_ADDFILEINEXISTINGZIP TRYFREE(zi->globalcomment); #endif TRYFREE(zi); return err; } golly-2.7-src/gui-common/MiniZip/unzip.h0000644000175000017500000003125012536111364015170 00000000000000/* unzip.h -- IO for uncompress .zip files using zlib Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g WinZip, InfoZip tools and compatible. Multi volume ZipFile (span) are not supported. Encryption compatible with pkzip 2.04g only supported Old compressions used by old PKZip 1.x are not supported I WAIT FEEDBACK at mail info@winimage.com Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution Condition of use and distribution are the same than zlib : This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ /* for more info about .ZIP format, see http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip http://www.info-zip.org/pub/infozip/doc/ PkWare has also a specification at : ftp://ftp.pkware.com/probdesc.zip */ #ifndef _unz_H #define _unz_H #ifdef __cplusplus extern "C" { #endif #ifndef _ZLIB_H #include "zlib.h" #endif #ifndef _ZLIBIOAPI_H #include "ioapi.h" #endif #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) /* like the STRICT of WIN32, we define a pointer that cannot be converted from (void*) without cast */ typedef struct TagunzFile__ { int unused; } unzFile__; typedef unzFile__ *unzFile; #else typedef voidp unzFile; #endif #define UNZ_OK (0) #define UNZ_END_OF_LIST_OF_FILE (-100) #define UNZ_ERRNO (Z_ERRNO) #define UNZ_EOF (0) #define UNZ_PARAMERROR (-102) #define UNZ_BADZIPFILE (-103) #define UNZ_INTERNALERROR (-104) #define UNZ_CRCERROR (-105) /* tm_unz contain date/time info */ typedef struct tm_unz_s { uInt tm_sec; /* seconds after the minute - [0,59] */ uInt tm_min; /* minutes after the hour - [0,59] */ uInt tm_hour; /* hours since midnight - [0,23] */ uInt tm_mday; /* day of the month - [1,31] */ uInt tm_mon; /* months since January - [0,11] */ uInt tm_year; /* years - [1980..2044] */ } tm_unz; /* unz_global_info structure contain global data about the ZIPfile These data comes from the end of central dir */ typedef struct unz_global_info_s { uLong number_entry; /* total number of entries in the central dir on this disk */ uLong size_comment; /* size of the global comment of the zipfile */ } unz_global_info; /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_info_s { uLong version; /* version made by 2 bytes */ uLong version_needed; /* version needed to extract 2 bytes */ uLong flag; /* general purpose bit flag 2 bytes */ uLong compression_method; /* compression method 2 bytes */ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ uLong crc; /* crc-32 4 bytes */ uLong compressed_size; /* compressed size 4 bytes */ uLong uncompressed_size; /* uncompressed size 4 bytes */ uLong size_filename; /* filename length 2 bytes */ uLong size_file_extra; /* extra field length 2 bytes */ uLong size_file_comment; /* file comment length 2 bytes */ uLong disk_num_start; /* disk number start 2 bytes */ uLong internal_fa; /* internal file attributes 2 bytes */ uLong external_fa; /* external file attributes 4 bytes */ tm_unz tmu_date; } unz_file_info; extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, const char* fileName2, int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi or strcasecmp) If iCaseSenisivity = 0, case sensitivity is defaut of your operating system (like 1 on Unix, 2 on Windows) */ extern unzFile ZEXPORT unzOpen OF((const char *path)); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer "zlib/zlib113.zip". If the zipfile cannot be opened (file don't exist or in not valid), the return value is NULL. Else, the return value is a unzFile Handle, usable with other function of this unzip package. */ extern unzFile ZEXPORT unzOpen2 OF((const char *path, zlib_filefunc_def* pzlib_filefunc_def)); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzipCloseCurrentFile before call unzipClose. return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, unz_global_info *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *szComment, uLong uSizeBuf)); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. return the number of byte copied or an error code <0 */ /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ extern int ZEXPORT unzLocateFile OF((unzFile file, const char *szFileName, int iCaseSensitivity)); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare return value : UNZ_OK if the file is found. It becomes the current file. UNZ_END_OF_LIST_OF_FILE if the file is not found */ /* ****************************************** */ /* Ryan supplied functions */ /* unz_file_info contain information about a file in the zipfile */ typedef struct unz_file_pos_s { uLong pos_in_zip_directory; /* offset in zip file directory */ uLong num_of_file; /* # of file */ } unz_file_pos; extern int ZEXPORT unzGetFilePos( unzFile file, unz_file_pos* file_pos); extern int ZEXPORT unzGoToFilePos( unzFile file, unz_file_pos* file_pos); /* ****************************************** */ extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, uLong commentBufferSize)); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain somes info about the current file if szFileName!=NULL, the filemane string will be copied in szFileName (fileNameBufferSize is the size of the buffer) if extraField!=NULL, the extra field information will be copied in extraField (extraFieldBufferSize is the size of the buffer). This is the Central-header version of the extra field if szComment!=NULL, the comment string of the file will be copied in szComment (commentBufferSize is the size of the buffer) */ /***************************************************************************/ /* for reading the content of the current zipfile, you can open it, read data from it, and close it (you can close it before reading all the file) */ extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, const char* password)); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, int raw)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, const char* password)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 *method will receive method of compression, *level will receive level of compression note : you can set level parameter as NULL (if you did not want known level, but you CANNOT set method parameter as NULL */ extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied len the size of buf. return the number of byte copied if somes bytes are copied return 0 if the end of file was reached return <0 with error code if there is an error (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ extern z_off_t ZEXPORT unztell OF((unzFile file)); /* Give the current position in uncompressed data */ extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is more info in the local-header version than in the central-header) if buf==NULL, it return the size of the local extra field if buf!=NULL, len is the size of the buffer, the extra header is copied in buf. the return value is the number of bytes copied in buf, or (if <0) the error code */ /***************************************************************************/ /* Get the current file offset */ extern uLong ZEXPORT unzGetOffset (unzFile file); /* Set the current file offset */ extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); #ifdef __cplusplus } #endif #endif /* _unz_H */ golly-2.7-src/gui-common/MiniZip/ioapi.h0000644000175000017500000000474712536111364015137 00000000000000/* ioapi.h -- IO base function header for compress/uncompress .zip files using zlib + zip or unzip API Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant */ #ifndef _ZLIBIOAPI_H #define _ZLIBIOAPI_H #define ZLIB_FILEFUNC_SEEK_CUR (1) #define ZLIB_FILEFUNC_SEEK_END (2) #define ZLIB_FILEFUNC_SEEK_SET (0) #define ZLIB_FILEFUNC_MODE_READ (1) #define ZLIB_FILEFUNC_MODE_WRITE (2) #define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) #define ZLIB_FILEFUNC_MODE_EXISTING (4) #define ZLIB_FILEFUNC_MODE_CREATE (8) #ifndef ZCALLBACK #if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) #define ZCALLBACK CALLBACK #else #define ZCALLBACK #endif #endif #ifdef __cplusplus extern "C" { #endif typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); typedef struct zlib_filefunc_def_s { open_file_func zopen_file; read_file_func zread_file; write_file_func zwrite_file; tell_file_func ztell_file; seek_file_func zseek_file; close_file_func zclose_file; testerror_file_func zerror_file; voidpf opaque; } zlib_filefunc_def; void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); #define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) #define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) #define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) #define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) #define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) #define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) #ifdef __cplusplus } #endif #endif golly-2.7-src/gui-common/MiniZip/crypt.h0000644000175000017500000001105712536111364015167 00000000000000/* crypt.h -- base code for crypt/uncrypt ZIPfile Version 1.01e, February 12th, 2005 Copyright (C) 1998-2005 Gilles Vollant This code is a modified version of crypting code in Infozip distribution The encryption/decryption parts of this source code (as opposed to the non-echoing password parts) were originally written in Europe. The whole source package can be freely distributed, including from the USA. (Prior to January 2000, re-export from the US was a violation of US law.) This encryption code is a direct transcription of the algorithm from Roger Schlafly, described by Phil Katz in the file appnote.txt. This file (appnote.txt) is distributed with the PKZIP program (even in the version without encryption capabilities). If you don't need crypting in your application, just define symbols NOCRYPT and NOUNCRYPT. This code support the "Traditional PKWARE Encryption". The new AES encryption added on Zip format by Winzip (see the page http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong Encryption is not supported. */ #define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) /*********************************************************************** * Return the next byte in the pseudo-random sequence */ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem * with any known compiler so far, though */ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); } /*********************************************************************** * Update the encryption keys with the next byte of plain text */ static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; { register int keyshift = (int)((*(pkeys+1)) >> 24); (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); } return c; } /*********************************************************************** * Initialize the encryption keys and the random header according to * the given password. */ static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; *(pkeys+2) = 878082192L; while (*passwd != '\0') { update_keys(pkeys,pcrc_32_tab,(int)*passwd); passwd++; } } #define zdecode(pkeys,pcrc_32_tab,c) \ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) #define zencode(pkeys,pcrc_32_tab,c,t) \ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) #ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED #define RAND_HEAD_LEN 12 /* "last resort" source for second part of crypt seed pattern */ # ifndef ZCR_SEED2 # define ZCR_SEED2 3141592654UL /* use PI as default pattern */ # endif static int crypthead( const char *passwd, /* password string */ unsigned char *buf, /* where to write header */ int bufSize, unsigned long* pkeys, const unsigned long* pcrc_32_tab, unsigned long crcForCrypting) { int n; /* index in random header */ int t; /* temporary */ int c; /* random byte */ unsigned char header[RAND_HEAD_LEN-2]; /* random header */ static unsigned calls = 0; /* ensure different random header each time */ if (bufSize> 7) & 0xff; header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); } /* Encrypt random header (last two bytes is high word of crc) */ init_keys(passwd, pkeys, pcrc_32_tab); for (n = 0; n < RAND_HEAD_LEN-2; n++) { buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); } buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); buf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); return n; } #endif golly-2.7-src/gui-common/layer.h0000644000175000017500000002450712536111364013567 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _LAYER_H_ #define _LAYER_H_ #include "bigint.h" // for bigint class #include "viewport.h" // for viewport class #include "utils.h" // for gColor, gRect #include "algos.h" // for algo_type, gBitmapPtr #include "select.h" // for Selection class class UndoRedo; // export from script.h if we ever support scripting!!! extern bool inscript; enum TouchModes { drawmode, pickmode, selectmode, movemode, zoominmode, zoomoutmode }; // Golly can support multiple layers. Each layer is a separate universe // (unless cloned) with its own algorithm, rule, viewport, pattern title, // selection, undo/redo history, etc. class Layer { public: Layer(); ~Layer(); // if this is a cloned layer then cloneid is > 0 and all the other clones // have the same cloneid int cloneid; lifealgo* algo; // this layer's universe (shared by clones) algo_type algtype; // type of universe (index into algoinfo) bool hyperspeed; // use acceleration while generating? bool showhashinfo; // show hashing info? bool autofit; // auto fit pattern while generating? bool dirty; // user has modified pattern? bool savedirty; // state of dirty flag before drawing/script change bool stayclean; // script has reset dirty flag? int currbase; // current base step int currexpo; // current step exponent int drawingstate; // current drawing state TouchModes touchmode; // current touch mode (drawing, selecting, etc) UndoRedo* undoredo; // undo/redo history (shared by clones) // each layer (cloned or not) has its own viewport for displaying patterns; // note that we use a pointer to the viewport to allow temporary switching // in wxrender.cpp (eg. in DrawStackedLayers) viewport* view; // WARNING: this string is used to remember the current rule when // switching to another layer; to determine the current rule at any // time, use currlayer->algo->getrule() std::string rule; Selection currsel; // current selection Selection savesel; // for saving/restoring selection bigint originx; // X origin offset bigint originy; // Y origin offset std::string currfile; // full path of current pattern file std::string currname; // name used for Pattern=... // for saving and restoring starting pattern algo_type startalgo; // starting algorithm bool savestart; // need to save starting pattern? bool startdirty; // starting state of dirty flag std::string startfile; // file for saving starting pattern std::string startname; // starting currname std::string startrule; // starting rule bigint startgen; // starting generation (>= 0) bigint startx, starty; // starting location int startbase; // starting base step int startexpo; // starting step exponent int startmag; // starting scale Selection startsel; // starting selection // temporary file used to restore starting pattern or to show comments; // each non-cloned layer uses a different temporary file std::string tempstart; // used when tilelayers is true //!!! PatternView* tilewin; // tile window gRect tilerect; // tile window's size and position // color scheme for this layer gColor fromrgb; // start of gradient gColor torgb; // end of gradient unsigned char cellr[256]; // red components for states 0..255 unsigned char cellg[256]; // green components for states 0..255 unsigned char cellb[256]; // blue components for states 0..255 // icons for this layer gBitmapPtr* icons7x7; // icons for scale 1:8 gBitmapPtr* icons15x15; // icons for scale 1:16 gBitmapPtr* icons31x31; // icons for scale 1:32 // texture data for rendering icons unsigned char** textures7x7; // texture data for 7x7 icons unsigned char** textures15x15; // texture data for 15x15 icons unsigned char** textures31x31; // texture data for 31x31 icons bool multicoloricons; // are icons multi-colored? (grayscale if not) // used if the layer has a timeline (see wxtimeline.cpp) int currframe; // current frame in timeline int autoplay; // +ve = play forwards, -ve = play backwards, 0 = stop int tlspeed; // controls speed at which frames are played long lastframe; // time (in msecs) when last frame was displayed }; const int MAX_LAYERS = 10; // maximum number of layers extern int numlayers; // number of existing layers extern int numclones; // number of cloned layers extern int currindex; // index of current layer (0..numlayers-1) extern Layer* currlayer; // pointer to current layer Layer* GetLayer(int index); // Return a pointer to the layer specified by the given index. void AddLayer(); // Add a new layer (with an empty universe) and make it the current layer. // The first call creates the initial layer. Later calls insert the // new layer immediately after the old current layer. The new layer // inherits the same type of universe, the same rule, the same scale // and location, and the same touch mode. void CloneLayer(); // Like AddLayer but shares the same universe and undo/redo history // as the current layer. All the current layer's settings are duplicated // and most will be kept synchronized; ie. changing one clone changes all // the others, but each cloned layer has a separate viewport so the same // pattern can be viewed at different scales and locations. void SyncClones(); // If the current layer is a clone then this call ensures the universe // and settings in its other clones are correctly synchronized. void DuplicateLayer(); // Like AddLayer but makes a copy of the current layer's pattern. // Also duplicates all the current settings but, unlike a cloned layer, // the settings are not kept synchronized. void DeleteLayer(); // Delete the current layer. The current layer changes to the previous // index, unless layer 0 was deleted, in which case the current layer // is the new layer at index 0. void DeleteOtherLayers(); // Delete all layers except the current layer. void SetLayer(int index); // Set the current layer using the given index (0..numlayers-1). void MoveLayer(int fromindex, int toindex); // Move the layer at fromindex to toindex and make it the current layer. // This is called by MoveLayerDialog and the movelayer script command. void MoveLayerDialog(); // Bring up a dialog that allows the user to move the current layer // to a new index (which becomes the current layer). void NameLayerDialog(); // Bring up a dialog that allows the user to change the name of the // current layer. void MarkLayerDirty(); // Set dirty flag in current layer and any of its clones. // Also prefix pattern title and layer name(s) with an asterisk. void MarkLayerClean(const char* title); // Reset dirty flag in current layer and any of its clones. // Also set pattern title, removing asterisk from it and layer name(s). void ToggleSyncViews(); // Toggle the syncviews flag. When true, every layer uses the same // scale and location as the current layer. void ToggleSyncModes(); // Toggle the syncmodes flag. When true, every layer uses the same // touch mode as the current layer. void ToggleStackLayers(); // Toggle the stacklayers flag. When true, the rendering code displays // all layers using the same scale and location as the current layer. // Layer 0 is drawn first (100% opaque), then all the other layers // are drawn as overlays using an opacity set by the user. The colors // for the live cells in each layer can be set via the Prefs dialog. void ToggleTileLayers(); // Toggle the tilelayers flag. When true, the rendering code displays // all layers in tiled sub-windows. bool CanSwitchLayer(int index); // Return true if the user can switch to the given layer. void SwitchToClickedTile(int index); // If allowed, change current layer to clicked tile. void ResizeLayers(int wd, int ht); // Resize the viewport in all layers. bool RestoreRule(const char* rule); // Try to set the current layer's rule to a previously known rule. // If this succeeds return true, but if it fails then warn the user, // switch to the current algorithm's default rule, and return false. // The latter can happen if the given rule's table/tree file was // deleted or was edited and some sort of error introduced. //??? move following color stuff into colors.* void CreateColorGradient(); // Create a color gradient for the current layer using // currlayer->fromrgb and currlayer->torgb. void UpdateCloneColors(); // If current layer has clones then update their colors. void UpdateLayerColors(); // Update the cell colors and icons for the current layer (and its clones) // according to the current algo and rule. Must be called very soon // after any algo/rule change, and before the viewport is updated. void InvertCellColors(); // Invert the cell colors in all layers, including the dead cell color, // grid lines, and the colors in all icon bitmaps. void SetLayerColors(); // Open a dialog to change the current layer's colors. #endif golly-2.7-src/gui-common/algos.h0000644000175000017500000001160612536111364013554 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _ALGOS_H_ #define _ALGOS_H_ #include "lifealgo.h" #include "utils.h" // for gColor // for storing icon info: typedef struct { int wd; int ht; unsigned char* pxldata; // RGBA data (size = wd * ht * 4) } gBitmap; typedef gBitmap* gBitmapPtr; // Golly supports multiple algorithms. The first algorithm // registered must *always* be qlifealgo. The second must // *always* be hlifealgo. The order of the rest does not matter. enum { QLIFE_ALGO, // QuickLife HLIFE_ALGO // HashLife }; const int MAX_ALGOS = 50; // maximum number of algorithms typedef int algo_type; // 0..MAX_ALGOS-1 // A class for all the static info we need about a particular algorithm: class AlgoData : public staticAlgoInfo { public: AlgoData(); virtual void setDefaultBaseStep(int v) { defbase = v; } // all hashing algos use maxhashmem and QuickLife uses 0 (unlimited) // virtual void setDefaultMaxMem(int v) { } static AlgoData& tick(); // static allocator // additional data bool canhash; // algo uses hashing? int defbase; // default base step gColor statusrgb; // status bar color gBitmapPtr* icons7x7; // icon bitmaps for scale 1:8 gBitmapPtr* icons15x15; // icon bitmaps for scale 1:16 gBitmapPtr* icons31x31; // icon bitmaps for scale 1:32 // default color scheme bool gradient; // use color gradient? gColor fromrgb; // color at start of gradient gColor torgb; // color at end of gradient // if gradient is false then use these colors for each cell state unsigned char algor[256]; unsigned char algog[256]; unsigned char algob[256]; }; extern AlgoData* algoinfo[MAX_ALGOS]; // static info for each algorithm extern algo_type initalgo; // initial algorithm // the following bitmaps are grayscale icons that can be used with any rules // with any number of states extern gBitmapPtr* circles7x7; // circular icons for scale 1:8 extern gBitmapPtr* circles15x15; // circular icons for scale 1:16 extern gBitmapPtr* circles31x31; // circular icons for scale 1:32 extern gBitmapPtr* diamonds7x7; // diamond icons for scale 1:8 extern gBitmapPtr* diamonds15x15; // diamond icons for scale 1:16 extern gBitmapPtr* diamonds31x31; // diamond icons for scale 1:32 extern gBitmapPtr* hexagons7x7; // hexagonal icons for scale 1:8 extern gBitmapPtr* hexagons15x15; // hexagonal icons for scale 1:16 extern gBitmapPtr* hexagons31x31; // hexagonal icons for scale 1:32 // NOTE: the triangular icons are only suitable for a 4-state rule that // is emulating a triangular neighborhood with 2 triangles per cell extern gBitmapPtr* triangles7x7; // triangular icons for scale 1:8 extern gBitmapPtr* triangles15x15; // triangular icons for scale 1:16 extern gBitmapPtr* triangles31x31; // triangular icons for scale 1:32 void InitAlgorithms(); // Initialize above data. Must be called before reading the prefs file. void DeleteAlgorithms(); // Deallocate memory allocated in InitAlgorithms(). lifealgo* CreateNewUniverse(algo_type algotype, bool allowcheck = true); // Create a new universe of given type. If allowcheck is true then // event checking is allowed. const char* GetAlgoName(algo_type algotype); // Return name of given algorithm. This name appears in various places // and is also stored in the prefs file. int NumAlgos(); // Return current number of algorithms. gBitmapPtr* CreateIconBitmaps(const char** xpmdata, int maxstates); // Create icon bitmaps using the given XPM data. gBitmapPtr* ScaleIconBitmaps(gBitmapPtr* srcicons, int size); // Return icon bitmaps scaled to given size. void FreeIconBitmaps(gBitmapPtr* icons); // Free all the memory used by the given set of icons. bool MultiColorImage(gBitmapPtr image); // Return true if image contains at least one color that isn't a shade of gray. #endif golly-2.7-src/gui-common/status.h0000644000175000017500000000372212536111364013772 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _STATUS_H_ #define _STATUS_H_ #include "bigint.h" #include // for std::string // The status bar area consists of 3 lines of text: extern std::string status1; // top line extern std::string status2; // middle line extern std::string status3; // bottom line void UpdateStatusLines(); // set status1 and status2 (SetMessage sets status3) void ClearMessage(); // erase bottom line of status bar void DisplayMessage(const char* s); // display given message on bottom line of status bar void ErrorMessage(const char* s); // beep and display given message on bottom line of status bar void SetMessage(const char* s); // set status3 without displaying it (until next update) int GetCurrentDelay(); // return current delay (in millisecs) char* Stringify(const bigint& b); // convert given number to string suitable for display void CheckMouseLocation(int x, int y); // on devices with a mouse we might need to update the // cursor's current XY cell location, where the given x,y // values are the cursor's viewport coordinates (in pixels) #endif golly-2.7-src/gui-common/prefs.h0000644000175000017500000001415012536111364013563 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _PREFS_H_ #define _PREFS_H_ #include // for std::string #include // for std::list #include "utils.h" // for gColor // Routines for loading and saving user preferences: void GetPrefs(); // Read preferences from prefsfile. void SavePrefs(); // Write preferences to prefsfile. // Various constants: const int minfontsize = 6; // minimum value of helpfontsize const int maxfontsize = 30; // maximum value of helpfontsize const int MAX_SPACING = 1000; // maximum value of boldspacing const int MAX_BASESTEP = 2000000000; // maximum base step const int MAX_DELAY = 5000; // maximum mindelay or maxdelay const int MAX_RECENT = 100; // maximum value of maxpatterns const int MIN_MEM_MB = 10; // minimum value of maxhashmem const int MAX_MEM_MB = 300; // maximum value of maxhashmem // These global paths must be set in platform-specific code before GetPrefs is called: extern std::string supplieddir; // path of parent directory for supplied help/patterns/rules extern std::string helpdir; // path of directory for supplied help extern std::string patternsdir; // path of directory for supplied patterns extern std::string rulesdir; // path of directory for supplied rules extern std::string userdir; // path of parent directory for user's rules/patterns/downloads extern std::string userrules; // path of directory for user's rules extern std::string savedir; // path of directory for user's saved patterns extern std::string downloaddir; // path of directory for user's downloaded files extern std::string tempdir; // path of directory for temporary data extern std::string clipfile; // path of temporary file for storing clipboard data extern std::string prefsfile; // path of file for storing user's preferences // Global preference data: extern int debuglevel; // for displaying debug info if > 0 extern int helpfontsize; // font size in help window extern char initrule[]; // initial rule extern bool initautofit; // initial autofit setting extern bool inithyperspeed; // initial hyperspeed setting extern bool initshowhashinfo; // initial showhashinfo setting extern bool savexrle; // save RLE file using XRLE format? extern bool showtool; // show tool bar? extern bool showlayer; // show layer bar? extern bool showedit; // show edit bar? extern bool showallstates; // show all cell states in edit bar? extern bool showstatus; // show status bar? extern bool showexact; // show exact numbers in status bar? extern bool showtimeline; // show timeline bar? extern bool showtiming; // show timing messages? extern bool showgridlines; // display grid lines? extern bool showicons; // display icons for cell states? extern bool swapcolors; // swap colors used for cell states? extern bool allowundo; // allow undo/redo? extern bool allowbeep; // okay to play beep sound? extern bool restoreview; // should reset/undo restore view? extern int canchangerule; // if > 0 then paste can change rule extern int randomfill; // random fill percentage extern int opacity; // percentage opacity of live cells in overlays extern int tileborder; // width of tiled window borders extern int mingridmag; // minimum mag to draw grid lines extern int boldspacing; // spacing of bold grid lines extern bool showboldlines; // show bold grid lines? extern bool mathcoords; // show Y values increasing upwards? extern bool syncviews; // synchronize viewports? extern bool syncmodes; // synchronize touch modes? extern bool stacklayers; // stack all layers? extern bool tilelayers; // tile all layers? extern bool asktosave; // ask to save changes? extern int newmag; // mag setting for new pattern extern bool newremovesel; // new pattern removes selection? extern bool openremovesel; // opening pattern removes selection? extern int mindelay; // minimum millisec delay extern int maxdelay; // maximum millisec delay extern int maxhashmem; // maximum memory (in MB) for hashlife-based algos // Recent patterns: extern int numpatterns; // current number of recent pattern files extern int maxpatterns; // maximum number of recent pattern files extern std::list recentpatterns; // list of recent pattern files // Colors: extern gColor borderrgb; // color for border around bounded grid extern gColor selectrgb; // color for selected cells extern gColor pastergb; // color for pattern to be pasted // Paste info: typedef enum { And, Copy, Or, Xor // logical paste modes } paste_mode; extern paste_mode pmode; // current paste mode const char* GetPasteMode(); // get pmode void SetPasteMode(const char* s); // set pmode #endif golly-2.7-src/gui-common/render.h0000644000175000017500000000327112536111364013725 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _RENDER_H_ #define _RENDER_H_ #include "utils.h" // for gRect class lifealgo; // Routines for rendering the pattern view: #ifdef WEB_GUI bool InitOGLES2(); // Return true if we can create the shaders and program object // required by OpenGL ES 2. #endif void DrawPattern(int tileindex); // Draw the current pattern, grid lines, selection, etc. // The given tile index is only used when drawing tiled layers. void CreatePasteImage(lifealgo* pastealgo, gRect& bbox); // Create an image used to draw the given paste pattern. // The given bounding box is not necessarily the *minimal* bounding box because // the paste pattern might have blank borders (in fact it could be empty). void DestroyPasteImage(); // Destroy the image created above (call when user ends paste). #endif golly-2.7-src/gui-common/select.cpp0000644000175000017500000020671012536111364014263 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include "lifealgo.h" #include "viewport.h" #include "utils.h" // for Warning, PollerReset, etc #include "prefs.h" // for randomfill, etc #include "status.h" // for Stringify, etc #include "undo.h" // for currlayer->undoredo->... #include "algos.h" // for *_ALGO, CreateNewUniverse #include "layer.h" // for currlayer, MarkLayerDirty, etc #include "view.h" // for OutsideLimits, etc #include "control.h" // for generating, etc #include "file.h" // for CreateUniverse #include "select.h" #ifdef ANDROID_GUI #include "jnicalls.h" // for BeginProgress, etc #endif #ifdef WEB_GUI #include "webcalls.h" // for BeginProgress, etc #endif #ifdef IOS_GUI #import "PatternViewController.h" // for BeginProgress, etc #endif // ----------------------------------------------------------------------------- Selection::Selection() { exists = false; } // ----------------------------------------------------------------------------- Selection::Selection(int t, int l, int b, int r) { // create rectangular selection if given edges are valid exists = (t <= b && l <= r); if (exists) { seltop = t; selleft = l; selbottom = b; selright = r; } } // ----------------------------------------------------------------------------- Selection::~Selection() { // no need to do anything at the moment } // ----------------------------------------------------------------------------- bool Selection::operator==(const Selection& s) const { if (!exists && !s.exists) { // neither selection exists return true; } else if (exists && s.exists) { // check if edges match return (seltop == s.seltop && selleft == s.selleft && selbottom == s.selbottom && selright == s.selright); } else { // one selection exists but not the other return false; } } // ----------------------------------------------------------------------------- bool Selection::operator!=(const Selection& s) const { return !(*this == s); } // ----------------------------------------------------------------------------- bool Selection::Exists() { return exists; } // ----------------------------------------------------------------------------- void Selection::Deselect() { exists = false; } // ----------------------------------------------------------------------------- bool Selection::TooBig() { return OutsideLimits(seltop, selleft, selbottom, selright); } // ----------------------------------------------------------------------------- void Selection::DisplaySize() { if (inscript) return; bigint wd = selright; wd -= selleft; wd += bigint::one; bigint ht = selbottom; ht -= seltop; ht += bigint::one; std::string msg = "Selection width x height = "; msg += Stringify(wd); msg += " x "; msg += Stringify(ht); #ifdef WEB_GUI msg += " (right-click on it to perform actions)"; #endif SetMessage(msg.c_str()); } // ----------------------------------------------------------------------------- void Selection::SetRect(int x, int y, int wd, int ht) { exists = (wd > 0 && ht > 0); if (exists) { seltop = y; selleft = x; // avoid int overflow ht--; wd--; selbottom = y; selbottom += ht; selright = x; selright += wd; } } // ----------------------------------------------------------------------------- void Selection::GetRect(int* x, int* y, int* wd, int* ht) { *x = selleft.toint(); *y = seltop.toint(); *wd = selright.toint() - *x + 1; *ht = selbottom.toint() - *y + 1; } // ----------------------------------------------------------------------------- void Selection::SetEdges(bigint& t, bigint& l, bigint& b, bigint& r) { exists = true; seltop = t; selleft = l; selbottom = b; selright = r; CheckGridEdges(); } // ----------------------------------------------------------------------------- void Selection::CheckGridEdges() { if (exists) { // change selection edges if necessary to ensure they are inside a bounded grid if (currlayer->algo->gridwd > 0) { if (selleft > currlayer->algo->gridright || selright < currlayer->algo->gridleft) { exists = false; // selection is outside grid return; } if (selleft < currlayer->algo->gridleft) selleft = currlayer->algo->gridleft; if (selright > currlayer->algo->gridright) selright = currlayer->algo->gridright; } if (currlayer->algo->gridht > 0) { if (seltop > currlayer->algo->gridbottom || selbottom < currlayer->algo->gridtop) { exists = false; // selection is outside grid return; } if (seltop < currlayer->algo->gridtop) seltop = currlayer->algo->gridtop; if (selbottom > currlayer->algo->gridbottom) selbottom = currlayer->algo->gridbottom; } } } // ----------------------------------------------------------------------------- bool Selection::Contains(bigint& t, bigint& l, bigint& b, bigint& r) { return ( seltop <= t && selleft <= l && selbottom >= b && selright >= r ); } // ----------------------------------------------------------------------------- bool Selection::Outside(bigint& t, bigint& l, bigint& b, bigint& r) { return ( seltop > b || selleft > r || selbottom < t || selright < l ); } // ----------------------------------------------------------------------------- bool Selection::ContainsCell(int x, int y) { return ( x >= selleft.toint() && x <= selright.toint() && y >= seltop.toint() && y <= selbottom.toint() ); } // ----------------------------------------------------------------------------- bool Selection::SaveDifferences(lifealgo* oldalgo, lifealgo* newalgo, int itop, int ileft, int ibottom, int iright) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; // compare patterns in given algos and call SaveCellChange for each different cell BeginProgress("Saving cell changes"); for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int oldstate = oldalgo->getcell(cx, cy); int newstate = newalgo->getcell(cx, cy); if ( oldstate != newstate ) { // assume this is only called if allowundo currlayer->undoredo->SaveCellChange(cx, cy, oldstate, newstate); } cntr++; if ((cntr % 4096) == 0) { abort = AbortProgress((double)cntr / maxcount, ""); if (abort) break; } } if (abort) break; } EndProgress(); return !abort; } // ----------------------------------------------------------------------------- void Selection::Advance() { if (generating) return; if (!exists) { ErrorMessage(no_selection); return; } if (currlayer->algo->isEmpty()) { ErrorMessage(empty_selection); return; } bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); // check if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { ErrorMessage(empty_selection); return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; //!!! if (savecells && inscript) SavePendingChanges(); bool boundedgrid = (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0); // check if selection encloses entire pattern; // can't do this if qlife because it uses gen parity to decide which bits to draw; // also avoid this if undo/redo is enabled (too messy to remember cell changes) if ( currlayer->algtype != QLIFE_ALGO && !savecells && Contains(top, left, bottom, right) ) { generating = true; PollerReset(); // step by one gen without changing gen count bigint savegen = currlayer->algo->getGeneration(); bigint saveinc = currlayer->algo->getIncrement(); currlayer->algo->setIncrement(1); if (boundedgrid) CreateBorderCells(currlayer->algo); currlayer->algo->step(); if (boundedgrid) DeleteBorderCells(currlayer->algo); currlayer->algo->setIncrement(saveinc); currlayer->algo->setGeneration(savegen); generating = false; // clear 1-cell thick strips just outside selection ClearOutside(); MarkLayerDirty(); UpdateEverything(); return; } // find intersection of selection and pattern to minimize work if (seltop > top) top = seltop; if (selleft > left) left = selleft; if (selbottom < bottom) bottom = selbottom; if (selright < right) right = selright; // check that intersection is within setcell/getcell limits if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage(selection_too_big); return; } // create a temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype); if (tempalgo->setrule(currlayer->algo->getrule())) tempalgo->setrule(tempalgo->DefaultRule()); // copy live cells in selection to temporary universe if ( !CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, tempalgo, false, "Saving selection") ) { delete tempalgo; return; } if ( tempalgo->isEmpty() ) { ErrorMessage(empty_selection); delete tempalgo; return; } // advance temporary universe by one gen generating = true; PollerReset(); tempalgo->setIncrement(1); if (boundedgrid) CreateBorderCells(tempalgo); tempalgo->step(); if (boundedgrid) DeleteBorderCells(tempalgo); generating = false; if ( !tempalgo->isEmpty() ) { // temporary pattern might have expanded bigint temptop, templeft, tempbottom, tempright; tempalgo->findedges(&temptop, &templeft, &tempbottom, &tempright); if (temptop < top) top = temptop; if (templeft < left) left = templeft; if (tempbottom > bottom) bottom = tempbottom; if (tempright > right) right = tempright; // but ignore live cells created outside selection edges if (top < seltop) top = seltop; if (left < selleft) left = selleft; if (bottom > selbottom) bottom = selbottom; if (right > selright) right = selright; } if (savecells) { // compare selection rect in currlayer->algo and tempalgo and call SaveCellChange // for each cell that has a different state if ( SaveDifferences(currlayer->algo, tempalgo, top.toint(), left.toint(), bottom.toint(), right.toint()) ) { if ( !currlayer->undoredo->RememberCellChanges("Advance Selection", currlayer->dirty) ) { // pattern inside selection didn't change delete tempalgo; return; } } else { currlayer->undoredo->ForgetCellChanges(); delete tempalgo; return; } } // copy all cells in new selection from tempalgo to currlayer->algo CopyAllRect(top.toint(), left.toint(), bottom.toint(), right.toint(), tempalgo, currlayer->algo, "Copying advanced selection"); delete tempalgo; MarkLayerDirty(); UpdateEverything(); } // ----------------------------------------------------------------------------- void Selection::AdvanceOutside() { if (generating) return; if (!exists) { ErrorMessage(no_selection); return; } if (currlayer->algo->isEmpty()) { ErrorMessage(empty_outside); return; } bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); // check if selection encloses entire pattern if (Contains(top, left, bottom, right)) { ErrorMessage(empty_outside); return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; //!!! if (savecells && inscript) SavePendingChanges(); bool boundedgrid = (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0); // check if selection is completely outside pattern edges; // can't do this if qlife because it uses gen parity to decide which bits to draw; // also avoid this if undo/redo is enabled (too messy to remember cell changes) if ( currlayer->algtype != QLIFE_ALGO && !savecells && Outside(top, left, bottom, right) ) { generating = true; PollerReset(); // step by one gen without changing gen count bigint savegen = currlayer->algo->getGeneration(); bigint saveinc = currlayer->algo->getIncrement(); currlayer->algo->setIncrement(1); if (boundedgrid) CreateBorderCells(currlayer->algo); currlayer->algo->step(); if (boundedgrid) DeleteBorderCells(currlayer->algo); currlayer->algo->setIncrement(saveinc); currlayer->algo->setGeneration(savegen); generating = false; // clear selection in case pattern expanded into it Clear(); MarkLayerDirty(); UpdateEverything(); return; } // check that pattern is within setcell/getcell limits if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Pattern is outside +/- 10^9 boundary."); return; } lifealgo* oldalgo = NULL; if (savecells) { // copy current pattern to oldalgo, using same type and gen count // so we can switch to oldalgo if user decides to abort below oldalgo = CreateNewUniverse(currlayer->algtype); if (oldalgo->setrule(currlayer->algo->getrule())) oldalgo->setrule(oldalgo->DefaultRule()); oldalgo->setGeneration( currlayer->algo->getGeneration() ); if ( !CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, oldalgo, false, "Saving pattern") ) { delete oldalgo; return; } } // create a new universe of same type lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); if (newalgo->setrule(currlayer->algo->getrule())) newalgo->setrule(newalgo->DefaultRule()); newalgo->setGeneration( currlayer->algo->getGeneration() ); // copy (and kill) live cells in selection to new universe int iseltop = seltop.toint(); int iselleft = selleft.toint(); int iselbottom = selbottom.toint(); int iselright = selright.toint(); if ( !CopyRect(iseltop, iselleft, iselbottom, iselright, currlayer->algo, newalgo, true, "Saving and erasing selection") ) { // aborted, so best to restore selection if ( !newalgo->isEmpty() ) { newalgo->findedges(&top, &left, &bottom, &right); CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), newalgo, currlayer->algo, false, "Restoring selection"); } delete newalgo; if (savecells) delete oldalgo; UpdateEverything(); return; } // advance current universe by 1 generation generating = true; PollerReset(); currlayer->algo->setIncrement(1); if (boundedgrid) CreateBorderCells(currlayer->algo); currlayer->algo->step(); if (boundedgrid) DeleteBorderCells(currlayer->algo); generating = false; if ( !currlayer->algo->isEmpty() ) { // find new edges and copy current pattern to new universe, // except for any cells that were created in selection // (newalgo contains the original selection) bigint t, l, b, r; currlayer->algo->findedges(&t, &l, &b, &r); int itop = t.toint(); int ileft = l.toint(); int ibottom = b.toint(); int iright = r.toint(); int ht = ibottom - itop + 1; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = currlayer->algo->getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; int v = 0; bool abort = false; BeginProgress("Copying advanced pattern"); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { currcount++; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; // only copy cell if outside selection if ( cx < iselleft || cx > iselright || cy < iseltop || cy > iselbottom ) { newalgo->setcell(cx, cy, v); } currcount++; } else { cx = iright; // done this row } if (currcount > 1024) { accumcount += currcount; currcount = 0; abort = AbortProgress(accumcount / maxcount, ""); if (abort) break; } } if (abort) break; } newalgo->endofpattern(); EndProgress(); if (abort && savecells) { // revert back to pattern saved in oldalgo delete newalgo; delete currlayer->algo; currlayer->algo = oldalgo; SetGenIncrement(); UpdateEverything(); return; } } // switch to new universe (best to do this even if aborted) delete currlayer->algo; currlayer->algo = newalgo; SetGenIncrement(); if (savecells) { // compare patterns in oldalgo and currlayer->algo and call SaveCellChange // for each cell that has a different state; note that we need to compare // the union of the original pattern's rect and the new pattern's rect int otop = top.toint(); int oleft = left.toint(); int obottom = bottom.toint(); int oright = right.toint(); if (!currlayer->algo->isEmpty()) { currlayer->algo->findedges(&top, &left, &bottom, &right); int ntop = top.toint(); int nleft = left.toint(); int nbottom = bottom.toint(); int nright = right.toint(); if (ntop < otop) otop = ntop; if (nleft < oleft) oleft = nleft; if (nbottom > obottom) obottom = nbottom; if (nright > oright) oright = nright; } if ( SaveDifferences(oldalgo, currlayer->algo, otop, oleft, obottom, oright) ) { delete oldalgo; if ( !currlayer->undoredo->RememberCellChanges("Advance Outside", currlayer->dirty) ) { // pattern outside selection didn't change UpdateEverything(); return; } } else { // revert back to pattern saved in oldalgo currlayer->undoredo->ForgetCellChanges(); delete currlayer->algo; currlayer->algo = oldalgo; SetGenIncrement(); UpdateEverything(); return; } } MarkLayerDirty(); UpdateEverything(); } // ----------------------------------------------------------------------------- void Selection::Modify(const int x, const int y, bigint& anchorx, bigint& anchory, bool* forceh, bool* forcev) { // assume tapped point is somewhere inside selection pair lt = currlayer->view->screenPosOf(selleft, seltop, currlayer->algo); pair rb = currlayer->view->screenPosOf(selright, selbottom, currlayer->algo); if (currlayer->view->getmag() > 0) { // move rb to pixel at bottom right corner of cell rb.first += (1 << currlayer->view->getmag()) - 1; rb.second += (1 << currlayer->view->getmag()) - 1; if (currlayer->view->getmag() > 1) { // allow for gap at scale 1:4 and above rb.first--; rb.second--; } } double wd = rb.first - lt.first + 1; double ht = rb.second - lt.second + 1; double onefifthx = lt.first + wd / 5.0; double fourfifthx = lt.first + wd * 4.0 / 5.0; double onefifthy = lt.second + ht / 5.0; double fourfifthy = lt.second + ht * 4.0 / 5.0; if ( y < onefifthy && x < onefifthx ) { // tap is near top left corner anchory = selbottom; anchorx = selright; } else if ( y < onefifthy && x > fourfifthx ) { // tap is near top right corner anchory = selbottom; anchorx = selleft; } else if ( y > fourfifthy && x > fourfifthx ) { // tap is near bottom right corner anchory = seltop; anchorx = selleft; } else if ( y > fourfifthy && x < onefifthx ) { // tap is near bottom left corner anchory = seltop; anchorx = selright; } else if ( x < onefifthx ) { // tap is near left edge *forceh = true; anchorx = selright; } else if ( x > fourfifthx ) { // tap is near right edge *forceh = true; anchorx = selleft; } else if ( y < onefifthy ) { // tap is near top edge *forcev = true; anchory = selbottom; } else if ( y > fourfifthy ) { // tap is near bottom edge *forcev = true; anchory = seltop; } else { // tap is in middle area, so move selection rather than resize *forceh = true; *forcev = true; } } // ----------------------------------------------------------------------------- void Selection::Move(const bigint& xcells, const bigint& ycells) { if (exists) { selleft += xcells; selright += xcells; seltop += ycells; selbottom += ycells; CheckGridEdges(); } } // ----------------------------------------------------------------------------- void Selection::SetLeftRight(const bigint& x, const bigint& anchorx) { if (x <= anchorx) { selleft = x; selright = anchorx; } else { selleft = anchorx; selright = x; } exists = true; } // ----------------------------------------------------------------------------- void Selection::SetTopBottom(const bigint& y, const bigint& anchory) { if (y <= anchory) { seltop = y; selbottom = anchory; } else { seltop = anchory; selbottom = y; } exists = true; } // ----------------------------------------------------------------------------- void Selection::Fit() { bigint newx = selright; newx -= selleft; newx += bigint::one; newx.div2(); newx += selleft; bigint newy = selbottom; newy -= seltop; newy += bigint::one; newy.div2(); newy += seltop; int mag = MAX_MAG; while (true) { currlayer->view->setpositionmag(newx, newy, mag); if (currlayer->view->contains(selleft, seltop) && currlayer->view->contains(selright, selbottom)) break; mag--; } } // ----------------------------------------------------------------------------- void Selection::Shrink(bool fit) { if (!exists) return; // check if there is no pattern if (currlayer->algo->isEmpty()) { ErrorMessage(empty_selection); if (fit) FitSelection(); return; } // check if selection encloses entire pattern bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if (Contains(top, left, bottom, right)) { // shrink edges SaveCurrentSelection(); seltop = top; selleft = left; selbottom = bottom; selright = right; RememberNewSelection("Shrink Selection"); DisplaySelectionSize(); if (fit) FitSelection(); // calls UpdateEverything else UpdatePatternAndStatus(); return; } // check if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { ErrorMessage(empty_selection); if (fit) FitSelection(); return; } // find intersection of selection and pattern to minimize work if (seltop > top) top = seltop; if (selleft > left) left = selleft; if (selbottom < bottom) bottom = selbottom; if (selright < right) right = selright; // check that selection is small enough to save if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage(selection_too_big); if (fit) FitSelection(); return; } // the easy way to shrink selection is to create a new temporary universe, // copy selection into new universe and then call findedges; // if only 2 cell states then use qlife because its findedges call is faster lifealgo* tempalgo = CreateNewUniverse(currlayer->algo->NumCellStates() > 2 ? currlayer->algtype : QLIFE_ALGO); // make sure temporary universe has same # of cell states if (currlayer->algo->NumCellStates() > 2) if (tempalgo->setrule(currlayer->algo->getrule())) tempalgo->setrule(tempalgo->DefaultRule()); // copy live cells in selection to temporary universe if ( CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, tempalgo, false, "Copying selection") ) { if ( tempalgo->isEmpty() ) { ErrorMessage(empty_selection); } else { SaveCurrentSelection(); tempalgo->findedges(&seltop, &selleft, &selbottom, &selright); RememberNewSelection("Shrink Selection"); DisplaySelectionSize(); if (!fit) UpdatePatternAndStatus(); } } delete tempalgo; if (fit) FitSelection(); } // ----------------------------------------------------------------------------- bool Selection::Visible(gRect* visrect) { if (!exists) return false; pair lt = currlayer->view->screenPosOf(selleft, seltop, currlayer->algo); pair rb = currlayer->view->screenPosOf(selright, selbottom, currlayer->algo); if (lt.first > currlayer->view->getxmax() || rb.first < 0 || lt.second > currlayer->view->getymax() || rb.second < 0) { // no part of selection is visible return false; } // all or some of selection is visible in viewport; // only set visible rectangle if requested if (visrect) { // first we must clip coords to viewport if (lt.first < 0) lt.first = 0; if (lt.second < 0) lt.second = 0; if (rb.first > currlayer->view->getxmax()) rb.first = currlayer->view->getxmax(); if (rb.second > currlayer->view->getymax()) rb.second = currlayer->view->getymax(); if (currlayer->view->getmag() > 0) { // move rb to pixel at bottom right corner of cell rb.first += (1 << currlayer->view->getmag()) - 1; rb.second += (1 << currlayer->view->getmag()) - 1; if (currlayer->view->getmag() > 1) { // avoid covering gaps at scale 1:4 and above rb.first--; rb.second--; } // clip to viewport again if (rb.first > currlayer->view->getxmax()) rb.first = currlayer->view->getxmax(); if (rb.second > currlayer->view->getymax()) rb.second = currlayer->view->getymax(); } visrect->x = lt.first; visrect->y = lt.second; visrect->width = rb.first - lt.first + 1; visrect->height = rb.second - lt.second + 1; } return true; } // ----------------------------------------------------------------------------- void Selection::EmptyUniverse() { // save current step, scale, position and gen count int savebase = currlayer->currbase; int saveexpo = currlayer->currexpo; int savemag = currlayer->view->getmag(); bigint savex = currlayer->view->x; bigint savey = currlayer->view->y; bigint savegen = currlayer->algo->getGeneration(); // kill all live cells by replacing the current universe with a // new, empty universe which also uses the same rule CreateUniverse(); // restore step, scale, position and gen count currlayer->currbase = savebase; SetStepExponent(saveexpo); // SetStepExponent calls SetGenIncrement currlayer->view->setpositionmag(savex, savey, savemag); currlayer->algo->setGeneration(savegen); UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void Selection::Clear() { if (!exists) return; // no need to do anything if there is no pattern if (currlayer->algo->isEmpty()) return; // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; //!!! if (savecells && inscript) SavePendingChanges(); bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( !savecells && Contains(top, left, bottom, right) ) { // selection encloses entire pattern so just create empty universe EmptyUniverse(); MarkLayerDirty(); return; } // no need to do anything if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { return; } // find intersection of selection and pattern to minimize work if (seltop > top) top = seltop; if (selleft > left) left = selleft; if (selbottom < bottom) bottom = selbottom; if (selright < right) right = selright; // can only use setcell in limited domain if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage(selection_too_big); return; } // clear all live cells in selection int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; double maxcount = (double)wd * (double)ht; int cntr = 0; int v = 0; bool abort = false; bool selchanged = false; BeginProgress("Clearing selection"); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; curralgo->setcell(cx, cy, 0); selchanged = true; if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, v, 0); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, ""); if (abort) break; } } if (abort) break; } if (selchanged) curralgo->endofpattern(); EndProgress(); if (selchanged) { if (savecells) currlayer->undoredo->RememberCellChanges("Clear", currlayer->dirty); MarkLayerDirty(); UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- bool Selection::SaveOutside(bigint& t, bigint& l, bigint& b, bigint& r) { if ( OutsideLimits(t, l, b, r) ) { ErrorMessage(pattern_too_big); return false; } int itop = t.toint(); int ileft = l.toint(); int ibottom = b.toint(); int iright = r.toint(); // save ALL cells if selection is completely outside pattern edges bool saveall = Outside(t, l, b, r); // integer selection edges must not be outside pattern edges int stop = itop; int sleft = ileft; int sbottom = ibottom; int sright = iright; if (!saveall) { if (seltop > t) stop = seltop.toint(); if (selleft > l) sleft = selleft.toint(); if (selbottom < b) sbottom = selbottom.toint(); if (selright < r) sright = selright.toint(); } int wd = iright - ileft + 1; int ht = ibottom - itop + 1; int cx, cy; int v = 0; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; BeginProgress("Saving outside selection"); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; if (saveall || cx < sleft || cx > sright || cy < stop || cy > sbottom) { // cell is outside selection edges currlayer->undoredo->SaveCellChange(cx, cy, v, 0); } } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, ""); if (abort) break; } } if (abort) break; } EndProgress(); if (abort) currlayer->undoredo->ForgetCellChanges(); return !abort; } // ----------------------------------------------------------------------------- void Selection::ClearOutside() { if (!exists) return; // no need to do anything if there is no pattern if (currlayer->algo->isEmpty()) return; // no need to do anything if selection encloses entire pattern bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if (Contains(top, left, bottom, right)) { return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; //!!! if (savecells && inscript) SavePendingChanges(); if (savecells) { // save live cells outside selection if ( !SaveOutside(top, left, bottom, right) ) { return; } } else { // create empty universe if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { EmptyUniverse(); MarkLayerDirty(); return; } } // find intersection of selection and pattern to minimize work if (seltop > top) top = seltop; if (selleft > left) left = selleft; if (selbottom < bottom) bottom = selbottom; if (selright < right) right = selright; // check that selection is small enough to save if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage(selection_too_big); return; } // create a new universe of same type lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); if (newalgo->setrule(currlayer->algo->getrule())) newalgo->setrule(newalgo->DefaultRule()); // set same gen count newalgo->setGeneration( currlayer->algo->getGeneration() ); // copy live cells in selection to new universe if ( CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, newalgo, false, "Saving selection") ) { // delete old universe and point currlayer->algo at new universe delete currlayer->algo; currlayer->algo = newalgo; SetGenIncrement(); if (savecells) currlayer->undoredo->RememberCellChanges("Clear Outside", currlayer->dirty); MarkLayerDirty(); UpdatePatternAndStatus(); } else { // CopyRect was aborted, so don't change current universe delete newalgo; if (savecells) currlayer->undoredo->ForgetCellChanges(); } } // ----------------------------------------------------------------------------- void Selection::AddEOL(char* &chptr) { // use LF on Mac *chptr = '\n'; chptr += 1; } // ----------------------------------------------------------------------------- const int WRLE_NONE = -3; const int WRLE_EOP = -2; const int WRLE_NEWLINE = -1; void Selection::AddRun(int state, // in: state of cell to write int multistate, // true if #cell states > 2 unsigned int &run, // in and out unsigned int &linelen, // ditto char* &chptr) // ditto { // output of RLE pattern data is channelled thru here to make it easier to // ensure all lines have <= maxrleline characters const unsigned int maxrleline = 70; unsigned int i, numlen; char numstr[32]; if ( run > 1 ) { sprintf(numstr, "%u", run); numlen = strlen(numstr); } else { numlen = 0; // no run count shown if 1 } // keep linelen <= maxrleline if ( linelen + numlen + 1 + multistate > maxrleline ) { AddEOL(chptr); linelen = 0; } i = 0; while (i < numlen) { *chptr = numstr[i]; chptr += 1; i++; } if (multistate) { if (state <= 0) *chptr = ".$!"[-state]; else { if (state > 24) { int hi = (state - 25) / 24; *chptr = hi + 'p'; chptr += 1; linelen += 1; state -= (hi + 1) * 24; } *chptr = 'A' + state - 1; } } else *chptr = "!$bo"[state+2]; chptr += 1; linelen += numlen + 1; run = 0; // reset run count } // ----------------------------------------------------------------------------- void Selection::CopyToClipboard(bool cut) { // can only use getcell/setcell in limited domain if (TooBig()) { ErrorMessage(selection_too_big); return; } int itop = seltop.toint(); int ileft = selleft.toint(); int ibottom = selbottom.toint(); int iright = selright.toint(); unsigned int wd = iright - ileft + 1; unsigned int ht = ibottom - itop + 1; // convert cells in selection to RLE data in textptr char* textptr; char* etextptr; int cursize = 4096; textptr = (char*)malloc(cursize); if (textptr == NULL) { ErrorMessage("Not enough memory for clipboard data!"); return; } etextptr = textptr + cursize; // add RLE header line sprintf(textptr, "x = %u, y = %u, rule = %s", wd, ht, currlayer->algo->getrule()); char* chptr = textptr; chptr += strlen(textptr); AddEOL(chptr); // save start of data in case livecount is zero int datastart = chptr - textptr; // add RLE pattern data unsigned int livecount = 0; unsigned int linelen = 0; unsigned int brun = 0; unsigned int orun = 0; unsigned int dollrun = 0; int laststate; int cx, cy; int v = 0; // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; //!!! if (savecells && inscript) SavePendingChanges(); double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; if (cut) BeginProgress("Cutting selection"); else BeginProgress("Copying selection"); lifealgo* curralgo = currlayer->algo; int multistate = curralgo->NumCellStates() > 2; for ( cy=itop; cy<=ibottom; cy++ ) { laststate = WRLE_NONE; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip > 0) { // have exactly "skip" empty cells here if (laststate == 0) { brun += skip; } else { if (orun > 0) { // output current run of live cells AddRun(laststate, multistate, orun, linelen, chptr); } laststate = 0; brun = skip; } } if (skip >= 0) { // found next live cell cx += skip; livecount++; if (cut) { curralgo->setcell(cx, cy, 0); if (savecells) currlayer->undoredo->SaveCellChange(cx, cy, v, 0); } if (laststate == v) { orun++; } else { if (dollrun > 0) // output current run of $ chars AddRun(WRLE_NEWLINE, multistate, dollrun, linelen, chptr); if (brun > 0) // output current run of dead cells AddRun(0, multistate, brun, linelen, chptr); if (orun > 0) // output current run of other live cells AddRun(laststate, multistate, orun, linelen, chptr); laststate = v; orun = 1; } } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, ""); if (abort) break; } if (chptr + 60 >= etextptr) { // nearly out of space; try to increase allocation char* ntxtptr = (char*) realloc(textptr, 2*cursize); if (ntxtptr == 0) { ErrorMessage("No more memory for clipboard data!"); // don't return here -- best to set abort flag and break so that // partially cut/copied portion gets saved to clipboard abort = true; break; } chptr = ntxtptr + (chptr - textptr); cursize *= 2; etextptr = ntxtptr + cursize; textptr = ntxtptr; } } if (abort) break; // end of current row if (laststate == 0) // forget dead cells at end of row brun = 0; else if (laststate >= 0) // output current run of live cells AddRun(laststate, multistate, orun, linelen, chptr); dollrun++; } if (livecount == 0) { // no live cells in selection so simplify RLE data to "!" chptr = textptr + datastart; *chptr = '!'; chptr++; } else { // terminate RLE data dollrun = 1; AddRun(WRLE_EOP, multistate, dollrun, linelen, chptr); if (cut) currlayer->algo->endofpattern(); } AddEOL(chptr); *chptr = 0; EndProgress(); if (cut && livecount > 0) { if (savecells) currlayer->undoredo->RememberCellChanges("Cut", currlayer->dirty); // update currlayer->dirty AFTER RememberCellChanges MarkLayerDirty(); UpdatePatternAndStatus(); } CopyTextToClipboard(textptr); free(textptr); } // ----------------------------------------------------------------------------- bool Selection::CanPaste(const bigint& wd, const bigint& ht, bigint& top, bigint& left) { bigint selht = selbottom; selht -= seltop; selht += 1; bigint selwd = selright; selwd -= selleft; selwd += 1; if ( ht > selht || wd > selwd ) return false; // set paste rectangle's top left cell coord top = seltop; left = selleft; return true; } // ----------------------------------------------------------------------------- void Selection::RandomFill() { if (!exists) return; // can only use getcell/setcell in limited domain if (TooBig()) { ErrorMessage(selection_too_big); return; } // save cell changes if undo/redo is enabled and script isn't constructing a pattern bool savecells = allowundo && !currlayer->stayclean; //!!! if (savecells && inscript) SavePendingChanges(); // no need to kill cells if selection is empty bool killcells = !currlayer->algo->isEmpty(); if ( killcells ) { // find pattern edges and compare with selection edges bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if (Contains(top, left, bottom, right)) { // selection encloses entire pattern so create empty universe if (savecells) { // don't kill pattern otherwise we can't use SaveCellChange below } else { EmptyUniverse(); killcells = false; } } else if (Outside(top, left, bottom, right)) { // selection is completely outside pattern edges killcells = false; } } int itop = seltop.toint(); int ileft = selleft.toint(); int ibottom = selbottom.toint(); int iright = selright.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; BeginProgress("Randomly filling selection"); int cx, cy; lifealgo* curralgo = currlayer->algo; int livestates = curralgo->NumCellStates() - 1; // don't count dead state for ( cy=itop; cy<=ibottom; cy++ ) { for ( cx=ileft; cx<=iright; cx++ ) { // randomfill is from 1..100 if (savecells) { // remember cell change only if state changes int oldstate = curralgo->getcell(cx, cy); if ((rand() % 100) < randomfill) { int newstate = livestates < 2 ? 1 : 1 + (rand() % livestates); if (oldstate != newstate) { curralgo->setcell(cx, cy, newstate); currlayer->undoredo->SaveCellChange(cx, cy, oldstate, newstate); } } else if (killcells && oldstate > 0) { curralgo->setcell(cx, cy, 0); currlayer->undoredo->SaveCellChange(cx, cy, oldstate, 0); } } else { if ((rand() % 100) < randomfill) { if (livestates < 2) { curralgo->setcell(cx, cy, 1); } else { curralgo->setcell(cx, cy, 1 + (rand() % livestates)); } } else if (killcells) { curralgo->setcell(cx, cy, 0); } } cntr++; if ((cntr % 4096) == 0) { abort = AbortProgress((double)cntr / maxcount, ""); if (abort) break; } } if (abort) break; } currlayer->algo->endofpattern(); EndProgress(); if (savecells) currlayer->undoredo->RememberCellChanges("Random Fill", currlayer->dirty); // update currlayer->dirty AFTER RememberCellChanges MarkLayerDirty(); UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- bool Selection::FlipRect(bool topbottom, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, int itop, int ileft, int ibottom, int iright) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; int v = 0; int cx, cy, newx, newy, newxinc, newyinc; if (topbottom) { BeginProgress("Flipping top-bottom"); newy = ibottom; newyinc = -1; newxinc = 1; } else { BeginProgress("Flipping left-right"); newy = itop; newyinc = 1; newxinc = -1; } for ( cy=itop; cy<=ibottom; cy++ ) { newx = topbottom ? ileft : iright; for ( cx=ileft; cx<=iright; cx++ ) { int skip = srcalgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; if (erasesrc) srcalgo->setcell(cx, cy, 0); newx += newxinc * skip; destalgo->setcell(newx, newy, v); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, ""); if (abort) break; } newx += newxinc; } if (abort) break; newy += newyinc; } if (erasesrc) srcalgo->endofpattern(); destalgo->endofpattern(); EndProgress(); return !abort; } // ----------------------------------------------------------------------------- bool Selection::Flip(bool topbottom, bool inundoredo) { if (!exists) return false; if (topbottom) { if (seltop == selbottom) return true; } else { if (selleft == selright) return true; } if (currlayer->algo->isEmpty()) return true; bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); bigint stop = seltop; bigint sleft = selleft; bigint sbottom = selbottom; bigint sright = selright; bool simpleflip; if (Contains(top, left, bottom, right)) { // selection encloses entire pattern so we may only need to flip a smaller rectangle if (topbottom) { bigint tdiff = top; tdiff -= stop; bigint bdiff = sbottom; bdiff -= bottom; bigint mindiff = tdiff; if (bdiff < mindiff) mindiff = bdiff; stop += mindiff; sbottom -= mindiff; sleft = left; sright = right; } else { bigint ldiff = left; ldiff -= sleft; bigint rdiff = sright; rdiff -= right; bigint mindiff = ldiff; if (rdiff < mindiff) mindiff = rdiff; sleft += mindiff; sright -= mindiff; stop = top; sbottom = bottom; } simpleflip = true; } else { // selection encloses part of pattern so we can clip some selection edges // if they are outside the pattern edges if (topbottom) { if (sleft < left) sleft = left; if (sright > right) sright = right; } else { if (stop < top) stop = top; if (sbottom > bottom) sbottom = bottom; } simpleflip = false; } // can only use getcell/setcell in limited domain if ( OutsideLimits(stop, sbottom, sleft, sright) ) { ErrorMessage(selection_too_big); return false; } int itop = stop.toint(); int ileft = sleft.toint(); int ibottom = sbottom.toint(); int iright = sright.toint(); if (simpleflip) { // selection encloses all of pattern so we can flip into new universe // (must be same type) without killing live cells in selection lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); if (newalgo->setrule(currlayer->algo->getrule())) newalgo->setrule(newalgo->DefaultRule()); newalgo->setGeneration( currlayer->algo->getGeneration() ); if ( FlipRect(topbottom, currlayer->algo, newalgo, false, itop, ileft, ibottom, iright) ) { // switch to newalgo delete currlayer->algo; currlayer->algo = newalgo; SetGenIncrement(); } else { // user aborted flip delete newalgo; return false; } } else { // flip into temporary universe and kill all live cells in selection; // if only 2 cell states then use qlife because its setcell/getcell calls are faster lifealgo* tempalgo = CreateNewUniverse(currlayer->algo->NumCellStates() > 2 ? currlayer->algtype : QLIFE_ALGO); // make sure temporary universe has same # of cell states if (currlayer->algo->NumCellStates() > 2) if (tempalgo->setrule(currlayer->algo->getrule())) tempalgo->setrule(tempalgo->DefaultRule()); if ( FlipRect(topbottom, currlayer->algo, tempalgo, true, itop, ileft, ibottom, iright) ) { // find pattern edges in temporary universe (could be much smaller) // and copy temporary pattern into current universe tempalgo->findedges(&top, &left, &bottom, &right); CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), tempalgo, currlayer->algo, false, "Adding flipped selection"); delete tempalgo; } else { // user aborted flip so flip tempalgo pattern back into current universe FlipRect(topbottom, tempalgo, currlayer->algo, false, itop, ileft, ibottom, iright); delete tempalgo; return false; } } // flips are always reversible so no need to use SaveCellChange and RememberCellChanges if (allowundo && !currlayer->stayclean && !inundoredo) { //!!! if (inscript) SavePendingChanges(); currlayer->undoredo->RememberFlip(topbottom, currlayer->dirty); } // update currlayer->dirty AFTER RememberFlip if (!inundoredo) MarkLayerDirty(); UpdatePatternAndStatus(); return true; } // ----------------------------------------------------------------------------- const char* rotate_clockwise = "Rotating selection +90 degrees"; const char* rotate_anticlockwise = "Rotating selection -90 degrees"; bool Selection::RotateRect(bool clockwise, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, int itop, int ileft, int ibottom, int iright, int ntop, int nleft, int nbottom, int nright) { int wd = iright - ileft + 1; int ht = ibottom - itop + 1; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; int cx, cy, newx, newy, newxinc, newyinc, v=0; if (clockwise) { BeginProgress(rotate_clockwise); newx = nright; newyinc = 1; newxinc = -1; } else { BeginProgress(rotate_anticlockwise); newx = nleft; newyinc = -1; newxinc = 1; } for ( cy=itop; cy<=ibottom; cy++ ) { newy = clockwise ? ntop : nbottom; for ( cx=ileft; cx<=iright; cx++ ) { int skip = srcalgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; if (erasesrc) srcalgo->setcell(cx, cy, 0); newy += newyinc * skip; destalgo->setcell(newx, newy, v); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, ""); if (abort) break; } newy += newyinc; } if (abort) break; newx += newxinc; } if (erasesrc) srcalgo->endofpattern(); destalgo->endofpattern(); EndProgress(); return !abort; } // ----------------------------------------------------------------------------- bool Selection::RotatePattern(bool clockwise, bigint& newtop, bigint& newbottom, bigint& newleft, bigint& newright, bool inundoredo) { // create new universe of same type as current universe lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); if (newalgo->setrule(currlayer->algo->getrule())) newalgo->setrule(newalgo->DefaultRule()); // set same gen count newalgo->setGeneration( currlayer->algo->getGeneration() ); // copy all live cells to new universe, rotating the coords by +/- 90 degrees int itop = seltop.toint(); int ileft = selleft.toint(); int ibottom = selbottom.toint(); int iright = selright.toint(); int wd = iright - ileft + 1; int ht = ibottom - itop + 1; double maxcount = (double)wd * (double)ht; int cntr = 0; bool abort = false; int cx, cy, newx, newy, newxinc, newyinc, firstnewy, v=0; if (clockwise) { BeginProgress(rotate_clockwise); firstnewy = newtop.toint(); newx = newright.toint(); newyinc = 1; newxinc = -1; } else { BeginProgress(rotate_anticlockwise); firstnewy = newbottom.toint(); newx = newleft.toint(); newyinc = -1; newxinc = 1; } lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { newy = firstnewy; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > iright) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell cx += skip; newy += newyinc * skip; newalgo->setcell(newx, newy, v); } else { cx = iright + 1; // done this row } cntr++; if ((cntr % 4096) == 0) { double prog = ((cy - itop) * (double)(iright - ileft + 1) + (cx - ileft)) / maxcount; abort = AbortProgress(prog, ""); if (abort) break; } newy += newyinc; } if (abort) break; newx += newxinc; } newalgo->endofpattern(); EndProgress(); if (abort) { delete newalgo; } else { // rotate the selection edges seltop = newtop; selbottom = newbottom; selleft = newleft; selright = newright; // switch to new universe and display results delete currlayer->algo; currlayer->algo = newalgo; SetGenIncrement(); DisplaySelectionSize(); // rotating entire pattern is easily reversible so no need to use // SaveCellChange and RememberCellChanges in this case if (allowundo && !currlayer->stayclean && !inundoredo) { //!!! if (inscript) SavePendingChanges(); currlayer->undoredo->RememberRotation(clockwise, currlayer->dirty); } // update currlayer->dirty AFTER RememberRotation if (!inundoredo) MarkLayerDirty(); UpdatePatternAndStatus(); } return !abort; } // ----------------------------------------------------------------------------- bool Selection::Rotate(bool clockwise, bool inundoredo) { if (!exists) return false; // determine rotated selection edges bigint halfht = selbottom; halfht -= seltop; halfht.div2(); bigint halfwd = selright; halfwd -= selleft; halfwd.div2(); bigint midy = seltop; midy += halfht; bigint midx = selleft; midx += halfwd; bigint newtop = midy; newtop += selleft; newtop -= midx; bigint newbottom = midy; newbottom += selright; newbottom -= midx; bigint newleft = midx; newleft += seltop; newleft -= midy; bigint newright = midx; newright += selbottom; newright -= midy; if (!inundoredo) { // check if rotated selection edges are outside bounded grid if ((currlayer->algo->gridwd > 0 && (newleft < currlayer->algo->gridleft || newright > currlayer->algo->gridright)) || (currlayer->algo->gridht > 0 && (newtop < currlayer->algo->gridtop || newbottom > currlayer->algo->gridbottom))) { ErrorMessage("New selection would be outside grid boundary."); return false; } } // if there is no pattern then just rotate the selection edges if (currlayer->algo->isEmpty()) { SaveCurrentSelection(); seltop = newtop; selbottom = newbottom; selleft = newleft; selright = newright; RememberNewSelection("Rotation"); DisplaySelectionSize(); UpdatePatternAndStatus(); return true; } // if the current selection and the rotated selection are both outside the // pattern edges (ie. both are empty) then just rotate the selection edges bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( (seltop > bottom || selbottom < top || selleft > right || selright < left) && (newtop > bottom || newbottom < top || newleft > right || newright < left) ) { SaveCurrentSelection(); seltop = newtop; selbottom = newbottom; selleft = newleft; selright = newright; RememberNewSelection("Rotation"); DisplaySelectionSize(); UpdatePatternAndStatus(); return true; } // can only use nextcell/getcell/setcell in limited domain if (TooBig()) { ErrorMessage(selection_too_big); return false; } // make sure rotated selection edges are also within limits if ( OutsideLimits(newtop, newbottom, newleft, newright) ) { ErrorMessage("New selection would be outside +/- 10^9 boundary."); return false; } // use faster method if selection encloses entire pattern if (Contains(top, left, bottom, right)) { return RotatePattern(clockwise, newtop, newbottom, newleft, newright, inundoredo); } int itop = seltop.toint(); int ileft = selleft.toint(); int ibottom = selbottom.toint(); int iright = selright.toint(); int ntop = newtop.toint(); int nleft = newleft.toint(); int nbottom = newbottom.toint(); int nright = newright.toint(); // save cell changes if undo/redo is enabled and script isn't constructing a pattern // and we're not undoing/redoing an earlier rotation bool savecells = allowundo && !currlayer->stayclean && !inundoredo; //!!! if (savecells && inscript) SavePendingChanges(); lifealgo* oldalgo = NULL; int otop = itop; int oleft = ileft; int obottom = ibottom; int oright = iright; if (savecells) { // copy current pattern to oldalgo using union of old and new selection rects if (otop > ntop) otop = ntop; if (oleft > nleft) oleft = nleft; if (obottom < nbottom) obottom = nbottom; if (oright < nright) oright = nright; oldalgo = CreateNewUniverse(currlayer->algo->NumCellStates() > 2 ? currlayer->algtype : QLIFE_ALGO); // make sure universe has same # of cell states if (currlayer->algo->NumCellStates() > 2) if (oldalgo->setrule(currlayer->algo->getrule())) oldalgo->setrule(oldalgo->DefaultRule()); if ( !CopyRect(otop, oleft, obottom, oright, currlayer->algo, oldalgo, false, "Saving part of pattern") ) { delete oldalgo; return false; } } // create temporary universe; doesn't need to match current universe so // if only 2 cell states then use qlife because its setcell/getcell calls are faster lifealgo* tempalgo = CreateNewUniverse(currlayer->algo->NumCellStates() > 2 ? currlayer->algtype : QLIFE_ALGO); // make sure temporary universe has same # of cell states if (currlayer->algo->NumCellStates() > 2) if (tempalgo->setrule(currlayer->algo->getrule())) tempalgo->setrule(tempalgo->DefaultRule()); // copy (and kill) live cells in selection to temporary universe, // rotating the new coords by +/- 90 degrees if ( !RotateRect(clockwise, currlayer->algo, tempalgo, true, itop, ileft, ibottom, iright, ntop, nleft, nbottom, nright) ) { // user aborted rotation if (savecells) { // use oldalgo to restore erased selection CopyRect(itop, ileft, ibottom, iright, oldalgo, currlayer->algo, false, "Restoring selection"); delete oldalgo; } else { // restore erased selection by rotating tempalgo in opposite direction // back into the current universe RotateRect(!clockwise, tempalgo, currlayer->algo, false, ntop, nleft, nbottom, nright, itop, ileft, ibottom, iright); } delete tempalgo; UpdatePatternAndStatus(); return false; } // copy rotated selection from temporary universe to current universe; // check if new selection rect is outside modified pattern edges currlayer->algo->findedges(&top, &left, &bottom, &right); if ( newtop > bottom || newbottom < top || newleft > right || newright < left ) { // safe to use fast nextcell calls CopyRect(ntop, nleft, nbottom, nright, tempalgo, currlayer->algo, false, "Adding rotated selection"); } else { // have to use slow getcell calls CopyAllRect(ntop, nleft, nbottom, nright, tempalgo, currlayer->algo, "Pasting rotated selection"); } // don't need temporary universe any more delete tempalgo; // rotate the selection edges seltop = newtop; selbottom = newbottom; selleft = newleft; selright = newright; if (savecells) { // compare patterns in oldalgo and currlayer->algo and call SaveCellChange // for each cell that has a different state if ( SaveDifferences(oldalgo, currlayer->algo, otop, oleft, obottom, oright) ) { Selection oldsel(itop, ileft, ibottom, iright); Selection newsel(ntop, nleft, nbottom, nright); currlayer->undoredo->RememberRotation(clockwise, oldsel, newsel, currlayer->dirty); } else { currlayer->undoredo->ForgetCellChanges(); Warning("You can't undo this change!"); } delete oldalgo; } // display results DisplaySelectionSize(); if (!inundoredo) MarkLayerDirty(); UpdatePatternAndStatus(); return true; } golly-2.7-src/gui-common/Help/0000755000175000017500000000000012536111364013242 500000000000000golly-2.7-src/gui-common/Help/about.gif0000644000175000017500000013617112536111364014774 00000000000000GIF89ayað1ÿÿÿ333!ÿ NETSCAPE2.0}!þGifBuilder 1.1!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷¾xÃý†Ä¢ñØ ‘̦óù»5”ЪõŠÚ"K„´› ‹ÇÌ­JhfHÉì¶ÛØM×`úúÏë=ñ©á^¸7HXø!˜@ågÈØèøW9‡øhyé3©ò€&è‰*Ê¢éP¸4ºÊz±ª’kGÛz‹›Hq:ÇË›,ü×2Ù9Œ|kKÌœºœMXê¬Û[]-­}I½íý­–!.A~fŽÎ®žÒÝï¸._?LMo¯¿Ï‘ÏÿïÎÔ8N š€öb<ƒ gó×ÁĆ +%zÕkFŠÿm‚ôŽÏÆŽ$+¨šf!„‘%[æPB–JY.kºR„ÊÂ9®ÚüirÅ12ùÛ 4i3f‘2õ"Ž¥Ò©ã^y:ÉtM$„N­˜XN(3°{p˜}*Ê—Z¯[ŽšfUYª¸®ú²#É–™­FñJ aUÛ±:¹@Íû±¯¦¶uÎ^û Ùq¸•qaIy²e´> ]œRJÏ^òÆÜ x.]p Ð ®%ö §ÖZ(#™ókŸ“éè\xsæà±I[>µ¬ÏðE‹?'^Jú/ã³s:¿Èó6RÕ¢«OÞøWaßË5n·ñð¶‘_þ°pÅ„¥_÷:>– äŸ¹ÿþ MWØì"Uuaav {=e0 J.•`9»°uTrtÂvÞsÖçÝy<)š€¿á—ÛJ'j‡^ˆš¸SÇiNW«ÝÈ ­)'>»Y04¦è¢f­ˆ—ò}XZ“ð5÷ã{Ðip™ƒÙã;‚‘’8~)áà})^&\ob"ItÎacæz‡]Z“RªØ!vê¸ÜYA‚Dçäù–ežµ˜æ¥š`.ZL¢²mè$—iŠh }é½Éç…„]xä¥-bF"‘SFúg”lަߓ£šÉ`™ZÖW ²Í7*¤¸¨inœRGi¤x†Ze‘›ÆÙ©°¥j)N­ÿú˜‘_aáhrT­3»FHеqÅj¥svE·žúq-AŽ’pk¦½rkª\±>:(•2Ê‘]ïZÈݘ,î)ª´íykŸ–Åq™dT˜ž)ðƒVzûÝFrG&—˫‚Ǫ¢¬i(¢ à¼ô¢3løR6¯¾Kl¤ùùúfe°Îº¿Á.©ò¤¶Ì2–ìÅô²¿<>¸”?öñO·9èvç>KƒŸâæ‚óÒ…”šÕ\5#ÙÐ28Ý.Ôûj}Å^X/Õ²~òØE³#önŒù'ô‚€®}ãI÷'¯GtÓS±AÌYjïÍÓs[`?„×=3¢Pž­øâ_†œŠä–ª o×&q¹Ñ)ñ¦ùkùÞy+3*l1é¥—Þ ƒ«/šáC‰¿®”Ô±LKûäåλa½ÿŽ‚í¸ûKÄ<ð÷æ|ç±WÞüT* ­zô “.¼õe3{vÙk¿ý@‚O·DWŸJ~E›ÿ«Sõé׺Ɇ"ý¾ÑybØ~ý{‰œtúïßùýOz3ù„ûx=”¬/×8ô=^œàï2fÁ Ê !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±õ[ÔhǦó %&É`ôŠÍjCÌG—Ê´nÇäòsÚø‚Íì¶«N„ÅrôûŽÏoâq%±¤'8Hè ö'ˆhÐÕWøɶ¨¤8y`w¹ÉéäHé¥ÈPÕYjªcIe¸æ5©y ;ô÷):”*«» ”™S „É;,{H’úØšKÜì|ùÁœ&ý\mJ­êq(lÝ+ ¬í=NŒaNž®Þ»ÞNžì/ŽR?g<‚œï¯w/Ø¿ÕÂ!!ˆ°DÀ1 :œc_‰+j0È.ÛD+ÿ¹Züˆ¥€¡<‰¢FJBè‡2&WSV¦œ&3gHnùñirÔ9Dúb„Œ¨Œ\Š:m©R$7žK›"}ŠU(Ò>Ê2äS5¤U¯pu3ËÎ¥ •j¸Ò¤¨Ñ‚ÚžYr…Ö–îO½G[e:Øœ´@oEØÆ(³W†¡aí㽆;.¼ pÄ„[*ö)øðHÄ›o%sÈÇܺíh™å#˜ccÙ\ .û™U(œ&G®Ìy2NÜ„w™H3¨ÑÁ1Ï9zXü_åhŽª6㉠¿úxoÑÊ}].¿Ù;h¶/‘§Fÿžùyß_K[=¬[¼ÆbÛÿãîY€½7`Z8 aÃ\ RƒÑ_á˜\_æýáE¶Ý§ƒÖQÖ™_òÙŸyÈebfãM8âräµèFtpè`%ëU²k:¦ÀÒyîÁŠéâw?Á˜}BŠB~Ffƒd|/^ô¡nö"c•ÔmÍ’;~ Q\Ú=È^^õÙR!ˆ>™Þ‹Ò1H£dzù¨¦slJÙ^wZ™dw¤¥i¥„4Ö¨dn]‚‰è s}2ØŠ“Ñ9‰…æyÛƒs~Ö‰"JzØž&¦HiŸ‚hcBeYâu†–$̨g2él.†Jé›–šišWÊ e§©ú ªˆ¢Æ©)p¶qÖ+­eÿ± `˜¤ú*„—ÏâWAŽÛáŸyF”Ÿ´¥­¬‹yê‚«†–i§Þó›\íò:í‘Ön¹m¼ôÌ›(H®éšÉºÓ”ië«öþXç™®ª§œ¹n¾J¬Šâ ¬£7‚{/ÃLnyonü/¿o„o¾­-'TøRUi°LÂE¯Ä·+'¸$Ál(Ÿ»œëÁÐ÷.=;‡;#´ßZxi8]©&²S¹èÕ˜GóÃ-–ƒ6ñ¿„ܶŸÔu0ʘ±yä²$ÀZ=Ö¨a†r†d')yñ´D³{° ¦T[oÈò¯5fL7JS÷ÛóÇÔÊEtßEM*†?e´Rƒë­à͋뫶ä}µå¸öäî$ž&8–kz¬Cü9è;»7á©Cez]IÎtì­n´X³ßïNVé¼ÿ^­ïÀ'öð®³k<îØE“üï05ýNÑO?t©»o=õY…½MæÚ§ó<äSü÷9©]¾ù#ß›­úˆî[Ùqé»¶ª|5&ýMÕ¯iúÓÞ8®îD)V-~à=:ä€ÛÊü(ò ‚" ø(˜/š`°uùÛ ŸæÁº !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf°Ö@:§ÔªU…$Ðíõ /irÔ,N«×L´"éEãìºýî±¹å†ìâ‡(8è°7aÈçG¸È¸¶…xyØx‰9$YÈ7C)•*Z÷Hé99šªúaJAwzÖº:K˲éùŠÚWÛëË{¡Û!Iü{LhœW¨ü׌ ñl++}}IA¬íÝØlý=.ÍM~Ž~Ó œÞ.(þF²îNß–_ŸŸ:‚«ÿÿ…Ÿ žùskÁ(Þâ°AD‡Æñ‚!'ÿ;–04‘™«HKÞòjN'¥LºüHÒÙ®™Åb²ë÷ äKŠ–$¶¢£³ÒΡÓôÔìÃͨHšƒmTÑcfüA´ù4ëÆIRAùˆ‹Â•Ã,îBYÚhz.¢\Ë•iN·WY9ÕZË«8m—l¹a”}× ³Ö\°`ÞԢ԰߃5?–x9°e¹%›R†F1ÆDèÞ š¯AY~z:KzWìÔ¸*ÏfFF¦F-gãw^úB¡hjV™Tj)Ófƒ²Yž›¢õ&˜âAig‹yž2Zsdž^ú¾v'ºñý .yßã²ï–?>þÉ®pH€Ÿ½ñ“¹Ìî€PÑßþˆ:¶-‚•ûW÷À ÚŽ[ì  !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~xà~Ä¢ñˆtUB[ò JËšS8Íj·ÜÙÕºvÇärôÛ¨ZÍì¶ÛD'nâ·ýŽ©ç89‚ž(88QWsà÷甈HèøHXg¨Ây‰I5ĸ±‡x5™):Ê"Úxöv Hú «qzˆ*Âi›«+cª×´ l2AlÀ)œ¬LaÌ@ܼ-}D-}=ÖƒŒÝí=¢ý-.´:Žþ ýÅîmÿN8ŸZŸ¯ó|oÑñOŸÀå| <˜%TÀ9x!|ø¢„…… ZŒ(g’ÂUÿv¼²jÖ>Ò ‰r7‰ž‘0™òâ¢4íî±<– f̃ž>©rv“IK :w>”´©ç1¥ …v(h4*GE¦”º¢¹æ)T©\ùl–ÓZ|&šò³9œXÚ.Së–ª¢¬”ú¹$Ë!h×q‘6ËT"»j¥e ´ØÜDp§Î2,´äá¶dYqÜ5Œk†‹9Èʼn?ÑÓCï^ˆ†.ó©¼Y. P˜gRöl`Km`&î›Ò/Ð8[~Ì08-ØÀ{ß¾ ùäî¡Tû´ö»Ô÷뢨!Û&~Z4VTΙkÄý{²Zã©“ÿ<½ùhðµÏ·ßhpÙ¹ù[ÿÕšY²Õx£áw WTÒtÞ— fâ%ZR^õ’u¿ˆ× rû±U^|ö•‡\P¹"|XÉמyÌlxÎ_`÷Ùq·ZŽÙ˜…²x÷Ot~øœc"fÖbÚØÔ{ºy8܈óÉ‚žpÒa!X•¦±çÓÿ馗§}I`}M·”SVyâŠóÕÆL€ÏÉ \iÉ9#‰ENyf”<úØc“ÅÍå–)ªf¢;ÀDŒszVç‘Ëñéœ:JœkW¦‡džoîÙbrf hYeYhšhnšÓ¨‡žéŠR†šäpqbš¢¦wJ*ªŠ•‚jdŸB:Z*iL b‘UÿQG‡iH„j¤îê& ’TÕ¥©1IæT~rø§‚8^Kì§f«›´ˆÚ´¤©èò ÃM—1;®¢)!µžFmèçw‡>« ·½bI§zU;‘¥™¾«&“ïÙ'tú¦*}ßÜpÀ A<ÒÁßùWT·öît]2B‰¡®ù‹2:骭r¦äÌÌQk§°1[̃¯–q±€ÖW2rÖ5®º#dÝ-b¼[½Z‚3(ÐÀ˜©´#o’UÊ)w9uír‘¯Õ»`-u[C-óÊ41üaÚK TX/NsÞÜz_Ëð×`LåÞs]rã\AÖ‚ËTIa*þäâ{­”‘SÀ ¹äQ} «˜þX¨¹QœjÒBr‡~µM˜ J5ê1©¾zì®Ïvà¶Ð&Ž!ãžûK¼ÿ®±š,ñ<ê+cñÊ'®Äò³Cþ¢óšÇ;ÅÒ'zù‚×ã.õéÛóåý÷Ó'_Šø‚‡½ùïü“é«o‘³/¾: :ÇQøõ_}«„5‰¼?ž ..V¡_I&’SY W— È@™¼Íl~‹ààüS; O!¶Ñ ðÇ:Ò€"ä+ôWÂJ !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf°Ö@:§ÔªÕ—\³(÷ ‹•´H™ñ«×ì& °}åyûŽÏwäóú[û§'8HÈqgg UÈØ8x¨•e·èx‰i”¨ˆ(™–* 39± eæ9ÊÚZq*™K—héz‹›:³Rç› l2Yª°*œ¬üʻ쮸NŽ.z.’´žþ^ElÌ_âîþ oßÿ‹“¿wÌ­H0!cóÞS‘T$SûR4ü1#¾/ÿ\æ™ HO£Èl°¶‰ÌEDfЬL ó„—/á8ÜC'¦NSÈhí éÔÁDUQsÈfŸŠ:u0 (@VÍù4«Ír'§bôz¬d%¨YbõPG YA[Ô>kë«”§v|ÈþìQS+9¹GYVý;\‰7~~ÁE3«l]™ídÉ[ZÃ7Ãî²8`âÊÔr†ê6.Ó»>c)º’سXô:UŠðçž!Ò†kÚçL»XËqÜç³åɸ!÷¥º‹pÍÀ'ú¦L¹0cÒ[9åÈQwÒµdoÿ†¾´%òÞF{nŒœ¸Û¤—u‘ß¾sðø¨Š‹6®¼}õûº©Ûÿú”—,´M$Í eQàU<%×”7·uú‰Wàrræ•bô}ãS’YØtw™7ßsW("ƒ¡U´a9ø½7bsÕÔÑ‹6ñÝi\¡èZ:\§\TIw‘긢c22w§=7]’ºè\y䆨…ü±H¥\5rÈb†ÈÚ€¯t˜Ÿ}.FiY›Rfib]’e~çeÉ&–U6ùÝœèµeä¨äiãž1¦HæNŽÉ¨!ÜÙv`‰¶ød‰Vòé‚t$›pZ _œˆJ^ ó‘ º¨æ Š¢ùži‚¦*ª´fº`Pëièi}µ&'ªžé1gª–p¡*¥¥ÿIÉë«(6K!^ùŒVä‹®iÔ¤xî൱Ñ’ÀJ[èˆuZ‘·$Lv&¥Åš{ƒTJ®šm£ön«^(k¤¸¶ª „±ú¥¡}á9y[h›R{d©rFÊéÁEö¹« GhÝÃvfV«¬†ÉÕ½zÍ*•™ˆ{å Zi~+Lð“07­¤æ¡ÖpÅÂÌž>—Ël´AâèåÇ´˜l²€"EWŽ‘ È8¯Ë±ºŒhl5!ÞYÜæÂ²é'5 €‚+ Öa¯±5ºd>­ÚÔG/ 7„Fv/¶¨·=s勘`Çõ‹wÞ{õmw8g-xd«xÖ‡‰?õÉ_N°¦¬ÃAŽÒJ*Ÿô { b>l8讜39¥›ÎJÖŽ×v9ëc¾þìO…½ºí:]ܹ«ºÃ-ÔçÿΨŸîåN|èkù|ó ] òÎë}BêÓÛøÓ×ç-ýövï}V•[~ø¸”T½Ëæ‹I{äâ®â¾÷-?üÖOùûT•o뱫2è §âK-’F@¦ý pßI`ñèÒú90# ÙÂ%8A ^ƒdšjØÁ{5ÐX!LáJø»ÿ p…0(!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5@ë ‡Ä¢±õ[ؒǦó 2I[ôŠÍjYK UQ nÇärTì˜RÑæ¶û]þ²©^¸ýŽ'©â9Ÿ(8ØðÅ`èw–HØèøÈƸfø×õx‰G9Ãø#™ Ú³IA fêõ)ºÊ‚º!'éÙJ[û ªòúg€k뛉x»¢ËKü{ìhÌ›¢«Œü $|á¼}¶›ÍÝR]ªè=n>JŽÞÔœ›fnOæ±oß6¯Ä“ï¯× ' ÿd7¡Þ‰^.<”0œ6j+Æ`¸ÍBA‹ÿwô’3cÇ‘JDJÔ$É•!˜ì·QË™¥Ö!Ú‹ZL4{œ&íe;}:œƒQq'¾3 µÐÍIRû "²hÔ­Å*bZç–1•8 bµ¦õŽ•µO‘±•öiVX¯%Éf<é#-×ZHAF+´mW:kðdéí¡±»)ntñÜ}‘é%F Ylã«‚e¾Âʹ²KÌp?[nÂ’ã±òåÈNëQ>ᙣ°¸˜Tš*NÔ«¨£lª«iÜŽV-@×Öy¥´÷éP…,‰mÔ®£\õX®¼cŠ'+ª”è~ÜŽ—¤µ•"<s㚚隘½éÎnÓkío‰‡®~ûÖok‡å«oC8Åb§erA p³óÒjàÅ[LZÚº7l²©ŒÇôñzž–gÜ–Æ8F,²§;Òùì» –ìžH ŒmZŒMò HgˆÏú'f\ ­|ÖÞâ#¨Â¬xÝ›¯fÛ»ÝAMwÒ ÃÕ$puï­Ó¤Sµ3Ygó=c‡m]Ⱦ/‚Mëé«¡Œ3®Ô–¦Â >yÔO ¹sæžëô¨u×¹Òùç&ÔbJ‘›.Û·Ù²ÞèÒä‹9ìäØU¶Ôn{: 9Ý{ÝEæ¼ç1É®{îÅÓ´“’ª/ß“¦NéÅ;ô|åV½õÂs¡=áÙgß=ªz5(¥4˼úÁµ¬EÃÜ´Ih‰ÜŸÜÞ¢Rk‡šHEs¤ÎMÛbêWpáíí“Dî°aaj‘ò·ž35H•MFüÐÏߘ#—âDù.Ù[6ƒ¬<ú›ç?¯…^|š´:ÉÿÂj5!xpÄÖW%—ÎÝÔí-ÓxKÆy™tlÍt3w¶«¹a½ÔךKb®<³]Ö¨×>œtjMèëc¶žJøêg¸¾oÿý:ãøËŸm>xäÕé«ÿÅžÜjHa§_Káù–jaÄ‚\`4PSÞZ{œY¸9+gà…*¢ufçWOZ ÷xª‰hÔ{Ÿù køE’ qº¨â‹ó¨c„³ôô£ˆªt¡ Zº)GlÅq'[:S-Xa‹÷UãŽ2æ†"‡ÞÙ‹·ÅH¥†É)sOþ}Y¢QÝÁ„’nFI]V;™µÝx£%¦$Žx8 „4ÝU—îmé%;|Ny¡‰Ú9a~wê5Y¡ÿé™'"¾‰)Q\jÊ¢3JЦ ÅÙŸétt]P¬ÇØóò‹®¬rþ™cüw®þŽ{]ž o_Æ Â~M￲-)^ÿ æ¡×/‘Á… ½U×0b†„í.P,¥J¢F}ÿÝýÁøm£H€Ilíëi¤Êrò4¡¬÷°ÚÊ™°XíÈG3§.w-§¼Ô 4¿*&kåøt#"/¥™4ê k§¦U*é´¢Ô­–“ÔT¡Ã±$c¦²‚ÚŒiá¬õ6 UJ0ÑlW[®ËªÊ±6BQ¡FëŠõ(—¨Ó¯JVÙÄÈ­ñÙŒXÏý},ÐðbÇŠ!á|‹™¬O_¤èLšK‹\Ë>qgìå Ž5ت‚-KÖÜ4e_µ‰Aþ8Øånß…u»6ôwïàx‡cÕ 74îÃYUYMM½³öçPùw¾=çÌŒ§+nžî÷ÉÇ›|ö¼úæéC¿ƒÞ2¹RMoÓÿíî߯ÉEß ;eæš0ï)¸_9àTÙ& &(L`juXh¨5 GðVyÀq†^yCµöblUÄÜfî™WK>ý3#Œ²áWk°í¨ŽñyÇLŒ/®¡œ~-zBF |GŸ‰:ÉÛXÒ! ¥‹DþçA‡<~ÉÇ–r$YŠáQÙžˆ/šˆßN€±wYub6Yßdk–鿇BrÙ]vÃ]ù¤‘+*ø’Ž`ª‡vÆùT–X zçynþµâ†}ŽV"‹IÚ™à)Ö=–‰›Ô(%§š^ÔÅ ‰5ú\”#FZX§”ÂYå¥DfºÜ¦f®©'¨Šú©¯îJ Z^êò+ŠqÿL´ ƒBʧ~ÑŽ·Žœ¢ê)LÂò°ç¤ª1ÊÓ€Í,ùj«µšË-ç’舾«â˜Óv†Tª¦&'í“øÅy¦æÙ¯¥¬Ž†$À³‡¹¼.z¸Ö>]ÃÛ!¬W­{âÂŽlÔy¦Þ:k¾ÊíKÚ  ŸÉ`¿Ä‰6§ˆŸü)¦S2œ\¶ñ 43`ß«°'Lɲ1ÇÁ0uh`õ€ÒZÝ&ƒrÆŒôäœ^áÖ.v0ãàtÖËH,õ"T3™ôYüæ5äÐF#ê#X‹†DBE¯NÛ£ôªtï]¡kiîÌwàâ­ÆÊ*Ì-¸2Ðþj+Ä'žSÞò®+!…¸sŒÜ…Q{9æèìxç`R„¶è¦'ê˨Ÿþn³TÖ™⬫Sú!”Ï›ë¶kŽûŽÔûè*ʼF…ò^<äÇ¿îlò35Ý8óÎK™!M¯¾¡‰}ç2qA|÷ð†-þ;sƒ~ù¡d\}¸é«¿þÍ&ûD>üð\¼5磾oÿ+’«K?þõï~Û VýH“cuA€ŒM×À½Å ŒàB&2 z¯v\;<Ó€p„;(!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇRµŒçúÎ÷!m¸ù†Ä¢ñÈ¢ J ò J‰JFÕ6Íj·Ü‘SQý2Ë®ùŒ†^™ñ8 ËÕírû`ǯçü¾Ÿãæ¶ ¨Gøwˆ˜ˆ§‘Ö¨)é±WWó8©¹©“™9X×àôÉYjšcF)jóHv ‹²ôiG(dŠ%ËÛ»‘ú¼ê ìk|¬;KZŒÜÌKê’뚭Ѹ#‡å; S ´+©‹‰óÂL=Œæü™…1 Dáìl•*¶šE›2zó.éÑ Ijtе-1BµLÆ2«X@—\îBê)eÕ÷0Q=Ûì†Ü·Îæb i‹k^Q_wôëM)TªxÓ²ÄÅóÃÃ6yÞ¢KÌ-ßVÙÚî²Ë8r¨Çpµæ|ïí܇75h«W+S×*f Ø ½ƒYKµ…qçwa'—L)™5eU»SSÆL8O1ÒwŠÿ¬òdäw1E×:ôŽ0É#ˤýka±tÞ…ÿ. ½2z×6ïúrïôÏÑ·¯î¾yÅ싘ÉÿÝ –u|½B‚%¡]³‚ ^…ƒâ<qjFÎM:W•Je½‡K%€3^vÀ57"}l`¸Y:_ÙõÒy™H¢}Ó…æ5¢HF ´^l>ª œjkÁÖÚqË#v0º¸_Ç•F“"jšŒ¡˜Ø‰ý©…£€õåG^T¯Áöc™Yê‡Ô˜÷…‰¦Yl²HåzO*ÈU{;j)!žò½('œJž(àm¾'—/•¸æ|D’if£Pz"\œ5y¢JªŽ¡{j:)••Î×gˆÓj$X%5y—–úyè©=QǦ«3ª÷ç¥sVX§|‚Ê*\•|ÚÊjœ1æhª¨ohxãªÆÿ÷MËH 1wåN¶´+…Ö·JE*d«=+ަªd Š“—i—ù-g.*¢…KI³(9Šï€.ÝÂh!‰R«m’ªF’[ð»íW "Ç/–½Þ70´¼fsnŹޯi^ôŽÁh‘ùÆ4)§`Ú&qx¨Íz±››–êÅÌNËÞžšç°»È1³BÌ‘w½e\êÆâ·¥VýÆ:rFžÙŸ~]œòƒdá§.$/‡Ã'S=œ¹GH)=g­ÈÖÓx ð×t}\o…7íãuâÅ´ÛáÑ]¦ÝH¦– žò=V¼þ:wãà„Çv›Å@.Îx-ÏF yå*¾/…ó„YrmùB‰ŸÕ]yhwþÑèÑrNzN¨»·zêM/l•…®ó½°éh¶>;?>…œyî€á.·ïfÂ>‹ðî~ðÆŸ³RÕV/¯:ºE ½£Kó^ýOÄ3Œcöù6ŸTïy‘í‚ç¦<ù±¤Ÿ)ûêŸb>Øú¾Tëþ±K?N&× üù¿~¤Zý+SC·H;x©„l¤[ãâ×@“HEoŒà÷\, vÎÒ ðÜçÁúA0„Ç« Oˆƒ!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇQ@Óòçú·uÝ ‡Ä¢ËÆøŒÌ¦ó9D.~€%ôŠÍjYÖj7¡ÜŠÇä«TÑ=#¨å¶û]<«§_°ŽÏë?õê¬À¶7HXØöð5fèøˆ·(ˆF险)d ÑY™Ô¸9Jº‡9è XÊÚzò‰†!Iëj{K![²¤‹û;X;!l ¨º«ê ¼LÚ©|ÈKÌ<%ˆ˜cM½Íô<œ¢Í-^&ý>³v>¾^œúÍ÷ÊNOX¾VŸ¯=™Í¸6ê„S§à±ƒ ¡xëWL!>y +ò’E1ÆC‰ÿ;ÒÆ‘ƒ”{Kòñ&ñ!:“,oôºv!ä™-k 7NF›<³){é®Xb4{7S¥<¥E:M—.Í*Œ3ŸZ!G‘(|?›^ýª!kB w"žJµ¬X6¬¸åöÖ\jq{«•ÑY;9ÿ…õáì-5„ EúñO{¡z‚º(.LgvQÍU\÷0âÄÿ"k^HYíD’™}ÕÊz™kŸ9¨õ¦NeNéÐÀ‚é­3öu®¶;; „2èáÓduzÖ Š·Ü·‘Ù:³ƒzèãÄ—¿s&?ØÄG®®+U4䉀‹ûM$ܺ'ó¸Å__ý}ePÚ^9øçÄ™ý´ÿÕßvBwÙwÐÁÝå%ˆŒb½qæ }“<‡V…mÖ`€®tá~èýány™ÕØI‚¶¡dîägYu¦¹‡âc÷ÉÈâ..®xÜá‡#yfùx ƒµ IÄY¬…x’%ÿièØ{“õh#fê(W*òS£t˜ý%$Œ Á%ØÞ’I‰& dyæˆ Ò×Þ;7·d9óÉ'Zv:ex¥}.egjÌÝéezŠå–êA$•L²¥ )AŒ©¨§˜-*:YeÊq]koÎCtº› Z)¨‹8gŸ1"(•…Žz)RÆwSžº $¨cŠšé¢˜îš'€O¢Âª¢®ÿbéÝ£•ÇTSR˜VÎF”ëyLòpš€`Vð[“¯ê`f©/zz̵Ñt™”ØË­‡è–‰¨,´EÊ^½¾Û¼fˆ!žåâÚ½Ô)ð¿Ÿî©e†•{Ê;ªëW˜ÂJô«.¾&­©1YK«’o›p±ê¹:0¸¤ Ûî¾pÞçðŒƒÇ%ÄãvI‰¦Bë|¤‚ÿu{bX÷Š,N³7«s‡kU8ô6C‡lHÎêè–VÔ‚ÆXgñ·¶h]¸Ø¬#Ëì2}a|ÅÊ%ÜpÙ(z±Õ´Ýq¯××»Úö“ßDN5£n©ª}°áµu¥™±à:Ny,±À­iYåšc%aÀ›þtãÞšó`æ ç›µÊxzë öëzìÞÊN»Ô׎»íäýaîh²UzÝKû^éðÌFüï2–¼UÌ#öuµÍ;¸•ÓØð×¼PáÛkš÷&hÿý#À Þûºå3ôâño9ùëõLÔó‹œöG¼ßßSýÎíÏ¿}ü/h%  ò‚78ÕÈÏ€)à%ÈÀÃ1KeŒ Kf± ‚ƒÔàݺf(Rq"¬]XÂ. !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰*Aʶî Çò¼öJçúÎ÷~xà~Ä¢ñˆtk·aò JK•Íàœj·Üîçú[WY¯ùŒ~VN±5 Ë¡íò›Ñœë÷üïl—à&¸Ögxˆ¨¢(t5xð˜(99ŨIdIéùI“9ÑÙ¸ F šªZ‚ê‘yʘ·:KY×ÀY»»Ûá‹ÅF!êÌ{¼Ú)*(\±ŒeŒ,Ûl-Q9Ímø<ªíìüÝ]®¬nήê«| Ô>O_¿¡^¯¯GŽÒ*ÖoŸ@5Ã0äÃ60¡™wBº§0â–€þ8´'1ãÄ/ÿ ÿiüØâ"Ç ð‚4`Žº¢[ºíFdJ¸„(zÅ@h~)Š·b é_†?Θ”e×PŒw\y>R7ÌT.v$Y‘jbHÞˆ$ù&c“Abù$ŽÛ•™Þ|p²)§IðUäå”f¢c&|KjueŸ¨…™%ŽNŠ™(>i®I醭'.¢Øbsw®ch{FšÚ–J¹Ü xÆ]žQ¶'[uüÑ é‹­ñ_ŠQrÙÞ§†úÖ¨–ŠÝ©žÒ*™‡ÿÖçg²öô8+§ºVJ¸ÂX•Óu™íOïi%jZ •ˆ2à¤ãœ©¥5º«îªo¢º,»6Æk![Ñš‹n¥þžŠ ¸“ñ{Û¹|’Kf«pΧ\½¿ª*ªÀÙÌvŒ2̨óbìŸÄ¤’jqÇãð£Õ&xáaøþ[Ï«õ56XÆ—F—g¸†¬ñs4k ±´97›rÄ"ßLòÎsél/ŠÆ)²d½z>ÂØ‹£’ÛÊ,w¬Ë†W0ÐÖ’T´½½ˆLð!MË,ŽmcÙµu½ÅvÙf“mõD!Ϧ¨°=ÄõÕ~<'ÚSœv y­`]Oxxã¬!è ýî8âÅÑ…ÊdˆVžØÞ¬vóMœå¦zAŽúƒŒCù¸©[ÅoI¬¼Nú_4þqî´ûÝ¡»ÿ~4îÀo»×Ä0ã#!ÿ7pƒë.9ó•bKܰÒÃnýäãyýn¡COW÷jR/ºøµ¯¼ù‡§¶ú´ËÞúyî³ä¼ëhy<D¾'¯¡˜uço6q¯]¬R¤#·:倎I [¦(áHå©{ÍÚ†* bC›×4È}Ѐ±ðÙ+Xž žsPY!ðJçBâ5á1¬! !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó ›KªôŠÍjAJHWnÇä2ô[ƒÕæ¶ûíD«Ø&ŽÏë1ì;  ·GXhx1øôàwøy¤(áXçgW©¹9“Ù¸6É9Júé5á9áÈXêúšñ•j1+È ›[Êû&j©+L Ì#Æ´<¼ YËKQ»èpÍl5[);Ý }ý .ø×ˆn~NY}RŒÞþȾ ¾êN¿Û TŸ,ϯðÊ6BD ˆ0г :ŒSμòZü·£âÅÿ5ÒâV‡£H…ž“üXEè9kŠõ6Öòh{sìÃ5·æÃ¡t36¬2Þ1ÙUfKë\²0]¸µžÎL4òU6—KíŒZõ8x‘¯½ËÛXcÒªn&7þ˜NdÍF¡V¼[»yÇÒÕ§ìþºýÍÁMÓÿï¿VèÉG;D¡tY‚ò— F4TÞ‚Ù1˜R…÷¸Û6‚ x.¿EGJçÕ·Ø€ÇñÒÓz ÎbqÓñGb9Ü%6£‰®-¶a\zùe[8éßj´5f zÙ˜š‹ûXQ{"96¾'Úˆ¨!”þµHÙ’O†Gå'µùHæG¾µ"¦‡ ‰¥pHòvã¿dÆ¡hY¢Õ&^!:)g•ú‡–oZ†Ù •¥¥¤&cYf£ü†{^¸§rЄi]ZvYbIòÅ祣1‡é~’ÝA¨v†æ©*ŠšF‰§Nzj¥×‰:'fšêæ‹R2yèž~Þ˜Ô¦½ªV㪟ÿ¶ºˆk>ˆ¦cCŒéƒâÅ’ Y ªÔ‚‹¦÷ŸÄ⊢¶ä| „MÐN sBêÀjR϶+¦£ö>[‡Â–fµ²¨gùZMœùíjg|"þ™k¦F¾ylišðŠ®2|$©ï;ÈrF΋-÷"ô]±Ñ¢/DùïÁ¥J|ḴTeļ2JçÄÇÔÄ…æüYÅò¶ã¢.é ø<·˜¥ ï r‚f~x1‰×,-lx3n›š*Â-¥Ö”'„ª”“wûùæ}«¹èN£ë¯éª¿äùê®SEÞS¾®·¿ZK{îøÂ®ûÜ¢â]zïJm%«ðÆïþ%>ÇÆrä-Ï<ñLCVó9Oý5Öm·WÝg?„† ¾>M‹üZù|ˆêNÂÛ¾Ïy쩤:Òôo„y¾ ³†½ý 7åÙãبIH YýC Lw@öè¸ÛN%ȹÁ]ƒLC9øn„á! —‚‰ª°!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±EkԒǦó 2?`ôŠÍj_¶ibÜŠÇd¨WVTËì¶»ÝM×ïºý>’3Έ%þè çñÃ'ˆ˜ÈF83xp”ĨHY‰2i B×Ç„i z’ö™Ñ¡é'ºÊêèŠÚG’*ÙZ[«ÙSš¹kë{÷I 3Ź×û‹ 7qlUûš-­ôõÀL!w=½M‰û<ªÍ-.ÈŒ>®œÞ쳈ëm,ow~ÙÛŽïŸÕZ¹±Ð£°ª„rÁæ0b¨tÇ„5úÀP¢Æÿ=Z¶1äbT.u‚(2%—ƒ%1¢³¦2¦oždÚEË1=„:æ²Àò¦P„“Hvâ Ê¡Lf3ŒNO“›Z]FÊ‹*5FÅùv5ìÊ£\Fš·+¡Ow¹‚¸åö¶ÙÚ|™êÅšµ¬NkS“š+ö×™*_?¢å«FobŒ’Òž<1¦Æ-Ë’[ ­…:f[ræ‹q;·Dì´áÏŠÏz•waˆ»UòtË©ëO4—KxbðYÚÞÁE«.~¹ô÷x†u<µñá˜1S^Üü´ÝÏHyÝž#·ÅÙ×aj®J}²iô²s*‡\jÞóÍ£‘WnŸùmy°çÇÿ:Q­-·YàL†Íx²q¤TvØ]ÐÏ@ýi·YE^T† fèx©yÝ_æQÇ^…!¶ÕWzÞ 5ÂA§Þr%J6HŽX Ž'îÇÞS±yG[mB Q“Ž}E|/šãtíµ““ƒõU7b2懟)SÖó :6™"t­éV™Cžé’‡guDRŒcnYÜ“m%H –œQ¨&-ú§"•Yöhšq\šµŒYîéJ6(’‡f£9øIŸ‹¥'g”r–h_’…I߉Ò%G§¢^fŠgœ%}y(œ.*J™™ ij¥“LVJ“é÷#õÈZ¥­~Îúâ~‚ÆêªÀ"ºjŽ~ÿle ‹Dù¡/I¥…Ìm¨‹–ƒv¨KÈÆÀã¥ÅæJ ´&XŠÕޤnš­§ÑvåCæ:Ц…¸‰|&NZèÊ®¯ÿ®+­•ü¶z«=ÕÊàÀ‹F[j—«-ª•ÂWþºĆÉ2/½¶ X1€¸‘‡¤‚bú0/Õ!pÃXª ‰Ï!¼$®¦Nû‚1‹©,Å ºÛw×]#1Œz\¹[Bå×¹†¶ìKÉG-uÇxr–UQAña5„ýöFÕ`Ã!v·yªŒÓZït²»H )•0 ƒh°É<¿íè`L‡h&¬Mã}¦t+©/à†£©«në*æØ‡¯C“‘Ž/þ¸Md»B;¹¨•3Õ·‹ûú¶ySVë£jš¡ ¥–y§¯¾êö°:éwÃN{ƒ¶|{íõ­—ì]ë>$?„OüëÅ_ðäÈŸ^1¶y,7‡‚½XvÿŽÆÕ[?’ôÛ‡u¡éS?Tøy(O~%`kcYú!ɾÔLî¿o̼Í/’ïnZË×ïø#CFd-cÿ‹ƒNE¹‚wdñŸ-ç¼£ ï)72 ƒµ+a§¸vpƒ",! !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰6Aʶî ÇòŒöJçúÎ÷¾xÃý†Ä¢ñ販7¤ó ›*ªôŠÍjAÖ*#(ÜŠÇd¨rqf†ݲû w¦½ßvüŽÏ‡ÖµÃ<¤'8(È÷ñè`HØè¨Å¸ô`ç§ùˆ™Ùry99Aéª9JÊÕÙ™±†˜¸(Zú Û×Z™ãª‹›Ë´(+Šáj°ªK¬û+Ü;ò;\ÜLÊ,í<Ýx¼qjÝ—MÍÝÆû™ì=þȼ-$M¶MÞ.†í›zÌî^—m½®nϯ™–Þ/ @4ôì§/ÞÁ…ä î’„Œ¡ÄÙ8ütJ\‹ÿ;b´¢ ŽK^[¦Qä ’&[Ê#¨ÜH–.]J«¨PÊ4kÚdI)£²>‹úJ-„žF›R…nÎ:¦ÒrеBR¥KÙ…ŒÀ4«Ç9mʆ’ÊiZOWy*Á×[܇añÌEë¡,Ÿ¨Á¶ÂËÔªX„PY5¯k ¥ëð²‰8Iê¬UsÒÈ YÇ:²Í¬æ›g°˜‘%¼q´6lqýi,8‘¡°±›ÜkX˜-Ö‹QÒ)­4eÈ“%_ÞEY3§Î¾…Ï&îå®iÎDS«¤.)R0¹¯ ®«[ó,ZËŒS®ú¼qéÉ_‡þ~jôå·Æ.ߢÌé¤ÓÏÿ·ã—rùq :_¹‡ZNãÅ—Šø,(šeÆÔ_[KX_²uf ô%\dþ…Úc#²rÚT•íwÜgʼnVŸsû¤J‰.F÷Üh¯eV›m>N±™~ÕtËoÖ…8Ù‹&ÆèÐ[ гbvJ2‡ÚEQReb%4Ú‡"‡’öøc™ vÇÕQè@H"yUV‰>Ô±×X„q(&ƒL¶ø¦,qÖ™åPÚNŒyªwÜåž™Ž:hʺêfppv‰!Y¥(Ž0ö·ç•IúÙ% xFß–'Îw¨”«•ÚæIk—£¡´bú‘¦—qzªzŸ~*—úÕ&¡è‰¸–ª¶ÿŠêª–hQ‘fdâÑãigQm>¦"øƒ•”J Ìr«Æð–Wø½+/d*c^¦S~;l£gšË–†ûh¾×†wäFëfØ©½¤¤tþ•K$®tö° n"¬ëÂÃVµÞ¦sŠËÖcÏi1¼Ìvèo¯‹îñ¯¾%íUØa]É;ò¸“.É_ÁÀÍv®e ׫Ã#\é}0yk¼•Þkç«ü§E)Ÿ·CÉ&ôkaÂ*"ÃJÉ37I;­ÇÑ\wÍ7•7µ‡1ËûÆÖh—á5PK§«c´Ò>M7·Još[uÓm¿cz7°{‹Õò†£*(¸Žƒ?Zä—†8Ñ‹g5öÛBÂOŽù r'~Hæ„+GÏÚžÿø5ƒ%8zK%c|Ó5©{þàà¾nê`#N{îYš£{ïCù< ¶ãÞpð°GE¡ÝÆùòΛ^¡Ë =_·èŽS¯ï¾>]¡ÛÀÍ>ïúõMŸ¿G»¯ï¯|ÆÚ»‰ X0ᨃØ*|øŒƒ/‡µàA¼L8ÿÐ6büè­ß¹_srx‰Ò µ2›A h¨dÊ™_œ˜&Í™+e’¤ GçΡ>Ðñ9iÑœK¢LMg) ŸšüšZ…ƒ«R0E}ªZZñªØ^¸˜AhÖåF¯²–¸ÕöV¦Ð@qYÍ%›U2V*/Üòwl²7„å%-»Ê죿È,zA·/:»R}•k²Í¬]WÖÜÙòËÌ©îm>$ZoZŸtrŒjê˜ ¶‚1z])5ê^AGôŒgX±nÔ¡…»&Ýõ˜QSÃÑx&ùy)ÇÄ.öêÉTn?Ý < oÓ]‚_½9g¾˜K&?}Öv²ÅÏ“voÝ9üʪ§ªÿ Va±ýtŠx„†U‚ñ]5„ Nè_?ÒI¸`¹m8ÉY´)x__òÙÜW†gÔI‘¸bƒÿåÇœqôANo5^à‰š˜TcµýHÆH£UÓÍ{#n†Þgç9”‹ˆúYK’:"éà…à1×ßRê7_„&ñ%b¥a‡a–õ"˜1’(e ÁHnוùdˆ¿ ØV½áÇcŸ`åU'ŸZ’Øb”ÎhcÉhHDZÙ¡Ÿv–ˆg“K®)h¤s–'ižw^Z(}\~%g œ.Öé”’Mj¨v¤Ê#xª**’n:ÕgœBšªf}ƒÚê)•kæ¨)¯¢z£zÄÿ±ú©« y=|(­3Q0)Юîð –t¦êªÊj£ž)jÛà™!Xz`š¥Rºè¡ÚÄRb€:o£Lywïn‹R"Ü”nŽDnĶ{fïnª¦Žˆš§0dì…ÛÞ[W» ³cº1­¸^i¦º€å«ï?üÞ›-ÉSxdÇ‘,1¸Â|ª±ërÅÕõZ¥Î¦í–Ưr<´'/ew*“\ò:õv”H²§(y0@C‹ŒÇÃ2“r³€ÈÂqt —;ØÕL¡5Ö¢µ¦­ád»cÓ ¨o"¾s¶Ü Ñ­ N²e€®Þ?®V«‹ßž·àóÀ†˜“€[«xmE2œŽ£îÂD.ØÄå…Í0æžø·_'Tþù¾gCXºç‰nsê@Ý0Æ»Þ4éŸN;æ«çλej÷<»ïºíI|îcùæñÉïðÏóäÃôzKo}éáž}æþ öÝ[Ííïãûád‚-þùÂ,÷=§£™ï>>4²î-§_+m-±jÏêŽé‡^¿Žö¹:H‡ Â{ì: óO¤3 =D|ˆŠ|ÿ\ˆeü8ÂÔ! -f¨2¥!OÎã‚R¥Ì^«ÌL23ç‘’*¸ñ¥ODÁñu¬T/¡“n}ª‡K{ÜQ'šþ‰j6 räj¥j•igªV¦ZcžRšzÙx¾~¹—­ÿò×b¬Æöªª¶Fz ¥žWqª¹D„¶Þ@报¹yù(šJk­v˜k‡2r®cg†ûão欫Cº3R ¤Ä‹én†› ¥j,µØq7g»œÎç®ÃàK­¨;ùj² ^ÇÓÞI'€®êÚÀˆ½)®µ“õ&˜¶œ#.ps)òžÿ5ì-Äõú{%~ ã§ÆìÜ,±Ÿù5ö³Å…й´‚­ýŠPœ1¯¼Á)ÞFQeS+¶´Ã¸Üêµ,Io=$¢fyâÌÈšT3Ùc€ 0]pìtšàFäËUTï}\ÙøÂ‰°SqóQ&èEUîN„ür‰d†¸xä;V”6 ƒÉKn6*[\œ™˜G˜‡›ýùL÷V%–k—^¸6V 9ë„ë–Õ nËŽ{>Ãí»¿ÃyÏ!ýNuåG§N|›¸òÙNò˜_¾’ó «+ýôQ«^ýïÿ š=îâøÞ½ìà‡¿Õò‰;8>ùÓø’è¿e«?˜èž ù¤ÿ‹¶€õÇß”ˆDîÏ&ƒÀ&vKI £ªPJeÔ >8c®Ñ5Ðtô"ô&¨Jä‚Ì`¿4ØAÉuå`!ÜÉ$XÂÅ‘0…ák _èƒ!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷>x»ý†Ä¢ñ³5‚8¤ó …‹  )Íj·\ö¡¬Z»ä²YvPã³û §}ÁsÄ*;Öãü¾_µ·W³öwˆØXEAhǤ–(9é´˜¶È†i`øÈIù gÙ ØzŠ ¥iW#¸é˜*;ûÓ´z«§tKÛëÛby{§÷[lÌŠËÛ¨|µt—{}j „]È,­-š}¢|½®hÝ-n~®2QŽÎÞ¾Yλî>O)ߨFM¯¿Ÿ‰œÎ/à™Q÷.`²'0!p¸:,v-Ÿ¿AäZ$Î?ÿ]ü¤£³†:D‚üȰ™Á &Oº 1 ßÊð^ÚD±Kb’€6Þü©îà+žBĴʈ„,ö‡ýú¥4\»Ö;×Íá,]ödÏŒ¶¢„A"ã·´±lµCе"˜ƒqõM¸qÄÒ\ Å_ò]8:]9x¦§EV'Ð ÓäºÅùÄrj¾Û™0Žï}¤ƒ^—T{[c6§£Þ‹¥sý±Ù°Ÿ¤íë·ß®;¸»_÷ïÂ<ÅðI2KaðÊõn<;[gN{ó^1¯·ôn*o½ôÔgßòì¹zÎýäoI~ãä¯^~ùÈC}ú/mOö>–µ7*ÿüÎÛn|ðëï ¡TÏn¥øÁ¾þYö È@ÍAækÏ0`c—'àäï‚KéÖbA:/2x¡ð V9JÐ]@Sá 7èÂã,†4ôA!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä" Øø!̦óÙ«%ЪõŠIÈ%BêÍŠÇä"BslËì¶V§ÑS@üÏë“Û\´(¸Whxò·à§ˆèø)·¡YiiIøuvÉÙyt’Y‘êizÚWJ±Ô(9ÕŠ+»ø š`{À kàg7û L‚K ¸Œœl7q|{ˬ,M­£è<]V[Û­ ŽíÁÌ~Þfn1þ…îÙå¢þ^_ÅnŸ¯ï›;L¿hß¾VÊÉ›ñ Â,^TýSÓn¡ÄD›ù{61£™yÿ«ú`¨¨1ä¸]¥jˆ2¤Êƒ€\™ìèq¥Ì ØZ9Lïå̶FÆKÈ!åΡhDõ»yÂ+¢LSAëÇ‹K/WO›ZBIª3›‰€^ýJëhÕˆËNª©ƒP~Á¡]«Ç­/ÃpåubtÁf» ï29%qý«é£°†óÜ’­E~r M K®<Ë™Ñ"¤uëd¨wÓ‘<(sÃvû®CìW\ÏÃFñšLõXЗ9ÇÑ,‰ÔÛпgëýfØ3@ÈóvKê÷h.ÏØÜy®]»¤‹ÁNmùdߌÇO­Ìûø©Û~mâò¦Q"µÝ}½Î õúÍñm·ý<ðµ„Ë{Ø„‹?a¶;ö ù):¯õýå•›BÓ0:¾ù—?imè‡þ«¦¯ÞÂ謿Þì²ã4»è‘ƒ];X®Ÿ†{î±iî;Ús|ñ&U¼— ‚þpòL¡þ¹äzîüD°|õà {û‰ÔkÿK£ôD7ø+!…÷^7šRò®7ûÏsˆý+ÙË/Žž¾¾R.þ9£„ûù5¹‘¾÷iå€Ô¢± o[’ áÒgAÙu+ƒ”A!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú·uÝ ‡Äb ÈøÙŒÌ¦óü%•ЪõŠõÑ"Û5 ‹¶®×°œšÇì¶;–† “€u¢ë÷|QÞkwðÕGXhØ(8xØèøøð§07)y‰yI‰ $™ù ʢȱ è`šªZaæ):Ú¹*;{”QÊYçJ»Ë;¹9ñçªÛ[lÌJ’H|̼º,ù\çÛ\M(MmÍ}ˆŒöýÝMîÖš3^®.–¾îþŽ~ 3 Õ>=“Œïo¤o"}ÿd7OÛÁ…& rç‡É7³wLJÿ;b”H޼„AÊ鈅"]=´™2¦…/ï¤á(3狚іàô¡3è ž €d)4é‰5s¶5²èP“J«Vâ¤ÌiÑ‹’~Fµ ö×¢ºå­šÝ©žyZ¨¿¾ŽèjÑŽ{Ú¹ïÎ{ï³GØûÒØžxðp_…Š5„TbI¯±J™5lê–ÚÔk3 è‹%®’q'Ím¸æô½F—ä×¥ïŠ5 hJªf…i¼†R°S1yèªA¢IãÃ(ÍYv¬´2áÉ–éuÎ<s·¸Ÿ¾æRYÔàÑŸ ¯i´.¦ØTaÉý{Î×k1^{M8gëÞÃ…†¦LiÙ™ó¼œ ¹qÎÁ”Cg~\³µµ8¥oV}½ö`á«‹n»umqב˫¯.ù:ÜÐj½¾~ZvøòKÇÿgsÚsÿy6Ò€÷¦-dÐÕkÌ4ÒƒÏU0DíÙÇV†áW‡bèápç‘w[p:W {ßðgš>¢m·"~)îàŒvÇ]uÞéGŒ ÅÜ*váF¤»åØM Çb{4V6$aî86‚×d/6G¥ö] `~'Jˆ˜zŠDYdšq¶J;0YcñAd`^îeG\˜1²Æbjt¶6_lri¦>B¹Ü2áQ'Œ*n€¦š’úu&£XÆ åœ:Ý‘z:Ù#ŸrV‰è}–îô)EÃHopu—çgxˆø øå5HØÈ˜8I'Ù8ȘwYù zFøjzú´XñÈf7Š+»¥êæ9‹››qÛJÁJª,ÌÂûe ñ;¬\™üÑŒg7ö¼LXŒ¼»Z½­|]ìÍŽ:ÝíÃv-®>ù­Èë¸?—žùRG/Ÿ/„¯ÿ¯‹Ü~ ÆðwœÁ…MVAGB!É%+'C EŠÿWÑ#HOÈŽ$ÿÜ)Bâ±’,UlÄØ¢”-k^ÔéÕŒz)múÔð’Á=_<b ù³$,À‚&}:Ðѽw’œB½ºBÌRŠ\‰Ä 6È ±[kýš6ôè\Hz!5ÔÖ˜Õ™dݪ²¨'-²·_ò¬‹­qûÝt„kΓKt²*ܯñ1Ȇq"~ Shfi˜ ­Œ9¹U3ÆœÂöù+Ù7jZK• ú"ßÊ~ò¾iiçÍs}I­GºêéÅ‘1ÅmûØÓh⨅ï^ü¸èᇅV…DŽrÓ¼åÊöí$3Ç`ÁsOmݸÛéU”_‡ÞܼÑò¡åR÷êΜ«ì›!bÿFžLÔµ¶WŒWSÅ­1ÁrÙ<¸“eFÍðJ¨áÛ‚š5X`œÑo^Ñ—ÞÁ]·‘v®Ÿ&&F'_ƒÏ1¸ßIwž6…4³Õ¤=S±¦•Iµ°˜Ÿs/8z6"hJæヤAÉ^‹%R©¥2c½I&Q¸IÊ‘õ%]!Þ ¸žwXÒ“Šž¸f•QºöaNéÍy߆ôÙ)(vn:Tn Yf£ðÅçzÊç$…ÏI'§Ÿ12×€ªIöfjÈ x›ñçiSHJi(Ž ¦Ê(’2Ù¦z^§ˆšºÈe§xÚž¨ìeúªª§ê8è³ÿÖè*†<•…’¢Ä€ôžZûP{+ˆ ö’s4B é…É$ŠºFèI©:¶)¹Ûq«l¡¼¶¨€ñjèh¾z¨mn?ÊÊÜ¡¥±˜W½I‚škŸ+J¸§ÀQ†–ܺ.Ü,bß^Ì,Ÿ[%¼¤6õ¬ð&•:“®¾ØkˆŠ|¯GKaJêǼL«Ì2ÇpÊq·;Xä…­jLÞ°½>ùaÌøÌV²Éù+òjúj‚¸rÜ4D» ×gFì^V«ƒõØplµo¸YÌvg41a¶Ó5°·K,wÞîèêÚ%*F¬wành*m˜· Žxdhå7gO‰ƒõ Ø÷ãO»é¥¶Œ–o~“JídÈùOi»0uèsWžó8›Îzë®›1úëúTþê²;úÑíA®¼ö¾fê^f2¨Û¼å¼Ÿñ #ϼ—«7ïSµi}ò¶ü;ÞÕ·¤Ü´Ûcå KÊÐõ‹fN¾MÔ³]a…éƒÏ |Û¾2þû³£å^ìö3Ô¼ÂÕ¿¿q ¯pŠO­§9®ù뀸Ûp„§@B®w) &ëî‚ÓwgÁF/",á !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡ÄâÊ2~H£ó êšµSŠÍj·œæAùð"ªb®ùŒŠÁ /»]MËçôVyö^Zãõ¾ÿïA•t·Çˆ˜¨’7ö³)©gðÖ8x8¹É9…GáæpÕIZZFX)ˆéh˜j ›óê–:*‹›»ñ*J[Á«+l\²Ì:¬¼,”Ìüœèü5« mí'MQOÿº®N¿µö9 ¿P¼ÂmÁ…§ìÉcñ\Â6gF¼Ø a7„ÿ1zd! •ÁÃ|<Ù¡Ú¯’ñ–Xd‰¥³œ‰ÓB†×ïê—%Oƒ<ƒn:¯Û2ëÉæø¨f¿‰AîåõçßÂk“®ÉUÒ¾>¥ÎØY³ëÈ@,þŠ9ßçb¿ûêe;\µèçÂ{Z¡ˆz³Ðç¼£o\*ÒÙŽøzw~^·pæÔ§{Öm})dæÚѯ/=Ÿnñ¯ø¯«ÿËžžB÷=¶wîE^^æýÓŸ|ñAgU„Ûd䃆¶‘bÀ€"†ŸÁWE]¡`T~Ç_€…݆S}ò5G ŠÐ±à~ìX}58Ù„;>…WW¹ÕF¤Û­uœˆøæâ‘2vG£M…ÐØÝr>>)b”75‰^•In¸ã{&r¶%xH¦$e‘jrábKš§å‰íç— jø‹’¢‘)ç˜øù3Õée Wþ¹ç¡ÿQJ›].¹f¤vÁxM\Nù真Ôi(mz—¢ŽQVÆáppÙè)žNž&*¢~‚é ~šÖ.]Úʨ–Ê© )ö4 ŸÀ’Jg–žù!p¬ÿ* l¢°bǨªçik‚V@ÚXC¤™êƒq;Ζ‘]Ø¥^0k«˜Ã®ƒÛ„è’P\¥­9I-¨=Pú¬½©²rkÖJz’™Ý.ö—Yúùj"¥¨òJì©õZk²6jk*J—ð±KKk’÷hh°ñTÌãˆ/ÌÈ»c´ž(o¿KoÆöuT³qÄuü¨ÄÑZ™ŸÅ%é\²±K-Ê$‹‰ïµ<-üòvBº²mg}–O³$LÒÿVäõ¶áͬ ¿Cš|ôBa3ó±Ê÷t\³kTmìÒ×Uë$’ºwêáÝ~;èÓã&»÷߆Ӊà¼Èšj÷áL•GÞp—êxå…ÇGU²r5nù3ˆuáÇçz§=º`Ûdzêà¸m†®K:´Ø³ßÞsè¸ÓNùî¾›ðµx¿On…­¿ŒÝ:âŠ/][zñõÓC™èå§•ðí¯-’6r¹âMv—3LzÈ ÀøõÎl Œ`‘S7 ЂïHÜ9ÈLÜ„·CàI8 ¢px#\¡ oP!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó ú„JGPŠÍj·! i­*‚^®ùŒ–¿ëX%NËçôV[…x/ïìxý¸ÀAxà—§'¸ÈØ8x¡8™çXiyyhȶԇéùi楙IxzŠ 3º9!Šèöš:K"+™ÙZ:YÛë;&ãªyû[l <²6J|ÜŒÉ|h í\Ý»úEÂdÍ]mòÝ-žEÍn5ž®np¹þþgø-úPŸ¶ÊÜž/à–~æ¨ðq%0¡‚7”S1GÃ'&F¼gЇÿ;ÒàÈŽR2mKz v¯P‹xLº¬ˆC È—4¹ðÛ¦cfÍtJjÃ2d+žD§»‡I€E›Ú+#s«Œþ„:½ªj´*@c2mi«Ø•PËB%5V µÈb%'Ô«·¸iwøAd—.°/|޵v·l"½7 ½pÎŒ¯äJP"×ñ a‡åTur]ºCýy=j8QfJ(/à üYYäÁ*÷µuø¯:¼Ñ’êíäÚïã{ŠGŸ~í[3dÎLºB-r™iÑ–ƒãZ 2ð§C–vήø#ì\#ÑÎÞãä=Ø75ï=ܳuãÔ1'n½k³úã8WKßÞžotååï#ÿSŽW|òèf<„ÜnÕYÐЋÖêrΣOí zéT·fz䕲àyê&}R×®Ïîí¡O»í³—3¥î’Ÿ^Ýæ¾s#OOÊ>öÅí€c’…AvÄÀèÄTÜ'WÁùh¤;è¶ât„$4@!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇRµŒçúÎ÷!m¸ù†Ä¢ñÈ¢ J ò J‰JFÕ6Íj·Ü‘SQý2Ë®ùŒ¦ŽË ñ8 Ëa쉛l4çü¾ßQGqhsõ‡˜(W–1ˆPó¨8IyÄ"t¸†Uéù‰tÙ±ùÖ zŠÊ#ªñVH–+ë² (*éT;»ËkŠ+tëȸ×[lŒñ5 l‘©yü -ø¡KH}}j ÈÚŒý .ÍNî©í%^®ŽX뜾–¬“ |.ŸŸ6¬ßïŸg' @€ÿ ¢º7Í B-ø \rg*â‰?.4¬p±”DŠÿé€!cÇ‘IV!$‰2)nïRºä²²”®“8D¾¼Yí!›8{î´S›™èù<*¢L² †– ÄïcQ¤Tí8C,çÀqzªz 鎛{°Úxã‰ÉÀhÿ°Í²…X¬C[lØ6îWr+•:Ýf¶¨É¶zr…ŒdËP‚‡;½ÝÖáUÅ WVFe+káFjf–˜Ÿ2†\vnaÂÝöRUe,PÁ¬Ÿ¶‚¸ðh©›Cç~©ÎÙÏÞö½¸÷ÇßÉoÜu›»Ç¸wͶ!ÜX½–ÜÛyòÁŠ{¶8:o“Ç—[wÜØ|ìàÉA«?o<<ýË`×ÿÕ8ßjµ…EÍ]ÄwW-ÍgV=¸U~¼1¡ƒ w{B è^{o”öœrÎØó^t®×ˆãÅ—X\ûM%†*ò—ŸŠ¤lBS®í˜†‘I8Êwص"yz…f(ÖHäŠà]D]ƒ€I5‡å™"+§Á&Ô4Gòf’€5ÖFÆG_/Â`‡J¢7åu¤¡Éæ ¹¡(ž›qnW•2²Xg–1^¹ç„p~©[˜ŠÊ•×2OÒY–£™GW}MÒ£‘Ì=¨Ôy•öÙ"gUŠXžœLšg{ZiU”ºiZ*§Á÷雯by*v›JÚi€µ˜h£žh®ž®)Ú£%ÿb„¨ExˆQÍø£˜=@)e…|v¹A³‚¬É+?¿vå­w¤n7£3ºúàê…—n9YuÙ¹h½«ñ ®ºÞQŠì¦íÊl¬üVki¢š¥‰lqùư| j‚~Ú­ ÿ{ê[⥺Üo¯”k‡öªc~ž5#¤—Wêp°Ï²‰ñˆ¶VÇ߯³Œ®–0/[ì‰xØNùÝl»Ó£¤•+Zv›~Žš{›ý9èÂL^zêg.¹êaâ¡Ä®Ï^ÑÓ´·¹³ÞÎ÷Ôˆó>Òï<Ï#>z Oü?°G›üQ»ÓÌ|ôÍ¿öŠGÓ_/YçØƒ2 öömèè¬~™÷૵Õg(“Ï òç÷AÔèo­'ôïë#þ¹õ[žóýýØ1§1Å|þSH†Ld—;°nìkÊðøÎ}”Ç/WA{%PÔ`‰¹–ŽL",! !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"ï4*—Ìf樒ΪõŠý@I*BêÍŠÇdåVq>/¤å¶ûÝ OÔ‰.×&‡ë÷ü¯†ŽxðÓWh—'"hÅvø锈ö79õ€©¹ùbÉU²8EÈIZŠãé:ƒgÚꪈz©Õ•˜ùz‹«è7SÊ›\«f ¼á(¼ÌŒILuL¡ÚL]­…m½ÝfL-Í-Îù b77žþ¨íS®þ~Ë?Ï<ý´KŸŸ -¯ï_è #Láþ;Ø \*|~ë7b{ZDA±Ž•Œÿ;^ ¨ÐB@$ßÐú(qaÉ•¦5J‘’¥Ìv¼î bHPàÌ ”šä“£¬1yµùåä"ŸkØ; Õ…-¢MEŒŠU§(/A#Éó©Õ›×Öüº í%¡RÃte”-Y”¢³²’ÄܨŸs‡2`‹iU q)ùMÆJ–Ú¿žŠÖxøoÅÁrSUOz>\ºÇß‘ûæÿ?cKÛ¿+e}ü `Æj/Òn Ô\˜¸ûAp] œ eP!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰*Aʶî Çò¼öJçúÎ÷~xà~Ä¢ñˆtk·aò JK•Íàœj·Üîçú[WY¯ùŒ~VN±5 Ë¡íòçN4çü¾ÿ›•džeG(ø‡˜ˆVÁˆ¥×t(ä¨hyIS iÈ ‰  £I*tÇt7¹d*êújÑÚª2A¦9I‰ »Ë;›áKYÃÆøÉk|\|1‹‹§Œ Í’wX'}ýèðœ¦Ç¾8è9¤{ºL±'ÎîZy®ŠOØ^ßi¯¿ïIÂÏ/ »w "ØoBƒ -¤Õ0¢1ór<”ˆñÌÅŒÿ-¢hãM³Ž$ùœÛˆ*eÉ•›½xg %Ë™Dþª¥.ŒLš,OâYFP¥KžD[\!¶FØË¢LS$FÝ·2;›ZöMU³5vª&¼ Vd :«X• ‹¶ÈسÚrµÍ:4˜¯sµýdw×–™b‚¶ÊÊénZcÔÖ¢Òµ.9¸Rsx:ÌqÖjoEEw—í6k”%+ut´kåyå~ݹޡ WçSv”ÞÔrÖdTÌ“ª³Âž !lúlëà)I…Æl—¸lÔœÈZtïÉÉO‡¨s¤y™Su~Ž9j5ù~ƒ9Þð¶Þõè×í¡«—nüréëù²7ÿ? ÞzøÕ‡|º1_)Î6œXÚÕ2ßMÚTʃ^Ha†öf™…jVY_hõLÓÃ^‡ˆ)÷ xÅ(àgí]&ÜHÜm j)’¦#1³%¨p¸ y®©'ÔcˆÑèÝ€*þÃd…ØUÇc…;ê¨AwRö÷È'òçŒYnˆ%‹¿ÜFdšXéÑ“ŠQfçÆ~µqùÆ”VI§~êDù˜˜ä‘ÍÅù…#ºwžž&Ù’š’z©p3Êyâu&W§t}ÊÈÚ¥±eJ]˜‚zZ&-^"J¥˜ƒ0ºž ŇЛ(Šª3GÚ™£M‚Êg{ŠJß©JÑÙϪÄÿ꫹6*+°æ ©` ÔöÊa7jA !¶ª5æ–±˜#e]‹ë¸fvy§vèš0j2sFçmTy¨°Ne(‚¶b8iÀºÏ2I²«ŸÌ Œ{Õ%졸/Âú"rã‘êÝØœí±8bº©Åý.ìj ÏÆ:F½*wð¯À`¡ÜÈ?*D1œkÊí{ëE›g±'WlrÆòš/Ê'Xs?Ó74»lr ¤‚U½ë2GAXQR( yoÒØÀJu]p%æmb1É5"'‡m Øi‡ õr1Ï[Ó¥øV­&W -éÏ~ã-©ÞÏüŸÑ€.Œ_}G¼ï‡ˆã–Ùo3þøU>Ëè+ÆpWnùmÐ*ÆyèÝÆõ¨áè‰Û#zêé4~ôæ­WžõŸÏŽû[[çÎ{¬»ÃÞ;â°M|ZÓV|ò§ý¥<êºE|óµ«ôÖ_?éNlÛŽ½DÏW/w‹Ý[<餻¸îøû0/ûšS¯~@ß§¿¦,ÑÇ/ÇêŽË[ßöø¯_¾ð®Zÿ³ 8àÀ–&-‹œÿØ[™Ël÷ƒ 4P¥¸ZHYÙ6Xµ­Ü „ÂSM¼Hˆ;¢pv \a ?èÂÊ !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Ä"@—̦SXkآϪõŠ)@E´› ‹ÇͭÜø‘×ìvœ„3ä$ÝÏë3Ý齇¶GXh˜¸x¦vèøX†1ˆÐø“¹É©•¢ ˆÙØIZê¡ù‘ˆ6Iagú ë5z:«J›KJ{${–¤,œV—ã7WÇ:¼üÊ«l±¥ŠÈL ú)m0ZÍíè vÝ->®õýIŽž>-¥Þ.Í%éN?_Á[¯Oô¼ïÿ0 À~ì^äˆÏAÏòI1•Ãx³Šýª1c‚ÿ/ÉÓÖê£Æ‘+:2 )¥RA’,‚šådË™ó¸À¹Î×Jš½ÚK*UpÉ^BhZR±8«‘Ö§œ/g-¥Uª­í o±’„tQC¹ZÁÁ‰V×´[–|t,1a›}­&þHx_È8“"ûê÷1±Ž“+*{1'h?Dã õQÚ…ã"† T§Ä”šáJMñYËZïTì±ö`Ç´tWvëØ÷åbœqÿ,únAxo–µógiê”Ù£'kMɹ¢cÓÑ2EÅ:¼wbë‘K¿ts:vèÊéƒlÞ~¾áàòyÓÿv­Œ`$øÝ ÙÚ©&ÓrðÙ‚Ò\êIˆào"gŸpr…B€Öax[{ß±Vg²÷•x#÷`d âÇ\q*š¢Œùù'nÑL¥ZNì¸Ö_t±òˆ,b>þÇžE6ºø’ ÎØ[“÷=yRüi`b•½u©`]>ŽY!{8rIä’s§f–’¥]†9êH¥“-Æ×Ê’pòâšž¹Ÿ”Ça$ä|K9[“¢If£0ˆé§ŸÅ±)âsvšçåi¹I™”xB($¦qž()2øMŠ"ƒµQz¨œQZºÁ¢nÝ9+¨o^™i4rzªÆj¦{Z™›©X Š¢„…ÿRªi³¯^)«’ÛEf‚iS£>ÓCLB“™ÓB*©Cú›ëgä¢V)ˆn¦ «`¥³¶µ9¬®Ü:ÊoƒùV-šçÖZ^¼þº'¼újiè­ÀI†/cå1kš…®ŠJqªÂKQ¯ªT¨} ¸n¿ý G%sÇç§ ¬¤Æ7‚Œä~ «ç±m\ è ö£{­&¬¥·{¸WÀùn4­Éõ„¢óÏ@5m­!¬R½ÇÍ+Ç ²T{•©=Ws£5Öçä•P݉;šÓn ó:f¿M÷†KcXß„tï  (_ç-5ßüòx­·… >S?Sýµˆ s#nW¤êÝîµ¾Cnz …yO…ûhç4•¬êF¢ó}Ïã—ŸžQz•W|!묇-{ítQî‰íˆµµîžç {p¾¯i>«|ÍɯFrð>,Ða«}B¥§ˆQ„IVïŽñÚ_cÏÜ‹#ýÙy?þ!¥U‘IJ§èïËÎûðG«æ˜õ~ÿH0Û¿§LÊoè  >Ç›DÌ€viÜxÇÀ1)NŒàjXA ’$MöÓ ÛäAȉ/„¢‹ OØ‚!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±EkԒǦó 2?`ôŠÍjcÓÄ2¸ ‹ÇÐ.£J5“×ìöZ}Xºçô: ­„äö¾ÿ¯„¡·—4xˆ(±hˆ ÷³˜8IÉãèu÷È$YéùÉÑé!:Aêeʪºú(bê ¹iËjëWûK»K¥Kë{;Ì&ܘ#›F¼ü'¬á¬Ë,==sÕM­Í›W½ý Z‹½÷~Þç{Ùj>2Žÿd¸ô¿aŸÏßÌÞ±¯Ÿ@\1eˆpUÁ„ a,¤` bÉ7èmÊä,b,ŠÿÝ­{¸1ÈŽ$#$3­] o,KºÔçÈâ™”>þ½¼ ‘Vžk D¤7gÉ“õÀøT´TR¡ÍLùræ£J¦TwtÁ“êTÌ}ЖVExuÑ8[ š=å°Mµä²±µ"³I$n³¢Šó*ï×[N9Õ³Ù­-ZF¤~†µÒ ÎÛ:/Vì¢bÁ!aòI™Q[¶óLò,üW3⨡ f$MÖ(ѬJCÄÝÛ±ÓẉG×Õ[š—å`¿l'nü–wÏ\Ùíz<¹ŸŽä]§¥H™q! %d™î$wà(HžÈ[FÈ–hžåX—ç5ך$œ½)˜Fz¸Ò’õñè[›o®¦M%ªif£V½¢gcw>Ç`u i\¶Èfyš¸(tçÍtc“žz£çs‡bXYŒcùY§èåyÌ¥qÒ©iŽœR‰'…©j—›¨[’  ©0Љ€µÿÊ)áQUÉØ˜öçŠÓ*XdtR<ÃF®'LÚi ˜š d¥ÞJÉ䇯pl”[.;ï­s¶;¡£úV©½Wz«§GáëªÀYþËj„Æ©lz/Jª®Á¡.(~Ê6lë‹_v¹'ÃFã¯}w¼»ïPsú´‚¬i0}×¶,#®‰ºw1‹ÓÇ­ÄÿJS²†bÜñ¦Õýj¶ oE²“%Ãruª / ?'}ÈÅT÷ Û5Zï”/?S§»…Õ`».]áRjW×K¯=œ½:V@l/=¢\le…s›Iîón<öÞLô¢Z(xHoè%ã‰37êÈüøP—¾ RÞ•“tµ8™†òùæ±Þ`M¢ŸŽoà¨ î¹æ«¿~~ªÃ.dÓWºI{îPo¬{ïà6»ïˆxõîÕÂ'„»ƒ­óÎìñ ÖÒò“;Ïùî_¿»ñÔ“<¿ÀoÏôŽ#>Uâß‘fù8I~ùZÁ«ßhßð¯8È„½?¿*¶›a/ÚçžÑ ÿàठ¸pnû‹þˆT,J+„`%¨2 >Ž€Ô`â¨åÁÕu0„°ƒ Oȃ!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~x³ý†Ä¢ñé‚Ȧó - AeôŠÍjASΊ¸ÀÛ²ùÜì:Ô &ú ?ÅÔù ¼Ë÷üþ‡ÝF·$èWhxÈ¥7Vµ†èø¨¥ضè噩I$Y‰!ɸ):*ÓÕ9–A‰gy©JúJzJÕhàºá «ûÉõ‰‹*»;,'Ìj¼ä…—Lì\fÜùè÷˜³3¥ =¶iù€ãKÿ§_žv¸áWÔ*Y9üYvÚjçÁ×_ÃYàW41ita/éôD ‚‘aè“@Ûí÷a~$Þg"bTwQq¯!÷ŸsÞùô]tû½èß$ôQ—Ò•ø¸ ƒ Öˆ#†ìHVÙR¼-ùÆW­ø‡d;Î7¤Ž2bãg6F¤yUbIX¹h—EjId˜YŽÛFì1 '_ª¥{bZååe:5褖›‘‰ yV.GД˜y9æ€Ïz¥~`Ö'¢qî9ç`¸åéæ^qnJR¦€ ºX¡­ø[¥<¢y#¨Ê ¢´‘©Ü2@ƈ]¤Caª(›¨&˜(qvÒ*ˆ”¢Ö™©Tî°«ÿ>ªŸ«ÍÑ*kšêÚ¦•+²¥öéQ>ö kˆ?|ûªj‘{Q˜Rx›Žó ‹§4Î~Æm#ðŽ0Y§] èÛ½Géš,„ØòHéºwZÉiÂÄYª¢¡TXµóªŠ¿úƒ*®Ž;Ú„jqw&>9©` ? pµ';Û.‹ŠšÒ› /‰Ü˜‹…Äë1€ R6”jÍ^û3ÇÇ©Éç…A‡FoÉ[½¥†×[n’¶Ò’¦3£bàb!N{ƒ«¿r¡Wjp-c|ÐØÝ”­5¾áæk2ÛBŽuo.®m)—yÿÍÙÒH¶Â÷†€+|³[ºZtä1ÎdXœÑçݘÌf×xy™ÓÅaçpú汆~§,ºR\,÷ã©Óä/å®ÿñ:WU{î-¤¦{ï–Ïþ*Þ¾ÿͺðÃo •¨ÇOBUËYé"GzðóÉF=‰@Z/D¡óŽzøÜO=…¡Ï)ö'¶ˆþè!š=¢äíÛ~v¶ó£ Ì÷/¯¿^Æï?ŒòU Eƒø‰±“}ÍQ×9 ç€±@µÐûhœWòEÁËEúË òa'ÂyPwÂéàs§ %‹à {'¿îO…2¬! !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋uÝ ‡Äb ¸øÙŒÌ¦ó)D*K¨õŠÍ®€4F·« ‹ÇPpò`N|Éì¶ûmK«ò·ýŽU§Ë:Zš(8¨·§¦D˜¨8hшÐçG÷³Xiéô˜”i°‰x* Ói²7Ù·9Úê:3Q:"9‰úz‹ë@{&õ› ìÆª1¬Z<ç¼xÌëQå ËÉ\m'm*ÛщmíM$Íý=NmÕ]žžˆNý®/øK1ߎ_ùþî•ïÏæ,Ͱhôþ¼f—ÀX:„„ì¡Düîé‚hn¢Æÿõ>Tœ‚áãÆ‘%›F2%O|žE©2&EG«,)Sæ/[œ±ÛWgΑ #~âùÒf¿?‡:Ý ÇL=CÎzŠ5ƒ@ª´(éªú¥½¬dÃþ9m'ÚÊ<†éÓNh¸tRÍ¥»RM.È-»,*Á…4Lý›lï!»È°­© Yo±­Œ1®…|ÒÝix+ƒ,Ì4SM“˜ùjK:’Oqg/NVѰÊÕ­?¶z1ßÒ-OóÎl«³æÉz'ýmÛ7ÚàqSù¾ÝôÞTÔ‹•^PÁL‘×ÒÛ{OÏÍ ?ƾÛìR‹—%“ü’9ü/`A¯§6]¼óúí›Óÿ'O›mÒIá ‚!S1ÑÅ—`ƒbé÷Ù wR„=m\Z,PXÖ™W\lð‘ÆÞu"ò¡{&ŽfØù¹Èbj+FøXr¨"[ZP†â69šV#t&Va…åŨߟ-G!“P*Y׌7>©¢VÔ¥WÒbÝAs¤bjéå† éàŽÁx"›Ïq©Ô‰R¶(Ÿ…¼ÁåäxT–Ùe•ý™·d–î×gœ|*•§ž`ŽÉhr…H¢sô¸ékF¥YdSPž7éø¹YŸ‘ýX ¨œ‚~J¨¡[bÙÛ)B*F¤¤8Ê‚§¥…ÆÊ꜑nÖ¢q‰¾™æ¨Šjª©©Í¥KÿU5P…ù¥E‘´ŠÚ÷^†Õ2è [ i›mP?±igQκV ·ã6 j¤<ðú-·¶ÊgWÙÁdm£cxmwˆqQ³ábÚ&ªÑî g¥©l0’ÒÊWkeÓ2 ²+MÖîT$íÑo© >w÷•Ê)ܾ6Öê…½ƒyª-–©$6’ŒáÔxPÞ›ìBÅ—‘äË _B¦º ¡e½s/ÒôÜhïäÏ›QŸÃµ©™­ÝºxeؾŒ×„Û™vqη£;Ï;Ü:羫Ðb~ü†)èæØS'ý9`öѯÕ{o¼[kùÌ«oÿ®Ùuÿ§_ràhÕ_¤”"’tóa×=³puËVÔ¬#5xhxჯa6ØJY5aƒ#·}¦‘”bgÿ±Wߊ‚ `¹Á·–vßÉHÜŽ®ä&^bw9C¢nFF!›]•äEd3¶ÇÎtüm£‹|T¬9zL1ÐÇ;4u"ã¹2UOC60Î.÷GX…>EØ%† ÃÇV'òóØjœèX@‚í‡Øl7äö?¯·qÊ’y5¥~(nÏæ xÔ/™˜Þ”!~õÔh–iÓˆOZ$ÕoQÉöÛÑ߃oL–Àïå^Öb2{ãùç™u‹wéª ~Ö˜«»o©¨¿®w-ŽûDûã–Ï{TÜ4Õjë½ÿ${ê?ý!9„-e»ëÏÉɯXüJ;ܤ¹êg¬ØÜΘ–eA,iDµüUpMµaÞaW›¹ïƒR ÍHػΠ…×£ ¹7Â^.]2¬á !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷>x»ý†Ä¢ñ³5‚8¤ó …‹  )Íj·Ü$ÁìŠÇä¬rVXËì¶û˜¦:Òêë÷Ïë5_ºÊ&·7HX¨rpW¸¶døiXEi'(™©©eù€‰Ø¸):Š÷Y5gGªºÊ‘˜Ñäú÷§Ëj{KÒ7W[׉û»‰å[rÇ;i œlˆ<¹#̬ý6¬ØìU-Ý]Ë «-Îõ‹4žNÎRGÁ[®.ŸŸ:Q?¯_f?£»°P8|2ú<(Æ` fÿ:Œâk` …+Z°'±Oÿ;&T!E$'"sEmDÆ#Kº¼s×)Tà-z‰ÓGJšZæüùΦ±‘>±=”箢v"} *·aÔ(Ú„Šõâ3©±Ö0Š™5¬:ŸúL­ÊÑš¦!ZÃÁ¶ÔÛ{yüŠcê\ÄDWUÆkËn_™2Ý-Të·Ø Jp“6ŽÙnèVƈÕHù2š¹0#²œ|(åcY™¹=^ŒÙgy{:ãT+àÙÅ/2ˆ).cÔ3Oò>Ýl7švÕNV>\ú3ä¹´ø*·¬×¸fäΧ÷fþÛ¬75¬£.–˜;ݶ¾SïÌW²Òå›­GM>œ}ãæ3_¯çÝ>òøsî‹cÿ7_Ýqv)ÒUC!䵟QñAWïv>õ˜ö`[k%Å`{²`›v7]‚‚pðÙçYl£ÝwÜu_XXaŠF tú±hÙŒ&¨Ù]ÝÍÆã6°•e`+ªáç_|±!÷œ‚'Ö袊$:Øß‡'c“uDÉn)Šwå1CÎ_=Ž9å1ü…¹âoŽ·ÜjõiÔ%gi•GË–¤ùGŸw Ú¦$ŽWÒ)'K•e7JN™'#>If£"µ˜¦)_¡ZYäœÊÕ‰%’ä©g™wžc§æš_Œ nY¥x0Õ }œ®E)pnÆ™¦“4Ñéš©ïáYë¥+†Öê“ì]˜£¤lÿâaz~âÅ(w7rHÜ+EDk&­RÚG„–_Qkm„¡¾Â«l%nµ¶ÄôÚ »˜¡‹)K"k£¨ïr›-œùò!¦£?yx&Ÿrê,£²rìz»j¥èaVS¯¶&œ¡¸ªÊÊæ|”fÙ`¥Û;î¶:Jû‚þf¥˜ÀŠ)ļ ·ëðŒ{êûéÇ·Y0”ï:3³T*ûéÃ4vóŸgq™°z,÷{²6·Š¼Ñv†;¡ê>òñÕf¸º¯ŸÁÑên2V3MFÖd›$°™pÁš„ˆÝ4@nDÜJ]KwÜ#{ÉQ¤Tçío99+Œ7àdzErÀzÂmxZ[Èx々--—ÊKŽùENÚB䙯¢uµŠ?úùQ‘{^:P%c”zÞœ«4zÅ­«^¡ M]&곋’ȸû®”î»kòº¯¿o üð™Pˆ{òÊÓ¶mÏM=ò²¶ƒC½ëµgÏý¡„›V÷Žch¼Ûâýñüžo8ó^ƒÏ>R‰~w—ǯ¶úñ=§óø“â-|ÍÂÿ ¸’¤(ð¾A‰É¨7ÆH”G¬UÁöAç‚÷Ë üˆ8*Ï¡áìZ¶?î.„*d_jZC#!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5`ë ‡Ä¢±õ[ÔhǦó %&É`ôŠÍjCÌG—Ê´nÇäòsÊ@'¾æ¶û}fSⵎÏë5_›\Y‡°´GXhè8ñwеxøi–˜fqgð3¹ÉùxI¤Ù9JŠä%Úà‡J—êWú ë¤j©Ù{‹Káx±ÚšŠÙ›+<œ \yjL¼¬§¼öáŒÌ<½ilµ{"6HÍmˆ=gíÛM^&¡­¨{ZÞ®u®‹š>ãånòÈïßdMк…åSçÞÁ‚ ]\ ¶°XÉc”E<†Ž¢F‡ÿä常1$‰‡ãè…«R¤JŒõ”°Cw-ÞÊ™÷u™’¦Îpò¢)ìÇk§PŸ¢gs¨R0¢¾%M¸4j6iN!J½*E›mL?býŠRM’É,Q‚‘³D(Ll©­ªÚÖ@ŸŠ‚kûkdZ°¹þÔÙ “«X˜ŒÔÎû ®"WŠß¦Yux‘ã~Mg³Øv-¶^‘)Å ±QÌYmÖ ¦UÒyúöòµGµØÊ´§•&Ñd_a2³• ¹ibΠSK.þ¸téÜ.kç-üYqòãÒ)ûf¼6ÙŬ[£¦ÎyÖ[ͺƒõm¶ºqÝÈCÿm9ñ˳Љ«¯>£rññúÿgôW:§•Ýs„x’D%‡à|Ιa{ ""Ü‚¡a`Ë`Ò€öT1ŠVØ}î ×ánô¡×mùiG!ˆõDWŸ~*²'âe->Å܉ hL‡¯ý(ÄawIˆad4†çâb5nbˆöÍØ’ù˜x¡|ðÉxã‘X*ˆä9nhJ>IfP— ¶Á%Ø16Cï iejC*—"a½-éÞp¦É'“Åõ——”(nã—5Òæ% :väZ™ŽZÈètâÉØr|þÇ›–éIɘEl^ç&ìL¢h”vºé3kbÚ¤uëÉ‘šüáùª“WØÜ¨šÖ©]§”êi(u£zöä©tze°‹ÿšZë/¡Ä:–Bb˜•‡JâÚ¦|´Xdš%%É“®án&Úgcfó©’Pb›eT¦š)«#H/¸b>Š/¤å–w.-Tšío^:'ƒÀÎj«¥yŽ‹Â,åzž@«VJ^’ïòZ±²ß¶I0Þå[¦¨nÚ `£UÌÛí{xÞÙêÆ î9ÚËÆm»É»Ù7ÇÄód¼«™<»znöÔo½ KUqÁÛ%Ó(‘gÀ\´'³FEl·–¬šºò–2uÓ’tMȇsjU™51öŽìÂuÚ.Ew—6hÛUËN§÷£¥>Ìà´yÿØcE xá2q+ïÙ†/x„2¹œ-I^pä–»Sí®å4)â^{­ù-žšI¸~¡Ešéªã|ºPék U­»~8QÔήRê+³:îÝÀí¥[û®ðHôNü=˜'ï»îP1ÿšñ<Þ†<ôn­måè·[¯÷ðw7ÎýN?Mˆ·Úá‹¿Waz|¾ø¼˜mvûÅKTUpÕË?Ñ>ú¯¿Nû“º¼þ-å‚£•Q1·ì€ørßfs?Dß“`Ü‘ ž®Ô`HøçÁÈ-¡ƒ!,á !ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú·uÝ ‡Ä¢‹ÖøÙŒÌ¦ó).”K¨õŠÍ‚IW¡ÔŠÇdë·›”–×ìöó À¶¹ûŽÏoÑòj"¬(88bçH˜¨èöåá8eا¶XiÙYhHuÙé)S%)§‘—&ú™ªŠµ‰¸ú ÛÑX‚Ú{‹KZê±{Л \ºçû+ŒÛë÷;Kqœ]ùìÀ,­ú°nŸ™±¾|Ï­/ ¼íLöï¹rø:$‘°žDϾ=¼h‚¯ÿô"büøZDMy‰RÅ»kýPhL ³K GƼ鲤1xâü9ãå >§=šâŒš—3/C u ³©Beò‹Š•Õ?Ž¡‚34HQˆ'ëÕ³$­-B”ʦ ÕÖi§Ïf½¶+6¥\'öíYêl;j¹Õq[–A-¥u2¶—¸áÈ=%rªßrçKvL²Y[C!!9Mõ+KÏv™Þ½hú¯±µ`š>švÁ̤-7¶š†ÜîG¡éü6Å»°ÚÜ&›*þ£¿è–E+'}ºÂ²'Í>f7QЛ?M¼E†"‹'ŸÜ7v£€…sn_þ=}ü×sOÿæ3[€ —\ö…t M¤4\sõÅ`edX‚¢)F’^;™¦Ù!áÕ6rbFpø±G\~Â7âLUuŒ*†¨.vÜs øÃk>fAIiÆI5Þ~#f8£€VgâFÖW’gÁ9˜]“ÁýgãUIn§ÝŠJrY"?®ýHf„ºÅ%¦þUt&bŒÑ‡!œLJwäyvuRŽ%NGe˜5¶hgŠxú‡œ 6§§thÎóa™ŽR¨ÕkVÈzv餈&wØ–’þ©çöt‡ŒñºiŒ¿Uêàså%êªÞx5_?Uöwé’W²˜*”Úê×r·’7j~UÒ åœÖÿ©J£±‚š˜W<-ê烮Î3Ę`û¥Žâ^¯×¾nÓ𿃲ñ8:e½¯|0t}õVÇž¼õ)3¿:õÝk”è—³-ø7ÉÚ;ßê››å"Èþö¯}üú¨TýöÃsx_‹Q»¿‡€~Ó_ÃÁ½æ•JxDI+LÖÀ2ñ¦€Œš$ XÁÅ탌TÓAÆõ/„®kŒIˆB!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰.Aʶî Çò¬öJçúÎ÷~xà~Ä¢ñˆtUB[ò JËšS8Íj·Ü×ê;LÃݲù ½>ÔV´û ‡_ÙâjüŽÏȈ9ÿpó§7HXÈ 81†ˆeèøiÀˆc×çÄ™©£FçQ 8·9J ƒ rÚÔXÚꊑ*ÙGâúõŠ› »§ªû ,Q Á›H\œœË[Œ¬ü º6+|ñŸÐn|Y«µ>e™É“¤»ê¼=/éer„9õèô^»éÚ?eõ¥ßO~òzêÒljþã9ÑImûy“—¶ü=íæpåöß/ÐËMÔ¿?sK?ŠË^ÛqÂu†qT^äÕÀ€¡ÈnœßWA V΀ôÐ:ºÅ0s`ààO€!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçúÎµÝ ‡Äb‹Ö°ÕŒÌ¦ó9\&¥ÐªõŠQ§Œ0 ‹ŸÈî¡ÜE×ì¶ð ئ“q¸ûŽÏ‹ìs³Z(øð‡ V¨ 7¸ÈØxÇ÷h€8Y鈙If8¡hè©*uy–@É9…:ÊÚê°êQº°úãj{k†!{Jú‰ ¼›Z×ÛG79ÌÜ|²¬ í<·‹&ýL­=]Ò½ kJHòŽ.nœÃ'ÉK—4‹½šÉ »š<5l¼¹™•=‹rGKÉÀ˜F›Ê8t ZReúœZ`êÏ>ë.à¼úðX¨1KÊ S—"…~­V ÙV6rÆJÚIç¹`ÃÙýeêÐ)kËøåÓ¶Û¸²BR:+®ÂÆIÆÊ¸R¾€…Z.˜8¤M^ž1/F’ïlçGÝò¾Ý·/âÁŸ¦½û2ri.¨3ËuÍùé—UŽ5åâߣ‰ÝÉ<`qÚˆB'k u^.–‹¤RæuEÖçô^~ðó\äˆï¦¾ý½hìšÓßæª;°{ÊÍÛ›ÿ¦¯]Ó…¤Z}¿(‡ŸõÒ˜OŽ” iŠM8CWBGHƒÂæa¬¡µZ4†%§[aöñòSyùù6PÕ]H‹K†â~2–øßŠÑÈUn=†`lBþCÖ`åtŒÒs^†+.×"oñ™(ßHTZÆ ü½X%r¨hÜŠFˆ–#‰æ†>®9Q-M’(Øi!:&–þI×å’P‰ܘlÞ§'â}VÖXLœvr蜟½çËQiNº—™‰Y(?ßÍ h˜\ژ鞅ö™—N^2(–TZánÙ•ÊÞ£ÀiÉÝ^$Ê`srªä]Sæ*˜æ‘ªk|§úê±¢ÿF©ß¥tvê%|ÀëxLj¨Ö×vÂk­$=!·±‡S€s9úY·é’„éŽ:þ9Ÿx_öšË–Gš—Q‘° ›+¥þ¶ÊZ ¾uë¹ÙùV*¶ë¥òª® ˆ«¤†6Üã¢h®¦ÿÊÑÃ?+p¬3*â™iÈû/<Þ}XÛ½–@l«›ÛN좄 û÷ñ›Î÷லÚ|1s9{<(¿xFG•4á…`rÊýèËòËð u GÈÇ\ß3[ KDi#[£ ¶³_I[ÛlÞŠ$ÚR$Öy>]çÜz£bxÖ ¸öÞiÖrÞ÷É-¸QµÄ|µ9‰ƒõ¦´vLùã²ÂñG/´Oš–¹å ažç¢ «éyO‘;Yzêmj.ú䪿žȲkû܈‹[ûÞçÎû³÷®øï£œð±I%¼ñÊsÎüíˇå8ëÒ?ÏÓîkºã<õÂ$öN¹Œu,ÞˆƒºãÓdý—ÙŸËRÇ~õÜk^&…ñ×ÔQ«f5nÜú÷£$øÝ$}ÿ ”’â¿Ú¾PJ¨2Ê” ‚BºRdHA‹ ðÔ *0ØÁ¢€0„ä ñgµªð!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5@ë ‡Ä¢±õ[ؒǦó 2I[ôŠÍjaAeͺ ‹ÇЮcJ5“×ìv—±‡pòk!Í ÉVž{9?Lñž]n,kÉE†ª—TÉå­Êø°f*¥ý†›§ˆ*åìÌÐ)cÁòÈå’,Ø×M|l6&h‡bsç~a¬>iK}ÀÉ%;0ÝzÏïO /½wà«Î„[\ Žø#oÁEàµZ'žÕØ‚^ š€ÃCþQµ_V>NǘµîÕ:Ìý¹(|9ˆz¥¥Ó]ïã2­.5Ð/D {O¤×Ž» ·ç®ÂŠ‚Äû¿;!|¤]Ž|çÅGŽí‹Ê/Ÿí g ½™_ï^ý=f„}öÆt?øÞßâ:ðã3¿ƒôç{ã{Ï6‡¼>KÉ”ÿ>r'ÇÑñì5‰øø³¢“W±Ksÿ£‰Šªæ¿Ú%’SŠê$Y‚ÖãŸâHÁlHP}Œ 9ØÁèa0„ª! U¦–žp…(!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–æ‰2Aʶî ÇòœöJçúÎ÷¾xÃý†Ä¢ñè²5V7¤ó •Ë ôŠÍjÔ³[³nÇä²ìmV…æ¶ûýD§×l¸ýŽBÔiyþXsÁ§R¨P'¨¸•Há‡p ÉhyYæh¨I)†ù ŠÔ¹ù@Úyªº’zàjèàÉJ[ÁiÀ†»‘Ziû ühª±‹|¼:ZœË‹ül§+¼³ mí&´[}²}í}ç\ÒMù].¨=Î<nÞ^›î/Ÿ!íQ?ÏÚÍþ ŸÿÃ_«I b[GÍ BüreÓ–£á‰¨†Åÿ#”@äðÑBHŽ$VáöðÃÅ’,Ãàò8feË’³IœFh¦N‘¾¾¼ùJ%ÁD×ÕQ¦ÎË-Go}ŠáTÍ9äÉÄ5«4\ =drò§ŠWé©ÃQöZf@£MôÕ•X¥Ój Ö5L¤žL ª7£š}×Våwo_DIe5¶ºxÐa§U×J]ªXÓÊbýÞz¶¯Ô¼?Û#«­Ñ»wåd‹Œê§ìÀ `N[8´çb— .3 ÙóãX†-of¼çå XÀõ ¿=¶2ÛÍÏý‚q ·ŸHb~SMnwrǾ9§† Ø»té™b^²ü÷ðÌî¡Ó-.ú¸äÄ´µ‡ÿÅj_|F^TÄàDUt[mÃÎ>ûQ¶`&ÈSEhéçÓ~A¨v^ss\Öà|È¥gn÷aÖ™ƒÌÅW"qõÉ Cèu£Œíõg_¬í(Š2p XÛ`( d®‡QŠ'Žw‘‡8]‹¾(åv1*å¨až=ò&j´éhaƒâw]}ˆé¤dêÙFàQQ¦IךCE)æ›]VIÝ™ R˜0f×]_†‰(=†þáuºé¢&K&9$’(º™–G7ÖŠWj‡B·õ ›fU zªRd&gf©jz§‰È Zi›bª¥ŒPþ§*­Lî™'‹¹è«sÅ>¹!H7ÿõf @…Cg„ÎxRTv§ †ŠV"¤Nª£ˆœ·‰kˆ”ʪ.}AšK•­«%J/h{Á{ïªãŽsc¨g*7Þ¬™:ºž¶6ÚTðœøîúç$ýúÉžÁ–ŠŠ&©Ú°1ÉÞ»i‘­ [ï?? ©\qáœÀ:·)ÆgJâËÁQ[1yrŠÉØÃ®¾ü\“¯ö¶0Æ'Ïle¸!gå#ÑI9#ɵצ«ó3:ƒŒ ¡k´» Õj ü4Swi°N64/ÕhÙùÎfÕh‡ÙÄk>A;2Ö¿½ã†šõ"®Öé€7>W‹Ø=u"8kqo‚ÔØv'y¶9>Þà‘¯Ce²¼-×ëå$5dy…žïä6 ¡Ž¹¨¿M 8§¯.rçÃN»€â\{í`Ãózîñ4®¬ï¾÷^´ðZŽ{GÆ£¾ûòÎßþ|ôˆKtó³ÏK½NÈS«(ñÙ3¿¢~´‘¦JþLüp’«é ™™{ÿ>^1—ýõ Î7ûáퟸÑè €­á ûHÀæO ÜÈØÀzIìzô+¹/0ƒd@!ù ,yaÿ„©Ëí£œ´Ú‹³Þ¼û†âH–扦êʶî ÇR@òçú΋5Ý ‡Ä¢ ȰՌ̦ó9\.~ôŠÍjYK¤âgÝŠÇä§÷{8#¨å¶ûýV†Ñj¸ýŽÍ“õ´4(è³·6ˆ˜ˆW8ÃøÕWŦ8Iä9 vYéù×Ö)jzúA:ש±Ù…  â¥ZR*‹››Y•vÂjð§;Œ ¼ö`L¬¼ì@›•Ì=¶ MRÝ+ 8ŠŒQÍ{­-®>n~®émÎÞî]îÏ /:Á‹ÏEýb¯ŸÀôô¥¨70!Ápûvù"Ø, Â‰¢º] 'ÑÅÿ” ˈi]0Ž$Õ]jØ ä”c%[6vlH•h\ÚÄäq%F0+ ¼ ÔÚZ=²4j‚fЄgÔ öÔg—ZÅ¹ËØ(IN6³ÃŠØ‘ËÆöBiêU$©OsŠâíÕqN›®zøuƒÜ”n#1k–V¶p±Y¬Õ'°_²cÁùýçèÖáˆkk~c¼Ö±à¬ýªüö‘¥sÍ":X߬C’ý˜óYžª?³Ôú:]âÜ¡ü[vU_(‹Þm8¯oà R~ݳ®ç“ÂHC]-ø¯lÉŸ'1Š;ùñÂZs.çŽ×ûʘá“_Œ­q)äÂ×wçݹøTÚõÙÿV×µ ÷˜¨ŸEä5ƒz>•#Ivy¶ß,Æe÷Ù^Ú'Ûd½½‡•{牶^{”ÉÅ\H(¦É]†DUZBTžjÁ¶gåq|"ZV`@ŠVq*~˜¢­ð¶R™-9^sõhc–qv…д¸]sô¥“d‡Êiž€«É'fpdJ9›“!šébkÌ5õ]he‚y&NJa©e üù wçÝ#†MÖ‰f¶ç„eöö‰?ú¶¥óÉ8iž´Yé©“3±h(f’©(‘Œ†˜æ£àM‰(”ºUJåŠtz¨$¬‰Êªªµj"/MõßEQØCj¬zÿZòä²Ä¶à…Wª *{ÊÒa^ùÍɤT

Hints and Tips

  • Displaying the population count can cause a significant slow-down when generating large patterns, especially when using HashLife. If you want to generate at maximum speed then hit the Full Screen button.
  • Editing operations are fastest in QuickLife.
  • Pasting large, sparse patterns is much faster when using OR mode, or if the current pattern is empty, or if the paste image is completely outside the current pattern edges.
  • After making a selection you can change its size by dragging inside the selection near a corner or edge, or move the selection by dragging near the middle.
golly-2.7-src/gui-common/Help/changes-ios.html0000644000175000017500000000460612536111364016256 00000000000000

Changes

Changes in version 1.2 (released !!! 2013)

  • Rendering speed has been improved in some cases.
  • Files with extensions .colors or .icons are no longer supported.
  • The Fit button will fit the paste image in the viewport if the current pattern is empty.
  • The action menu has a new Fit item that will fit the current selection in the viewport.
  • Double-tapping the paste image now stops generating (the same as tapping the Paste button).
  • Fixed minor problems with status bar messages.
  • Major reorganization of source code so that the iOS and Android versions of Golly can share common code.

Changes in version 1.1 (released June 2013)

  • This version introduces a new rule format. A file in the new format has a .rule extension and contains all the information about the rule: its name, description, table/tree data, and any color/icon information. More details can be found here.
  • The RuleTable and RuleTree algorithms have been replaced by a new algorithm called RuleLoader.
  • If the Paste button sees clipboard text starting with "@RULE rulename" then it will save the text as Documents/Rules/rulename.rule and switch to that rule.
  • When the Rule dialog is switched to the RuleLoader algorithm it will display links to all the .rule files in Documents/Rules/ and to the supplied .rule files. Any deprecated files (.table or .tree or .colors or .icons) are automatically converted to .rule files and then deleted.
  • Icons can be displayed at scales 1:8, 1:16 and 1:32 by turning on the "Show icons" option in either the Settings tab or the Pattern tab's state picker window.
  • Fixed a bug that could cause the Undo/Redo buttons to be incorrectly enabled/disabled after tapping STOP.
  • The Open tab has READ and EDIT links that let you display or change the contents of pattern files. Only files stored in the Documents folder can be edited.
  • After tapping on a DELETE link you now get a warning dialog asking if you really want to delete the corresponding file.
  • The size of text in the Help tab has been increased.
  • Added support for file sharing using iTunes. More details here.

Version 1.0 released August 2012

golly-2.7-src/gui-common/Help/open-ios.html0000644000175000017500000000402312536111364015600 00000000000000

Open Tab

The Open tab lets you select a pattern to load from a number of different sources:

  • The large collection of patterns supplied with the app.
  • The most recently opened patterns (from newest to oldest).
  • Patterns you have saved (stored in Documents/Saved/).
  • Patterns you have downloaded (stored in Documents/Downloads/).

In the last two cases you have the option of deleting a file by tapping on the "DELETE" link.

Text files stored in Documents have an "EDIT" link which will display the file's contents and let you edit it. The resulting view has a Save button which lets you save any changes to the original file or to a new file. Text files supplied with the app have a "READ" link so you can view the file (editing is disabled and there is no Save button).

When you tap on a link to a pattern file, Golly will load the pattern and automatically switch to the Pattern tab. (However, if you tap on a link to a zip file, Golly will switch to the Help tab and display its contents there.)

File sharing using iTunes

Golly supports the transfer of pattern files and rule files from a desktop computer to your iPad (or vice versa) by using iTunes file sharing.

A minor annoyance is that iTunes only lets you put files into the Documents folder and not inside the various sub-folders that Golly uses. But it's not really a problem because when you switch to Golly's Open tab or tap the Pattern tab's Rule button, Golly will check for files in the Documents folder and automatically move them into the appropriate sub-folders. Any files with extensions of .rule, .tree or .table are moved into Documents/Rules/. Any .colors or .icons files are ignored. All other files are assumed to be pattern files and are moved into Documents/Saved/. Note that any existing files with the same names as the files being moved will be replaced. golly-2.7-src/gui-common/Help/open-android.html0000644000175000017500000000204512536111364016430 00000000000000

Open Screen

The Open screen lets you select a pattern to load from a number of different sources:

  • The large collection of patterns supplied with the app.
  • The most recently opened patterns (from newest to oldest).
  • Patterns you have saved.
  • Patterns you have downloaded.

In the last two cases you have the option of deleting a file by tapping on the "DELETE" link.

Text files stored in Documents have an "EDIT" link which will display the file's contents and let you edit it. The resulting view has a Save button which lets you save any changes to the original file or to a new file. Text files supplied with the app have a "READ" link so you can view the file (editing is disabled and there is no Save button).

When you tap on a link to a pattern file, Golly will load the pattern and automatically switch to the Golly screen. (However, if you tap on a link to a zip file, Golly will switch to the Help screen and display its contents there.) golly-2.7-src/gui-common/Help/Algorithms/0000755000175000017500000000000012536111364015353 500000000000000golly-2.7-src/gui-common/Help/Algorithms/HashLife.html0000644000175000017500000000120512536111364017642 00000000000000 Golly Help: HashLife

HashLife uses Bill Gosper's hashlife algorithm to achieve remarkable speeds when generating patterns that have a lot of regularity in time and/or space.

HashLife supports the same set of rules as QuickLife, but with one exception: if a rule contains B0 it must also contain S8 (or S6 if the rule ends with H, or S4 if it ends with V).

Note that HashLife performs very poorly on highly chaotic patterns, so in those cases you are better off switching to QuickLife. golly-2.7-src/gui-common/Help/Algorithms/Generations.html0000644000175000017500000000637212536111364020447 00000000000000 Golly Help: Generations

The Generations algorithm supports rules similar to Life but with an extra history component that allows cells to have up to 256 states. The rule notation is "0..8/1..8/n" where the 1st set of digits specify the live neighbor counts necessary for a cell to survive to the next generation. The 2nd set of digits specify the live neighbor counts necessary for a cell to be born in the next generation. The final number n specifies the maximum number of cell states (from 2 to 256).

Here are some example rules:

2367/3457/5 [Banners] - an exploding rule by Mirek Wojtowicz.
234/34678/24 [Bloomerang] - an expanding rule by John Elliott.
/2/3 [Brian's Brain] - a chaotic rule by Brian Silverman.
124567/378/4 [Caterpillars] - a chaotic rule by Mirek Wojtowicz.
23/2/8 [Cooties] - an exploding rule by Rudy Rucker.
2/13/21 [Fireworks] - an exploding rule by John Elliott.
12/34/3 [Frogs] - a chaotic rule by Scott Robert Ladd.
12345/45678/8 [Lava] - an expanding rule by Mirek Wojtowicz.
012345/458/3 [Lines] - a stable rule by Anders Starmark.
345/2/4 [Star Wars] - an exploding rule by Mirek Wojtowicz.
3456/2/6 [Sticks] - an exploding rule by Rudy Rucker.
345/26/5 [Transers] - an exploding rule by John Elliott.
1456/2356/16 [Xtasy] - an exploding rule by John Elliott.

Other rules in this family, along with more detailed descriptions, can be found at Mirek Wojtowicz's MCell website. See also the Patterns/Generations folder which contains a number of interesting patterns extracted from the MCell pattern collection. golly-2.7-src/gui-common/Help/Algorithms/RuleLoader.html0000644000175000017500000003170212536111364020222 00000000000000 Golly Help: RuleLoader

The RuleLoader algorithm allows rules to be specified in external files. Given the rule string "Foo", RuleLoader will search for a file called Foo.rule. The format of a .rule file is described here. A number of examples can be found in the Rules folder:

B3/S23 or Life
Conway's Life. This is the default rule for the RuleLoader algorithm and is built in (there is no corresponding .rule file).

Banks-I, Banks-II, Banks-III, Banks-IV
In 1971, Edwin Roger Banks (a student of Ed Fredkin) made simpler versions of Codd's 1968 CA, using only two states in some cases. These four rules are found in his PhD thesis. To see the rules in action, open Banks-I-demo.rle and the other examples in Patterns/Banks/.

BBM-Margolus-emulated
Ed Fredkin's Billiard Ball Model, using the Margolus neighborhood to implement a simple reversible physics of bouncing balls. In this implementation we are emulating the system using a Moore-neighborhood CA with extra states. Open BBM.rle to see the rule in action.

BriansBrain
An alternative implementation of the Generations rule /2/3.

Byl-Loop
A six state 5-neighborhood CA that supports small self-replicating loops. To see the rule in action, open Byl-Loop.rle.

Caterpillars
An alternative implementation of the Generations rule 124567/378/4.

Chou-Reggia-1 and Chou-Reggia-2
Two 5-neighborhood CA that supports tiny self-replicating loops. To see the rules in action, open Chou-Reggia-Loop-1.rle and Chou-Reggia-Loop-2.rle.

Codd
In 1968, Edgar F. Codd (who would later invent the relational database) made a simpler version of von Neumann's 29-state CA, using just 8 states. To see the rule in action, open repeater-emitter-demo.rle and the other examples in Patterns/Codd/.

Codd2
A very minor extension of Codd's transition table, to allow for some sheathing cases that were found with large patterns. See sheathing-problems.rle for a demonstration of the problem cases.

CrittersMargolus_emulated
The Critters rule is reversible and has Life-like gliders. See CrittersCircle.rle.

Devore
In 1973, John Devore altered Codd's transition table to allow for simple diodes and triodes, enabling him to make a much smaller replicator than Codd's. See Devore-rep.rle and the other examples in Patterns/Devore/.

DLA-Margolus-emulated
Diffusion-limited aggregation (DLA) is where moving particles can become stuck, forming a distinctive fractal pattern seen in several different natural physical systems. See DLA.rle.

Ed-rep
A version of Fredkin's parity rule, for 7 states. See Ed-rep.rle for an image of Ed Fredkin that photocopies itself.

Evoloop and Evoloop-finite
An extension of the SDSR Loop, designed to allow evolution through collisions. To see the rule in action, open Evoloop-finite.rle.

HPP
The HPP lattice gas. A simple model of gas particles moving at right angles at a fixed speed turns out to give an accurate model of fluid dynamics on a larger scale. Though the later FHP gas improved on the HPP gas by using a hexagonal lattice for more realistic results, the HPP gas is where things began. Open HPP-demo.rle.

Langtons-Ant
Chris Langton's other famous CA. An ant walks around on a binary landscape, collecting and depositing pheremones. See Langtons-Ant.rle.

Langtons-Loops
The original loop. Chris Langton adapted Codd's 1968 CA to support a simple form of self-replication based on a circulating loop of instructions. To see the rule in action, open Langtons-Loops.rle.

LifeHistory
A 7-state extension of the HistoricalLife rule from MCell, allowing for on and off marked cells (states 3 and 4) as well as the history envelope (state 2). State 3 is useful for labels and other identifying marks, since an active pattern can touch or even cross it without being affected. State 5 is an alternate marked ON state most often used to mark a 'starting' location; once a cell changes to state 2, it can not return to this start state. State 6 cells kill any adjacent live cells; they are intended to be used as boundaries between subpatterns, e.g. in an active stamp collection where flying debris from one subpattern might adversely affect another subpattern. See Herschel-conduit-stamp-collection.rle for an example using all of LifeHistory's extra states.

LifeOnTheEdge
A CA proposed by Franklin T. Adams-Watters in which all the action occurs on the edges of a square grid. Each edge can be on or off and has six neighbors, three at each end. An edge is on in the next generation iff exactly two of the edges in its seven edge neighborhood (including the edge itself) are on. This implementation has 3 live states with suitable icons that allow any pattern of edges to be created. Open life-on-the-edge.rle.

LifeOnTheSlope
The same behavior as LifeOnTheEdge but patterns are rotated by 45 degrees. This implementation has only 2 live states (with icons \ and /), so it's a lot easier to enter patterns and they run faster. Open life-on-the-slope.rle.

Perrier
Perrier extended Langton's Loops to allow for universal computation. See Perrier-Loop.rle.

Sand-Margolus-emulated
MCell's Sand rule is a simple simulation of falling sand particles. See Sand.rle.

SDSR-Loop
An extension of Langton's Loops, designed to cause dead loops to disappear, allowing other loops to replicate further. To see the rule in action, open SDSR-Loop.rle.

StarWars
An alternative implementation of the Generations rule 345/2/4.

Tempesti
A programmable loop that can construct shapes inside itself after replication. To see the rule in action, open Tempesti-Loop.rle. This loop prints the letters 'LSL' inside each copy — the initials of Tempesti's university group.

TMGasMargolus_emulated
A different version of the HPP gas, implemented in the Margolus neighborhood, see TMGas.rle.

TripATronMargolus_emulated
The Trip-A-Tron rule in the Margolus neighborhood. See TripATron.rle.

WireWorld
A 4-state CA created by Brian Silverman. WireWorld models the flow of currents in wires and makes it relatively easy to build logic gates and other digital circuits. Open primes.mc and the other examples in Patterns/WireWorld/.

Worm-1040512, Worm-1042015, Worm-1042020, Worm-1252121, Worm-1525115
Examples of Paterson's Worms, a simulation created by Mike Paterson in which a worm travels around a triangular grid according to certain rules. There's also a rule called Worm-complement which can be used to show the uneaten edges within a solid region. Open worm-1040512.rle and the other examples in Patterns/Patersons-Worms/.

References:

Banks-I, Banks-II, Banks-III, Banks-IV (1971)
E. R. Banks. "Information Processing and Transmission in Cellular Automata" PhD Thesis, MIT, 1971.

Byl-Loop (1989)
J. Byl. "Self-Reproduction in small cellular automata." Physica D, Vol. 34, pages 295-299, 1989.

Chou-Reggia-1 and Chou-Reggia-2 (1993)
J. A. Reggia, S. L. Armentrout, H.-H. Chou, and Y. Peng. "Simple systems that exhibit self-directed replication." Science, Vol. 259, pages 1282-1287, February 1993.

Codd (1968)
E. F. Codd, "Cellular Automata" Academic Press, New York, 1968.

Devore (1973)
Devore, J. and Hightower, R. (1992) "The Devore variation of the Codd self-replicating computer" Third Workshop on Artificial Life, Santa Fe, New Mexico, Original work carried out in the 1970s though apparently never published. Reported by John R. Koza, "Artificial life: spontaneous emergence of self-replicating and evolutionary self-improving computer programs," in Christopher G. Langton, Artificial Life III, Proc. Volume XVII Santa Fe Institute Studies in the Sciences of Complexity, Addison-Wesley Publishing Company, New York, 1994, p. 260.

Evoloop (1999)
Hiroki Sayama "Toward the Realization of an Evolving Ecosystem on Cellular Automata", Proceedings of the Fourth International Symposium on Artificial Life and Robotics (AROB 4th '99), M. Sugisaka and H. Tanaka, eds., pp.254-257, Beppu, Oita, Japan, 1999.

HPP (1973)
J. Hardy, O. de Pazzis, and Y. Pomeau. J. Math. Phys. 14, 470, 1973.

Langtons-Ant (1986)
C. G. Langton. "Studying artificial life with cellular automata" Physica D 2(1-3):120-149, 1986.

Langtons-Loops (1984)
C. G. Langton. "Self-reproduction in cellular automata." Physica D, Vol. 10, pages 135-144, 1984.

Paterson's Worms (1973)
See these sites for a good description and the latest results:
http://www.maa.org/editorial/mathgames/mathgames_10_24_03.html
http://wso.williams.edu/~Ebchaffin/patersons_worms/
http://tomas.rokicki.com/worms.html

Perrier (1996)
J.-Y. Perrier, M. Sipper, and J. Zahnd. "Toward a viable, self-reproducing universal computer" Physica D 97: 335-352. 1996

SDSR-Loop (1998)
Hiroki Sayama. "Introduction of Structural Dissolution into Langton's Self-Reproducing Loop." Artificial Life VI: Proceedings of the Sixth International Conference on Artificial Life, C. Adami, R. K. Belew, H. Kitano, and C. E. Taylor, eds., pp.114-122, Los Angeles, California, 1998, MIT Press.

Tempesti (1995)
G. Tempesti. "A New Self-Reproducing Cellular Automaton Capable of Construction and Computation". Advances in Artificial Life, Proc. 3rd European Conference on Artificial Life, Granada, Spain, June 4-6, 1995, Lecture Notes in Artificial Intelligence, 929, Springer Verlag, Berlin, 1995, pp. 555-563.

WireWorld (1987)
A. K. Dewdney, Computer Recreations. Scientific American 282:136-139, 1990. golly-2.7-src/gui-common/Help/Algorithms/JvN.html0000644000175000017500000000472612536111364016667 00000000000000 Golly Help: JvN

John von Neumann created the very first cellular automata in the 1940's, together with fellow mathematician Stanislaw Ulam. The JvN algorithm supports 3 rules:

JvN29
The original 29-state CA as created by von Neumann. To see how his rules work, load the simpler examples first: counter-demo.rle and cell-coders-demo.rle and read their pattern info (hit the 'i' button). For a more complex example, see read-arm-demo.rle which shows one component of von Neumann's original design, the tape reader. For a complete self-replicating machine within von Neumann's CA, open sphinx.mc.gz.

Nobili32
An extension of JvN29 created by Renato Nobili in 1994. This rule adds three new states to allow signal crossing, allowing self-replicating machines to be greatly reduced in size. The example pattern construction-arm-demo.rle shows some of the crossing cells in action under this rule. The pattern NP-replicator.rle.gz shows the 1994 design that was the first implementation of von Neumann's vision of a self-reproducing universal constructor in a CA.

Hutton32
Created by Tim Hutton in 2008, this rule uses the same states as Nobili32 but has a slightly modified rule table. Examples golly-constructor.rle and Hutton-replicator.rle show what it can do.

References:

http://en.wikipedia.org/wiki/Von_Neumann_universal_constructor
http://en.wikipedia.org/wiki/Von_Neumann_cellular_automata
http://www.pd.infn.it/~rnobili/wjvn/index.htm
http://www.pd.infn.it/~rnobili/au_cell/
http://www.sq3.org.uk/Evolution/JvN/

golly-2.7-src/gui-common/Help/Algorithms/QuickLife.html0000644000175000017500000001254612536111364020045 00000000000000 Golly Help: QuickLife

QuickLife is a fast, conventional (non-hashing) algorithm for exploring Life and other 2D outer-totalistic rules. Such rules are defined using "B0...8/S0...8" notation, where the digits after B specify the counts of live neighbors necessary for a cell to be born in the next generation, and the digits after S specify the counts of live neighbors necessary for a cell to survive to the next generation. Here are some example rules:

B3/S23 [Life]
John Conway's rule is by far the best known and most explored CA.

B36/S23 [HighLife]
Very similar to Conway's Life but with an interesting replicator.

B3678/S34678 [Day & Night]
Dead cells in a sea of live cells behave the same as live cells in a sea of dead cells.

B35678/S5678 [Diamoeba]
Creates diamond-shaped blobs with unpredictable behavior.

B2 [Seeds]
Every living cell dies every generation, but most patterns still explode.

B234 [Persian Rug]
A single 2x2 block turns into a set of Persian rugs.

B345/S5 [LongLife]
Oscillators with extremely long periods can occur quite naturally.

 
Emulating B0 rules

Rules containing B0 are tricky to handle in an unbounded universe because every dead cell becomes alive in the next generation. If the rule doesn't contain S8 then the "background" cells alternate from all-alive to all-dead, creating a nasty strobing effect. To avoid these problems, Golly emulates rules with B0 in the following way:

A rule containing B0 and S8 is converted into an equivalent rule (without B0) by inverting the neighbor counts, then using S(8-x) for the B counts and B(8-x) for the S counts. For example, B0123478/S01234678 (AntiLife) is changed to B3/S23 (Life) via these steps: B0123478/S01234678 -> B56/S5 -> B3/S23.

A rule containing B0 but not S8 is converted into a pair of rules (both without B0): one is used for the even generations and the other for the odd generations. The rule for even generations uses inverted neighbor counts. The rule for odd generations uses S(8-x) for the B counts and B(8-x) for the S counts. For example, B03/S23 becomes B1245678/S0145678 (even) and B56/S58 (odd).

In both cases, the replacement rule(s) generate patterns that are equivalent to the requested rule. However, you need to be careful when editing an emulated pattern in a rule that contains B0 but not S8. If you do a cut or copy then you should only paste into a generation with the same parity.

 
Von Neumann neighborhood

The above rules use the Moore neighborhood, where each cell has 8 neighbors. In the von Neumann neighborhood each cell has only the 4 orthogonal neighbors. To specify this neighborhood just append "V" to the usual "B.../S..." notation and use neighbor counts ranging from 0 to 4 (counts above 4 are silently ignored). For example, try B13/S012V or B2/S013V.

Note that when viewing patterns at scales 1:8 or 1:16 or 1:32, Golly displays diamond-shaped icons for rules using the von Neumann neighborhood and circular dots for rules using the Moore neighborhood.

 
Hexagonal neighborhood

QuickLife can emulate a hexagonal neighborhood on a square grid by ignoring the NE and SW corners of the Moore neighborhood so that every cell has 6 neighbors:

   NW N NE         NW  N
   W  C  E   ->   W  C  E
   SW S SE         S  SE
To specify a hexagonal neighborhood just append "H" to the usual "B.../S..." notation and use neighbor counts ranging from 0 to 6 (counts above 6 are silently ignored). Here's an example:
x = 7, y = 6, rule = B245/S3H
obo$4bo$2bo$bo2bobo$3bo$5bo!
Editing hexagonal patterns in a square grid can be somewhat confusing, so to help make things a bit easier Golly displays slanted hexagons (in icon mode) at scales 1:8 or 1:16 or 1:32.

 
Wolfram's elementary rules

QuickLife supports Stephen Wolfram's elementary 1D rules. These rules are specified as "Wn" where n is an even number from 0 to 254. For example:

W22
A single live cell creates a beautiful fractal pattern.

W30
Highly chaotic and an excellent random number generator.

W110
Matthew Cook proved that this rule is capable of universal computation.

The binary representation of a particular number specifies the cell states resulting from each of the 8 possible combinations of a cell and its left and right neighbors, where 1 is a live cell and 0 is a dead cell. Here are the state transitions for W30:

   111  110  101  100  011  010  001  000
    |    |    |    |    |    |    |    | 
    0    0    0    1    1    1    1    0  = 30 (2^4 + 2^3 + 2^2 + 2^1)
Note that odd-numbered rules have the same problem as B0 rules, but Golly currently makes no attempt to emulate such rules. golly-2.7-src/gui-common/Help/help-ios.html0000644000175000017500000000321112536111364015565 00000000000000

Help Tab

The Help tab behaves like a simplified browser and is used to display HTML information on a variety of topics.

Special links

A number of Golly-specific links are used for various purposes:

  • edit:file
    Display the given file in a modal view.
  • get:url
    Download the specified file and process it according to its type:
    • A HTML file (.htm or .html) is displayed in the Help tab. Note that this HTML file can contain get links with partial URLs. For a good example of their use, see the LifeWiki Pattern Archive.
    • A text file (.txt or .doc or a name containing "readme") is displayed in a modal view.
    • A zip file's contents are displayed in the Help tab.
    • A rule file (.rule) is installed into Documents/Rules/ and Golly then switches to the corresponding rule.
    • A pattern file is loaded and displayed in the Pattern tab.
  • lexpatt:pattern
    Load the given Life Lexicon pattern and display it in the Pattern tab.
  • open:file
    Load the given pattern and display it in the Pattern tab.
  • rule:rulename
    Load the given rule and switch to the Pattern tab.
  • unzip:zip:file
    Extract a file from the given zip file and process it in the same manner as a get link (see above). Golly creates unzip links when it opens a zip file and displays its contents in the Help tab.
golly-2.7-src/gui-common/Help/pattern-android.html0000644000175000017500000000351312536111364017145 00000000000000

Golly Screen

The Golly screen lets you display, edit and generate patterns. There are three toolbars:

  • The top toolbar has buttons for generating the current pattern, changing the speed (by setting how often the pattern is rendered), and for changing the scale and/or location.
  • The middle toolbar has buttons for editing the current pattern. You can undo or redo all editing changes (and generating changes), select all of the current pattern, perform a variety of actions on the selection, paste, or change the current drawing state. The buttons at the right edge of the toolbar let you choose an editing mode: drawing cells, picking cell states, selecting cells, or moving the viewport (with a one-finger drag).
  • The bottom toolbar has buttons for miscellaneous functions. You can create a new pattern, change the current rule (and/or algorithm), display comment information in the current pattern file, save the current pattern, or switch to full screen mode.

The thin area in between the top two toolbars is used to display status information about the current pattern. It consists of three lines: The 1st line shows the pattern name, the current algorithm, and the current rule. The 2nd line shows the generation count, the population (ie. number of live cells), the current scale (in cells per pixels), the current step size, and the XY location of the cell in the middle of the viewport. The 3rd line is for various messages.

The background color of the status area depends on the current algorithm: pale yellow for QuickLife, pale blue for HashLife, etc.

The large area above the bottom toolbar is for displaying the current pattern. Two-finger pinching can be used to zoom in or out, and two-finger dragging can be used to move the viewport. golly-2.7-src/gui-common/Help/about.html0000644000175000017500000000422612536111364015166 00000000000000


© 2014 The Golly Gang:
Andrew Trevorrow, Tom Rokicki, Tim Hutton, Dave Greene,
Jason Summers, Maks Verver, Robert Munafo, Brenton Bostick.

Golly is an open source, cross-platform application for
exploring the Game of Life and other cellular automata.

http://golly.sourceforge.net/
golly-2.7-src/gui-common/Help/formats.html0000644000175000017500000010170712536111364015531 00000000000000

File Formats

Here are the important file formats used by Golly:

Extended RLE format (.rle)
Macrocell format (.mc)
Rule format (.rule)
     @RULE
     @TABLE
     @TREE
     @COLORS
     @ICONS
          Specifying icons using XPM
          Grayscale icons or multi-color icons
          Requesting built-in icons
     How Golly finds .rule files
     Related rules can share colors and/or icons
     How to override a supplied or built-in rule
     The easy way to install a new .rule file
     Deprecated files (.table, .tree)
Zip files (.zip)

Extended RLE format

Golly prefers to store patterns and pattern fragments in a simple concise textual format we call "Extended RLE" (it's a modified version of the RLE format created by Dave Buckingham). The data is run-length encoded which works well for sparse patterns while still being easy to interpret (either by a machine or by a person). The format permits retention of the most critical data:

  • The cell configuration; ie. which cells have what values.
  • The transition rule to be applied.
  • Any comments or description.
  • The generation count.
  • The absolute position on the screen.

Golly uses this format for internal cuts and pastes, which makes it very convenient to move cell configurations to and from text files. For instance, the r-pentomino is represented as

x = 3, y = 3, rule = B3/S23
b2o$2o$bo!

Pattern data in this format can be cut from a browser or email window and pasted directly into Golly.

RLE data is indicated by a file whose first non-comment line starts with "x". A comment line is either a blank line or a line beginning with "#". The line starting with "x" gives the dimensions of the pattern and usually the rule, and has the following format:

x = width, y = height, rule = rule

where width and height are the dimensions of the pattern and rule is the rule to be applied. Whitespace can be inserted at any point in this line except at the beginning or where it would split a token. The dimension data is ignored when Golly loads a pattern, so it need not be accurate, but it is not ignored when Golly pastes a pattern; it is used as the boundary of what to paste, so it may be larger or smaller than the smallest rectangle enclosing all live cells.

Any line that is not blank, or does not start with a "#" or "x " or "x=" is treated as run-length encoded pattern data. The data is ordered a row at a time from top to bottom, and each row is ordered left to right. A "$" represents the end of each row and an optional "!" represents the end of the pattern.

For two-state rules, a "b" represents an off cell, and a "o" represents an on cell. For rules with more than two states, a "." represents a zero state; states 1..24 are represented by "A".."X", states 25..48 by "pA".."pX", states 49..72 by "qA".."qZ", and on up to states 241..255 represented by "yA".."yO". The pattern reader is flexible and will permit "b" and "." interchangeably and "o" and "A" interchangeably.

Any data value or row terminator can be immediately preceded with an integer indicating a repetition count. Thus, "3o" and "ooo" both represent a sequence of three on cells, and "5$" means finish the current row and insert four blank rows, and start at the left side of the row after that.

The pattern writer attempts to keep lines about 70 characters long for convenience when sharing patterns or storing them in text files, but the reader will accept much longer lines.

Comment lines with a specific format will be added at the start of the file to convey extra information. These comment lines start with "#CXRLE" and contain keyword/value pairs. The keywords currently supported are "Pos", which denotes the absolute position of the upper left cell (which may be on or off), and "Gen", which denotes the generation count. For instance,

#CXRLE Pos=0,-1377 Gen=3480106827776

indicates that the upper left corner of the enclosing rectange is at an X coordinate of 0 and a Y coordinate of -1377, and that the pattern stored is at generation 3,480,106,827,776.

All comment lines that occur at the top or bottom of the file are treated as information lines and are displayed in a modal view when you tap the Info button in the Pattern tab's bottom toolbar. Any comment lines interspersed with the pattern data will not be displayed.

Macrocell format

The size of an Extended RLE file is frequently proportional to the number of cells it contains, yet Golly supports universes that can contain trillions of cells or more, using hashlife-based algorithms. The storage of these huge universes, for which Extended RLE is not feasible, is done by essentially dumping the in-memory compressed representation of the universe in "Macrocell format". Since little translation need be done between external and internal representation, this format is also used to store backups of universes at certain points in Golly's operation when using one of the hashlife-based algorithms.

The macrocell format has two parts: the header, and the tree. The first portion of the file is the header; this contains the format identifier, the rule, the generation count (if non-zero), and any comments associated with this file. The format identifier is a line that starts with "[M2]" and contains the name and version of the program used to write it:

[M2] (golly 2.0)

Following this is any comment lines, which are lines that begin with '#'. If the first two characters of a line are '#R', then the remainder of the line (after intervening whitespace) is the rule for the pattern. If the first two characters are '#G', then the remainder of the line is the current generation count. Any other line starting with a '#' is treated as an ordinary comment line.

Following the header is is a child-first textual representation of a canonicalized quadtree. Each line is either a leaf node, or a non-leaf node. For two-state algorithms, the leaf nodes contain an 8x8 pixel array in a simplified raster format, left-to-right, then top-down, with "." representing an empty cell, "*" representing a live cell, and "$" representing the end of line; empty cells at the end of each row are suppressed. No whitespace is permitted; lines representing leaf nodes for two-state algorithms are recognized because they start with ".", "*", or "$". A sample leaf node containing a glider is:

$$..*$...*$.***$$$$

For algorithms with more than two states, leaf nodes represent a two-by-two square of the universe. They contain five integers separated by single spaces; the first integer is 1, and the next four are the state values for the northwest, northeast, southwest, and southeast values of the square.

Nodes with children are represented by lines with five integers. The first integer is the logarithm base 2 of the size of the square this node representes; for two-state patterns, this must be 4 or larger; for multi-state patterns, this must be 2 or larger. The next four values are the node numbers of the northwest, northeast, southwest, and southeast child nodes. Each of these child nodes must be the appropriate size; that is, a square one fourth the area of the current node.

All nodes, both leaf and non-leaf, are numbered in the order they occur in the file, starting with 1. No node number can point to a node that has yet been defined. The special node number "0" is used to represent all squares that have no live cells.

The total universe represented by a macrocell file is that of the last node in the file (the root node), which also must be the single node with the largest size. By convention, the upper left cell of the southeast child of the root node is at coordinate position (x=0,y=1).

Macrocell files saved from two-state algorithms and from multi-state algorithms are not compatible.

Rule format

A .rule file contains all the information about a rule: its name, documentation, table/tree data (used by the RuleLoader algorithm), and any color/icon information. The .rule format is textual and consists of one or more sections. Each section starts with a line of the form @XXX... where X is an uppercase letter. If there is more than one section with the same name then only the first one is used. Any unrecognized sections are silently ignored (this will allow us to add new sections in the future without breaking old versions of Golly).

The currently recognized sections are described below. You might like to refer to WireWorld.rule while reading about each section.

@RULE

This is the only mandatory section. The first line of a .rule must start with @RULE followed by a space and then the rule name. For example:

@RULE WireWorld

The supplied rule name must match exactly the name of the .rule file. This helps Golly to avoid problems that can occur on case-sensitive file systems. When naming a new rule it's best to stick to the following conventions, especially if you'd like to share the .rule file with other Golly users:

  • Please capitalize all rule names and create files like Foo.rule rather than foo.rule. This helps to emphasize that rule names are important, especially on case-sensitive file systems. If the rule "foo" is specified inside a .rle or .mc file then Golly won't be able to find Foo.rule on a case-sensitive system like Linux.
  • To allow for possible future extensions in the way Golly handles rule names, it's best to use only letters and digits. Hyphens and underscores are also okay if you need some sort of separator. Hyphens can allow a set of related rules to share colors and/or icons (see below). Note in particular that spaces and colons must not be used.

After the @RULE line and before the next section (or end of file) you can include any amount of arbitrary text, so this is the place to include a description of the rule or any other documentation. If the .rule file has a @TREE section then this is a good place to put the Python transition function that was used to create the tree data.

@TABLE

This section is optional. If present, it contains a transition table that can be loaded by the RuleLoader algorithm. The contents of this section is identical to the contents of a .table file. A detailed specification of the table format is available here. This is a simple example:

# Signals (2/3) pass alongside a wire (1):
n_states:4
neighborhood:vonNeumann
symmetries:rotate4
var a={2,3}
var b={2,3}
var c={2,3}
a,0,b,1,c,b

Empty lines and anything following the hash symbol "#" are ignored. The following descriptors must appear before other content:

  • n_states: specifies the number of states in the CA (from 0 to n_states-1 inclusive).
  • neighborhood: specifies the cell neighborhood for the CA update step. Must be one of: vonNeumann, Moore, hexagonal, oneDimensional.
  • Other neighborhoods are supported through emulation, using RuleTableToTree.py, see the RoadMap for a full list.
  • symmetries: can be none, permute or one of the symmetries supported for the neighborhood you have chosen. For a full list, see the RoadMap.

After the descriptors comes the variables and transitions. Each variable line should follow the form given in the above example to list the states. Variables should appear before the first transition that uses them. Variables can be used inside later variables.

Transition lines should have states or variables separated by commas. If there are no variables and n_states is less than 11 then the commas can be omitted. Only one transition (or variable) should appear on each line. Inputs are listed in the order C,N,E,S,W,C' for the von Neumann neighborhood, C,N,NE,E,SE,S,SW,W,NW,C' for the Moore neighborhood, C,N,E,SE,S,W,NW,C' for the hexagonal neighborhood, and C,W,E,C' for the oneDimensional neighborhood.

Where the same variable appears more than once in a transition, it stands for the same state each time. For example, the transition in the example above expands to the following: 20212->2, 20213->2, 20312->3, 20313->3, 30212->2, 30213->2, 30312->3, 30313->3, and all 90-degree rotations of those (because of the rotate4 symmetry).

A transition can have a variable as its output (C') if that variable appears more than once in the transition (as in the example above), so that it has a definite value.

Rule tables usually don't specify every possible set of inputs. For those not listed, the central cell remains unchanged.

Transition rules are checked in the order given — the first rule that matches is applied. If you want, you can write rules in the form of general cases and exceptions, as long as the exceptions appear first.

(This form of CA rule table representation was inspired by that in Gianluca Tempesti's PhD thesis: http://lslwww.epfl.ch/pages/embryonics/thesis/AppendixA.html.)

To share your rule tables with others, you can archive them at the public Rule Table Repository.

@TREE

This section is optional. If present, it contains a rule tree that can be loaded by the RuleLoader algorithm. (If the .rule file also contains a @TABLE section, RuleLoader will use the first one it finds.) The contents of this section is identical to the contents of a .tree file.

Essentially, the tree format allows you to add your own rules to Golly without needing to know how to recompile Golly and without dealing with the intricacies of external libraries; it generates relatively compact files, and the data structure is designed for very fast execution.

A rule tree is nothing more than a complete transition table for a rule, expressed in a compressed, canonicalized tree format. For an n state rule, each tree node has n children; each child is either another tree node or a next state value. To look up a function of m variables, each of which is a state value, you start at the root node and select the child node corresponding to the value of the first variable. From that node, you select the child node corresponding to the value of the second variable, and so on. When you finally look up the value of the final variable in the last node, the result value is the actual next state value, rather than another node.

The tree format has fixed the order of variables used for these lookups. For a four-neighbor rule, the order is always north, west, east, south, center; for an eight-neighbor rule, the order is always northwest, northeast, southwest, southeast, north, west, east, south, center.

Without compression, for an n-state rule, there would be a total of 1+n+n^2+n^3+n^4 nodes for a four-neighbor rule, and 1+n+...+n^8 for an eight-neighbor rule; this could quickly get unmanageable. Almost all rules show significant redundancy, with identical rows in the transition table, and identical nodes in the rule tree. To compress this tree, all we do is merge identical nodes, from the bottom up. This can be done explicitly as we construct the tree from a transition function (see Rules/TreeGenerators/RuleTreeGen.java) or symbolically as we evaluate a more expressive format.

The tree format itself is simple, and has similarities to the macrocell format. It is not intended for human authorship or consumption. The tree format has two parts: a header, and the rule tree itself. The header consists of comments (lines starting with a "#") that are ignored, and three required parameter values that must be defined before the first tree node. These values are defined, one per line, starting with the parameter name, then an equals sign, and finally an integer value. The three parameters are num_states, which must be in the range 2..256 inclusive, num_neighbors, which must be 4 or 8, and num_nodes, which must match the number of node lines.

The tree is represented by a sequence of node lines. Each node line consists of exactly num_states integers separated by single spaces. The first integer of each node line is the depth of that node, which must range from 1..num_neighbors+1. The remaining integers for nodes of depth one are state values. The remaining integers for nodes of depth greater than one are node numbers. Nodes are numbered in the order they appear in the file, starting with zero; each node must be defined before its node number is used. The root node, which must be the single node at depth num_neighbors+1, must be the last node defined in the file.

@COLORS

This section is optional and can be used to specify the RGB colors for one or more states using lines with 4 numbers, like these:

0  48  48  48   dark gray
1   0 128 255   light blue
2 255 255 255   white
3 255 128   0   orange

Golly silently ignores any states that are invalid for the rule. To specify a color gradient for all live states (all states except 0) you can use a line with 6 numbers, like this:

0 0 255  255 0 0   blue to red

In both cases, any text after the final number on each line is ignored. Blank lines or lines starting with "#" are also ignored.

Note that a .rule file is loaded after switching to the current algorithm's default color scheme, so you have the choice of completely changing all the default colors, or only changing some of them.

@ICONS

This section is optional and can be used to override the default icons displayed for this rule (when Golly is in icon mode).

Specifying icons using XPM

Icon bitmaps can be specified using a simple subset of the XPM format. Here's a small example that describes two 7x7 icons suitable for a 3-state rule (icons are never used for state 0):

XPM
/* width height num_colors chars_per_pixel */
"7 14 2 1"
/* colors */
". c #000000"
"A c #FFFFFF"
/* icon for state 1 */
"A......"
".A....."
"..A...."
"...A..."
"....A.."
".....A."
"......A"
/* icon for state 2 */
"......A"
".....A."
"....A.."
"...A..."
"..A...."
".A....."
"A......"

Any blank lines or lines starting with "#" or "/" are ignored. A line with XPM by itself indicates the start of a set of icon bitmaps at a particular size. The @ICONS section can contain any number of XPM subsections, and their order is not important. Three different icon sizes are currently supported: 7x7, 15x15 and 31x31 (for displaying at scales 1:8, 1:16 and 1:32 respectively). Any missing icon sizes will be created automatically by scaling a supplied size. Scaled icons can look rather ugly, so if you want good looking icons it's best to supply all three sizes.

After seeing an XPM line, Golly then looks for lines containing strings delimited by double quotes. The first double quote must be at the start of the line (any text after the second double quote is ignored). The first string contains crucial header information in the form of 4 positive integers:

  • The 1st number is the bitmap's width which also defines the icon size. If it is not 7, 15 or 31 then Golly simply ignores the rest of the XPM data. (This provides upward compatibility if we ever decide to support more sizes.)
  • The 2nd number is the bitmap's height. This must be an integer multiple of the width — the number of icons is the height divided by the width.
  • The 3rd number is the total number of different colors used in the bitmap. After the first string comes the strings that specify each color.
  • The 4th number is the number of characters used to specify each pixel and must be 1 or 2. After the color strings comes the strings with the pixel data for each row of the bitmap. Each such string should contain width × chars_per_pixel characters.

The total number of strings after the XPM line should be 1 + num_colors + height. You'll get an error message if there aren't enough strings. Any extra strings are ignored.

The 1st icon specified is for state 1, the 2nd is for state 2, etc. If the number of icons supplied is fewer than the number of live states then the last icon is automatically duplicated. If there are more icons than required then the extra icons are simply ignored.

Grayscale icons or multi-color icons

Golly recognizes two types of icons: grayscale or multi-color. Grayscale icons only use shades of gray (including black and white), as in the above example. Any black areas will be transparent; ie. those pixels will be replaced by the color for state 0. White pixels will be replaced by the color for the cell's current state. Gray pixels are used to do anti-aliasing; ie. the darker the gray the greater the transparency. Using grayscale icons minimizes the amount of XPM data needed to describe a set of icons, especially if the icons use the same shape for each state (as in WireWorld.rule).

If a set of icons contains at least one color that isn't a shade of gray (including black or white) then the icons are said to be multi-colored. Any black pixels are still converted to the state 0 color, but non-black pixels are displayed without doing any substitutions.

If you want to use multi-colored icons then you'll probably want a @COLORS section as well so that the non-icon colors match the icon colors as closely as possible. For example, if the icon for state 1 consists of red and blue triangles then it would be best to set the color of state 1 to purple in the @COLORS section. This minimizes "color shock" when switching between icon and non-icon display mode.

Requesting built-in icons

Instead of specifying icon bitmaps using XPM data, you might prefer to use Golly's built-in grayscale icons by supplying one of the following words on a line by itself:

  • circles — circular icons (normally used for Moore neighborhood rules).
  • diamonds — diamond-shaped icons (normally used for von Neumann neighborhood rules).
  • hexagons — hexagonal icons (normally used for hexagonal neighborhood rules).
  • triangles — triangular icons (only suitable for a 4-state rule that is emulating a triangular neighborhood).

How Golly finds .rule files

There are two situations where Golly needs to look for a .rule file:

1. If the RuleLoader algorithm is asked to switch to a rule called "Foo" then it first looks for Foo.rule in Documents/Rules/. If not found, or if Foo.rule has no @TABLE or @TREE section, it will then look for Foo.rule in the supplied Rules folder. If Foo.rule doesn't exist then it will use the same search procedure to look for Foo.table, then Foo.tree.

2. After switching to a new rule (not necessarily using RuleLoader), Golly needs to look for color and/or icon information specific to that rule. A similar search procedure to the one above is used again, where this time Golly looks for any @COLORS and/or @ICONS sections in Foo.rule. (Unlike the above search, if Foo.rule is found in Documents/Rules/ but doesn't have any color/icon info then Golly will not look for Foo.rule in the supplied Rules folder.)

Related rules can share colors and/or icons

If rulename.rule is missing either the @COLORS or @ICONS section, Golly checks to see if rulename contains a hyphen. If it does then it looks for the missing color/icon data in another .rule file called prefix-shared.rule where prefix consists of all the characters before the final hyphen. (As in the above searches, it looks in Documents/Rules/ first, then in the supplied Rules folder.) This allows related rules to share a single source of colors and/or icons.

For example, suppose you have a set of related rules in files called Foo-1.rule, Foo-2.rule, etc. If you want all these rules to use the same colors then create a file called Foo-shared.rule:

@RULE Foo-shared
This file contains the colors shared by Foo-* rules.

@TABLE
n_states:3
neighborhood:Moore
symmetries:none
# do nothing

@COLORS
0 0 0 0     black
1 255 0 0   red
2 0 0 255   blue

Note that a shared .rule file should contain a valid @TABLE section with an appropriate value for n_states (the neighborhood setting doesn't really matter, as long as it's legal). This allows the RuleLoader algorithm to load it.

For another good example, see Worm-shared.rule. It contains the icons shared by all the other Worm-* rules.

How to override a supplied or built-in rule

The search procedure described above makes it easy to override a supplied .rule file, either completely or partially. For example, if you want to override the colors and icons used in the supplied WireWorld.rule then you can create a file with the same name in Documents/Rules/. Its contents might look like this:

@RULE WireWorld

@COLORS
0 0 0 0               black background
0 255 0   255 255 0   live states fade from green to yellow

@ICONS
diamonds

It's also possible to override a built-in rule (ie. a rule recognized by an algorithm other than RuleLoader). A built-in rule name can contain characters not allowed in file names ("/" and "\"), so Golly will substitute those characters with underscores when looking for the corresponding .rule file. For example, if you want to change the colors and/or icons for Life (B3/S23) then you'll need to create a file called B3_S23.rule. This example uses a multi-colored icon to show a blue sphere on a white background:

@RULE B3_S23

Override the default colors and icons for Life (B3/S23).

@COLORS

0 255 255 255   white (matches icon background below)
1 54 54 194     dark blue (average color of icon below)

@ICONS

# 7x7 and 15x15 icons will be created by scaling down this 31x31 icon:

XPM
/* width height num_colors chars_per_pixel */
"31 31 78 2"
/* colors */
".. c #FFFFFF"   white background
"BA c #CECEDE"
"CA c #7B7BAD"
"DA c #4A4A84"
"EA c #18187B"
"FA c #08006B"
"GA c #18186B"
"HA c #29297B"
"IA c #6B6BAD"
"JA c #ADADDE"
"KA c #EFF7FF"
"LA c #ADADC6"
"MA c #39398C"
"NA c #3939BD"
"OA c #7B7BCE"
"PA c #ADB5DE"
"AB c #8C8CD6"
"BB c #4A4A9C"
"CB c #18188C"
"DB c #EFEFEF"
"EB c #EFEFFF"
"FB c #525A9C"
"GB c #08088C"
"HB c #ADADE7"
"IB c #DEDEEF"
"JB c #D6D6F7"
"KB c #DEE7F7"
"LB c #BDBDEF"
"MB c #525ABD"
"NB c #21219C"
"OB c #292984"
"PB c #CECEE7"
"AC c #ADB5CE"
"BC c #2929BD"
"CC c #7B7BDE"
"DC c #BDC6E7"
"EC c #CECEF7"
"FC c #8C8CE7"
"GC c #4242C6"
"HC c #A5A5BD"
"IC c #08087B"
"JC c #3939CE"
"KC c #5A5AC6"
"LC c #BDBDF7"
"MC c #BDBDDE"
"NC c #6B6BD6"
"OC c #9494DE"
"PC c #3931DE"
"AD c #1818AD"
"BD c #2929CE"
"CD c #9C9CC6"
"DD c #10087B"
"ED c #9C9CBD"
"FD c #1818B5"
"GD c #1818C6"
"HD c #847BCE"
"ID c #181094"
"JD c #6B6BCE"
"KD c #7B7BB5"
"LD c #2121AD"
"MD c #BDC6D6"
"ND c #0808AD"
"OD c #4A42B5"
"PD c #00009C"
"AE c #3942BD"
"BE c #3129B5"
"CE c #B5B5CE"
"DE c #0000BD"
"EE c #0000CE"
"FE c #0000DE"
"GE c #42427B"
"HE c #C6CECE"
"IE c #0000EF"
"JE c #9494AD"
"KE c #F7FFEF"
"LE c #10086B"
"ME c #7B849C"
"NE c #0000F7"
/* icon for state 1 */
".............................................................."
".............................................................."
"......................BACADAEAFAGAHAIAJA......................"
"................KALAMAFANAOAJAPAJAABBBCBEAIADB................"
"..............EBFBGBNAHBIBDBJBKAKBEBJBLBMBNBOBPB.............."
"............ACHABCCCDCECIBPBJBPBIBPBJBIBECFCGCCBCAKA.........."
"..........HCICJCKCLBLCLBMCLBLBLBLBMCLBLBMCLCNCJCCBCAKA........"
"........DBOBBCJCCCJAJAJAJAJAJAJAJAJAJAJAJAJAOCJCPCICAC........"
"......KADAADBDBCABABOCABOCOCOCOCABOCABOCABCDFCJCBDBCDDBA......"
"......EDGBFDGDADCCABOAOAOAOAOAOAOAOAHDOAHDCCCCNAADGDIDMA......"
"....KAHAADFDFDADJDMBOAJDJDJDJDJDKDJDJDJDJDJDJDLDFDFDFDICBA...."
"....MDFANDNDNDADODMBMBMBMBMBMBMBKCKCMBMBMBMBODADNDNDNDGBIA...."
"....CAGBNDPDNDPDADGCODODODODODODNAODODGCODAEBCPDNDPDNDPDGA...."
"....OBPDPDNDPDNDNDADBCBEBCBEBCBCBEBCBCBCNAADPDNDNDPDPDNDICPB.."
"....ICNDNDPDNDNDNDPDNDADADADADADADADADADNDNDNDNDNDNDNDPDGBCE.."
"....FANDNDDENDNDNDDENDDENDNDNDNDNDNDNDNDNDNDNDNDNDNDNDNDGBLA.."
"....FANDDENDDEDENDDEDENDDENDDEDEDEDEDEDEDEDEDEDEDENDDEDEGBED.."
"....GANDEEDEDEDEDEDEDEDEDEDEDEDENDDENDDEDEDEDEDEDEDEDEDEGBLA.."
"....BBPDEEDEEEDEEEDEEEDEEEDEDEDEEEDEEEDEDEDEDEDEEEDEEEDEFABA.."
"....EDGBDEEEDEEEEEEEDEEEDEEEEEEEEEEEEEEEEEEEEEEEEEDEEENDGADB.."
"....KBICDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEGBDA...."
"......FBNDFEFEEEEEEEEEFEEEEEFEEEEEEEEEEEEEEEEEEEEEFEDEICHC...."
"......IBEADEFEFEEEFEFEFEFEFEEEFEFEFEFEFEFEFEFEFEFEDEGBGEDB...."
"........LAGBFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFENDGAHE......"
"..........FBNDFEFEIEFEFEIEIEIEFEIEFEFEIEFEFEFEFEEEDDJEKE......"
"..........EBFBIDEEIEIEIEFEFEFEIEFEIEIEIEIEIEIENDLEMEKE........"
"..............CDGBDEIEIENENEIEIEIEIEIEIEIEGDPDGAJEKE.........."
"................BAOBGBADFEIENEIENEIEIEEENDFAGECEKE............"
"....................CDBBDDPDIDNDADPDICEAGEJEDB................"
"........................EBBALAEDEDHCMCDBKE...................."
".............................................................."

The easy way to install a new .rule file

Golly provides a quick and easy way to create a new .rule file in the right place. Simply copy the rule contents to the clipboard, then tap the Paste button. If the first line of the clipboard starts with "@RULE rulename" then Golly will save the text as Documents/Rules/rulename.rule and switch to that rule.

Deprecated files (.table, .tree)

Golly still supports files with extensions of .table or .tree, but their use is discouraged. When Golly opens a .zip file containing .table/tree files it will automatically convert them into .rule files, but only if the zip file has no .rule files. Any existing .rule files are overwritten (in case the zip file contents have changed).

Note that files with extensions of .colors or .icons are no longer supported and are simply ignored. The .rule format can be used to specify color and/or icon information via the @COLORS and @ICONS sections, as described above.

Zip files

Golly can open a standard zip file and display its contents in the Help tab. It does this by building a temporary HTML file with special unzip links to each included file. Any .rule files in the zip file are automatically extracted and installed into Documents/Rules/.

A number of pattern collections in the form of zip files can be downloaded from the online archives. golly-2.7-src/gui-common/Help/index.html0000644000175000017500000000400612536111364015157 00000000000000

Table of Contents

  • References
  • File Formats
  • Bounded Grids
  • Known Problems
  • Credits
golly-2.7-src/gui-common/Help/Lexicon/0000755000175000017500000000000012536111364014643 500000000000000golly-2.7-src/gui-common/Help/Lexicon/lex_m.htm0000644000175000017500000005647012536111364016415 00000000000000 Life Lexicon (M)

Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:mango (p1)

.OO..
O..O.
.O..O
..OO.

:mathematician (p5) Found by Dave Buckingham, 1972.

....O....
...O.O...
...O.O...
..OO.OO..
O.......O
OOO...OOO
.........
OOOOOOOOO
O.......O
...OOOO..
...O..OO.

:Max A name for the smallest known spacefiller. The name represents the fact that the growth rate is the fastest possible. (This has not quite been proved, however. There remains the possibility, albeit not very likely, that a periodic agar could have an average density greater than 1/2, and a spacefiller stretching such an agar at the same speed as the known spacefillers would have a faster average growth rate.)

:mazing (p4) In terms of its minimum population of 12 this ties with mold as the smallest p4 oscillator. Found by Dave Buckingham in December 1973. For some constructions using mazings, see popover and sixty-nine.

...OO..
.O.O...
O.....O
.O...OO
.......
...O.O.
....O..

:medium fish = MWSS

:metacatacryst A 52-cell pattern exhibiting quadratic growth. Found by Nick Gotts, December 2000. This is currently the smallest known pattern (in terms of initial population) with superlinear growth. See also catacryst.

:metamorphosis An oscillator built by Robert Wainwright that uses the following reaction (found by Bill Gosper) to turn gliders into LWSS, and converts these LWSS back into gliders by colliding them head on. (There are in fact two ways to do the following reaction, because the spark of the twin bees shuttle is symmetric.)

...................O.........
....................O........
..................OOO........
.............................
.............................
.............................
.............................
.............................
............O...O.....O.OO...
OO.........O.....O....O.O.O..
OO.........O.........O....O..
...........OO...O.....O.O.O..
.............OOO......O.OO...
.............................
.............OOO.............
...........OO...O............
OO.........O...............OO
OO.........O.....O.........OO
............O...O............

:metamorphosis II An oscillator built by Robert Wainwright in December 1994 based on the following p30 glider-to-LWSS converter. This converter was first found by Paul Rendell, January 1986 or earlier, but wasn't widely known about until Paul Callahan rediscovered it in December 1994.

......................O.
.....................O..
.....................OOO
........................
........................
.........O.O............
.........O..O...........
OO..........OO..........
OO........O...OO........
.....OO.....OO..........
....O....O..O...........
.........O.O............
........................
........................
........................
........................
................O.......
...............OOO......
..............OOOOO.....
.............O.O.O.O....
.............OO...OO....
........................
........................
................O.......
...............O.O......
...............O.O......
................O.......
...............OO.......
...............OO.......
...............OO.......

:methuselah Any small pattern that stabilizes only after a long time. Term coined by Conway. Examples include rabbits, acorn, the R-pentomino, blom, Iwona, Justyna and Lidka. See also ark.

:Mickey Mouse (p1) A name proposed by Mark Niemiec for the following still life:

.OO....OO.
O..O..O..O
O..OOOO..O
.OO....OO.
...OOOO...
...O..O...
....OO....

:middleweight emulator = MW emulator

:middleweight spaceship = MWSS

:middleweight volcano = MW volcano

:mini pressure cooker (p3) Found by Robert Wainwright before June 1972. Compare pressure cooker.

.....O.....
....O.O....
....O.O....
...OO.OO...
O.O.....O.O
OO.O.O.O.OO
...O...O...
...O.O.O...
....O.O....
.....O.....

:M.I.P. value The maximum population divided by the initial population for an unstable pattern. For example, the R-pentomino has an M.I.P. value of 63.8, since its maximum population is 319. The term is no longer in use.

:MIT oscillator = cuphook

:MMM breeder See breeder.

:MMS breeder See breeder.

:mod The smallest number of generations it takes for an oscillator or spaceship to reappear in its original form, possibly subject to some rotation or reflection. The mod may be equal to the period, but it may also be a quarter of the period (for oscillators that rotate 90 degrees every quarter period) or half the period (for other oscillators which rotate 180 degrees every half period, and also for flippers).

:mold (p4) Found by Achim Flammenkamp in 1988, but not widely known until Dean Hickerson rediscovered it (and named it) in August 1989. Compare with jam. In terms of its minimum population of 12 it ties with mazing as the smallest p4 oscillator. But in terms of its 6x6 bounding box it wins outright. In fact, of all oscillators that fit in a 6x7 box it is the only one with period greater than 2.

...OO.
..O..O
O..O.O
....O.
O.OO..
.O....

:monogram (p4) Found by Dean Hickerson, August 1989.

OO...OO
.O.O.O.
.OO.OO.
.O.O.O.
OO...OO

:moose antlers (p1)

OO.....OO
O.......O
.OOO.OOO.
...O.O...
....O....

:mosquito See mosquito1, mosquito2. mosquito3, mosquito4 and mosquito5.

:mosquito1 A breeder constructed by Nick Gotts in September 1998. The original version had an initial population of 103, which was then the smallest for any known pattern with superlinear growth (beating the record previously held by Jaws). This was reduced to 97 by Stephen Silver the following month, but was then almost immediately superseded by mosquito2.

Mosquito1 consists of the classic puffer train plus four LWSS and four MWSS (mostly in predecessor form, to keep the population down). Once it gets going it produces a new block-laying switch engine (plus a lot of junk) every 280 generations. It is therefore an MMS breeder, albeit a messy one.

:mosquito2 A breeder constructed by Nick Gotts in October 1998. Its initial population of 85 was for a couple of hours the smallest for any known pattern with superlinear growth, but was then beaten by mosquito3.

Mosquito2 is very like mosquito1, but uses two fewer MWSS and one more LWSS.

:mosquito3 A breeder constructed by Nick Gotts in October 1998. Its initial population of 75 was at the time the smallest for any known pattern with superlinear growth, but was beaten a few days later by mosquito4.

Mosquito3 has one less LWSS than mosquito2. It is somewhat different from the earlier mosquitoes in that the switch engines it makes are glider-producing rather than block-laying.

:mosquito4 A slightly improved version of mosquito3 which Stephen Silver produced in October 1998 making use of another discovery of Nick Gotts (September 1997): an 8-cell pattern that evolves into a LWSS plus some junk. Mosquito4 is a breeder with an initial population of 73, at the time the smallest for any known pattern with superlinear growth, but superseded a few days later by mosquito5.

:mosquito5 A slightly improved version of mosquito4 which Nick Gotts produced in October 1998. The improvement is of a similar nature to the improvement of mosquito4 over mosquito3. Mosquito5 is a breeder with an initial population of 71. At the time, this was the smallest population for any known pattern with superlinear growth, but it has since been superseded by teeth, catacryst and metacatacryst.

:mould = mold

:moving sawtooth A sawtooth such that no cell is ON for more than a finite number generations. David Bell has constructed patterns of this type, with a c/2 front end and a c/3 back end.

:MSM breeder See breeder.

:multi-state Life = colorized Life

:multum in parvo (stabilizes at time 3933) A methuselah found by Charles Corderman, but not as long-lasting as his acorn.

...OOO
..O..O
.O....
O.....

:muttering moat Any oscillator whose rotor consists of a closed chain of cells each of which is adjacent to exactly two other rotor cells. Compare babbling brook. Examples include the bipole, the blinker, the clock, the cuphook, the Gray counter, the quad, the scrubber, the skewed quad and the p2 snake pit. The following diagram shows a p2 example (by Dean Hickerson, May 1993) with a larger rotor. See ring of fire for a very large one.

OO.....
O.O.OO.
.....O.
.O..O..
..O....
..O.O.O
.....OO

:MW emulator (p4) Found by Robert Wainwright in June 1980. See also emulator and filter.

.......O.......
..OO.O...O.OO..
..O.........O..
...OO.....OO...
OOO..OOOOO..OOO
O..O.......O..O
.OO.........OO.

:MWSS (c/2 orthogonally, p4) A middleweight spaceship, the third most common spaceship. Found by Conway in 1970. See also LWSS and HWSS.

...O..
.O...O
O.....
O....O
OOOOO.

:MWSS emulator = MW emulator

:MWSS out of the blue The following reaction, found by Peter Rott in November 1997, in which a LWSS passing by a p46 oscillator creates a MWSS travelling in the opposite direction. Together with some reactions found by Dieter Leithner, and a LWSS-turning reaction which Rott had found in November 1993 (but which was not widely known until Paul Callahan rediscovered it in June 1994) this can be used to prove that there exist gliderless guns for LWSS, MWSS and HWSS for every period that is a multiple of 46.

O..O.................................
....O................................
O...O................................
.OOOO................................
.....................................
.....................................
.....................................
.....................................
.....................................
...................OO..............OO
..................OO...............OO
...................OOOOO.............
..OO................OOOO.............
..OO.....O...........................
........OOO.........OOOO.............
.......O.O.O.......OOOOO.............
........O..O......OO...............OO
........OOO........OO..............OO
.........O...........................
.....................................
.....................................
.....................................
.....................................
..O.......O..........................
.....................................
OOO.......OOO........................
.OO.OO.OO.OO.........................
..OOO...OOO..........................
...O.....O...........................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
.....................................
..OO.....OO..........................
..OO.....OO..........................

:MW volcano (p5) Found by Dean Hickerson in April 1992.

......O......
....O...O....
.............
...O.....O...
.OOO.OOO.OOO.
O...OO.OO...O
O.OOO.O.OOOO.
.O...........
...O.O.O.OO.O
..OO.OOO.O.OO
...O.O..O....
...O..OO.....
..OO.........

:My Experience with B-heptominos in Oscillators An article by Dave Buckingham (October 1996) that describes his discovery of Herschel conduits, including sufficient (indeed ample) stable conduits to enable, for the first time, the construction of period n oscillators - and true period n guns - for every sufficiently large integer n. (See Herschel loop and emu.)


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_w.htm0000644000175000017500000003244712536111364016425 00000000000000 Life Lexicon (W)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:washerwoman (2c/3 p18 fuse) A fuse by Earl Abbe.

O.......................................................
OO....O.....O.....O.....O.....O.....O.....O.....O.....O.
OOO..O.O...O.O...O.O...O.O...O.O...O.O...O.O...O.O...O.O
OO....O.....O.....O.....O.....O.....O.....O.....O.....O.
O.......................................................

:washing machine (p2) Found by Robert Wainwright before June 1972.

.OO.OO.
O.OO..O
OO....O
.O...O.
O....OO
O..OO.O
.OO.OO.

:wasp (c/3 orthogonally, p3) The following spaceship which produces a domino spark at the back. It is useful for perturbing other objects. Found by David Bell, March 1998.

..........OO.OO.......
........OO.O.OO.OO....
.....OOO.O..OOO..OOOO.
.OOO....OOO.....O....O
O.O.O.OOO.O........OO.
O.O.O.OOOO............
.O.O....O..O..........
..........O...........
..O...................
..O...................

:wavefront (p4) Found by Dave Buckingham, 1976 or earlier.

........OO...
........O....
.........O...
........OO...
.....OO...OO.
....O..OOO..O
....O.....OO.
.....O...O...
OO.O.O...O...
O.OO.O.OO....
....O.O......
....O.O......
.....O.......

:waveguide See superstring.

:weekender (2c/7 orthogonally, p7) Found by David Eppstein in January 2000. In April 2000 Stephen Silver found a tagalong for a pair of weekenders. At present, n weekenders pulling n-1 tagalongs constitute the only known spaceships of this speed or period.

.O............O.
.O............O.
O.O..........O.O
.O............O.
.O............O.
..O...OOOO...O..
......OOOO......
..OOOO....OOOO..
................
....O......O....
.....OO..OO.....

:weld To join two or more still lifes or oscillators together. This is often done in order to fit the objects into a smaller space than would otherwise be possible. The simplest useful example is probably the integral sign, which can be considered as a pair of welded eater1s.

:Wheels, Life, and other Mathematical Amusements One of Martin Gardner's books (1983) that collects together material from his column in Scientific American. The last three chapters of this book contain all the Life stuff.

:why not (p2) Found by Dave Buckingham, July 1977.

...O...
...O.O.
.O.....
O.OOOOO
.O.....
...O.O.
...O...

:wick A stable or oscillating linearly repeating pattern that can be made to burn at one end. See fuse.

:wickstretcher A spaceship-like object which stretches a wick that is fixed at the other end. The wick here is assumed to be in some sense connected, otherwise most puffers would qualify as wickstretchers. The first example of a wickstretcher was found in October 1992 (front end by Hartmut Holzwart and back end by Dean Hickerson) and stretches ants at a speed of c/4. This is shown below with an improved back end found by Hickerson the following month.

.................OO..............................
.............OO....O.............................
............OOO.O................................
O.OO..OO...O...OOOO.O.O....OO.......OO...........
O....OO..O........O.OOO....O....OO.O..O.OO.O.....
O.OO....OO.OO....O...........O...O.O.OO.O.OO.....
......O.......O.............OO.....O..O.O...OO...
.....O.........O.O....OOO...O....O..O.O.OOO...O..
.....O.........O.O....OOO.OO.O..OO.O.O...O..OO.O.
......O.......O.............OO.O...OO....OO....O.
O.OO....OO.OO....O..........O........OO.O.O.OO.OO
O....OO..O........O.OOO........O...O...OO.O..O.O.
O.OO..OO...O...OOOO.O.O.......O.O...OO....O..O.O.
............OOO.O..............O.....O.OOO....O..
.............OO....O.................O.O.........
.................OO...................O..........
Diagonally moving c/4 and c/12 wickstretchers have also been built: see tubstretcher and linestretcher. In July 2000 Jason Summers constructed a c/2 wickstretcher, stretching a p50 traffic jam wick, based on an earlier (October 1994) pattern by Hickerson.

:wicktrailer Any extensible tagalong, that is, one which can be attached to the back of itself, as well as to the back of a spaceship. The number of generations which it takes for the tagalong to occur again in the same place is often called the period of the wicktrailer - this has little relation to the period of the tagalong units themselves.

:windmill (p4) Found by Dean Hickerson, November 1989.

...........O......
.........OO.O.....
.......OO.........
..........OO......
.......OOO........
..................
OOO...............
...OO..OOO.OO.....
..........OOOOOOO.
.OOOOOOO..........
.....OO.OOO..OO...
...............OOO
..................
........OOO.......
......OO..........
.........OO.......
.....O.OO.........
......O...........

:wing The following induction coil. This is generation 2 of block and glider.

.OO.
O..O
.O.O
..OO

:WinLifeSearch Jason Summers' GUI version of lifesrc for MS Windows. It is available from http://entropymine.com/jason/life/software/.

:Winning Ways A two-volume book (1982) by Elwyn Berlekamp, John Conway and Richard Guy on mathematical games. The last chapter of the second volume concerns Life, and outlines a proof of the existence of a universal constructor.

:with-the-grain grey ship A grey ship in which the region of density 1/2 consists of lines of ON cells lying parallel to the direction in which the spaceship moves. See also against-the-grain grey ship.

:WLS = WinLifeSearch

:worker bee (p9) Found by Dave Buckingham in 1972. Unlike the similar snacker this produces no sparks, and so is not very important. Like the snacker, the worker bee is extensible - it is, in fact, a finite version of the infinite oscillator which consists of six ON cells and two OFF cells alternating along a line. Note that Dean Hickerson's new snacker ends also work here.

OO............OO
.O............O.
.O.O........O.O.
..OO........OO..
................
.....OOOOOO.....
................
..OO........OO..
.O.O........O.O.
.O............O.
OO............OO

:W-pentomino Conway's name for the following pentomino, a common loaf predecessor.

O..
OO.
.OO

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_a.htm0000644000175000017500000003660012536111364016372 00000000000000 Life Lexicon (A)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Achim's p144 (p144) This was found (minus the blocks shown below) on a cylinder of width 22 by Achim Flammenkamp in July 1994. Dean Hickerson reduced it to a finite form using figure-8s the same day. The neater finite form shown here - replacing the figure-8s with blocks - was found by David Bell in August 1994. See factory for a use of this oscillator.

OO........................OO
OO........................OO
..................OO........
.................O..O.......
..................OO........
..............O.............
.............O.O............
............O...O...........
............O..O............
............................
............O..O............
...........O...O............
............O.O.............
.............O..............
........OO..................
.......O..O.................
........OO..................
OO........................OO
OO........................OO

:Achim's p16 (p16) Found by Achim Flammenkamp, July 1994.

.......OO....
.......O.O...
..O....O.OO..
.OO.....O....
O..O.........
OOO..........
.............
..........OOO
.........O..O
....O.....OO.
..OO.O....O..
...O.O.......
....OO.......

:Achim's p4 (p4) Dave Buckingham found this in a less compact form (using two halves of sombreros) in 1976. The form shown here was found by Achim Flammenkamp in 1988. The rotor is two copies of the rotor of 1-2-3-4, so the oscillator is sometimes called the "dual 1-2-3-4".

..OO...OO..
.O..O.O..O.
.O.OO.OO.O.
OO.......OO
..O.O.O.O..
OO.......OO
.O.OO.OO.O.
.O..O.O..O.
..OO...OO..

:Achim's p5 = pseudo-barberpole

:Achim's p8 (p8) Found by Achim Flammenkamp, July 1994.

.OO......
O........
.O...O...
.O...OO..
...O.O...
..OO...O.
...O...O.
........O
......OO.

:acorn (stabilizes at time 5206) A methuselah found by Charles Corderman.

.O.....
...O...
OO..OOO

:A for all (p6) Found by Dean Hickerson in March 1993.

....OO....
...O..O...
...OOOO...
.O.O..O.O.
O........O
O........O
.O.O..O.O.
...OOOO...
...O..O...
....OO....

:against-the-grain grey ship A grey ship in which the region of density 1/2 consists of lines of ON cells lying perpendicular to the direction in which the spaceship moves. See also with-the-grain grey ship.

:agar Any pattern covering the whole plane that is periodic in both space and time. The simplest (nonempty) agar is the stable one extended by the known spacefillers. For some more examples see chicken wire, houndstooth agar, onion rings, squaredance and Venetian blinds. Tiling the plane with the pattern O......O produces another interesting example: a p6 agar which has a phase of density 3/4, which is the highest yet obtained for any phase of an oscillating pattern.

:aircraft carrier (p1) This is the smallest still life that has more than one island.

OO..
O..O
..OO

:airforce (p7) Found by Dave Buckingham in 1972. The rotor consists of two copies of that used in the burloaferimeter.

.......O......
......O.O.....
.......O......
..............
.....OOOOO....
....O.....O.OO
...O.OO...O.OO
...O.O..O.O...
OO.O...OO.O...
OO.O.....O....
....OOOOO.....
..............
......O.......
.....O.O......
......O.......

:AK47 reaction The following reaction (found by Rich Schroeppel and Dave Buckingham) in which a honey farm predecessor, catalysed by an eater and a block, reappears at another location 47 generations later, having produced a glider and a traffic light. This is the basis of a very small (but pseudo) p94 glider gun found by Paul Callahan in July 1994, and was in 1990 the basis for the Dean Hickerson's construction of the first true p94 gun. (This latter gun was enormous, and has now been superseded by comparatively small Herschel loop guns.)

.....O....
....O.O...
...O...O..
...O...O..
...O...O..
....O.O...
.....O....
..........
..OO......
...O......
OOO.....OO
O.......OO

:Al Jolson = Jolson

:almosymmetric (p2) Found in 1971.

....O....
OO..O.O..
O.O......
.......OO
.O.......
O......O.
OO.O.O...
.....O...

:anteater A pattern that consumes ants.

:antlers = moose antlers

:ants (p5 wick) The standard form is shown below. It is also possible for any ant to be displaced by one or two cells relative to either or both of its neighbouring ants. Dean Hickerson found fenceposts for both ends of this wick in October 1992 and February 1993. See electric fence, and also wickstretcher.

OO...OO...OO...OO...OO...OO...OO...OO...OO..
..OO...OO...OO...OO...OO...OO...OO...OO...OO
..OO...OO...OO...OO...OO...OO...OO...OO...OO
OO...OO...OO...OO...OO...OO...OO...OO...OO..

:antstretcher Any wickstretcher that stretches ants.

:anvil The following induction coil.

.OOOO.
O....O
.OOO.O
...O.OO

:APPS (c/5 orthogonally, p30) An asymmetric PPS. The same as the SPPS, but with the two halves 15 generations out of phase with one another. Found by Alan Hensel in May 1998.

:ark A pair of mutually stabilizing switch engines. The archetype is Noah's ark. The diagram below shows an ark found by Nick Gotts that takes until generation 736692 to stabilize, and can therefore be considered as a methuselah.

...........................O....
............................O...
.............................O..
............................O...
...........................O....
.............................OOO
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
................................
OO..............................
..O.............................
..O.............................
...OOOO.........................

:arm A long extension hanging off from the main body of a spaceship or puffer perpendicular to the direction of travel.

A lot of known spaceships have multiple arms. This is an artefact of the search methods used to find such spaceships, rather than an indication of what a "typical" spaceship might look like.

:ash The (stable or oscillating) debris left by a random reaction. Experiments show that for random soups with moderate initial densities (say 0.25 to 0.5) the resulting ash has a density of about 0.0287. (This is, of course, based on what happens in finite fields. In infinite fields the situation may conceivably be different in the long run because of the effect of certain initially very rare objects such as replicators.)

:aVerage (p5) Found by Dave Buckingham, 1973. The average number of live rotor cells is five (V), which is also the period.

...OO........
....OOO......
..O....O.....
.O.OOOO.O....
.O.O....O..O.
OO.OOO..O.O.O
.O.O....O..O.
.O.OOOO.O....
..O....O.....
....OOO......
...OO........

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_u.htm0000644000175000017500000002327512536111364016422 00000000000000 Life Lexicon (U)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:underpopulation Death of a cell caused by it having fewer than two neighbours. See also overpopulation.

:unit Life cell A rectangular pattern, of size greater than 1x1, that can simulate Life in the following sense. The pattern by itself represents a dead Life cell, and some other pattern represents a live Life cell. When the plane is tiled by these two patterns (which then represent the state of a whole Life universe) they evolve, after a fixed amount of time, into another tiling of the plane by the same two patterns which correctly represents the Life generation following the one they initially represented. It is usual to use capital letters for the simulated things, so, for example, for the first known unit Life cell (constructed by David Bell in January 1996), one Generation is 5760 generations, and one Cell is 500x500 cells.

In December 2005, Jason Summers constructed an analogous unit cell for Wolfram's Rule 100, a one-dimensional cellular automaton that is know be universal.

:universal computer A computer that can compute anything that is computable. (The concept of computability can be defined in terms of Turing machines, or by Church's lambda calculus, or by a number of other methods, all of which can be shown to lead to equivalent definitions.) The relevance of this to Life is that both Bill Gosper and John Conway proved early on that it is possible to construct a universal computer in the Life universe. (To prove the universality of a cellular automaton with simple rules was in fact Conway's aim in Life right from the start.) Conway's proof is outlined in Winning Ways, and also in The Recursive Universe.

Until recently, no universal Life computer had ever been built in practice, because it would be enormous, even with the improvements that have been devised since those early proofs. In April 2000, Paul Rendell completed a Turing machine construction (described in http://www.cs.ualberta.ca/~bulitko/F02/papers/tm_words.pdf). This, however, has a finite tape, as opposed to the infinite tape of a true Turing machine, and is therefore not a universal computer. But in November 2002, Paul Chapman announced the construction of a universal computer, details of which can be found at http://www.igblan.free-online.co.uk/igblan/ca/. This is a universal register machine based around Dean Hickerson's sliding block memory.

See also universal constructor.

:universal constructor A pattern that is capable of constructing almost any pattern that has a glider synthesis. This definition is a bit vague. A precise definition seems impossible because it has not been proved that all possible glider fleets are constructible. In any case, a universal constructor ought to be able to construct itself in order to qualify as such. An outline of Conway's proof that such a pattern exists can be found in Winning Ways, and also in The Recursive Universe. The key mechanism for the production of gliders with any given path and timing is known as side-tracking, and is based on the kickback reaction. A universal constructor designed in this way can also function as a universal destructor - it can delete almost any pattern that can be deleted by gliders.

In May 2004, Paul Chapman and Dave Greene produced a prototype programmable universal constructor. This is able to construct objects by means of slow glider constructions. It likely that it could be programmed to be construct itself, but the necessary program would be very large; moreover an additional mechanism would be needed in order to copy the program.

A universal constructor is most useful when attached to a universal computer, which can be programmed to control the constructor to produce the desired pattern of gliders. In what follows I will assume that a universal constructor always includes this computer.

The existence of a universal constructor/destructor has a number of theoretical consequences.

For example, the constructor could be programmed to make copies of itself. This is a replicator.

The constructor could even be programmed to make just one copy of itself translated by a certain amount and then delete itself. This would be a (very large, very high period) spaceship. Any translation is possible (except that it must not be too small), so that the spaceship could travel in any direction. It could also travel slower than any given speed, since we could program it to perform some time-wasting task (such as repeatedly constructing and deleting a block) before copying itself. Of course, we could also choose for it to leave some debris behind, thus making a puffer.

It is also possible to show that the existence of a universal constructor implies the existence of a stable reflector. This proof is not so easy, however, and is no longer of much significance now that explicit examples of such reflectors are known.

:universal destructor See universal constructor.

:universal register machine = URM

:universal regulator A regulator in which the incoming gliders are aligned to period 1, that is, they have arbitrary timing (subject to some minimum time required for the regulator to recover from the previous glider).

Paul Chapman constructed the first universal regulator in March 2003. It is adjustable, so that the output can be aligned to any desired period.

:unix (p6) Two blocks eating a long barge. This is a useful sparker, found by Dave Buckingham in February 1976. The name derives from the fact that it was for some time the mascot of the Unix lab of the mathematics faculty at the University of Waterloo.

.OO.....
.OO.....
........
.O......
O.O.....
O..O..OO
....O.OO
..OO....

:up boat with tail = trans-boat with tail

:U-pentomino Conway's name for the following pentomino, which rapidly dies.

O.O
OOO

:URM A universal register machine, particularly Paul Chapman's Life implementation of such a machine. See universal computer for more information.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_f.htm0000644000175000017500000005502712536111364016403 00000000000000 Life Lexicon (F)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:factory Another word for gun, but not used in the case of glider guns. The term is also used for a pattern that repeatedly manufactures objects other than spaceships or rakes. In this case the new objects do not move out of the way, and therefore must be used up in some way before the next one is made. The following shows an example of a p144 gun which consists of a p144 block factory whose output is converted into gliders by a p72 oscillator. (This gun is David Bell's improvement of the one Bill Gosper found in July 1994. The p72 oscillator is by Robert Wainwright, 1990, and the block factory is Achim's p144 minus one of its stabilizing blocks.)

.......................OO........................OO
.......................OO........................OO
.........................................OO........
........................................O..O.......
.........................................OO........
...................................................
....................................OOO............
....................................O.O............
.........OO.........................OOO............
.........OO.........................OO.............
........O..O.......................OOO.............
........O..O.OO....................O.O.............
........O....OO....................OOO.............
..........OO.OO....................................
...............................OO..................
.....................OO.......O..O.................
.....................OO........OO..................
.................................................OO
.................................................OO
...................................................
....OO..................O..........................
OO....OOOO..........OO..OO.OOO.....................
OO..OO.OOO..........OO....OOOO.....................
....O...................OO.........................

:familiar fours Common patterns of four identical objects. The five commonest are traffic light (4 blinkers), honey farm (4 beehives), blockade (4 blocks), fleet (4 ships, although really 2 ship-ties) and bakery (4 loaves, although really 2 bi-loaves).

:fanout A mechanism that emits two or more objects of some type for each one that it receives. Typically the objects are gliders or Herschels; glider duplicators are a special case.

:Fast Forward Force Field The following reaction found by Dieter Leithner in May 1994. In the absence of the incoming LWSS the gliders would simply annihilate one another, but as shown they allow the LWSS to advance 11 spaces in the course of the next 6 generations. A neat illusion. See also star gate. (Leithner named the Fast Forward Force Field in honour of his favourite science fiction writer, the physicist Robert L. Forward.)

.......O......O..
........O......OO
..OO..OOO.....OO.
OO.OO............
OOOO.........O...
.OO.........OO...
............O.O..

:father = parent

:featherweight spaceship = glider

:fencepost Any pattern that stabilizes one end of a wick.

:Fermat prime calculator A pattern constructed by Jason Summers in January 2000 that exhibits infinite growth if and only if there are no Fermat primes greater than 65537. The question of whether or not it really does exhibit infinite growth is therefore equivalent to a well-known and long-standing unsolved mathematical problem. It will, however, still be growing at generation 102585827975. The pattern is based on Dean Hickerson's primer and caber tosser patterns and a p8 beehive puffer by Hartmut Holzwart.

:F-heptomino Name given by Conway to the following heptomino.

OO..
.O..
.O..
.OOO

:figure-8 (p8) Found by Simon Norton in 1970.

OOO...
OOO...
OOO...
...OOO
...OOO
...OOO

:filter Any oscillator used to delete some but not all of the spaceships in a stream. An example is the blocker, which can be positioned so as to delete every other glider in a stream of period 8n+4, and can also do the same for LWSS streams. Other examples are the MW emulator and T-nosed p4 (either of which can be used to delete every other LWSS in a stream of period 4n+2), the fountain (which does the same for MWSS streams) and a number of others, such as the p6 pipsquirter, the pentadecathlon and the p72 oscillator shown under factory. Another example, a p4 oscillator deleting every other HWSS in a stream of period 4n+2, is shown below. (The p4 oscillator here was found, with a slightly larger stator, by Dean Hickerson in November 1994.)

..........OOOO............
....OO...OOOOOO...........
OOOO.OO..OOOO.OO..........
OOOOOO.......OO...........
.OOOO.....................
..........................
................OO........
..............O....O......
..........................
.............O.O..O.O.....
...........OOOO.OO.OOOO...
........O.O....O..O....O.O
........OO.OO.O....O.OO.OO
...........O.O......O.O...
........OO.O.O......O.O.OO
........OO.O..........O.OO
...........O.O.OOOO.O.O...
...........O.O......O.O...
..........OO.O.OOOO.O.OO..
..........O..OOO..OOO..O..
............O..OOOO..O....
...........OO.O....O.OO...
...........O..O....O..O...
............O..O..O..O....
.............OO....OO.....

:fire-spitting (p3) Found by Nicolay Beluchenko, September 2003.

...O......
.OOO......
O.........
.O.OOO....
.O.....O..
..O..O....
..O.O..O.O
........OO

:fish A generic term for LWSS, MWSS and HWSS, or, more generally, for any spaceship.

:fishhook = eater1

:fleet (p1) A common formation of two ship-ties.

....OO....
....O.O...
.....OO...
.......OO.
OO.....O.O
O.O.....OO
.OO.......
...OO.....
...O.O....
....OO....

:flip-flop Any p2 oscillator. However, the term is also used in two more specific (and non-equivalent) senses: (a) any p2 oscillator whose two phases are mirror images of one another, and (b) any p2 oscillator in which all rotor cells die from underpopulation. In the latter sense it contrasts with on-off. The term has also been used even more specifically for the 12-cell flip-flop shown under phoenix.

:flip-flops Another name for the flip-flop shown under phoenix.

:flipper Any oscillator or spaceship that forms its mirror image halfway through its period.

:flotilla A spaceship composed of a number of smaller interacting spaceships. Often one or more of these is not a true spaceship and could not survive without the support of the others. The following example shows an OWSS escorted by two HWSS.

....OOOO.......
...OOOOOO......
..OO.OOOO......
...OO..........
...............
...........OO..
.O............O
O..............
O.............O
OOOOOOOOOOOOOO.
...............
...............
....OOOO.......
...OOOOOO......
..OO.OOOO......
...OO..........

:fly A certain c/3 tagalong found by David Bell, April 1992. Shown here attached to the back of a small spaceship (also by Bell).

..O...............................
.O.O..............................
.O.O......................O.O...O.
.O.......................OO.O.O..O
...........OOO........O.........O.
OO.........OO..O.OO...O..OOOO.....
.O.O.........OOOO..O.O..OO....OO..
.OO........O..O...OOO.....OOO.....
..O.......O....O..OO..OO..O..O....
...O..O...O....O..OOO.O.O....OO...
.......O.OO....O..OOOO.....O......
....OO...OO....O..OOOO.....O......
....O.O...O....O..OOO.O.O....OO...
...OO.....O....O..OO..OO..O..O....
....O.O....O..O...OOO.....OOO.....
.....O.......OOOO..O.O..OO....OO..
...........OO..O.OO...O..OOOO.....
...........OOO........O.........O.
.........................OO.O.O..O
..........................O.O...O.

:flying machine = Schick engine

:fore and back (p2) Compare snake pit. Found by Achim Flammenkamp, July 1994.

OO.OO..
OO.O.O.
......O
OOO.OOO
O......
.O.O.OO
..OO.OO

:forward glider A glider which moves at least partly in the same direction as the puffer(s) or spaceship(s) under consideration.

:fountain (p4) Found by Dean Hickerson in November 1994, and named by Bill Gosper. See also filter and superfountain.

.........O.........
...................
...OO.O.....O.OO...
...O.....O.....O...
....OO.OO.OO.OO....
...................
......OO...OO......
OO...............OO
O..O...O.O.O...O..O
.OOO.OOOOOOOOO.OOO.
....O....O....O....
...OO.........OO...
...O...........O...
.....O.......O.....
....OO.......OO....

:fourteener (p1)

....OO.
OO..O.O
O.....O
.OOOOO.
...O...

:fox (p2) This is the smallest asymmetric p2 oscillator. Found by Dave Buckingham, July 1977.

....O..
....O..
..O..O.
OO.....
....O.O
..O.O.O
......O

:French kiss (p3) Found by Robert Wainwright, July 1971.

O.........
OOO.......
...O......
..O..OO...
..O....O..
...OO..O..
......O...
.......OOO
.........O

:frog II (p3) Found by Dave Buckingham, October 1972.

..OO...OO..
..O.O.O.O..
....O.O....
...O.O.O...
...OO.OO...
.OO.....OO.
O..O.O.O..O
.O.O...O.O.
OO.O...O.OO
....OOO....
...........
...O.OO....
...OO.O....

:frothing puffer A frothing puffer (or a frothing spaceship) is a puffer (or spaceship) whose back end appears to be unstable and breaking apart, but which nonetheless survives. The exhaust festers and clings to the back of the puffer/spaceship before breaking off. The first known frothing puffers were c/2, and most were found by slightly modifying the back ends of p2 spaceships. A number of these have periods which are not a multiple of 4 (as with some line puffers). Paul Tooke has also found c/3 frothing puffers.

The following p78 c/2 frothing puffer was found by Paul Tooke in April 2001.

.......O.................O.......
......OOO...............OOO......
.....OO....OOO.....OOO....OO.....
...OO.O..OOO..O...O..OOO..O.OO...
....O.O..O.O...O.O...O.O..O.O....
.OO.O.O.O.O....O.O....O.O.O.O.OO.
.OO...O.O....O.....O....O.O...OO.
.OOO.O...O....O.O.O....O...O.OOO.
OO.........OO.O.O.O.OO.........OO
............O.......O............
.........OO.O.......O.OO.........
..........O...........O..........
.......OO.O...........O.OO.......
.......OO...............OO.......
.......O.O.O.OOO.OOO.O.O.O.......
......OO...O...O.O...O...OO......
......O..O...O.O.O.O...O..O......
.........OO....O.O....OO.........
.....OO....O...O.O...O....OO.....
.........O.OO.O...O.OO.O.........
..........O.O.O.O.O.O.O..........
............O..O.O..O............
...........O.O.....O.O...........

:frothing spaceship See frothing puffer.

:fumarole (p5) Found by Dean Hickerson in September 1989. In terms of its 7x8 bounding box this is the smallest p5 oscillator.

...OO...
.O....O.
.O....O.
.O....O.
..O..O..
O.O..O.O
OO....OO

:fuse A wick burning at one end. For examples, see baker, beacon maker, blinker ship, boat maker, cow, harvester, lightspeed wire, pi ship, reverse fuse, superstring and washerwoman. Useful fuses are usually clean.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_c.htm0000644000175000017500000013501312536111364016372 00000000000000 Life Lexicon (C)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:c = speed of light

:CA = cellular automaton

:caber tosser Any pattern whose population is asymptotic to c.log(t) for some constant c, and which contains a glider (or other spaceship) bouncing between a slower receding spaceship and a fixed reflector which emits a spaceship (in addition to the reflected one) whenever the bouncing spaceship hits it.

As the receding spaceship gets further away the bouncing spaceship takes longer to complete each cycle, and so the extra spaceships emitted by the reflector are produced at increasingly large intervals. More precisely, if v is the speed of the bouncing spaceship and u the speed of the receding spaceship, then each interval is (v+u)/(v-u) times as long as the previous one. The population at time t is therefore n.log(t)/log((v+u)/(v-u)) + O(1), where n is the population of one of the extra spaceships (assumed constant).

The first caber tosser was built by Dean Hickerson in May 1991.

:Cambridge pulsar CP 48-56-72 = pulsar (The numbers refer to the populations of the three phases. The Life pulsar was indeed discovered at Cambridge, like the first real pulsar a few years earlier.)

:Canada goose (c/4 diagonally, p4) Found by Jason Summers, January 1999. It consists of a glider plus a tagalong.

OOO..........
O.........OO.
.O......OOO.O
...OO..OO....
....O........
........O....
....OO...O...
...O.O.OO....
...O.O..O.OO.
..O....OO....
..OO.........
..OO.........
At the time of its discovery the Canada goose was the smallest known diagonal spaceship other than the glider, but this record has since been beaten, first by the second spaceship shown under Orion, and more recently by quarter.

:candelabra (p3) By Charles Trawick. See also the note under cap.

....OO....OO....
.O..O......O..O.
O.O.O......O.O.O
.O..O.OOOO.O..O.
....O.O..O.O....
.....O....O.....

:candlefrobra (p3) Found by Robert Wainwright in November 1984.

.....O....
.O.OO.O.OO
O.O...O.OO
.O....O...
.....OO...
The following diagram shows that a pair of these can act in some ways like killer toads. See also snacker.
....O...........O....
OO.O.OO.O...O.OO.O.OO
OO.O...O.O.O.O...O.OO
...O....O...O....O...
...OO...........OO...
.....................
.....................
.........OOO.........
.........O..O........
.........O...........
.........O...O.......
.........O...O.......
.........O...........
..........O.O........

:canoe (p1)

...OO
....O
...O.
O.O..
OO...

:cap The following induction coil. It can also be easily be stabilized to form a p3 oscillator - see candelabra for a slight variation on this.

.OO.
O..O
OOOO

:carnival shuttle (p12) Found by Robert Wainwright in September 1984 (using MW emulators at the end, instead of the monograms shown here).

.................................O...O
OO...OO..........................OOOOO
.O.O.O...O..O......OO...O..O.......O..
.OO.OO..OO...OO....OO..OO...OO....O.O.
.O.O.O...O..O......OO...O..O.......O..
OO...OO..........................OOOOO
.................................O...O

:carrier = aircraft carrier

:casing That part of the stator of an oscillator which is not adjacent to the rotor. Compare bushing.

:catacryst A 58-cell quadratic growth pattern found by Nick Gotts in April 2000. This was formerly the smallest known pattern with superlinear growth, but has since been superseded by the related metacatacryst. The catacryst consists of three arks plus a glider-producing switch engine. It produces a block-laying switch engine every 47616 generations. Each block-laying switch engine has only a finite life, but the length of this life increases linearly with each new switch engine, so that the pattern overall grows quadratically, as an unusual type of MMS breeder.

:catalyst An object that participates in a reaction but emerges from it unharmed. The term is mostly applied to still lifes, but can also be used of oscillators, spaceships, etc. The still lifes and oscillators which form a conduit are examples of catalysts.

:caterer (p3) Found by Dean Hickerson, August 1989. Compare with jam. In terms of its minimum population of 12 this is the smallest p3 oscillator. See also double caterer and triple caterer.

..O.....
O...OOOO
O...O...
O.......
...O....
.OO.....
More generally, any oscillator which serves up a bit in the same manner may be referred to as a caterer.

:Caterpillar A spaceship that works by laying tracks at its front end. The only example constructed to date is a p270 17c/45 spaceship built by Gabriel Nivasch in December 2004, based on work by himself, Jason Summers and David Bell. This Caterpillar has a population of about 12 million in each generation and was put together by a computer program that Nivasch wrote. It is by far the largest and most complex Life object ever constructed.

The 17c/45 Caterpillar is based on the following reaction between a pi-heptomino and a blinker:

...............O
O.............OO
O............OO.
O.............OO
...............O
In this reaction, the pi moves forward 17 cells in the course of 45 generations, while the blinker moves back 6 cells and is rephased. This reaction has been known for many years, but it was only in September 2002 that David Bell suggested that it could be used to build a 17c/45 spaceship, based on a reaction he had found in which pis crawling along two rows of blinkers interact to emit a glider every 45 generations. Similar glider-emitting interactions were later found by Gabriel Nivasch and Jason Summers. The basic idea of the spaceship design is that streams of gliders created in this way can be used to construct fleets of standard spaceships which convey gliders to the front of the blinker tracks, where they can be used to build more blinkers.

A different Caterpillar may be possible based on the following reaction, in which the pattern at top left reappears after 31 generations displaced by (13,1), having produced a new NW-travelling glider. In this case the tracks would be waves of backward-moving gliders.

.OO.....................
...O....................
...O.OO.................
OOO....O................
.......O................
.....OOO................
........................
........................
........................
........................
........................
........................
.....................OOO
.....................O..
......................O.

:Catherine wheel = pinwheel

:cauldron (p8) Found in 1971 independently by Don Woods and Robert Wainwright. Compare with Hertz oscillator.

.....O.....
....O.O....
.....O.....
...........
...OOOOO...
O.O.....O.O
OO.O...O.OO
...O...O...
...O...O...
....OOO....
...........
....OO.O...
....O.OO...

:cavity = eater plug

:cell The fundamental unit of space in the Life universe. The term is often used to mean a live cell - the sense is usually clear from the context.

:cellular automaton A certain class of mathematical objects of which Life is an example. A cellular automaton consists of a number of things. First there is a positive integer n which is the dimension of the cellular automaton. Then there is a finite set of states S, with at least two members. A state for the whole cellular automaton is obtained by assigning an element of S to each point of the n-dimensional lattice Zn (where Z is the set of all integers). The points of Zn are usually called cells. The cellular automaton also has the concept of a neighbourhood. The neighbourhood N of the origin is some finite (nonempty) subset of Zn. The neighbourhood of any other cell is obtained in the obvious way by translating that of the origin. Finally there is a transition rule, which is a function from SN to S (that is to say, for each possible state of the neighbourhood the transition rule specifies some cell state). The state of the cellular automaton evolves in discrete time, with the state of each cell at time t+1 being determined by the state of its neighbourhood at time t, in accordance with the transition rule.

There are some variations on the above definition. It is common to require that there be a quiescent state, that is, a state such that if the whole universe is in that state at generation 0 then it will remain so in generation 1. (In Life the OFF state is quiescent, but the ON state is not.) Other variations allow spaces other than Zn, neighbourhoods that vary over space and/or time, probabilistic or other non-deterministic transition rules, etc.

It is common for the neighbourhood of a cell to be the 3x...x3 (hyper)cube centred on that cell. (This includes those cases where the neighbourhood might more naturally be thought of as a proper subset of this cube.) This is known as the Moore neighbourhood.

:centinal (p100) Found by Bill Gosper. This combines the mechanisms of the p46 and p54 shuttles (see twin bees shuttle and p54 shuttle).

OO................................................OO
.O................................................O.
.O.O.....................OO.....................O.O.
..OO........O............OO............OO.......OO..
...........OO..........................O.O..........
..........OO.............................O..........
...........OO..OO......................OOO..........
....................................................
....................................................
....................................................
...........OO..OO......................OOO..........
..........OO.............................O..........
...........OO..........................O.O..........
..OO........O............OO............OO.......OO..
.O.O.....................OO.....................O.O.
.O................................................O.
OO................................................OO

:century (stabilizes at time 103) This is a common pattern which evolves into three blocks and a blinker. In June 1996 Dave Buckingham built a neat p246 glider gun using a century as the engine. See also bookend and diuresis.

..OO
OOO.
.O..

:chemist (p5)

.......O.......
.......OOO.....
..........O....
.....OOO..O..OO
....O.O.O.O.O.O
....O...O.O.O..
.OO.O.....O.OO.
..O.O.O...O....
O.O.O.O.O.O....
OO..O..OOO.....
....O..........
.....OOO.......
.......O.......

:C-heptomino Name given by Conway to the following heptomino, a less common variant of the B-heptomino.

.OOO
OOO.
.O..

:Cheshire cat A block predecessor by C. R. Tompkins that unaccountably appeared both in Scientific American and in Winning Ways. See also grin.

.O..O.
.OOOO.
O....O
O.OO.O
O....O
.OOOO.

:chicken wire A type of stable agar of density 1/2. The simplest version is formed from the tile:

OO..
..OO
But the "wires" can have length greater than two and need not all be the same. For example:
OO...OOOO.....
..OOO....OOOOO

:cigar = mango

:cis-beacon on anvil (p2)

...OO.
....O.
.O....
.OO...
......
.OOOO.
O....O
.OOO.O
...O.OO

:cis-beacon on table (p2)

..OO
...O
O...
OO..
....
OOOO
O..O

:cis-boat with tail (p1)

.O...
O.O..
OO.O.
...O.
...OO

:cis fuse with two tails (p1) See also pulsar quadrant.

...O..
.OOO..
O...OO
.O..O.
..O.O.
...O..

:cis-mirrored R-bee (p1)

.OO.OO.
O.O.O.O
O.O.O.O
.O...O.

:cis snake = canoe

:clean Opposite of dirty. A reaction which produces a small number of different products which are desired or which are easily deleted is said to be clean. For example, a puffer which produces just one object per period is clean. Clean reactions are useful because they can be used as building blocks in larger constructions.

When a fuse is said to be clean, or to burn cleanly, this usually means that no debris at all is left behind.

:clock (p2) Found by Simon Norton, May 1970. This is the fifth or sixth most common oscillator, being about as frequent as the pentadecathlon, but much less frequent than the blinker, toad, beacon or pulsar. But it's surprisingly rare considering its small size.

..O.
O.O.
.O.O
.O..

:clock II (p4) Compare with pinwheel.

......OO....
......OO....
............
....OOOO....
OO.O....O...
OO.O..O.O...
...O..O.O.OO
...O.O..O.OO
....OOOO....
............
....OO......
....OO......

:cloud of smoke = smoke

:cloverleaf This name was given by Robert Wainwright to his p2 oscillator washing machine. But Achim Flammenkamp also gave this name to Achim's p4.

:cluster Any pattern in which each live cell is connected to every other live cell by a path that does not pass through two consecutive dead cells. This sense is due to Nick Gotts, but the term has also been used in other senses, often imprecise.

:CNWH Conweh, creator of the Life universe.

:Coe ship (c/2 orthogonally, p16) A puffer engine discovered by Tim Coe in October 1995.

....OOOOOO
..OO.....O
OO.O.....O
....O...O.
......O...
......OO..
.....OOOO.
.....OO.OO
.......OO.

:Coe's p8 (p8) Found by Tim Coe in August 1997.

OO..........
OO..OO......
.....OO.....
....O..O....
.......O..OO
.....O.O..OO

:colorized Life A cellular automaton which is the same as Life except for the use of a number of different ON states ("colours"). All ON states behave the same for the purpose of applying the Life rule, but additional rules are used to specify the colour of the resulting ON cells. Examples are Immigration and QuadLife.

:colour of a glider The colour of a glider is a property of the glider which remains constant while the glider is moving along a straight path, but which can be changed when the glider bounces off a reflector. It is an important consideration when building something using reflectors.

The colour of a glider can be defined as follows. First choose some cell to be the origin. This cell is then considered to be white, and all other cells to be black or white in a checkerboard pattern. (So the cell with coordinates (m,n) is white if m+n is even, and black otherwise.) Then the colour of a glider is the colour of its leading cell when it is in a phase which can be rotated to look like this:

OOO
..O
.O.

A reflector which does not change the colour of gliders obviously cannot be used to move a glider onto a path of different colour than it started on. But a 90-degree reflector which does change the colour of gliders is similarly limited, as the colour of the resulting glider will depend only on the direction of the glider, no matter how many reflectors are used. For maximum flexibility, therefore, both types of reflector are required.

:complementary blinker = fore and back

:compression = repeat time

:conduit Any arrangement of still lifes and/or oscillators which move an active object to another location, perhaps also transforming it into a different active object at the same time, but without leaving any permanent debris (except perhaps gliders, or other spaceships) and without any of the still lifes or oscillators being permanently damaged. Probably the most important conduit is the following remarkable one (Dave Buckingham, July 1996) in which a B-heptomino is transformed into a Herschel in 59 generations.

.........OO.O
O.OO......OOO
OO.O.......O.
.............
.........OO..
.........OO..

:confused eaters (p4) Found by Dave Buckingham before 1973.

O..........
OOO........
...O.......
..O........
..O..O.....
.....O.....
...O.O.....
...OO..OO..
.......O.O.
.........O.
.........OO

:converter A conduit in which the input object is not of the same type as the output object. This term tends to be preferred when either the input object or the output object is a spaceship.

The following diagram shows a p8 pi-heptomino-to-HWSS converter. This was originally found by Dave Buckingham in a larger form (using a figure-8 instead of the boat). The improvement shown here is by Bill Gosper (August 1996). Dieter Leithner has since found (much larger) oscillators of periods 44, 46 and 60 to replace the Kok's galaxy.

.O.O..O........
.OOO.O.OO......
O......O.....O.
.O.....OO...O.O
.............OO
OO.....O.......
.O......O......
OO.O.OOO.......
..O..O.O.......
............OOO
............O.O
............O.O

:convoy A collection of spaceships all moving in the same direction at the same speed.

:Corder- Prefix used for things involving switch engines, after Charles Corderman.

:Corder engine = switch engine

:Cordergun A gun firing Corderships. The first was built by Jason Summers in July 1999, using a glider synthesis by Stephen Silver.

:Cordership Any spaceship based on switch engines. These necessarily move at a speed of c/12 diagonally with a period of 96 (or a multiple thereof). The first was found by Dean Hickerson in April 1991. Corderships are the slowest spaceships so far constructed, although arbitrarily slow spaceships are known to exist (see universal constructor). Hickerson's original Cordership used 13 switch engines. He soon reduced this to 10, and in August 1993 to 7. In July 1998 he reduced it to 6. In January 2004, Paul Tooke found the 3-engine Cordership shown below.

................................OO.O...........................
...............................OOO.O......O.O..................
..............................O....O.O....O....................
...............................OO......O.O...O.................
................................O...O..O..OO...................
...................................O.OO...O....................
..................................O.O................OO........
..................................O.O................OO........
...............................................................
...............................................................
...............................................................
...............................................................
...............................................................
...............................................................
.............................................................OO
....................................................OO.......OO
.......................................O.........O.OOOO........
..................................O...OOOOO.....OO.O...OO......
.................................O.O.......OO....O..OO.OO......
.................................O.......O.OO.....OOOOOO.......
..................................O........OO......O...........
...................................O...OOOO....................
........................................OOO....................
........................O.O.........OO.........................
........................O.O.O......O.O.........................
.......................O..OO.O....OO...........................
........................OO...O.O.OO.O..........................
........................OO...OO.OOOOO..........................
............................O.OO...OO..........................
...........................O.O.................................
..OO.O.........................................................
.OOO.O......O.O................................................
O....O.O....O..................................................
.OO......O.O...O...............................................
..O...O..O..OO...........O.....................................
.....O.OO...O...........OOO....................................
....O.O.................O..O...................................
....O.O................O....O..................................
........................O......................................
...............................................................
........................O..O...................................
.........................O.O...................................
...............................................................
.....................O.........................................
....................OOO........................................
...................OO.OO.......................................
.........O........OO.O.....O...................................
....O...OOOOO....OO......OO....................................
...O.O.......OO..OO.......OO...................................
...O.......O.OO................................................
....O........OO................................................
.....O...OOOO..................................................
..........OOO..................................................
...............................................................
...............................................................
...............................................................
...........OO..................................................
...........OO..................................................

:cousins (p3) This contains two copies of the stillater rotor.

.....O.OO....
...OOO.O.O...
O.O......O...
OO.OO.OO.O.OO
...O.O....O.O
...O.O.OOO...
....OO.O.....

:cover The following induction coil. See scrubber for an example of its use.

....O
..OOO
.O...
.O...
OO...

:covered table = cap

:cow (c p8 fuse)

OO.......OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO.....
OO....O.OOO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO...OO
....OO.O.................................................O.O
....OO...OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO..
....OO.O..................................................O.
OO....O.OOO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO.
OO.......OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO.....

:CP pulsar = pulsar

:crane (c/4 diagonally, p4) The following spaceship found by Nicolay Beluchenko in September 2005, a minor modification of a tubeater found earlier by Hartmut Holzwart. The wing is of the same form as in the swan and Canada goose.

.OO.................
OO..................
..O.................
....OO...O..........
....OO..O.O.........
.......OO.O.........
.......OO...........
.......OO...........
.................OO.
.........O....OO.O..
.........OOO..OO....
.........OOO..OO....
..........OO........
....................
............O.......
...........OO.......
...........O........
............O.......
....................
.............OO.....
..............O.OO..
..................O.
...............OO...
...............OO...
.................O..
..................OO

:cross (p3) Found by Robert Wainwright in October 1989.

..OOOO..
..O..O..
OOO..OOO
O......O
O......O
OOO..OOO
..O..O..
..OOOO..
In February 1993, Hartmut Holzwart noticed that this is merely the smallest of an infinite family of p3 oscillators. The next smallest member is shown below.
..OOOO.OOOO..
..O..O.O..O..
OOO..OOO..OOO
O...........O
O...........O
OOO.......OOO
..O.......O..
OOO.......OOO
O...........O
O...........O
OOO..OOO..OOO
..O..O.O..O..
..OOOO.OOOO..

:crowd (p3) Found by Dave Buckingham in January 1973.

...........O..
.........OOO..
.....OO.O.....
.....O...O....
.......OO.O...
...OOOO...O...
O.O.....O.O.OO
OO.O.O.....O.O
...O...OOOO...
...O.OO.......
....O...O.....
.....O.OO.....
..OOO.........
..O...........

:crown The p12 part of the following p12 oscillator, where it is hassled by caterer, a jam and a HW emulator. This oscillator was found by Noam Elkies in January 1995.

..........O...........
..........O......O....
...O....O...O...OO....
...OO....OOO..........
.........OOO..OOO..O.O
.O..OOO.........O.OOOO
O.O.O...............OO
O..O..................
.OO........OO.........
......OO.O....O.OO....
......O..........O....
.......OO......OO.....
....OOO..OOOOOO..OOO..
....O..O........O..O..
.....OO..........OO...

:crucible = cauldron

:crystal A regular growth that is sometimes formed when a stream of gliders, or other spaceships, is fired into some junk.

The most common example is initiated by the following collision of a glider with a block. With a glider stream of even period at least 82, this gives a crystal which forms a pair beehives for every 11 gliders which hit it.

.O......
..O...OO
OOO...OO

:cuphook (p3) Found by Rich Schroeppel, October 1970. This is one of only three essentially different p3 oscillators with only three cells in the rotor. The others are 1-2-3 and stillater.

....OO...
OO.O.O...
OO.O.....
...O.....
...O..O..
....OO.O.
.......O.
.......OO
The above is the original form, but it can be made more compact:
....OO.
...O.O.
...O...
OO.O...
OO.O..O
...O.OO
...O...
..OO...

:curl = loop


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_r.htm0000644000175000017500000005011712536111364016412 00000000000000 Life Lexicon (R)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:R = R-pentomino

:R2D2 (p8) This was found, in the form shown below, by Peter Raynham in the early 1970s. The name derives from a form with a larger and less symmetric stator discovered by Noam Elkies in August 1994. Compare with Gray counter.

.....O.....
....O.O....
...O.O.O...
...O.O.O...
OO.O...O.OO
OO.O...O.OO
...O...O...
...O.O.O...
....O.O....
.....O.....

:r5 = R-pentomino

:rabbits (stabilizes at time 17331) A 9-cell methuselah found by Andrew Trevorrow in 1986.

O...OOO
OOO..O.
.O.....
The following predecessor, found by Trevorrow in October 1995, has the same number of cells and lasts two generations longer.
..O....O
OO......
.OO.OOO.

:rake Any puffer whose debris consists of spaceships. A rake is said to be forwards, backwards or sideways according to the direction of the spaceships relative to the direction of the rake. Originally the term "rake" was applied only to forwards c/2 glider puffers (see space rake). Many people prefer not to use the term in the case where the puffed spaceships travel parallel or anti-parallel to the puffer, as in this case they do not rake out any significant region of the Life plane (and, in contrast to true rakes, these puffers cannot travel in a stream, and so could never be produced by a gun).

Although the first rakes (circa 1971) were c/2, rakes of other velocities have since been built. Dean Hickerson's construction of Corderships in 1991 made it easy for c/12 diagonal rakes to be built, although no one actually did this until 1998, by which time David Bell had constructed c/3 and c/5 rakes (May 1996 and September 1997, respectively). Jason Summers constructed a 2c/5 rake in June 2000 (building on work by Paul Tooke and David Bell) and a c/4 orthogonal rake in October 2000 (based largely on reactions found by David Bell).

The smallest possible period for a rake is probably 7, as this could be achieved by a 3c/7 orthogonal backwards glider puffer. The smallest period attained to date is 8 (Jason Summers, March 2001) - see backrake.

:$rats (p6) Found by Dave Buckingham, 1972.

.....OO.....
......O.....
....O.......
OO.O.OOOO...
OO.O.....O.O
...O..OOO.OO
...O....O...
....OOO.O...
.......O....
......O.....
......OO....

:R-bee = bun

:receiver See Herschel receiver.

:reflector Any stable or oscillating pattern that can reflect some type of spaceship (usually a glider) without suffering permanent damage. The first known reflector was the pentadecathlon, which functions as a 180-degree glider reflector (see relay). Other examples include the buckaroo, the twin bees shuttle and some oscillators based on the traffic jam reaction. Glider guns can also be made into reflectors, although these are mostly rather large.

In September 1998 Noam Elkies found some fast small-period glider reflectors. The p8 version is shown below. Replacing the figure-8 by the p6 pipsquirter gives a p6 version. A more complicated construction allows a p5 version (which, as had been anticipated, soon led to a true p55 gun - see Quetzal). And in August 1999 Elkies found a suitable p7 sparker, allowing the first p49 oscillator to be constructed.

......OO.....OO..
O.O...OO.....O...
.OO........O.O...
.O.........OO....
.......OO........
.......O.O.......
........O........
.................
...........OOO...
...........OOO...
...........OOO...
..............OOO
..............OOO
..............OOO

Stable reflectors are special in that if they satisfy certain conditions they can be used to construct oscillators of all sufficiently large periods. It was known for some time that stable reflectors were possible (see universal constructor), but no one was able to construct an explicit example until Paul Callahan did so in October 1996.

All known stable reflectors are very slow. Callahan's original reflector has a repeat time of 4840, soon improved to 1686 and then 894 and then 850. In November 1996 Dean Hickerson found a variant in which this is reduced to 747. Dave Buckingham reduced it to 672 in May 1997 using a somewhat different method, and in October 1997 Stephen Silver reduced it to 623 by a method closer to the original. In November 1998 Callahan reduced this to 575 with a new initial reaction. A small modification by Silver a few days later brought this down to 497.

But in April 2001 Dave Greene found a 180-degree stable reflector with a repeat time of only 202 (see boojum reflector). This reflector also won the $100 prize that Dieter Leithner had offered in April 1997 for the first stable reflector to fit in a 50x50 box, and the additional $100 that Alan Hensel had offered in January 1999 for the same feat. Dave Greene has subsequently offered $50 for the first 90-degree stable glider reflector that fits in a 50x50 box, and a further $50 for the first in a 35x35 box.

See also glider turner.

:regulator An object which converts input gliders aligned to some period to output gliders aligned to a different period. The most interesting case is a universal regulator.

:relay Any oscillator in which spaceships (typically gliders) travel in a loop. The simplest example is the p60 one shown below using two pentadecathlons. Pulling the pentadecathlons further apart allows any period of the form 60+120n to be achieved - this is the simplest proof of the existence of oscillators of arbitrarily large period.

...........................O....O..
................OO.......OO.OOOO.OO
.................OO........O....O..
................O..................
..O....O...........................
OO.OOOO.OO.........................
..O....O...........................

:repeater Any oscillator or spaceship.

:repeat time The minimum number of generations that is possible between the arrival of one object and the arrival of the next. This term is used for things such as reflectors or conduits and the objects (gliders or Herschels, for example) will interact fatally with each other (or one will interact fatally with a disturbance caused by the other) if they are too close together. For example, the repeat time of Dave Buckingham's 59-step B-heptomino to Herschel conduit (shown under conduit) is 58.

:rephaser The following reaction that shifts the phase and path of a pair of gliders. There is another form of this reaction that reflects the gliders 180 degrees - see glider-block cycle.

..O..O..
O.O..O.O
.OO..OO.
........
........
...OO...
...OO...

:replicator A finite pattern which repeatedly creates copies of itself. Such objects are known to exist (see universal constructor), but no concrete example is known.

:reverse fuse A fuse that produces some initial debris, but then burns cleanly. The following is a simple example.

.............OO
............O.O
...........O...
..........O....
.........O.....
........O......
.......O.......
......O........
.....O.........
....O..........
...O...........
..O............
OO.............

:revolver (p2)

O............O
OOO....O...OOO
...O.O.O..O...
..O......O.O..
..O.O......O..
...O..O.O.O...
OOO...O....OOO
O............O

:ring of fire (p2) The following muttering moat found by Dean Hickerson in September 1992.

................O.................
..............O.O.O...............
............O.O.O.O.O.............
..........O.O.O.O.O.O.O...........
........O.O.O..OO.O.O.O.O.........
......O.O.O.O......O..O.O.O.......
....O.O.O..O..........O.O.O.O.....
.....OO.O..............O..O.O.O...
...O...O..................O.OO....
....OOO....................O...O..
..O.........................OOO...
...OO...........................O.
.O...O........................OO..
..OOOO.......................O...O
O.............................OOO.
.OOO.............................O
O...O.......................OOOO..
..OO........................O...O.
.O...........................OO...
...OOO.........................O..
..O...O....................OOO....
....OO.O..................O...O...
...O.O.O..O..............O.OO.....
.....O.O.O.O..........O..O.O.O....
.......O.O.O..O......O.O.O.O......
.........O.O.O.O.OO..O.O.O........
...........O.O.O.O.O.O.O..........
.............O.O.O.O.O............
...............O.O.O..............
.................O................

:rle Run-length encoded. Run-length encoding is a simple (but not very efficient) method of file compression. In Life the term refers to a specific ASCII encoding used for Life patterns (and patterns for other similar cellular automata). This encoding was introduced by Dave Buckingham and is now the usual means of exchanging Life patterns (especially large ones) by e-mail.

:rock Dean Hickerson's term for an eater which remains intact throughout the eating process. The snake in Dave Buckingham's 59-step B-to-Herschel conduit (shown under conduit) is an example. Other still lifes that sometimes act as rocks include the tub, the hook with tail, the eater1 (eating with its tail) and the hat (in Heinrich Koenig's stabilization of the twin bees shuttle).

:roteightor (p8) Found by Robert Wainwright in 1972.

.O............
.OOO........OO
....O.......O.
...OO.....O.O.
..........OO..
..............
.....OOO......
.....O..O.....
.....O........
..OO..O...O...
.O.O......O...
.O.......O....
OO........OOO.
............O.

:rotor The cells of an oscillator that change state. Compare stator. It is easy to see that any rotor cell must be adjacent to another rotor cell.

:R-pentomino This is by far the most active polyomino with less than six cells: all the others stabilize in at most 10 generations, but the R-pentomino does not do so until generation 1103, by which time it has a population of 116.

.OO
OO.
.O.

:rule 22 Wolfram's rule 22 is the 2-state 1-D cellular automaton in which a cell is ON in the next generation if and only if exactly one of its three neighbours is ON in the current generation (a cell being counted as a neighbour of itself). This is the behaviour of Life on a cylinder of width 1.

:ruler A pattern constructed by Dean Hickerson in May 2005 that produces a stream of LWSS with gaps in it, such that the number of LWSS between successive gaps follows the "ruler function" (sequence A001511 in The On-Line Encyclopedia of Integer Sequences).

:rumbling river Any oscillator in which the rotor is connected and contained in a strip of width 2. The following p3 example is by Dean Hickerson, November 1994.

..............OO......OO......OO...O.OO..........
....O........O..O....O..O....O..O..OO.O..........
O..O.O....O...OO..O...OO..O...O.O.....O.OO.......
OOOO.O..OOOOOO..OOOOOO..OOOOOO..OOOOOO.O.O.......
.....O.O.....O.O.....O.O.....O.O.....O.O......OO.
..OO.O.O.O.O...O.O.O...O.O.O...O.O.O...O.O.....O.
.O.....O.O...O.O.O...O.O.O...O.O.O...O.O.O.O.OO..
.OO......O.O.....O.O.....O.O.....O.O.....O.O.....
.......O.O.OOOOOO..OOOOOO..OOOOOO..OOOOOO..O.OOOO
.......OO.O.....O.O...O..OO...O..OO...O....O.O..O
..........O.OO..O..O....O..O....O..O........O....
..........OO.O...OO......OO......OO..............

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_l.htm0000644000175000017500000005327412536111364016413 00000000000000 Life Lexicon (L)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:lake Any still life consisting of a simple closed curve made from diagonally connected dominoes. The smallest example is the pond, and the next smallest is this (to which the term is sometimes restricted):

....OO....
...O..O...
...O..O...
.OO....OO.
O........O
O........O
.OO....OO.
...O..O...
...O..O...
....OO....

:Laputa (p2) Found by Rich Schroeppel, September 1992.

...OO.OO....
...OO.O...OO
........O..O
.OOOOOO.OOO.
O..O.O......
OO...O.OO...
....OO.OO...

:large S = big S

:Lidka (stabilizes at time 29053) A methuselah found by Andrzej Okrasinski in July 2005.

..........OOO..
..........O....
..........O...O
...........O..O
............OOO
...............
.O.............
O.O............
.O.............
The following variant, pointed out by David Bell, has two fewer cells and lasts two generations longer.
..........OOO..
...............
...........OO.O
............O.O
..............O
...............
.O.............
O.O............
.O.............

:Life A 2-dimensional 2-state cellular automaton discovered by John Conway in 1970. The states are referred to as ON and OFF (or live and dead). The transition rule is as follows: a cell that is ON will remain ON in the next generation if and only if exactly 2 or 3 of the 8 adjacent cells are also ON, and a cell that is OFF will turn ON if and only if exactly 3 of the 8 adjacent cells are ON. (This is more succinctly stated as: "If 2 of your 8 nearest neighbours are ON, don't change. If 3 are ON, turn ON. Otherwise, turn OFF.")

:Life32 A freeware Life program by Johan Bontes for Microsoft Windows 95/98/ME/NT/2000/XP: http://www.xs4all.nl/~jbontes/.

:LifeLab A shareware Life program by Andrew Trevorrow for the Macintosh (MacOS 8.6 or later): http://www.trevorrow.com/lifelab/.

:LifeLine A newsletter edited by Robert Wainwright from 1971 to 1973. During this period it was the main forum for discussions about Life. The newsletter was nominally quarterly, but the actual dates of its eleven issues were as follows:


Mar, Jun, Sep, Dec 1971
Sep, Oct, Nov, Dec 1972
Mar, Jun, Sep 1973

:Lifenthusiast A Life enthusiast. Term coined by Robert Wainwright.

:lifesrc David Bell's Life search program, for finding new spaceships and oscillators. This is a C implementation of an algorithm developed by Dean Hickerson in 6502 assembler. Most of the spaceships and many of the oscillators shown in this lexicon were found with lifesrc or by Hickerson's original program.

Although lifesrc itself is a command-line program, Jason Summers has made a GUI version called WinLifeSearch for Microsoft Windows.

The lifesrc algorithm is only useful for very small periods, as the amount of computing power required rises rapidly with increasing period. For most purposes, period 7 is the practical limit with current hardware.

Lifesrc is available from http://www.canb.auug.org.au/~dbell/ (source code only).

Compare gfind.

:light bulb (p2) Found in 1971.

.OO.O..
.O.OO..
.......
..OOO..
.O...O.
.O...O.
..O.O..
O.O.O.O
OO...OO
The same rotor can be embedded in a slightly smaller stator like this:
...O.....
.OOO.....
O........
OOOOOO...
......O..
..O...O..
..OO.O...
......OOO
........O

:lightspeed ribbon = superstring

:lightspeed wire Any wick that can burn non-destructively at the speed of light. These are potentially useful for various things, but so far no one has found the necessary mechanisms. The following diagram shows an example of a lightspeed wire, with a small defect that travels along it at the speed of light.

....OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO....
....OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO....
..........................................................
..OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO..
.O......O...............................................O.
O.OOOOO....OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO.O
.O.....O................................................O.
..OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO..
..........................................................
....OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO....
....OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO..OO....

:lightweight emulator = LW emulator

:lightweight spaceship = LWSS

:lightweight volcano = toaster

:line puffer A puffer which produces its output by means of an orthogonal line of cells at right angles to the direction of travel. The archetypal line puffer was found by Alan Hensel in March 1994, based on a spaceship found earlier that month by Hartmut Holzwart. The following month Holzwart found a way to make extensible c/2 line puffers, and Hensel found a much smaller stabilization the following day. But in October 1995 Tim Coe discovered that for large widths these were often unstable, although typically lasting millions of generations. In May 1996, however, Coe found a way to fix the instability. The resulting puffers appear to be completely stable and to exhibit an exponential increase in period as a function of width, although neither of these things has been proved.

Line puffers have enabled the construction of various difficult periods for c/2 spaceships and puffers, including occasionally periods which are not multiples of 4 and which would therefore be impossible to attain with the usual type of construction based on standard spaceships. (See frothing puffer for another method of constructing such periods.) In particular, the first c/2 rake with period not divisible by 4 was achieved in January 2000 when David Bell constructed a p42 backrake by means of line puffers.

See also hivenudger and puff suppressor.

:line ship A spaceship in which the front end is a linestretcher, the line being eaten by the back end.

:linestretcher A wickstretcher that stretches a single diagonal line of cells. The first example was constructed by Jason Summers in March 1999; this was c/12 and used switch engine based puffers found earlier by Dean Hickerson. The first c/4 example was found by Hartmut Holzwart in November 2004.

:loading dock (p3) Found by Dave Buckingham, September 1972.

....O....
..OOO....
.O...OO..
O.OO...O.
.O...OO.O
..OO...O.
....OOO..
....O....

:loaf (p1)

.OO.
O..O
.O.O
..O.

:loaflipflop (p15) Here four pentadecathlons hassle a loaf. Found by Robert Wainwright in 1990.

................O.................
...............OOO................
..................................
..................................
...............OOO................
..................................
...............O.O................
...............O.O................
..................................
...............OOO................
..................................
..................................
...............OOO................
................O.................
..................................
.O..O.OO.O..O...............OO....
OO..O....O..OO...OO.......O....O..
.O..O.OO.O..O...O..O.....O......O.
................O.O.....O........O
.................O......O........O
........................O........O
.........................O......O.
..........................O....O..
............................OO....
..................OOO.............
.................O...O............
................O.....O...........
..................................
...............O.......O..........
...............O.......O..........
..................................
................O.....O...........
.................O...O............
..................OOO.............

:loaf on loaf = bi-loaf

:loaf siamese barge (p1)

..OO.
.O..O
O.O.O
.O.O.
..O..

:LoM = lumps of muck

:lone dot agar An agar in which every live cell is isolated in every generation.

:lonely bee = worker bee

:long A term applied to an object that is of the same basic form as some standard object, but longer. For examples see long barge, long boat, long bookend, long canoe, long shillelagh, long ship and long snake.

:long^3 The next degree of longness after long long. Some people prefer "extra long".

:long^4 The next degree of longness after long^3. Some people prefer "extra extra long".

:long barge (p1)

.O...
O.O..
.O.O.
..O.O
...O.

:long boat (p1)

.O..
O.O.
.O.O
..OO

:long bookend The following induction coil, longer than a bookend.

...OO
O...O
OOOO.

:long canoe (p1)

....OO
.....O
....O.
...O..
O.O...
OO....

:long hat = loop

:long hook = long bookend

:long house = dock

:long integral (p1)

..OO
.O.O
.O..
..O.
O.O.
OO..

:long long The next degree of longness after long. Some people prefer "very long".

:long long barge (p1)

.O....
O.O...
.O.O..
..O.O.
...O.O
....O.

:long long boat (p1)

.O...
O.O..
.O.O.
..O.O
...OO

:long long canoe (p1)

.....OO
......O
.....O.
....O..
...O...
O.O....
OO.....

:long long ship (p1)

OO...
O.O..
.O.O.
..O.O
...OO

:long long snake (p1)

OO....
O.O...
...O.O
....OO

:long shillelagh (p1)

OO..OO
O..O.O
.OO...

:long ship (p1)

OO..
O.O.
.O.O
..OO

:long sinking ship = long canoe

:long snake (p1)

OO...
O.O.O
...OO

:loop (p1)

.OO..
O..O.
.O.O.
OO.OO

:low-density Life = sparse Life

:lumps of muck The common evolutionary sequence that ends in the blockade. The name is sometimes used of the blockade itself, and can in general be used of any stage of the evolution of the stairstep hexomino.

:LW emulator (p4) The smallest (and least useful) emulator, found by Robert Wainwright in June 1980.

..OO.O..O.OO..
..O........O..
...OO....OO...
OOO..OOOO..OOO
O..O......O..O
.OO........OO.

:LWSS (c/2 orthogonally, p4) A lightweight spaceship, the smallest known orthogonally moving spaceship, and the second most common (after the glider). Found by Conway in 1970. See also MWSS and HWSS.

.O..O
O....
O...O
OOOO

:LWSS emulator = LW emulator

:LWTDS Life Worker Time Deficiency Syndrome. Term coined by Dieter Leithner to describe the problem of having to divide scarce time between Life and real life.

:LW volcano = toaster


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex.htm0000644000175000017500000001721312536111364016071 00000000000000 Life Lexicon (Introduction)
Life Lexicon

Release 25, 2006 February 28
Multipage HTML version


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

INTRODUCTION
This is a lexicon of terms relating to John Horton Conway's Game of Life. It is also available in a single-page HTML version and an ASCII version.

This lexicon was compiled by Stephen A. Silver - see below for additional credits. See my web-site for contact information.

The latest versions of this lexicon (both HTML and ASCII) should be available from the Life Lexicon Home Page.

CREDITS
The largest single source for the early versions of this lexicon was a glossary compiled by Alan Hensel "with indispensable help from John Conway, Dean Hickerson, David Bell, Bill Gosper, Bob Wainwright, Noam Elkies, Nathan Thompson, Harold McIntosh, and Dan Hoey".

Other sources include the works listed in the bibliography at the end of this lexicon, as well as pattern collections by Alan Hensel and David Bell (and especially Dean Hickerson's file stamp.l in the latter collection), and the web sites of Mark Niemiec, Paul Callahan, Achim Flammenkamp, Robert Wainwright and Heinrich Koenig. Recent releases also use a lot of information from Dean Hickerson's header to his 1995 stamp file.

Most of the information on recent results is from the discoverers themselves.

The following people all provided useful comments on earlier releases of this lexicon: David Bell, Nicolay Beluchenko, Johan Bontes, Scot Ellison, Nick Gotts, Dave Greene, Alan Hensel, Dean Hickerson, Dieter Leithner, Mark Niemiec, Gabriel Nivasch, Andrew Okrasinski, Peter Rott, Ken Takusagawa, Andrew Trevorrow and Malcolm Tyrrell.

The format, errors, use of British English and anything else you might want to complain about are by Stephen Silver.

COPYING
This lexicon is copyright © Stephen Silver, 1997-2005. It may be freely copied and/or modified as long as due credit is given. This includes not just credit to those who have contributed in some way to the present version (see above), but also credit to those who have made any modifications.
LEXICOGRAPHIC ORDER
I have adopted the following convention: all characters (including spaces) other than letters and digits are ignored for the purposes of ordering the entries in this lexicon. (Many terms are used by some people as a single word, with or without a hyphen, and by others as two words. My convention means that I do not have to list these in two separate places. Indeed, I list them only once, choosing whichever form seems most common or sensible.) Digits lexicographically precede letters.
FORMAT
The diagrams in this lexicon are in a very standard format. You should be able to simply copy a pattern, paste it into a new file and run it in your favourite Life program. If you use Johan Bontes' Life32, Mirek Wojtowicz' MCell or Andrew Trevorrow and Tomas Rokicki's Golly then you can just paste the pattern directly into the Life program. I have restricted myself to diagrams of size 64x64 or less.

Most definitions that have a diagram have also some data in brackets after the keyword. Oscillators are maked as pn (where n is a positive integer), meaning that the period is n (p1 indicates a still life). Wicks are marked in the same way but with the word "wick" added. For spaceships the speed (as a fraction of c, the speed of light), the direction and the period are given. Fuses are marked with speed and period and have the word "fuse" added. Wicks and fuses are infinite in extent and so have necessarily been truncated, with the ends stabilized wherever practical.

SCOPE
This lexicon covers only Conway's Life, and provides no information about other cellular automata. David Bell has written articles on two other interesting cellular automata: HighLife (which is similar to Life, but has a tiny replicator) and Day & Night (which is very different, but exhibits many of the same phenomena). These articles can be found on his web-site.
ERRORS AND OMISSIONS
If you find any errors (including typos) or serious omissions, then please let me know.
NAMES
When deciding whether to use full or abbreviated forms of forenames I have tried, wherever possible, to follow the usage of the person concerned.
QUOTE
Every other author may aspire to praise; the lexicographer can only hope to escape reproach.    Samuel Johnson, 1775
DEDICATION
This lexicon is dedicated to the memory of Dieter Leithner, who died on 26 February 1999.
1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_n.htm0000644000175000017500000002242712536111364016411 00000000000000 Life Lexicon (N)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:natural Occurring often in random patterns. There is no precise measure of naturalness, since the most useful definition of "random" in this context is open to debate. Nonetheless, it is clear that objects such as blocks, blinkers, beehives and gliders are very natural, while eater2s, darts, guns, etc., are not.

:negentropy (p2) Compare Hertz oscillator.

...OO.O....
...O.OO....
...........
....OOO....
...O.O.O.OO
...OO..O.OO
OO.O...O...
OO.O...O...
....OOO....
...........
....OO.O...
....O.OO...

:neighbour Any of the eight cells adjacent to a given cell. A cell is therefore not considered to be a neighbour of itself, although the neighbourhood used in Life does in fact include this cell (see cellular automaton).

:new five (p3) Found by Dean Hickerson, January 1990.

..OO.....
.O..O....
.O.O..O..
OO.O.OO..
O........
.OOO.OOOO
.....O..O
O.OO.....
OO.OO....

:new gun An old name for the second known basic gun (found, like the first, by Bill Gosper), shown below. A number of other ways of constructing a gun from two twin bees shuttles have since been found - see edge shooter for one of these.

.........................OO.....OO
.........................OO.....OO
..................................
..................................
..................................
..................................
..................................
..................................
..................................
..................................
..................................
..................................
..................................
...........................OO.OO..
..........................O.....O.
..................................
.........................O.......O
.........................O..O.O..O
.........................OOO...OOO
..................................
..................................
..................................
..................................
.................O................
OO...............OO...............
OO................OO..............
.............OO..OO...............
..................................
..................................
..................................
.............OO..OO...............
OO................OO.......OO.....
OO...............OO........OO.....
.................O................

:Noah's ark The following diagonal puffer consisting of two switch engines. This was found by Charles Corderman in 1971. The name comes from the variety of objects it leaves behind: blocks, blinkers, beehives, loaves, gliders, ships, boats, long boats, beacons and block on tables.

..........O.O..
.........O.....
..........O..O.
............OOO
...............
...............
...............
...............
...............
.O.............
O.O............
...............
O..O...........
..OO...........
...O...........

See also ark.

:n-omino Any polyomino with exactly n cells.

:non-monotonic A spaceship is said to be non-monotonic if its leading edge falls back in some generations. The first example (shown below) was found by Hartmut Holzwart in August 1992. This is p4 and travels at c/4. In April 1994, Holzwart found examples of p3 spaceships with this property, and this is clearly the smallest possible period. Another non-monotonic spaceship is the weekender.

..........OO.O.......
......OOO.O.OOO......
..O.O..........O...OO
OO....OO.....O...OOOO
..O.OO..O....OOO.O...
........O....O.......
..O.OO..O....OOO.O...
OO....OO.....O...OOOO
..O.O..........O...OO
......OOO.O.OOO......
..........OO.O.......

:non-spark Something that looks like a spark, but isn't. An OWSS produces one of these instead of a belly spark, and is destroyed by it.

:non-standard spaceship Any spaceship other than a glider, LWSS, MWSS or HWSS.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/fix-lex-files.py0000644000175000017500000000402012536111364017605 00000000000000# Fix lexicon .htm files included with iGolly. # # We replace this text: # #

# .O.....
# ...O...
# OO..OOO
# 
etc... # # with: # #

# .O.....
# ...O...
# OO..OOO
# 
# # We also increase font size used for links at top and bottom of each page. import re # ------------------------------------------------------------------------------ def fix_file(filename): print 'fixing ' + filename f = open(filename, 'r') contents = f.read() # use re.DOTALL to include newlines in match for pattdata in re.findall('\n(.*?)', contents, re.DOTALL): ### print pattdata newdata = pattdata.replace('\n','$') ### print newdata contents = contents.replace('\n'+pattdata+'', ''+pattdata+'', 1) # remove small font used for links at top and bottom of each page contents = contents.replace('', '', 2) contents = contents.replace('Z', 'Z', 2) f.close() f = open(filename, 'w') f.write(contents) f.close() # ------------------------------------------------------------------------------ fix_file("lex.htm") fix_file("lex_1.htm") fix_file("lex_a.htm") fix_file("lex_b.htm") fix_file("lex_c.htm") fix_file("lex_d.htm") fix_file("lex_e.htm") fix_file("lex_f.htm") fix_file("lex_g.htm") fix_file("lex_h.htm") fix_file("lex_i.htm") fix_file("lex_j.htm") fix_file("lex_k.htm") fix_file("lex_l.htm") fix_file("lex_m.htm") fix_file("lex_n.htm") fix_file("lex_o.htm") fix_file("lex_p.htm") fix_file("lex_q.htm") fix_file("lex_r.htm") fix_file("lex_s.htm") fix_file("lex_t.htm") fix_file("lex_u.htm") fix_file("lex_v.htm") fix_file("lex_w.htm") fix_file("lex_x.htm") fix_file("lex_y.htm") fix_file("lex_z.htm") golly-2.7-src/gui-common/Help/Lexicon/lex_x.htm0000644000175000017500000000664712536111364016431 00000000000000 Life Lexicon (X)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:x66 (c/2 orthogonally, p4) Found by Hartmut Holzwart, July 1992. Half of this can be escorted by a HWSS. The name refers to the fact that every cell (live or dead) has at most 6 live neighbours (in contrast to spaceships based on LWSS, MWSS or HWSS). In fact this spaceship was found by a search with this restriction.

..O......
OO.......
O..OOO..O
O....OOO.
.OOO..OO.
.........
.OOO..OO.
O....OOO.
O..OOO..O
OO.......
..O......

:Xlife A popular freeware Life program that runs under the X Window System. The main Life code was written by Jon Bennett, and the X code by Chuck Silvers.

:X-pentomino Conway's name for the following pentomino, a traffic light predecessor.

.O.
OOO
.O.

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_t.htm0000644000175000017500000014606112536111364016420 00000000000000 Life Lexicon (T)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:T = T-tetromino

:table The following induction coil.

OOOO
O..O

:table on table (p1)

O..O
OOOO
....
OOOO
O..O

:tag = tagalong

:tagalong An object which is not a spaceship in its own right, but which can be attached to one or more spaceships to form a larger spaceship. For examples see Canada goose, fly, pushalong, sidecar and sparky. See also Schick engine, which consists of a tagalong attached to two LWSS (or similar).

:tail spark A spark at the back of a spaceship. For example, the 1-bit spark at the back of a LWSS, MWSS or HWSS in their less dense phases.

:tame To perturb a dirty reaction using other patterns so as to make it clean and hopefully useful. Or to make a reaction work which would otherwise fail due to unwanted products which interfere with the reaction.

:taming See tame.

:teardrop The following induction coil, or the formation of two beehives that it evolves into after 20 generations. (Compare butterfly, where the beehives are five cells further apart.)

OOO.
O..O
O..O
.OO.

:technician (p5) Found by Dave Buckingham, January 1973.

.....O.....
....O.O....
....OO.....
..OO.......
.O...OOO...
O..OO...O.O
.OO....O.OO
...O.O.O...
...O...O...
....OOO....
......O.O..
.......OO..

:technician finished product = technician

:teeth A 65-cell quadratic growth pattern found by Nick Gotts in March 2000. This (and a related 65-cell pattern which Gotts found at about the same time) beat the record previously held by mosquito5 for smallest population known to have superlinear growth. Now superseded by catacryst and metacatacryst.

:ternary reaction Any reaction between three objects. In particular, a reaction in which two gliders from one stream and one glider from a crossing stream of the same period annihilate each other. This can be used to combine two glider guns of the same period to produce a new glider gun with double the period.

:test tube baby (p2)

OO....OO
O.O..O.O
..O..O..
..O..O..
...OO...

:tetraplet Any 4-cell polyplet.

:tetromino Any 4-cell polyomino. There are five such objects, shown below. The first is the block, the second is the T-tetromino and the remaining three rapidly evolve into beehives.

OO......OOO......OOOO......OOO......OO.
OO.......O...................O.......OO

:The Recursive Universe A popular science book by William Poundstone (1985) dealing with the nature of the universe, illuminated by parallels with the game of Life. This book brought to a wider audience many of the results that first appeared in LifeLine. It also outlines the proof of the existence of a universal constructor in Life first given in Winning Ways.

:thumb A spark-like protrusion which flicks out in a manner resembling a thumb being flicked.

Here are two examples. On the left is a p9 thumb sparker found by Dean Hickerson in October 1998. On the right is a p4 one found by David Eppstein in June 2000.

.......O..............O.....
...OO...O.........OO...O....
...O.....O.OO.....O.....O...
OO.O.O......O......OOO.O.OO.
OO.O.OO.OOOO............OO.O
...O.O...........OOOOOO....O
...O.O.OOO.......O....OOOOO.
....O.O...O.........O.......
......O..OO........O.OOOO...
......OO...........O.O..O...
....................O.......

:thunderbird (stabilizes at time 243)

OOO
...
.O.
.O.
.O.

:tick = generation

:tie A term used in naming certain still lifes (and the stator part of certain oscillators). It indicates that the object consists of two smaller objects joined point to point, as in ship tie boat.

:time bomb The following pattern by Doug Petrie, which is really just a glider-producing switch engine in disguise. See infinite growth for some better examples of a similar nature.

.O...........OO
O.O....O......O
.......O....O..
..O..O...O..O..
..OO......O....
...O...........

:titanic toroidal traveler The superstring with the following repeating segment. The front part becomes p16, but the eventual fate of the detached back part is unknown.

OOOOOO
OOO...

:TL = traffic light

:T-nosed p4 (p4) Found by Robert Wainwright in October 1989. See also filter.

.....O.....
.....O.....
....OOO....
...........
...........
...........
...OOOOO...
..O.OOO.O..
..O.O.O.O..
.OO.O.O.OO.
O..OO.OO..O
OO.......OO

:T-nosed p6 (p6) Found by Achim Flammenkamp in September 1994. There is also a much larger and fully symmetric version found by Flammenkamp in August 1994.

......OO...OO......
......O.O.O.O......
.......O...O.......
...................
..O.O.O.....O.O.O..
OOO.O.OO...OO.O.OOO
..O.O.O.....O.O.O..
...................
.......O...O.......
......O.O.O.O......
......OO...OO......

:toad (p2) Found by Simon Norton, May 1970. This is the second most common oscillator, although blinkers are more than a hundred times as frequent. See also killer toads.

.OOO
OOO.

:toad-flipper A toad hassler that works in the manner of the following example. Two domino sparkers, here pentadecathlons, apply their sparks to the toad in order to flip it over. When the sparks are applied again it is flipped back. Either or both domino sparkers can be moved down two spaces from the position shown and the toad-flipper will still work, but because of symmetry there are really only two different types. Compare toad-sucker.

.O..............O.
.O..............O.
O.O............O.O
.O..............O.
.O......O.......O.
.O......OO......O.
.O......OO......O.
O.O......O.....O.O
.O..............O.
.O..............O.

:toad-sucker A toad hassler that works in the manner of the following example. Two domino sparkers, here pentadecathlons, apply their sparks to the toad in order to shift it. When the sparks are applied again it is shifted back. Either or both domino sparkers can be moved down two spaces from the position shown and the toad-sucker will still work, but because of symmetry there are really only three different types. Compare toad-flipper.

.O................
.O..............O.
O.O.............O.
.O.............O.O
.O......O.......O.
.O......OO......O.
.O......OO......O.
O.O......O......O.
.O.............O.O
.O..............O.
................O.

:toaster (p5) Found by Dean Hickerson, April 1992.

....O......OO..
...O.O.OO..O...
...O.O.O.O.O...
..OO.O...O.OO..
O...OO.O.OO...O
...O.......O...
...O.......O...
O...OO.O.OO...O
..OO.O...O.OO..
...O.O.O.O.O...
...O.O.OO..O...
....O......OO..

:torus As applies to Life, usually means a finite Life universe which takes the form of an m x n rectangle with the bottom edge considered to be joined to the top edge and the left edge joined to the right edge, so that the universe is topologically a torus. There are also other less obvious ways of obtaining an toroidal universe.

See also Klein bottle.

:total aperiodic Any finite pattern which evolves in such a way that no cell in the Life plane is eventually periodic. The first example was found by Bill Gosper in November 1997. A few days later he found the following much smaller example consisting of three copies of a p12 backrake by Dave Buckingham.

.........................................O.................
........................................OOO................
.......................................OO.O.....O..........
.......................................OOO.....OOO.........
........................................OO....O..OO...OOO..
..............................................OOO....O..O..
........................................................O..
........................................................O..
........................................................O..
........................................OOO............O...
........................................O..O...............
........................................O..................
........................................O..................
.........................................O.................
...........................................................
...........................................................
...........................................................
...........................................................
...........................................................
...........................................................
......................................OOO..................
......................................O..O...........O.....
......................................O.............OOO....
......................................O............OO.O....
......................................O............OOO.....
.......................................O............OO.....
...........................................................
...........................................................
...................................OOO.....................
..................................OOOOO....................
..................................OOO.OO.......OO........O.
.....................................OO.......OOOO........O
..............................................OO.OO...O...O
................................................OO.....OOOO
...........................................................
...........................................................
....................O......................................
.....................O.....................................
.OO.............O....O................................OOO..
OOOO.............OOOOO..................................O..
OO.OO...................................................O..
..OO...................................................O...
....................................O......................
.....................................O.....................
.....................OO..........O...O.....................
......................OO..........OOOO...............OO....
.....................OO...........................OOO.OO...
.....................O............................OOOOO....
...................................................OOO.....
...........................................................
......................OO...................................
.............OOOO....OOOO..................................
............O...O....OO.OO.................................
.OOOOO..........O......OO..................................
O....O.........O...........................................
.....O.....................................................
....O......................................................

:T-pentomino Conway's name for the following pentomino, which is a common parent of the T-tetromino.

OOO
.O.
.O.

:track A path made out of conduits, often ending where it begins so that the active object is cycled forever, forming an oscillator or a gun.

:tractor beam A stream of spaceships that can draw an object towards the source of the stream. The example below shows a tractor beam pulling a loaf; this was used by Dean Hickerson to construct a sawtooth.

.....................O..O......................
.....OOOO...........O..............OOOO........
.....O...O..........O...O..........O...O.......
.....O........OO....OOOO...........O........OO.
.OO...O..O...OOOO...........OO......O..O...OOOO
O..O........OO.OO..........OO.OO..........OO.OO
O.O..........OO.............OOOO...........OO..
.O...........................OO................

:traffic circle (p100)

.....................OO....OO...................
.....................O.O..O.O...................
.......................O..O.....................
......................OO..OO....................
.....................OOO..OOO...................
.......................O..O.....................
...............................O................
..............................O.OO..............
..................................O.............
..........................O...O..O.O............
..........................O.....O..O............
..........................O......OO.............
.........OO.....................................
........O..O..........OOO...OOO.................
.......O.O.O....................................
......OOO.O...............O.....................
......OOO.................O.....................
..........................O.....................
............OOO.................................
OO..O................OOO........................
O..OO.....O.....O...............................
.OOOOO....O.....O..O.....O.................O..OO
..........O.....O..O.....O.................OO..O
...................O.....O.......OOO......OOOOO.
.OOOOO......OOO.................................
O..OO................OOO.......O.....O..........
OO..O..........................O.....O....OOOOO.
...............................O.....O.....OO..O
...........................................O..OO
.................................OOO............
.......................................OO.......
......................................OOO.......
.....................................O.OO.......
....................................O.O.........
....................OOO.............O..O........
.....................................OO.........
.............OO....O..O.........................
............O..O................................
............O.O.O...............................
.............O..O...............................
.................O..............................
..............O.O...............................
.....................O..O.......................
...................OOO..OOO.....................
....................OO..OO......................
.....................O..O.......................
...................O.O..O.O.....................
...................OO....OO.....................

:traffic jam Any traffic light hassler, such as traffic circle. The term is also applied to the following reaction, used in most traffic light hasslers, in which two traffic lights interact in such a way as to reappear after 25 generations with an extra 6 spaces between them.

..OOO...........
...........OOO..
O.....O.........
O.....O..O.....O
O.....O..O.....O
.........O.....O
..OOO...........
...........OOO..

:traffic light (p2) A common formation of four blinkers.

..OOO..
.......
O.....O
O.....O
O.....O
.......
..OOO..

:trans-beacon on table (p2)

....OO
.....O
..O...
..OO..
......
OOOO..
O..O..

:trans-boat with tail (p1)

OO...
O.O..
.O.O.
...O.
...OO

:transceiver See Herschel transceiver.

:trans-loaf with tail (p1)

.O....
O.O...
O..O..
.OO.O.
....O.
....OO

:transmitter See Herschel transmitter.

:transparent block reaction A certain reaction between a block and a Herschel predecessor in which the block reappears in its original place some time later, the reaction having effectively passed through it. This reaction was found by Dave Buckingham in 1988. It has been used in some Herschel conduits, and in the gunstars. Because the reaction involves a Herschel predecessor rather than an actual Herschel, the following diagram shows instead a B-heptomino (which by itself would evolve into a block and a Herschel).

O.............
OO..........OO
.OO.........OO
OO............

:transparent debris effect A reaction in which a Herschel or other active region destroys a still life, then later, having passed through the place where the still life was, recreates the still life in its original position. For an example, see transparent block reaction.

:trice tongs (p3) Found by Robert Wainwright, February 1982. In terms of its 7x7 bounding box this ties with jam as the smallest p3 oscillator.

..O....
..OOO..
OO...O.
.O.O.O.
.O.....
..OO..O
.....OO

:triomino Either of the two 3-cell polyominoes. The term is rarely used in Life, since the two objects in question are simply the blinker and the pre-block.

:triple caterer (p3) Found by Dean Hickerson, October 1989. Compare caterer and double caterer.

.....OO.........
....O..O..OO....
....OO.O...O....
......O.OOO....O
..OOO.O.O....OOO
.O..O..O....O...
O.O..O...O..OO..
.O..............
..OO.OO.OO.OO...
...O...O...O....
...O...O...O....

:triplet Any 3-cell polyplet. There are 5 such objects, shown below. The first two are the two triominoes, and the other three vanish in two generations.

O..................O.......O.......O..
OO......OOO......OO.......O.O.......O.
.....................................O

:tripole (p2) The barberpole of length 3.

OO....
O.O...
......
..O.O.
.....O
....OO

:tritoad (p3) Found by Dave Buckingham, October 1977.

.........OO.......
.........O........
..........O..OO...
.......OOO.O..O...
......O....OO.O.OO
......O.OO..O.O.OO
...OO.O...OO..O...
...O..OO...O.OO...
OO.O.O..OO.O......
OO.O.OO....O......
...O..O.OOO.......
...OO..O..........
........O.........
.......OO.........

:true Opposite of pseudo. A gun emitting a period n stream of spaceships (or rakes) is said to be a true period n gun if its mechanism oscillates with period n. (The same distinction between true and pseudo also exists for puffers.) True period n guns are known to exist for all periods greater than 61 (see My Experience with B-heptominos in Oscillators), but only a few smaller periods have been achieved, namely 22, 24, 30, 36, 44, 46, 48, 50, 54, 55, 56 and 60. (Credits for these small period guns are: p30, p46 and p60 by Bill Gosper in 1970-1971, p44 by Dave Buckingham in 1992, p50 by Dean Hickerson in 1996, p24 and p48 by Noam Elkies in 1997, p54 and p56 by Dieter Leithner in early 1998, p55 by Stephen Silver in late 1998, p22 by David Eppstein in 2000 and p36 by Jason Summers in 2004.)

The following diagram shows the p22 gun (David Eppstein, August 2000, using two copies of a p22 oscillator found earlier the same day by Jason Summers).

..................OO.........................
...................O.......O.................
...................O.O..............OO.......
....................OO............OO..O......
........................OOO.......OO.OO......
........................OO.OO.......OOO......
........................O..OO............OO..
.........................OO..............O.O.
...................................O.......O.
...........................................OO
.............................................
OO.......................O...................
.O.....................O.O...................
.O.O.............OOO....OO...................
..OO...O........O...O........................
......O.OO......O....O.......................
.....O....O......OO.O.........O..............
......O...O........O...OO......O.............
.......OOO.............O.O...OOO.............
.........................O...................
.........................OO..................

:T-tetromino The following common predecessor of a traffic light.

OOO
.O.

:tub (p1)

.O.
O.O
.O.

:tubber (p3) Found by Robert Wainwright before June 1972.

....O.O......
....OO.O.....
.......OOO...
....OO....O..
OO.O..OO..O..
.O.O....O.OO.
O...O...O...O
.OO.O....O.O.
..O..OO..O.OO
..O....OO....
...OOO.......
.....O.OO....
......O.O....

:tubeater A pattern that consumes the output of a tubstretcher. The smallest known tubeater was found by Hartmut Holzwart, and is shown below in conjunction with the smallest known tubstretcher.

.......OO.........................
.......O.O........................
.......O..........................
..........O.......................
..........OO......................
..........OO......................
.........OO.......................
OO......OO...O....................
O.O...OO..O.O.O...................
O.....OOO....O.O..................
...O..........O.O.................
...OO..........O.O................
................O.O...............
.................O.O...O..........
..................OO..O.O.........
.....................OO.O.........
.....................OO...........
.....................OO...........
...............................OO.
.......................O....OO.O..
.......................OOO..OO....
.......................OOO..OO....
........................OO........
..................................
..........................O.......
.........................OO.......
.........................O........
..........................O.......
..................................
...........................OO.....
............................O.OO..
................................O.
.............................OO...
.............................OO...
...............................O..
................................OO

:tubstretcher Any wickstretcher in which the wick is two diagonal lines of cells forming, successively, a tub, a barge, a long barge, etc. The first one was found by Hartmut Holzwart in June 1993, although at the time this was considered to be a boatstretcher (as it was shown with an extra cell, making the tub into a boat). The following small example is by Nicolay Beluchenko (August 2005), using a quarter.

.......OOO.....
.......O.......
........O......
..........OO...
...........O...
...............
........OO...O.
OOO.....OO..O.O
O......O.O...O.
.O....OO.......
...OOOO.O......
....OO.........

:tub with tail (p1)

.O...
O.O..
.O.O.
...O.
...OO

:tugalong = tagalong

:tumbler (p14) The smallest known p14 oscillator. Found by George Collins in 1970.

.O.....O.
O.O...O.O
O..O.O..O
..O...O..
..OO.OO..

:tumbling T-tetson (p8) A T-tetromino hassled by two figure-8s. Found by Robert Wainwright.

.OOO.................
O..................OO
O...O............O.OO
O..O.O..........O....
..O.O..O...........O.
...O...O.......OO.O..
.......O.......OO....
....OOO....O.........
.........OO..........
...........O.........

:Turing machine See universal computer.

:turning toads (p4 wick) Found by Dean Hickerson, October 1989.

..............OO.....OO.....OO.....OO.....OO..............
.......O.....O......O......O......O......O................
......OO...O....O.O....O.O....O.O....O.O....O.O.O.OO......
..OO.O.OOO.O..OO..O..OO..O..OO..O..OO..O..OO..O..O..O.OO..
O..O.OO.........................................OOOOO.O..O
OO.O..............................................OO..O.OO
...O..................................................O...
...OO................................................OO...

:turtle (c/3 orthogonally, p3) Found by Dean Hickerson.

.OOO.......O
.OO..O.OO.OO
...OOO....O.
.O..O.O...O.
O....O....O.
O....O....O.
.O..O.O...O.
...OOO....O.
.OO..O.OO.OO
.OOO.......O

:twin bees shuttle (p46) Found by Bill Gosper in 1971, this is the basis of all known p46 oscillators, and so of all known true p46 guns (see new gun for an example). There are numerous ways to stabilize the ends, two of which are shown in the diagram. On the left is David Bell's double block reaction (which results in a shorter, but wider, shuttle than usual), and on the right is the stabilization by a single block. This latter method produces a very large spark which is useful in a number of ways (see, for example, metamorphosis). Adding a symmetrically placed block below this one suppresses the spark. See also p54 shuttle.

.OO........................
.OO........................
...........................
...............O...........
OO.............OO........OO
OO..............OO.......OO
...........OO..OO..........
...........................
...........................
...........................
...........OO..OO..........
OO..............OO.........
OO.............OO..........
...............O...........
...........................
.OO........................
.OO........................

:twinhat (p1) See also hat and sesquihat.

..O...O..
.O.O.O.O.
.O.O.O.O.
OO.O.O.OO
....O....

:twin peaks = twinhat

:twirling T-tetsons II (p60) Found by Robert Wainwright. This is a pre-pulsar hassled by killer toads.

.......OO...OO..........
......O.......O.........
.........O.O............
.......OO...OO..........
........................
........................
........................
.....................OOO
....................OOO.
.............O..........
OOO.........OOO.........
.OOO....................
....................OOO.
.....................OOO
........................
.OOO....................
OOO.........OOO.........
.............O..........
........................
........................
..........OO...OO.......
............O.O.........
.........O.......O......
..........OO...OO.......

:TWIT = tub with tail

:two eaters (p3) Found by Bill Gosper, September 1971.

OO.......
.O.......
.O.O.....
..OO.....
.....OO..
.....O.O.
.......O.
.......OO

:two pulsar quadrants (p3) Found by Dave Buckingham, July 1973. Compare pulsar quadrant.

....O....
....O....
...OO....
..O......
O..O..OOO
O...O.O..
O....O...
.........
..OOO....

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_q.htm0000644000175000017500000002161712536111364016414 00000000000000 Life Lexicon (Q)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Q = Quetzal

:Q-pentomino Conway's name for the following pentomino, a traffic light predecessor.

OOOO
...O

:quad (p2) Found by Robert Kraus, April 1971. Of all oscillators that fit in a 6x6 box this is the only flipper.

OO..OO
O..O.O
.O....
....O.
O.O..O
OO..OO

:QuadLife A form of colorized Life in which there are four types of ON cell. A newly-born cell takes the type of the majority of its three parent cells, or the remaining type if its parent cells are all of different types. In areas where there are only two types of ON cell QuadLife reduces to Immigration.

:quadpole (p2) The barberpole of length 4.

OO.....
O.O....
.......
..O.O..
.......
....O.O
.....OO

:quapole = quadpole

:quarter (c/4 diagonally, p4) The following 25-cell spaceship, found by Jason Summers in September 2000. See also tubstretcher.

........OO...
.......OO....
.........O...
...........OO
..........O..
.............
.........O..O
.OO.....OO...
OO.....O.....
..O....O.O...
....OO..O....
....OO.......

:quasar (p3) Found by Robert Wainwright, August 1971. See pulsar.

..........OOO...OOO..........
.............................
........O....O.O....O........
........O....O.O....O........
........O....O.O....O........
..........OOO...OOO..........
.............................
........OOO.......OOO........
..OOO..O....O...O....O..OOO..
.......O....O...O....O.......
O....O.O....O...O....O.O....O
O....O.................O....O
O....O..OOO.......OOO..O....O
..OOO...................OOO..
.............................
..OOO...................OOO..
O....O..OOO.......OOO..O....O
O....O.................O....O
O....O.O....O...O....O.O....O
.......O....O...O....O.......
..OOO..O....O...O....O..OOO..
........OOO.......OOO........
.............................
..........OOO...OOO..........
........O....O.O....O........
........O....O.O....O........
........O....O.O....O........
.............................
..........OOO...OOO..........

:queen bee See queen bee shuttle.

:queen bee shuttle (p30) Found by Bill Gosper in 1970. There are a number of ways to stabilize the ends. Gosper originally stabilized shuttles against one another in a square of eight shuttles. Two simpler methods are shown here; for a third see buckaroo. The queen bee shuttle is the basis of all known true p30 guns (see Gosper glider gun).

.........O............
.......O.O............
......O.O.............
OO...O..O.............
OO....O.O.............
.......O.O........OO..
.........O........O.O.
....................O.
....................OO

:Quetzal Dieter Leithner's name for the true p54 glider gun he built in January 1998. (This is short for Quetzalcoatlus and expresses the fact that the gun was a very large Herschel loop that was not an emu.) Shortly afterwards Leithner also built a p56 Quetzal using a mechanism found by Noam Elkies for this purpose. In October 1998 Stephen Silver constructed a p55 Quetzal using Elkies' p5 reflector of the previous month.

Some of the more recent Quetzals are not Herschel loops, but are instead short Herschel tracks firing several glider streams all but one of which is reflected back to the beginning of the track to create a new Herschel. Noam Elkies first had the idea of doing this for the p55 case, and Stephen Silver constructed the resulting gun shortly after building the original (much larger) p55 Quetzal. Jason Summers later built a p54 version, which is more complicated because the evenness of the period makes the timing problems considerably more difficult.

:Quetzalcoatlus A giant flying dinosaur after which Dieter Leithner named his p54 gun. Usually abbreviated to Quetzal, or simply Q (as in Q54, Q55, Q56, Q-gun, etc.).

:quilt = squaredance


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_1.htm0000644000175000017500000001177212536111364016315 00000000000000 Life Lexicon (1)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:101 (p5) Found by Achim Flammenkamp in August 1994. The name was suggested by Bill Gosper, noting that the phase shown below displays the period in binary.

....OO......OO....
...O.O......O.O...
...O..........O...
OO.O..........O.OO
OO.O.O..OO..O.O.OO
...O.O.O..O.O.O...
...O.O.O..O.O.O...
OO.O.O..OO..O.O.OO
OO.O..........O.OO
...O..........O...
...O.O......O.O...
....OO......OO....

:1-2-3 (p3) Found by Dave Buckingham, August 1972. This is one of only three essentially different p3 oscillators with only three cells in the rotor. The others are stillater and cuphook.

..OO......
O..O......
OO.O.OO...
.O.O..O...
.O....O.OO
..OOO.O.OO
.....O....
....O.....
....OO....

:1-2-3-4 (p4) See also Achim's p4.

.....O.....
....O.O....
...O.O.O...
...O...O...
OO.O.O.O.OO
O.O.....O.O
...OOOOO...
...........
.....O.....
....O.O....
.....O.....

:14-ner = fourteener

:2 eaters = two eaters

:4-8-12 diamond The following pure glider generator.

....OOOO....
............
..OOOOOOOO..
............
OOOOOOOOOOOO
............
..OOOOOOOO..
............
....OOOO....

:4 boats (p2)

...O....
..O.O...
.O.OO...
O.O..OO.
.OO..O.O
...OO.O.
...O.O..
....O...

:4F = Fast Forward Force Field


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_y.htm0000644000175000017500000000456112536111364016423 00000000000000 Life Lexicon (Y)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Y-pentomino Conway's name for the following pentomino, which rapidly dies.

..O.
OOOO

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_b.htm0000644000175000017500000013047512536111364016400 00000000000000 Life Lexicon (B)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:B = B-heptomino

:B29 (c/4 diagonally, p4) The following spaceship, found by Hartmut Holzwart in September 2004.

.......OOO.......
.......O.........
OOO......O.......
O......O.O.......
.O....OO.OOOO....
...OOOO.OOOOO.OO.
....OO.......OO.O

:B-52 bomber The following p104 double-barrelled glider gun. It uses a B-heptomino and emits one glider every 52 generations. It was found by Noam Elkies in March 1996, except that Elkies used blockers instead of molds, the improvement being found by David Bell later the same month.

.OO....................................
.OO.................O..................
...................O.O............O.O..
....................O............O.....
OO.......OO.......................O..O.
OO.O.....OO.......................O.O.O
...O.......................O.......O..O
...O.......................OO.......OO.
O..O.................OO.....O..........
.OO..................O.................
.....................OOO...............
....................................OO.
....................................OO.
.OO....................................
O..O...................................
O.O.O................O.O....OO.....OO..
.O..O.................OO....OO.....OO.O
.....O............O...O...............O
..O.O............O.O..................O
..................O................O..O
....................................OO.

:babbling brook Any oscillator whose rotor consists of a string of cells each of which is adjacent to exactly two other rotor cells, except for the endpoints which are adjacent to only one other rotor cell. Compare muttering moat. Examples include the beacon, the great on-off, the light bulb and the spark coil. The following less trivial example (by Dean Hickerson, August 1997) is the only one known with more than four cells in its rotor. It is p4 and has a 6-cell rotor.

.......O........
.....OOO....OO..
....O...OO..O...
.O..O.OO..O.O...
O.O.O....OO..OO.
.OO..OO....O.O.O
...O.O..OO.O..O.
...O..OO...O....
..OO....OOO.....
........O.......

:backrake Another term for a backwards rake. A p8 example by Jason Summers is shown below. See total aperiodic for a p12 example.

.....OOO...........OOO.....
....O...O.........O...O....
...OO....O.......O....OO...
..O.O.OO.OO.....OO.OO.O.O..
.OO.O....O.OO.OO.O....O.OO.
O....O...O..O.O..O...O....O
............O.O............
OO.......OO.O.O.OO.......OO
............O.O............
......OOO.........OOO......
......O...O.........O......
......O.O....OOO...........
............O..O....OO.....
...............O...........
...........O...O...........
...........O...O...........
...............O...........
............O.O............

:backward glider A glider which moves at least partly in the opposite direction to the puffer(s) or spaceship(s) under consideration.

:baker (c p4 fuse) A fuse by Keith McClelland.

..............OO
.............O.O
............O...
...........O....
..........O.....
.........O......
........O.......
.......O........
......O.........
.....O..........
....O...........
...O............
OOO.............
.O..............

:baker's dozen (p12) A loaf hassled by two blocks and two caterers. The original form (using p4 and p6 oscillators to do the hassling) was found by Robert Wainwright in August 1989.

OO.........OO..........
OOOO.O.....OO..........
O.O..OOO...............
...........O...........
....OO....O.O..........
....O.....O..O....O....
...........OO....OO....
.......................
...............OOO..O.O
..........OO.....O.OOOO
..........OO.........OO

:bakery (p1) A common formation of two bi-loaves.

....OO....
...O..O...
...O.O....
.OO.O...O.
O..O...O.O
O.O...O..O
.O...O.OO.
....O.O...
...O..O...
....OO....

:barberpole Any p2 oscillator in the infinite sequence bipole, tripole, quadpole, pentapole, hexapole, heptapole ... (It wasn't my idea to suddenly change from Latin to Greek.) This sequence of oscillators was found by the MIT group in 1970. The term is also used (usually in the form "barber pole") to describe other extensible sections of oscillators or spaceships, especially those (usually of period 2) in which all generations look alike except for a translation and/or rotation/reflection.

:barberpole intersection = quad

:barber's pole = barberpole

:barge (p1)

.O..
O.O.
.O.O
..O.

:basic shuttle = queen bee shuttle

:beacon (p2) The third most common oscillator. Found by Conway, March 1970.

OO..
O...
...O
..OO

:beacon maker (c p8 fuse)

..............OO
.............O.O
............O...
...........O....
..........O.....
.........O......
........O.......
.......O........
......O.........
.....O..........
....O...........
...O............
OOO.............
..O.............
..O.............

:beehive (p1) The second most common still life.

.OO.
O..O
.OO.

:beehive and dock (p1)

...OO.
..O..O
...OO.
......
.OOOO.
O....O
OO..OO

:beehive on big table = beehive and dock

:beehive pusher = hivenudger

:beehive with tail (p1)

.OO...
O..O..
.OO.O.
....O.
....OO

:belly spark The spark of a MWSS or HWSS other than the tail spark.

:bent keys (p3) Found by Dean Hickerson, August 1989. See also odd keys and short keys.

.O........O.
O.O......O.O
.O.OO..OO.O.
....O..O....
....O..O....

:B-heptomino (stabilizes at time 148) This is a very common pattern. It often arises with the cell at top left shifted one space to the left, which does not affect the subsequent evolution. B-heptominoes acquired particular importance in 1996 due to Dave Buckingham's work on B tracks - see in particular My Experience with B-heptominos in Oscillators.

O.OO
OOO.
.O..

:B-heptomino shuttle = twin bees shuttle

:bi-block (p1) The smallest pseudo still life.

OO.OO
OO.OO

:bi-boat = boat-tie

:biclock The following pure glider generator consisting of two clocks.

..O....
OO.....
..OO...
.O...O.
...OO..
.....OO
....O..

:big beacon = figure-8

:big fish = HWSS

:big glider (c/4 diagonally, p4) This was found by Dean Hickerson in December 1989 and was the first known diagonal spaceship other than the glider.

...OOO............
...O..OOO.........
....O.O...........
OO.......O........
O.O....O..O.......
O........OO.......
.OO...............
.O..O.....O.OO....
.O.........OO.O...
...O.O......OO..O.
....OO.O....OO...O
........O.......O.
.......OOOO...O.O.
.......O.OO...OOOO
........O...OO.O..
.............OO...
.........O.OOO....
..........O..O....

:big S (p1)

....OO.
...O..O
...O.OO
OO.O...
O..O...
.OO....

:big table = dock

:billiard table configuration Any oscillator in which the rotor is enclosed within the stator. Examples include airforce, cauldron, clock II, Hertz oscillator, negentropy, pinwheel, pressure cooker and scrubber.

:bi-loaf This term has been used in at least three different senses. A bi-loaf can be half a bakery:

.O.....
O.O....
O..O...
.OO.O..
...O.O.
...O..O
....OO.
or it can be the following much less common still life:
..O....
.O.O...
O..O...
.OO.OO.
...O..O
...O.O.
....O..
or the following pure glider generator:
..O.
.O.O
O..O
.OO.
O..O
O.O.
.O..

:bipole (p2) The barberpole of length 2.

OO...
O.O..
.....
..O.O
...OO

:bi-pond (p1)

.OO....
O..O...
O..O...
.OO.OO.
...O..O
...O..O
....OO.

:bi-ship = ship-tie

:bit A live cell.

:biting off more than they can chew (p3) Found by Peter Raynham, July 1972.

O...........
OOO.........
...O........
..OO........
...OO.......
....OO......
...O..O.....
...O..OO....
....OO.OOO..
........O.O.
..........O.
..........OO

:Black&White = Immigration

:blasting cap The pi-heptomino (after the shape at generation 1). A term used at MIT and still occasionally encountered.

:blinker (p2) The smallest and most common oscillator. Found by Conway, March 1970.

OOO

:blinker puffer Any puffer whose output is blinkers. However, the term is particularly used for p8 c/2 puffers. The first such blinker puffer was found by Robert Wainwright in 1984, and was unexpectedly simple:

...O.....
.O...O...
O........
O....O...
OOOOO....
.........
.........
.........
.OO......
OO.OOO...
.OOOO....
..OO.....
.........
.....OO..
...O....O
..O......
..O.....O
..OOOOOO.
Since then many more blinker puffers have been found. The following one was found by David Bell in 1992 when he was trying to extend an x66:
.............OOO.
............OOOOO
...........OO.OOO
............OO...
.................
.................
.........O.O.....
..O.....O..O.....
.OOOOO...O.O.....
OO...OO.OO.......
.O.......O.......
..OO..O..O.......
..........O......
..OO..O..O.......
.O.......O.......
OO...OO.OO.......
.OOOOO...O.O.....
..O.....O..O.....
.........O.O.....
.................
.................
............OO...
...........OO.OOO
............OOOOO
.............OOO.
The importance of this larger blinker puffer (and others like it), is that the engine which produces the blinker output is only p4. The blinker row produced by the puffer can easily be ignited, and burns cleanly with a speed of 2c/3. When the burning catches up to the engine, it causes a phase change in the puffer. This fact allows p8 blinker puffers to be used to construct rakes of all periods which are large multiples of four.

:blinkers bit pole (p2) Found by Robert Wainwright, June 1977.

.....OO
OOO.O.O
.......
.O.O..O
O....O.
OO...O.

:blinker ship A growing spaceship in which the wick consists of a line of blinkers. An example by Paul Schick based on his Schick engine is shown below. Here the front part is p12 and moves at c/2, while the back part is p26 and moves at 6c/13. Every 156 generations 13 blinkers are created and 12 are destroyed, so the wick becomes one blinker longer.

..........OOOO.............
..........O...O............
..........O................
.OO........O..O............
OO.OO......................
.OOOO...O..................
..OO...O.OO........O....OOO
......O...O........O....O.O
..OO...O.OO........O....OOO
.OOOO...O..................
OO.OO......................
.OO........O..O............
..........O................
..........O...O............
..........OOOO.............

:block (p1) The most common still life.

OO
OO

:blockade (p1) A common formation of four blocks. The final form of lumps of muck.

OO.....................
OO.....................
.......................
.......................
.OO.................OO.
.OO.................OO.
.......................
.......................
.....................OO
.....................OO

:block and dock (p1)

...OO.
...OO.
......
.OOOO.
O....O
OO..OO

:block and glider (stabilizes at time 106)

OO..
O.O.
..OO

:blocker (p8) Found by Robert Wainwright. See also filter.

......O.O.
.....O....
OO..O....O
OO.O..O.OO
....OO....

:block on big table = block and dock

:block on table (p1)

..OO
..OO
....
OOOO
O..O

:block pusher A pattern emitting streams of gliders which can repeatedly push a block further away. This can be used as part of a sliding block memory.

The following pattern, in which three gliders push a block one cell diagonally, is an example of how a block pusher works.

...................O.O
...................OO.
....................O.
......................
......................
......................
...O..................
..O...................
..OOO.................
......................
......................
......................
......................
OO...O................
OO...O.O..............
.....OO...............

:blom (stabilizes at time 23314) The following methuselah, found by Dean Hickerson in July 2002.

O..........O
.OOOO......O
..OO.......O
..........O.
........O.O.

:blonk A block or a blinker. This term is mainly used in the context of sparse Life and was coined by Rich Schroeppel in September 1992.

:blonker (p6) The following oscillator, found by Nicolay Beluchenko in April 2004.

O..OO....O..
OO..O.OO.O..
....O.O.....
.....OO.....
.......O....
.......O...O
.........O.O
..........O.

:boat (p1) The only 5-cell still life.

OO.
O.O
.O.

:boat-bit A binary digit represented by the presence of a boat next to a snake (or other suitable object, such as an aircraft carrier). The bit can be toggled by a glider travelling along a certain path. A correctly timed glider on a crossing path can detect whether the transition was from 1 to 0 (in which case the crossing glider is deleted) or from 0 to 1 (in which case it passes unharmed). Three gliders therefore suffice for a non-destructive read. The mechanisms involved are shown in the diagram below. Here the bit is shown in state 0. It is about to be set to 1 and then switched back to 0 again. The first crossing glider will survive, but the second will be destroyed. (In January 1997 David Bell found a method of reading the bit while setting it to 0. A MWSS is fired at the boat-bit. If it is already 0 then the MWSS passes unharmed, but if it is 1 then the boat and the MWSS are destroyed and, with the help of an eater1, converted into a glider which travels back along exactly the same path that is used by the gliders that toggle the boat-bit.)

......O..................
.......O.................
.....OOO.................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
................O........
..............O.O........
..........OO...OO........
...........OO............
..........O..........O.OO
.....................OO.O
.........................
.........................
.........................
.........................
.........................
.O.......................
.OO......................
O.O......................

:boat maker (c p4 fuse)

................OO
...............O.O
..............O...
.............O....
............O.....
...........O......
..........O.......
.........O........
........O.........
.......O..........
......O...........
.....O............
OOOOO.............
....O.............
....O.............
....O.............
....O.............

:boat on boat = boat-tie

:boat-ship-tie = ship tie boat

:boatstretcher See tubstretcher.

:boat-tie (p1) A 10-cell still life consisting of two boats placed tip-to-tip. The name is a pun on "bow tie".

.O....
O.O...
.OO...
...OO.
...O.O
....O.

:boojum reflector (p1) Dave Greene's name for the following reflector which he found in April 2001, and which is currently the smallest known stable reflector.

....O.O......OO.............................
.....OO......OO.............................
.....O......................................
............................................
............................................
............................................
............................................
............................................
............................................
........................................O...
.......................................O.O..
.......................................O.O..
....................OO................OO.OO.
....................OO......................
......................................OO.OO.
..OO..................................OO.O..
.O.O.......................................O
.O........................................OO
OO..........................................
............................................
..................................OO........
..................................OO....OO..
...........OO...........................O.O.
..........O.O.............................O.
..........O...............................OO
.........OO.......................OO........
..................................OO........
............................................
............................................
.............................O..............
............................O.O.............
.............................O..............

:bookend The following induction coil. It is generation 1 of century.

..OO
O..O
OOO.

:bookends (p1)

OO...OO
O.O.O.O
..O.O..
.OO.OO.

:boss (p4) Found by Dave Buckingham, 1972.

.....O.....
....O.O....
....O.O....
...OO.OO...
..O.....O..
.O.O.O.O.O.
.O.O...O.O.
OO.O...O.OO
O..O.O.O..O
..O.....O..
...OO.OO...
....O.O....
....O.O....
.....O.....

:bottle (p8) Found by Achim Flammenkamp in August 1994. The name is a back-formation from ship in a bottle.

....OO......OO....
...O..O....O..O...
...O.O......O.O...
.OO..OOO..OOO..OO.
O......O..O......O
O.OO..........OO.O
.O.O..........O.O.
...OO........OO...
..................
..................
...OO........OO...
.O.O..........O.O.
O.OO..........OO.O
O......O..O......O
.OO..OOO..OOO..OO.
...O.O......O.O...
...O..O....O..O...
....OO......OO....

:bounding box The smallest rectangular array of cells that contains the whole of a given pattern. For oscillators and guns this usually is meant to include all phases of the pattern, but excludes, in the case of guns, the outgoing stream(s).

:bow tie = boat-tie

:brain (c/3 orthogonally, p3) Found by David Bell, May 1992.

.OOO.........OOO.
O.O.OO.....OO.O.O
O.O.O.......O.O.O
.O.OO.OO.OO.OO.O.
.....O.O.O.O.....
...O.O.O.O.O.O...
..OO.O.O.O.O.OO..
..OOO..O.O..OOO..
..OO..O...O..OO..
.O....OO.OO....O.
.O.............O.

:breeder Any pattern whose population grows at a quadratic rate, although it is usual to exclude spacefillers. It is easy to see that this is the fastest possible growth rate.

The term is also sometimes used to mean specifically the breeder created by Bill Gosper's group at MIT, which was the first known pattern exhibiting superlinear growth.

There are four basic types of breeder, known as MMM, MMS, MSM and SMM (where M=moving and S=stationary). Typically an MMM breeder is a rake puffer, an MMS breeder is a puffer producing puffers which produce stationary objects (still lifes and/or oscillators), an MSM breeder is a gun puffer and an SMM breeder is a rake gun. There are, however, less obvious variants of these types. The original breeder was of type MSM (a p64 puffer puffing p30 glider guns).

The known breeder with the smallest initial population is the metacatacryst.

:bridge A term used in naming certain still lifes (and the stator part of certain oscillators). It indicates that the object consists of two smaller objects joined edge to edge, as in snake bridge snake.

:broken lines A pattern constructed by Dean Hickerson in May 2005 which produces complex broken lines of gliders and blocks.

:broth = soup

:BTC = billiard table configuration

:B track A track for B-heptominoes. The term is more-or-less synonymous with Herschel track, since a B-heptomino becomes a Herschel plus a block in twenty generations.

:buckaroo A queen bee shuttle stabilized at one end by an eater in such a way that it can turn a glider, as shown below. This was found by Dave Buckingham in the 1970s. The name is due to Bill Gosper.

..O.....................
O.O.....................
.OO.....................
...........O............
.........O.O............
........O.O.............
.......O..O...........OO
........O.O...........OO
...OO....O.O............
..O.O......O............
..O.....................
.OO.....................

:bullet heptomino Generation 1 of the T-tetromino.

.O.
OOO
OOO

:bun The following induction coil. By itself this is a common predecessor of the honey farm. See also cis-mirrored R-bee.

.OO.
O..O
.OOO

:bunnies (stabilizes at time 17332) This is a parent of rabbits and was found independently by Robert Wainwright and Andrew Trevorrow.

O.....O.
..O...O.
..O..O.O
.O.O....

:burloaf = loaf

:burloaferimeter (p7) Found by Dave Buckingham in 1972. See also airforce.

....OO....
.....O....
....O.....
...O.OOO..
...O.O..O.
OO.O...O.O
OO.O....O.
....OOOO..
..........
....OO....
....OO....

:bushing That part of the stator of an oscillator which is adjacent to the rotor. Compare casing.

:butterfly The following pattern, or the formation of two beehives that it evolves into after 33 generations. (Compare teardrop, where the beehives are five cells closer together.)

O...
OO..
O.O.
.OOO

:by flops (p2) Found by Robert Wainwright.

...O..
.O.O..
.....O
OOOOO.
.....O
.O.O..
...O..

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_o.htm0000644000175000017500000002513512536111364016411 00000000000000 Life Lexicon (O)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:obo spark A spark of the form O.O (so called after its rle encoding).

:octagon II (p5) The first known p5 oscillator, discovered in 1971 independently by Sol Goodman and Arthur Taber. The name is due to the latter.

...OO...
..O..O..
.O....O.
O......O
O......O
.O....O.
..O..O..
...OO...

:octagon IV (p4) Found by Robert Wainwright, January 1979.

.......OO.......
.......OO.......
................
......OOOO......
.....O....O.....
....O......O....
...O........O...
OO.O........O.OO
OO.O........O.OO
...O........O...
....O......O....
.....O....O.....
......OOOO......
................
.......OO.......
.......OO.......

:octomino Any 8-cell polyomino. There are 369 such objects. The word is particularly applied to the following octomino (or its two-generation successor), which is fairly common but lacks a proper name:

..OO
..OO
OOO.
.O..

:odd keys (p3) Found by Dean Hickerson, August 1989. See also short keys and bent keys.

..........O.
.O.......O.O
O.OOO..OO.O.
.O..O..O....
....O..O....

:omino = polyomino

:omniperiodic A cellular automaton is said to be omniperiodic if it has oscillators of all periods. It is not known if Life is omniperiodic, although this seems likely. Dave Buckingham's work on Herschel conduits in 1996 (see My Experience with B-heptominos in Oscillators) reduced the number of unresolved cases to a finite number. At the time of writing the only periods for which no oscillator is known are 19, 23, 31, 37, 38, 41, 43 and 53. If we insist that the oscillator must contain a cell oscillating at the full period, then 34 and 51 should be added to this list. The most recently achieved periods were all found by Noam Elkies: p49 in August 1999 (a glider loop using p7 reflectors built from his new p7 pipsquirter), p39 (previously only possible without a p39 cell) in July 2000, and p27 in November 2002.

Note that if we were to allow infinite oscillators, then all periods are certainly possible, as any period of 14 or more can be obtained using a glider (or LWSS) stream.

:one-sided spaceship synthesis A glider synthesis of a spaceship in which all gliders come from the same side of the spaceship's path. Such syntheses are used extensively in the 17c/45 Caterpillar.

:onion rings For each integer n>1 onion rings of order n is a stable agar of density 1/2 obtained by tiling the plane with a certain 4n x 4n pattern. The tile for order 3 onion rings is shown below - the reader should then be able to deduce the form of tiles of other orders.

......OOOOOO
.OOOO.O....O
.O..O.O.OO.O
.O..O.O.OO.O
.OOOO.O....O
......OOOOOO
OOOOOO......
O....O.OOOO.
O.OO.O.O..O.
O.OO.O.O..O.
O....O.OOOO.
OOOOOO......

:on-off Any p2 oscillator in which all rotor cells die from overpopulation. The simplest example is a beacon. Compare flip-flop.

:O-pentomino Conway's name for the following pentomino, a traffic light predecessor, although not one of the more common ones.

OOOOO

:orbit A term proposed by Jason Summers to refer to a natural stabilization of a puffer. For example, the switch engine has two (known) orbits, the block-laying one and the glider-producing one.

:Orion (c/4 diagonally, p4) Found by Hartmut Holzwart, April 1993.

...OO.........
...O.O........
...O..........
OO.O..........
O....O........
O.OO......OOO.
.....OOO....OO
......OOO.O.O.
.............O
......O.O.....
.....OO.O.....
......O.......
....OO.O......
.......O......
.....OO.......
In May 1999, Jason Summers found the following smaller variant:
.OO..........
OO...........
..O..........
....O....OOO.
....OOO....OO
.....OOO.O.O.
............O
.....O.O.....
....OO.O.....
.....O.......
...OO.O......
......O......
....OO.......

:orphan Conway's preferred term for a Garden of Eden.

:oscillator Any pattern that is a predecessor of itself. The term is usually restricted to non-stable finite patterns. An oscillator is divided into a rotor and a stator. See also omniperiodic.

In general cellular automaton theory the term "oscillator" usually covers spaceships as well, but this usage is not normal in Life.

:overcrowding = overpopulation

:over-exposure = underpopulation

:overpopulation Death of a cell caused by it having more than three neighbours. See also underpopulation.

:overweight spaceship = OWSS

:OWSS A would-be spaceship similar to LWSS, MWSS and HWSS but longer. On its own an OWSS is unstable, but it can be escorted by true spaceships to form a flotilla.

:Ox A 1976 novel by Piers Anthony which involves Life.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_s.htm0000644000175000017500000020255212536111364016415 00000000000000 Life Lexicon (S)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:S Usually means big S, but may sometimes mean paperclip.

:sailboat (p16) A boat hassled by a Kok's galaxy, a figure-8 and two eater3s. Found by Robert Wainwright in June 1984.

........O...........O........
.......O.O.........O.O.......
........O...........O........
.............................
......OOOOO.......OOOOO......
.....O....O.......O....O.....
....O..O.............O..O....
.O..O.OO.............OO.O..O.
O.O.O.....O.......O.....O.O.O
.O..O....O.O.....O.O....O..O.
....OO..O..O.....O..O..OO....
.........OO.......OO.........
.............OO..............
.............O.O.............
........O..O..O..............
.......O.....................
.....OO..........OOO.........
..O......OO.O....OOO.........
.....O...O..O....OOO.........
.....OOO.O...O......OOO......
..O...........O.....OOO......
...O...O.OOO........OOO......
....O..O...O.................
....O.OO......O..............
..........OO.................
.........O...................
.....O..O....................

:sawtooth Any finite pattern whose population grows without bound but does not tend to infinity. (In other words, the population reaches new heights infinitely often, but also infinitely often returns to some fixed value.) Conway's preferred plural is "sawteeth".

The first sawtooth was constructed by Dean Hickerson in April 1991. The least infinitely repeating population of any known sawtooth is 262 (David Bell, July 2005).

See also tractor beam.

:SBM = sliding block memory

:Schick engine (c/2 orthogonally, p12) This spaceship, found by Paul Schick in 1972, produces a large spark (the 15 live cells at the rear in the phase shown below) which can be perturbed by other c/2 spaceships to form a variety of puffers. The diagram below shows the smallest form of the Schick engine, using two LWSS. It is also possible to use two MWSS or two HWSS, or even a LWSS and a HWSS.

OOOO..............
O...O.........O...
O...........OO....
.O..O..OO.....OOO.
......OOO......OOO
.O..O..OO.....OOO.
O...........OO....
O...O.........O...
OOOO..............

:Schick ship = Schick engine

:scorpion (p1)

...O...
.OOO...
O...OO.
O.O.O.O
.OO.O.O
.....O.

:scrubber (p2) Found in 1971.

....O......
..OOO......
.O.........
.O..OOO....
OO.O...O...
...O...O...
...O...O.OO
....OOO..O.
.........O.
......OOO..
......O....

:SE = switch engine

:seal (c/6 diagonally, p6) The first c/6 diagonal spaceship, found by Nicolay Beluchenko in September 2005.

...O..OO..........................
.OOO.O.O.O........................
.O..OOO..OO.......................
O..OOOOOO.O.OOO...................
.O..OOO.O.OOOOO...................
......O.O.O.O.....................
O.O...O.O.OOOOO...................
O..O.O..O.OO...O..................
...O..OO.......OOO................
.O...OOOOO.OOO..OO................
....O.........O...................
..O.O.........O...................
....OO.OOOOO...O..................
......O.OOO..O.....OO.............
......O..O...O.OOO.OO.............
........OO...OOO.O..O...O.........
........OO....OO.OOOO...OOO.......
...................O.O..O.........
.............O.O.....OO..OO.......
.............O..O.....O.OOO.....O.
.............O...O....OO..O...O..O
...............OOO.....OO........O
...............O.O..O..O.....OO..O
.................O..OO.OO.O..O....
................O.......O.O.......
.................O...OOOO.........
..................O...O...........
..................................
.......................O..........
......................O.O.........
.....................OO...........
.....................O.O..........
.....................OO...........
.......................O..........
......................O...........

:second glider domain The second glider domain of an edge shooter is the set of displacements (in space and time, relative to the glider stream emitted by the edge shooter) that a glider stream may have without interfering with the edge shooter. This is useful to know, because edge shooters are often used to generate glider streams very close to other glider streams.

:sesquihat (p1) Halfway between a hat and a twinhat.

....O
OO.O.O.
.O.O.O.
.O.O.OO
..O...

:SGR Abbreviation for stable glider reflector.

:shillelagh (p1)

OO...
O..OO
.OO.O

:ship (p1) The term is also used as a synonym of spaceship.

OO.
O.O
.OO

:ship in a bottle (p16) Found by Bill Gosper in August 1994. See also bottle.

....OO......OO....
...O..O....O..O...
...O.O......O.O...
.OO..OOO..OOO..OO.
O......O..O......O
O.OO..........OO.O
.O.O..........O.O.
...OO...OO...OO...
.......O.O........
.......OO.........
...OO........OO...
.O.O..........O.O.
O.OO..........OO.O
O......O..O......O
.OO..OOO..OOO..OO.
...O.O......O.O...
...O..O....O..O...
....OO......OO....

:ship on boat = ship tie boat

:ship on ship = ship-tie

:ship-tie (p1) The name is by analogy with boat-tie.

OO....
O.O...
.OO...
...OO.
...O.O
....OO

:ship tie boat (p1)

OO....
O.O...
.OO...
...OO.
...O.O
....O.

:short keys (p3) Found by Dean Hickerson, August 1989. See also bent keys and odd keys.

.O........O.
O.OOO..OOO.O
.O..O..O..O.
....O..O....

:shuttle Any oscillator which consists of an active region moving back and forth between stabilizing objects. The most well-known examples are the queen bee shuttle (which has often been called simply "the shuttle") and the twin bees shuttle. See also p54 shuttle and Eureka. Another example is the p72 R-pentomino shuttle that forms part of the pattern given under factory.

:siamese A term used in naming certain still lifes (and the stator part of certain oscillators). It indicates that the object consists of two smaller objects sharing two or more cells. See snake siamese snake and loaf siamese barge for examples.

:side Half a sidewalk. In itself this is unstable and requires an induction coil.

OO...
O.OOO
....O

:sidecar A small tagalong for a HWSS that was found by Hartmut Holzwart in 1992. The resulting spaceship (shown below) has a phase with only 24 cells, making it in this respect the smallest known spaceship other than the standard spaceships and some trivial two-spaceship flotillas derived from them. Note also that a HWSS can support two sidecars at once.

.O......
O.....O.
O.....O.
OOOOO.O.
........
....OO..
..O....O
.O......
.O.....O
.OOOOOO.

:side-shooting gun = slide gun

:side-tracking See universal constructor.

:sidewalk (p1)

.OO.OO
..O.O.
.O..O.
.O.O..
OO.OO.

:siesta (p5) Found by Dave Buckingham in 1973. Compare sombreros.

...........OO...
...OO.....O.O...
...O.O....O.....
.....O...OO.O...
...O.OO.....OOO.
.OOO.....O.O...O
O...O.O.....OOO.
.OOO.....OO.O...
...O.OO...O.....
.....O....O.O...
...O.O.....OO...
...OO...........

:signal Movement of information through the Life universe. Signals can be carried by spaceships, fuses, drifters, or conduits. Spaceships can only transfer a signal at the speed of the spaceship, while fuses can transfer a signal at speeds up to the speed of light.

In practice, many signals are encoded as the presence or absence of a glider (or other spaceship) at a particular point at a particular time. Such signals can be combined by the collision of gliders to form logic operations such as AND, OR, and NOT gates. Signals can be duplicated using glider duplicators or other fanout devices, and can be used up by causing perturbations on other parts of the Life object.

Signals are used in pseudo-random glider generators, the unit Life cell and the Fermat prime calculator, among others.

:Silver's p5 (p5) The following oscillator found by Stephen Silver in February 2000:

OO.........
O..........
.O..O......
...OO......
...O...O.OO
..O....OO.O
..OO.......

As this has no spark, it appears useless. Nonetheless, in March 2000, David Eppstein found a way to use it to reduce the size of Noam Elkies' p5 reflector.

:singular flip flop (p2) Found by Robert Wainwright, July 1972.

..O...
..O.O.
O....O
OOOOOO
......
..OO..
..OO..

:sinking ship = canoe

:six Ls (p3) This is a compact form of loading dock.

...O...
.OOO..O
O...OOO
OOO....
....OOO
OOO...O
O..OOO.
...O...

:sixty-nine (p4) Found by Robert Wainwright, October 1978.

.........O...........
........O.O..........
.....................
......O...OO.........
.....O.....O.........
......O.O............
........OO......O....
................O....
..O.....OO....OOO....
..O...........OO.....
OOO.......OO..OO..OOO
OO......O.OO....OOO..
OO..OOO.O.O.....OOO..
..OOO................
..OOO......O.........
..........O.O........
.....................
........O...OO.......
.......O.....O.......
........O.O..........
..........OO.........

:skewed quad (p2)

.OO....
.O...OO
..O.O.O
.......
O.O.O..
OO...O.
....OO.

:skewed traffic light (p3) Found by Robert Wainwright, August 1989.

.............OO.........
............O..O........
.............O.O........
.........OO...O.........
..........O.OO..........
............O...........
............O...........
........................
OO........OOO......O....
OOOO.O........O...OO....
O.O..OOO.O....O.........
.........O....O.OOO..O.O
....OO...O........O.OOOO
....O......OOO........OO
........................
...........O............
...........O............
..........OO.O..........
.........O...OO.........
........O.O.............
........O..O............
.........OO.............

:slide gun A gun which fires sideways from an extending arm. The arm consists of streams of spaceships which are pushing a pattern away from the body of the gun and releasing an output spaceship every time they do so. Each output spaceship therefore travels along a different path.

Dieter Leithner constructed the first slide gun in July 1994 (although he used the term "side shooting gun"). The following pattern shows the key reaction of this slide gun. The three gliders shown will push the block one cell diagonally, thereby extending the length of the arm by one cell, and at the same time they release an output glider sideways. (In 1999, Jason Summers constructed slide guns using other reactions.)

..............OO.
..............OO.
........OOO......
..........O......
.........O.....OO
..............O.O
................O
.................
.................
.................
.................
.................
.................
.................
.................
.................
.................
.O...............
.OO..............
O.O..............

:sliding block memory A memory register whose value is stored as the position of a block. The block can be moved by means of glider collisions - see block pusher for an example.

In Conway's original formulation (as part of his proof of the existence of a universal computer in Life) 2 gliders were used to pull the block inwards by three diagonal spaces, and 30 gliders were used to push it out by the same amount. Dean Hickerson later greatly improved on this, finding a way to pull a block inwards by one diagonal space using 2 gliders, and push it out using 3 gliders. In order for the memory to be of any use there also has to be a way to read the value held. It suffices to be able to check whether the value is zero (as Conway did), or to be able to detect the transition from one to zero (as Hickerson did).

Dean Hickerson's sliding block memory is used in Paul Chapman's URM.

:slow glider construction Construction an object by a "slow salvo" of gliders all coming from the same direction, in such a way that timing of the gliders does not matter as long as they are not too close behind one another. This type of construction requires an initial seed object, such as a block, which is modified by each glider in turn until the desired object is produced.

In May 1997, Nick Gotts produced a slow glider construction of a block-laying switch engine from a block, using a slow salvo of 53 gliders. Constructions like this are important in the study of sparse Life, as they will occur naturally as gliders created in the first few generations collide with blonks and other debris.

Slow glider constructions are also useful in some designs for universal constructors. However, in this case the above definition is usually too restrictive, and it is desirable to allow constructions in which some gliders in the salvo are required to have a particular timing modulo 2 (a "p2 slow salvo"). This gives much greater flexibility, as blinkers can now be freely used in the intermediate construction steps.

:slow salvo See slow glider construction.

:small fish = LWSS

:small lake (p1) See also lake.

....O....
...O.O...
...O.O...
.OO...OO.
O.......O
.OO...OO.
...O.O...
...O.O...
....O....

:smiley (p8) Found by Achim Flammenkamp in July 1994 and named by Alan Hensel.

OO.O.OO
...O...
O.....O
.OOOOO.
.......
.......
OOO.OOO

:SMM breeder See breeder.

:smoke Debris which is fairly long-lived but eventually dies completely. Basically, a large spark. This term is used especially when talking about the output from a spaceship - see smoking ship.

:smoking ship A spaceship which produces smoke. If the smoke extends past the edge of the rest of the spaceship, then it can be used to perturb other objects as the spaceship passes by. Running gliders into the smoke is often a good way to turn or duplicate the them, or convert them into other objects. Sometimes the smoke from a smoking ship may itself be perturbed by accompanying spaceships in order to form a puffer. A simple example of a smoking ship is the Schick engine.

:snacker (p9) Found by Mark Niemiec in 1972. This is a pentadecathlon with stabilizers which force it into a lower period.

OO................OO
.O................O.
.O.O............O.O.
..OO............OO..
.......O....O.......
.....OO.OOOO.OO.....
.......O....O.......
..OO............OO..
.O.O............O.O.
.O................O.
OO................OO
The stabilizers make the domino spark largely inaccessible, but the snacker is extensible, as shown in the next diagram, and so a more accessible p9 domino spark can be obtained. In April 1998 Dean Hickerson found an alternative stabilizer that is less obtrusive than the original one, and this is also shown in this diagram.
OO................................
.O................................
.O.O.........................OO...
..OO.......................O..O...
.......O....O..............OOO....
.....OO.OOOO.OO...O....O......OOO.
.......O....O...OO.OOOO.OO...O...O
..OO..............O....O......OOO.
.O.O.......................OOO....
.O.........................O..O...
OO...........................OO...
An end can also be stabilized by killer candlefrobras, although this isn't efficient.

:snail (c/5 orthogonally, p5) The first known c/5 spaceship, discovered by Tim Coe in January 1996. For some time it was the slowest known orthogonal spaceship.

.O....................................
.O....................................
O.....................................
.OOO.................OOO...OOO........
.OO.O.........O...O.O......OOO........
..O...........OO.O.......O....OOOO....
......O......O...O.O...OO.O.....OO....
...O..O.OOO...OO.........O........OO.O
...OO.O.....O.....O.................O.
.........O.OOOOOOO....................
......................................
.........O.OOOOOOO....................
...OO.O.....O.....O.................O.
...O..O.OOO...OO.........O........OO.O
......O......O...O.O...OO.O.....OO....
..O...........OO.O.......O....OOOO....
.OO.O.........O...O.O......OOO........
.OOO.................OOO...OOO........
O.....................................
.O....................................
.O....................................

:snake (p1)

OO.O
O.OO

:snake bit An alternative name for a boat-bit. Not a very sensible name, because various other things can be used instead of a snake.

:snake bridge snake (p1)

....OO
....O.
.....O
....OO
OO.O..
O.OO..

:snake dance (p3) Found by Robert Wainwright, May 1972.

...OO.O..
...O.OO..
OO.O.....
.O..O.OOO
O..O.O..O
OOO.O..O.
.....O.OO
..OO.O...
..O.OO...

:snake pit This term has been used for two different oscillators: the p2 snake pit (essentially the same as fore and back)

O.OO.OO
OO.O.O.
......O
OOO.OOO
O......
.O.O.OO
OO.OO.O
and the p3 snake pit.
.....OO....
....O..O...
....O.OO...
.OO.O......
O.O.O.OOOO.
O.........O
.OOOO.O.O.O
......O.OO.
...OO.O....
...O..O....
....OO.....

:snake siamese snake (p1)

OO.OO.O
O.OO.OO

:sombrero One half of sombreros or siesta.

:sombreros (p6) Found by Dave Buckingham in 1972. If the two halves are moved three spaces closer to one another then the period drops to 4, and the result is just a less compact form of Achim's p4. Compare also siesta.

...OO........OO...
...O.O......O.O...
.....O......O.....
...O.OO....OO.O...
.OOO..........OOO.
O...O.O....O.O...O
.OOO..........OOO.
...O.OO....OO.O...
.....O......O.....
...O.O......O.O...
...OO........OO...

:soup A random initial pattern, often assumed to cover the whole Life universe.

:space dust A part of a spaceship or oscillator which looks like a random mix of ON and OFF cells. It is usually very difficult to find a glider synthesis for an object that consists wholly or partly of space dust.

:spacefiller Any pattern that grows at a quadratic rate by filling space with an agar. The first example was found in September 1993 by Hartmut Holzwart, following a suggestion by Alan Hensel. The diagram below shows a smaller spacefiller found by Tim Coe. See also Max. Spacefillers can be considered as breeders (more precisely, MMS breeders), but they are very different from ordinary breeders. The word "spacefiller" was suggested by Harold McIntosh and soon became the accepted term.

..................O........
.................OOO.......
............OOO....OO......
...........O..OOO..O.OO....
..........O...O.O..O.O.....
..........O....O.O.O.O.OO..
............O....O.O...OO..
OOOO.....O.O....O...O.OOO..
O...OO.O.OOO.OO.........OO.
O.....OO.....O.............
.O..OO.O..O..O.OO..........
.......O.O.O.O.O.O.....OOOO
.O..OO.O..O..O..OO.O.OO...O
O.....OO...O.O.O...OO.....O
O...OO.O.OO..O..O..O.OO..O.
OOOO.....O.O.O.O.O.O.......
..........OO.O..O..O.OO..O.
.............O.....OO.....O
.OO.........OO.OOO.O.OO...O
..OOO.O...O....O.O.....OOOO
..OO...O.O....O............
..OO.O.O.O.O....O..........
.....O.O..O.O...O..........
....OO.O..OOO..O...........
......OO....OOO............
.......OOO.................
........O..................

:space rake The following p20 forwards glider rake, which was the first known rake. It consists of an ecologist with a LWSS added to turn the dying debris into gliders.

...........OO.....OOOO
.........OO.OO...O...O
.........OOOO........O
..........OO.....O..O.
......................
........O.............
.......OO........OO...
......O.........O..O..
.......OOOOO....O..O..
........OOOO...OO.OO..
...........O....OO....
......................
......................
......................
..................OOOO
O..O.............O...O
....O................O
O...O............O..O.
.OOOO.................

:spaceship Any finite pattern that reappears (without additions or losses) after a number of generations and displaced by a non-zero amount. By far the most natural spaceships are the glider, LWSS, MWSS and HWSS. For further examples see B29, big glider, brain, Canada goose, Coe ship, Cordership, crane, dart, dragon, ecologist, edge-repair spaceship, Enterprise, flotilla, fly, hammerhead, hivenudger, non-monotonic, Orion, puff suppressor, pushalong, quarter, Schick engine, seal, sidecar, snail, still life tagalong, sparky, swan, turtle, wasp, weekender and x66. See also Caterpillar.

It is known that there exist spaceships travelling in all rational directions and at arbitrarily slow speeds (see universal constructor). Before 1989, however, the only known examples travelled at c/4 diagonally (gliders) or c/2 orthogonally (everything else). In 1989 Dean Hickerson started to use automated searches to look for new spaceships, and had considerable success. Other people have continued these searches using tools such as lifesrc and gfind, and as a result we now have a great variety of spaceships travelling at twelve different velocities. The following table details the discovery of spaceships with new velocities.


-----------------------------------------------------
Speed   Direction    Discoverer                Date
-----------------------------------------------------
c/4     diagonal     Richard Guy                 1970
c/2     orthogonal   John Conway                 1970
c/3     orthogonal   Dean Hickerson          Aug 1989
c/4     orthogonal   Dean Hickerson          Dec 1989
c/12    diagonal     Dean Hickerson          Apr 1991
2c/5    orthogonal   Dean Hickerson          Jul 1991
c/5     orthogonal   Tim Coe                 Jan 1996
2c/7    orthogonal   David Eppstein          Jan 2000
c/6     orthogonal   Paul Tooke              Apr 2000
c/5     diagonal     Jason Summers           Nov 2000
17c/45  orthogonal   Gabriel Nivasch et al.  Dec 2004
c/6     diagonal     Nicolay Beluchenko      Sep 2005
-----------------------------------------------------

A period p spaceship that displaces itself (m,n) during its period, where m>=n, is said to be of type (m,n)/p. It was proved by Conway in 1970 that p>=2m+2n. (This follows immediately from the easily-proved fact that a pattern cannot advance diagonally at a rate greater than one half diagonal step every other generation.)

The following diagram shows one of only two known c/5 diagonal spaceships. It was found by Jason Summers in January 2005.

..........OO..........
.........O..O.........
........OO............
.........O.OO.........
..........O.OOO.......
..........OO.OOO......
............O....OO...
............OOO....OO.
..O.........O.O.......
.OOO........O..O......
O...OO................
O..O.O.......OO.O..O..
.O.OO.OOOO...O...OOOO.
....OO.O...OO.......O.
....OO.OO..O.........O
.....O...O........O.OO
...........O.......O..
......O.....O......O..
......O.....O..O......
.......O...OO...OO....
.......O....OO.O......
..............OO......

:Spaceships in Conway's Life A series of articles posted by David Bell to the newsgroup comp.theory.cell-automata during the period August-October 1992 that described many of the new spaceships found by himself, Dean Hickerson and Hartmut Holzwart. Bell produced an addendum covering more recent developments in 1996.

:spark A pattern that dies. The term is typically used to describe a collection of cells periodically thrown off by an oscillator or spaceship, but other dying patterns, particularly those consisting or only one or two cells (such as produced by certain glider collisions, for example), are also described as sparks. For examples of small sparks see unix and HWSS. For an example of a much larger spark see Schick engine.

:spark coil (p2) Found in 1971.

OO....OO
O.O..O.O
..O..O..
O.O..O.O
OO....OO

:sparker An oscillator or spaceship that produces sparks. These can be used to perturb other patterns without being themselves affected.

:sparky A certain c/4 tagalong, shown here attached to the back of a spaceship.

..........O....................
..........O...............OO...
......OO.O.OOO..........OO...O.
O.OO.OO.OO..O.O...OO.OOOO......
O...OO..O.OO..OOO..O.OO..OO...O
O.OO....OOO.O.OOO......OO..O...
........OO.O...............O..O
O.OO....OOO.O.OOO......OO..O...
O...OO..O.OO..OOO..O.OO..OO...O
O.OO.OO.OO..O.O...OO.OOOO......
......OO.O.OOO..........OO...O.
..........O...............OO...
..........O....................

:sparse Life This refers to the study of the evolution of a Life universe which starts off as a random soup of extremely low density. Such a universe is dominated at an early stage by blocks and blinkers (often referred to collectively as blonks) in a ratio of about 2:1. Much later it will be dominated by simple infinite growth patterns (presumably mostly switch engines). The long-term fate of a sparse Life universe is less certain. It may possibly become dominated by self-reproducing patterns (see universal constructor), but it is not at all clear that there is any mechanism for these to deal with the all junk produced by switch engines.

:speed of light A speed of one cell per generation, the greatest speed at which any effect can propagate.

:S-pentomino Conway's name for the following pentomino, which rapidly dies.

..OO
OOO.

:spider (c/5 orthogonally, p5) This is the smallest known c/5 spaceship, and was found by David Bell in April 1997. Its side sparks have proved very useful in constructing c/5 puffers, including rakes. See also pre-pulsar.

......O...OOO.....OOO...O......
...OO.OOOOO.OO...OO.OOOOO.OO...
.O.OO.O.....O.O.O.O.....O.OO.O.
O...O.O...OOOOO.OOOOO...O.O...O
....OOO.....OO...OO.....OOO....
.O..O.OOO.............OOO.O..O.
...O.......................O...

:spiral (p1) Found by Robert Wainwright in 1971.

OO....O
.O..OOO
.O.O...
..O.O..
...O.O.
OOO..O.
O....OO

:SPPS (c/5 orthogonally, p30) The symmetric PPS. The original PPS found by David Bell in May 1998. Compare APPS.

:squaredance The p2 agar formed by tiling the plane with the following pattern. Found by Don Woods in 1971.

OO......
....OO..
..O....O
..O....O
....OO..
OO......
...O..O.
...O..O.

:squirter = pipsquirter

:S-spiral = big S

:stable A pattern is said to be stable if it is a parent of itself. See still life.

:stairstep hexomino (stabilizes at time 63) The following predecessor of the blockade.

..OO
.OO.
OO..

:stamp collection A collection of oscillators (or perhaps other Life objects) in a single diagram, displaying the exhibits much like stamps in a stamp album. The classic examples are by Dean Hickerson (see http://www.radicaleye.com/DRH/stamps.html).

:standard spaceship A glider, LWSS, MWSS or HWSS. These have all been known since 1970.

:star (p3) Found by Hartmut Holzwart, February 1993.

.....O.....
....OOO....
..OOO.OOO..
..O.....O..
.OO.....OO.
OO.......OO
.OO.....OO.
..O.....O..
..OOO.OOO..
....OOO....
.....O.....

:star gate A device by Dieter Leithner (October 1996) for transporting a LWSS faster than the speed of light. The key reaction is the Fast Forward Force Field.

:stator The cells of an oscillator that are always on. Compare rotor. (The stator is sometimes taken to include also some of those cells which are always off.) The stator is divided into the bushing and the casing.

By analogy, the cells of an eater that remain on even when the eater is eating are considered to constitute the stator of the eater. This is not necessarily well-defined, because the eater may have more than one eating action.

:step Another term for a generation. This term is particularly used in describing conduits. For example, a 64-step conduit is one through which the active object takes 64 generations to pass.

:stillater (p3) Found by Robert Wainwright, September 1985. This is one of only three essentially different p3 oscillators with only three cells in the rotor. The others are 1-2-3 and cuphook.

...O....
..O.O.OO
..O.OO.O
OO......
.O.O.OO.
.O.O..O.
..O..O..
...OO...

:still life Any stable pattern, usually assumed to be finite and nonempty. For the purposes of enumerating still lifes this definition is, however, unsatisfactory because, for example, any pair of blocks would count as a still life, and there would therefore be an infinite number of 8-bit still lifes. For this reason a stricter definition is often used, counting a stable pattern as a single still life only if its islands cannot be divided into two nonempty sets both of which are stable in their own right. Compare pseudo still life.

The requirement that a still life not be decomposable into two separate stable patterns may seem a bit arbitrary, as it does not rule out the possibility that it might be decomposable into more than two. This is shown by the patterns in the following diagram, both found by Gabriel Nivasch in July 2001. On the left is a 32-cell pattern that can be broken down into three stable pieces but not into two. On the right is a 34-cell pattern that can be broken down into four stable pieces but not into two or three. (Note that, as a consequence of the Four-Colour Theorem, four is as high as you need ever go.) It is arguable that patterns like these ought not to be considered as single still lifes.

......OO...........OO.
..O.O..O......OO.O..O.
.O.OO.O.......O.OO.O..
.O....OO...........OO.
OO.OO.........O.OO...O
...OO.OO....OOO.OO.OO.
OO....O....O.......O..
.O.OO.O.....OOO.OO.O..
O..O.O........O.O.O...
OO....................

Still lifes have been enumerated by Conway (4-7 bits), Robert Wainwright (8-10 bits), Dave Buckingham (11-13 bits), Peter Raynham (14 bits) and Mark Niemiec (15-24 bits). The resulting figures are shown below. (These figures shouldn't be affected by the above discussion of the strict definition of "still life", because it is unlikely that there are any doubtful cases with much less than 32 cells.)


-------------
Bits   Number
-------------
  4        2
  5        1
  6        5
  7        4
  8        9
  9       10
 10       25
 11       46
 12      121
 13      240
 14      619
 15     1353
 16     3286
 17     7773
 18    19044
 19    45759
 20   112243
 21   273188
 22   672172
 23  1646147
 24  4051711
-------------

:still life tagalong A tagalong which takes the form of a still life in at least one phase. An example is shown below.

..OO...............
.OO.OO.............
..OOOO.............
...OO..............
...................
...OOOOO...........
..OOOOOOO..........
.OO.OOOOO..........
..OO...............
...................
........O.O.....OO.
......O....O...O..O
......OO.....O.O..O
.O..O..OOOO.O...OO.
O.......OO.........
O...O..............
OOOO...............

:stretcher Any pattern that grows by stretching a wick or agar. See wickstretcher and spacefiller.

:strict volatility A term suggested by Noam Elkies in August 1998 for the proportion of cells involved in a period n oscillator which themselves oscillate with period n. For prime n this is the same as the ordinary volatility.

:super beehive = honeycomb

:superfountain (p4) A p4 sparker which produces a 1-cell spark that is separated from the rest of the oscillator by two clear rows of cells. The first superfountain was found by Noam Elkies in February 1998. In January 2006 Nicolay Beluchenko found the much smaller one shown below. See also fountain.

...........O...........
.......................
.......................
.....O..O.....O..O.....
...OO..O.OOOOO.O..OO...
.....O...........O.....
...O.OO.........OO.O...
.O.O...OOO...OOO...O.O.
OOO.O.............O.OOO
..........O.O..........
....OOO...O.O...OOO....
....O..O...O...O..O....
...OOOO..O.O.O..OOOO...
...OO..OOO.O.OOO..OO...
..O...O...O.O...O...O..
...O..O.O.O.O.O.O..O...
....O.O.OO...OO.O.O....
.....O...........O.....

:superstring An infinite orthogonal row of cells stabilized on one side so that it moves at the speed of light, often leaving debris behind. The first examples were found in 1971 by Edward Fitzgerald and Robert Wainwright. Superstrings were studied extensively by Peter Rott during 1992-1994, and he found examples with many different periods. (But no odd periods. In August 1998 Stephen Silver proved that odd-period superstrings are impossible.)

Sometimes a finite section of a superstring can be made to run between two tracks ("waveguides"). This gives a fuse which can be made as wide as desired. The first example was found by Tony Smithurst and uses tubs. (This is shown below. The superstring itself is p4 with a repeating section of width 9 producing one blinker per period and was one of those discovered in 1971. With the track in place, however, the period is 8. This track can also be used with a number of other superstrings.) Shortly after seeing this example, in March 1997 Peter Rott found another superstring track consisting of boats. At present these are the only two waveguides known. Both are destroyed by the superstring as it moves along - it would be interesting to find one that remains intact.

See titanic toroidal traveler for another example of a superstring.

.OO..........................................................
O..O...O...O...O...O...O...O...O...O...O...O...O...O...O...O.
....O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O
O..O...O...O...O...O...O...O...O...O...O...O...O...O...O...O.
.OOO.........................................................
..OO.........................................................
..OO.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
...O.........................................................
..OO.........................................................
..OO.........................................................
.OOO.........................................................
O..O...O...O...O...O...O...O...O...O...O...O...O...O...O...O.
....O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O.O
O..O...O...O...O...O...O...O...O...O...O...O...O...O...O...O.
.OO..........................................................

:support Those parts of an object which are only present in order to keep the rest of the object (such an engine or an edge spark) working correctly. These can be components of the object, or else accompanying objects used to perturb the object. In many cases there is a wide variation of support possible for an engine. The arms in many puffers are an example of support.

:surprise (p3) Found by Dave Buckingham, November 1972.

...O....OO
...OOO..O.
.OO...O.O.
O..OO.O.OO
.O......O.
OO.O.OO..O
.O.O...OO.
.O..OOO...
OO....O...

:swan (c/4 diagonally, p4) A diagonal spaceship producing some useful sparks. Found by Tim Coe in February 1996.

.O..........OO..........
OOOOO......OO...........
O..OO........O.......OO.
..OO.O.....OO......OOO.O
...........OO...O.OO....
.....O.O......OO........
..........OOO.O....O....
.......OOO...O....O.....
........O.......O.......
........O......O........
........................
...........O............

:switch engine The following pattern, which in itself is unstable, but which can be used to make c/12 diagonal puffers and spaceships.

.O.O..
O.....
.O..O.
...OOO

The switch engine was discovered by Charles Corderman in 1971. He also found the two basic types of stabilized switch engine: a p288 block-laying type (the more common of the two) and p384 glider-producing type. These two puffers are the most natural infinite growth patterns in Life, being the only ones ever seen to occur from random starting patterns.

Patterns giving rise to block-laying switch engines can be seen under infinite growth, and one giving rise to a glider-producing switch engine is shown under time bomb. See also Cordership and ark.

:synthesis = glider synthesis


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_h.htm0000644000175000017500000012241712536111364016403 00000000000000 Life Lexicon (H)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:half bakery See bi-loaf.

:half fleet = ship-tie

:hammer To hammer a LWSS, MWSS or HWSS is to smash things into the rear end of it in order to transform it into a different type of spaceship. A hammer is the object used to do the hammering. In the following example by Dieter Leithner a LWSS is hammered by two more LWSS to make it into a MWSS.

O..O................
....O...OO..........
O...O..OOO.....OOOO.
.OOOO..OO.O....O...O
........OOO....O....
.........O......O..O

:hammerhead A certain front end for c/2 spaceships. The central part of the hammerhead pattern is supported between two MWSS. The picture below shows a small example of a spaceship with a hammerhead front end (the front 9 columns).

................O..
.OO...........O...O
OO.OOO.......O.....
.OOOOO.......O....O
..OOOOO.....O.OOOO.
......OOO.O.OO.....
......OOO....O.....
......OOO.OOO......
..........OO.......
..........OO.......
......OOO.OOO......
......OOO....O.....
......OOO.O.OO.....
..OOOOO.....O.OOOO.
.OOOOO.......O....O
OO.OOO.......O.....
.OO...........O...O
................O..

:handshake An old MIT name for lumps of muck, from the following form (2 generations on from the stairstep hexomino):

..OO.
.O.OO
OO.O.
.OO..

:harbor (p5) Found by Dave Buckingham in September 1978. The name is by Dean Hickerson.

.....OO...OO.....
.....O.O.O.O.....
......O...O......
.................
.....OO...OO.....
OO..O.O...O.O..OO
O.O.OO.....OO.O.O
.O.............O.
.................
.O.............O.
O.O.OO.....OO.O.O
OO..O.O...O.O..OO
.....OO...OO.....
.................
......O...O......
.....O.O.O.O.....
.....OO...OO.....

:harvester (c p4 fuse) Found by David Poyner, this was the first published example of a fuse. The name refers to the fact the it produces debris in the form of blocks which contain the same number of cells as the fuse has burnt up.

................OO
...............O.O
..............O...
.............O....
............O.....
...........O......
..........O.......
.........O........
........O.........
.......O..........
......O...........
.....O............
OOOOO.............
OOOO..............
O.OO..............

:hashlife A Life algorithm by Bill Gosper that is designed to take advantage of the considerable amount of repetitive behaviour in many large patterns of interest. This algorithm is described by Gosper in his paper listed in the bibliography at the end of this lexicon. Roughly speaking, the idea is to store subpatterns in a hash table so that the results of their evolution do not need to be recomputed if they arise again at some other place or time in the evolution of the full pattern. This does, however, mean that complex patterns can require substantial amounts of memory.

Hashlife provides a means of evolving repetitive patterns millions (or even billions or trillions) of generations further than normal Life algorithms can manage in a reasonable amount of time. It is not, however, suitable for showing a continuous display of the evolution of a pattern, because it works asynchronously - at any given moment it will usually have evolved different parts of the pattern through different numbers of generations.

:hassle See hassler.

:hassler An oscillator that works by hassling (repeatedly moving or changing) some object. For some examples, see Jolson, baker's dozen, toad-flipper, toad-sucker and traffic circle.

:hat (p1) Found in 1971. See also twinhat and sesquihat.

..O..
.O.O.
.O.O.
OO.OO

:heat For an oscillator or spaceship, the average number of cells which change state in each generation. For example, the heat of a glider is 4, because 2 cells are born and 2 die every generation.

For a period n oscillator with an r-cell rotor the heat is at least 2r/n and no more than r(1-(n mod 2)/n). For n=2 and n=3 these bounds are equal.

:heavyweight emulator = HW emulator

:heavyweight spaceship = HWSS

:heavyweight volcano = HW volcano

:hebdarole (p7) Found by Noam Elkies, November 1997. Compare fumarole. The smaller version shown below was found soon after by Alan Hensel using a component found by Dave Buckingham in June 1977. The top tens rows can be stabilized by their mirror image (giving an inductor) and this was the original form found by Elkies.

...........OO...........
....OO...O....O...OO....
.O..O..O.O....O.O..O..O.
O.O.O.OO.O....O.OO.O.O.O
.O..O..O.O.OO.O.O..O..O.
....OO....O..O....OO....
...........OO...........
.......O..O..O..O.......
......O.OO....OO.O......
.......O........O.......
........................
...OO..............OO...
...O..OOOO....OOOO..O...
....O.O.O.O..O.O.O.O....
...OO.O...OOOO...O.OO...
.......OO......OO.......
.........OO..OO.........
.........O..O.O.........
..........OO............

:hectic (p30) Found by Robert Wainwright in September 1984.

......................OO...............
......................OO...............
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.........O..........OO...OO............
.......O.O............OOO..............
......O.O............O...O.............
OO...O..O.............O.O..............
OO....O.O..............O...............
.......O.O......O.O....................
.........O......OO.....................
.................O...O.................
.....................OO......O.........
....................O.O......O.O.......
...............O..............O.O....OO
..............O.O.............O..O...OO
.............O...O............O.O......
..............OOO............O.O.......
............OO...OO..........O.........
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
.......................................
...............OO......................
...............OO......................

:Heisenburp device A pattern which can detect the passage of a glider without affecting the glider's path or timing. The first such device was constructed by David Bell in December 1992. The term is due to Bill Gosper.

The following is an example of the kind of reaction used at the heart of a Heisenburp device. The glider at bottom right alters the reaction of the other two gliders without itself being affected in any way.

O.....O....
.OO...O.O..
OO....OO...
...........
...........
...........
.........OO
........O.O
..........O

:helix A convoy of standard spaceships used in a Caterpillar to move some piece of debris at the speed of the Caterpillar. The following diagram illustrates the idea.

...............................O.............
.................O............OOO............
................OOO....OOO....O.OO...........
.........OOO....O.OO...O..O....OOO..OOO......
.........O..O....OOO...O.......OO...O........
.........O.......OO....O...O.........O.......
.........O...O.........O...O.................
OOO......O...O.........O.....................
O..O.....O..............O.O..................
O.........O.O................................
O............................................
.O.O.........................................
.............................................
.............................................
..........O..................................
.........OOO.................................
.........O.OO................................
..........OOO................................
..........OO.................................
.............................................
.............................................
...............OOO...........................
...............O..O....O.....OOO.............
...............O......OOO....O..O....O.......
...............O.....OO.O....O......OOO......
....OOO.........O.O..OOO.....O.....OO.O......
....O..O.............OOO......O.O..OOO.......
....O................OOO...........OOO.......
....O.................OO...........OOO.......
.....O.O............................OO.......
...........................................O.
..........................................OOO
.........................................OO.O
.........................................OOO.
..........................................OO.
.............................................
.............................................
.............................................
.............................................
.............................................
.............................................
.........................................O...
..............................OOO.......OOO..
................OOO.....O....O..O......OO.O..
..........O....O..O....OOO......O......OOO...
.........OOO......O....O.OO.....O......OOO...
.........O.OO.....O.....OOO..O.O........OO...
..........OOO..O.O......OOO..................
.O........OOO...........OOO..................
OOO.......OOO...........OO...................
O.OO......OO.................................
.OOO......................................O..
.OO......................................OOO.
........................................OO.O.
........................................OOO..
.........................................OO..
.........OOO.................................
........O..O.................................
...........O.................................
...........O.................................
........O.O..................................

:heptaplet Any 7-cell polyplet.

:heptapole (p2) The barberpole of length 7.

OO........
O.O.......
..........
..O.O.....
..........
....O.O...
..........
......O.O.
.........O
........OO

:heptomino Any 7-cell polyomino. There are 108 such objects. Those with names in common use are the B-heptomino, the Herschel and the pi-heptomino.

:Herschel (stabilizes at time 128) The following pattern which occurs at generation 20 of the B-heptomino.

O..
OOO
O.O
..O

:Herschel conduit A conduit that moves a Herschel from one place to another. See also Herschel loop.

Sixteen simple stable Herschel conduits are currently known, having been discovered from 1995 onwards by Dave Buckingham (DJB) and Paul Callahan (PBC). (Of course, the number depends on what is meant by "simple".) These are shown in the following table. In this table "steps" is the number of steps, "m" tells how the Herschel is moved (R = turned right, L = turned left, B = turned back, F = unturned, f = flipped), and "dx" and "dy" give the displacement of the centre cell of the Herschel (assumed to start in the orientation shown above).


------------------------------------
steps  m     dx   dy     discovery
------------------------------------
  64   R    -11    9   DJB, Sep 1995
  77   Ff   -25   -8   DJB, Aug 1996
 112   L    -12  -33   DJB, Jul 1996
 116   F    -32    1   PBC, Feb 1997
 117   F    -40   -6   DJB, Jul 1996
 119   Ff   -20   14   DJB, Sep 1996
 125   Bf     9  -17   PBC, Nov 1998
 153   Ff   -48   -4   PBC, Feb 1997
 156   L    -17  -41   DJB, Aug 1996
 158   Ff   -27   -5   DJB, Jul 1996
 166   F    -49    3   PBC, May 1997
 176   Ff   -45    0   PBC, Oct 1997
 190   R    -24   16   DJB, Jul 1996
 200   Lf   -17  -40   PBC, Jun 1997
 202   Rf    -7   32   DJB, May 1997
 222   Bf     6  -16   PBC, Oct 1998
------------------------------------

See also Herschel transceiver.

:Herschel loop A cyclic Herschel track. Although no loop of length less than 256 generations has been constructed it is possible to make oscillators of smaller periods by putting more than one Herschel in the track. In this way oscillators, and in most cases guns, of all periods from 54 onwards can now be constructed (although the p55 case is a bit strange, shooting itself with gliders in order to stabilize itself). See also emu and omniperiodic.

:Herschel receiver A pattern found by Paul Callahan in 1996, as part of the first stable glider reflector. Used as a receiver, it converts two parallel input gliders (with path separations of 2, 5, or 6) to an R-pentomino, which is then converted to a Herschel by one of two known mechanisms (the first of which was found by Dave Buckingham way back in 1972, and the second by Stephen Silver in October 1997). The version using Buckingham's R-to-Herschel converter is shown below.

...............................................O.O
......................................OO.......OO.
......................................OO........O.
...OO.............................................
...O..............................................
....O.............................................
...OO.............................................
............OO....................................
...........O.O....................................
............O..............................O......
......................................OO...O.O....
.....................................O..O..OO.....
OO....................................OO..........
OO.............................OO.................
...............................OO.................
..................................................
..................................................
..................................................
..................................................
..................................................
..................................................
............................................OO....
............................................OO....
........................................OO........
........................................O.O.......
..........................................O.......
..........................................OO......
.............................OO...................
.............................OO...................
..................................................
..................................................
...........................OO.....................
...........................OO.....................

:Herschel track A track for Herschels. See also B track.

:Herschel transceiver An adjustable Herschel conduit made up of a Herschel transmitter and a Herschel receiver. The intermediate stage consists of two gliders on parallel tracks, so the transmitter and receiver can be separated by any required distance. The conduit may be stable, or may contain low-period oscillators.

:Herschel transmitter Any Herschel-to-glider converter that produces two gliders on parallel tracks which can be used as input to a Herschel receiver. If the gliders are far enough apart, a suitably oriented mirror image of the receiver will also work: the first glider triggers the receiver and the second glider deletes the extra beehive.

The following diagram shows a stable Herschel transmitter found by Paul Callahan in May 1997:

......OO...........
.....O.O...........
...OOO.............
..O...O......O.....
..OO.OO......OOO...
.............O.O...
...............O...
...................
...................
OO.O...............
O.OO...............
...................
...................
...................
...............OO..
...............O...
................OOO
..................O
Examples of small reversible p6 and p7 transmitters are also known.

:Hertz oscillator (p8) Compare negentropy, and also cauldron. Found by Conway's group in 1970.

...OO.O....
...O.OO....
...........
....OOO....
...O.O.O.OO
...O...O.OO
OO.O...O...
OO.O...O...
....OOO....
...........
....OO.O...
....O.OO...

:hexadecimal = beehive and dock

:hexaplet Any 6-cell polyplet.

:hexapole (p2) The barberpole of length 6.

OO.......
O.O......
.........
..O.O....
.........
....O.O..
.........
......O.O
.......OO

:hexomino Any 6-cell polyomino. There are 35 such objects. For some examples see century, stairstep hexomino, table, toad and Z-hexomino.

:H-heptomino Name given by Conway to the following heptomino. After one generation this is the same as the I-heptomino.

OO..
.O..
.OOO
..O.

:hive = beehive

:hivenudger (c/2 orthogonally, p4) A spaceship found by Hartmut Holzwart in July 1992. (The name is due to Bill Gosper.) It consists of a pre-beehive escorted by four LWSS. In fact any LWSS can be replaced by a MWSS or a HWSS, so that there are 45 different single-hive hivenudgers.

OOOO.....O..O
O...O...O....
O.......O...O
.O..O...OOOO.
.............
.....OO......
.....OO......
.....OO......
.............
.O..O...OOOO.
O.......O...O
O...O...O....
OOOO.....O..O
Wider versions can be made by stabilizing the front of the extended "pre-beehive", as in the line puffer shown below.
.........O.O..................
........O..O..................
.......OO.....................
......O...O...................
.....OOO.O....................
..OO..........................
.O...OOOOO.......OOOO.....O..O
O...O............O...O...O....
O.....OO.........O.......O...O
OOO...OOOO........O..O...OOOO.
.O.......O....................
.OO...................OO......
.O.O..................OO......
.OO..OO.O........O.O..OO......
..O.OOO.O...O.OOOO.O..OO......
.........OO.O.OO..O...OO...OOO
....OOOOOO.OO...OOOO..OO...OOO
.....O....OOO......O..OO...OOO
......OO.....OO..OO...OO......
.......O..O.....OOOO..OO......
........O.O.OO.....O..OO......
......................OO......
..............................
..................O..O...OOOO.
.................O.......O...O
.................O...O...O....
.................OOOO.....O..O

:honeycomb (p1)

..OO..
.O..O.
O.OO.O
.O..O.
..OO..

:honey farm (p1) A common formation of four beehives.

......O......
.....O.O.....
.....O.O.....
......O......
.............
.OO.......OO.
O..O.....O..O
.OO.......OO.
.............
......O......
.....O.O.....
.....O.O.....
......O......

:hook Another term for a bookend. It is also used for other hook-shaped things, such as occur in the eater1 and the hook with tail, for example.

:hook with tail (p1) For a long time this was the smallest still life without a well-established name. It is now a vital component of the smallest known HWSS gun, where it acts as a rock.

O.O..
OO.O.
...O.
...OO

:houndstooth agar The p2 agar that results from tiling the plane with the following pattern.

.OOO
.O..
..O.
OOO.

:house The following induction coil. It is generation 3 of the pi-heptomino. See spark coil and dead spark coil.

.OOO.
O...O
OO.OO

:hustler (p3) Found by Robert Wainwright, June 1971.

.....OO....
.....OO....
...........
...OOOO....
O.O....O...
OO.O...O...
...O...O.OO
...O....O.O
....OOOO...
...........
....OO.....
....OO.....

:hustler II (p4)

....O...........
....OOO.........
.......O........
......O..OO.....
O.OO.O.OO..O....
OO.O.O.....O....
.....O....O.....
....O.....O.O.OO
....O..OO.O.OO.O
.....OO..O......
........O.......
.........OOO....
...........O....

:HW emulator (p4) Found by Robert Wainwright in June 1980. See also emulator.

.......OO.......
..OO.O....O.OO..
..O..........O..
...OO......OO...
OOO..OOOOOO..OOO
O..O........O..O
.OO..........OO.

:HWSS (c/2 orthogonally, p4) A heavyweight spaceship, the fourth most common spaceship. Found by Conway in 1970. See also LWSS and MWSS.

...OO..
.O....O
O......
O.....O
OOOOOO.

:HWSS emulator = HW emulator

:HW volcano (p5) A p5 domino sparker, found by Dean Hickerson in February 1995. There are at least two known forms for this, one of which is shown below.

.........O..........................
........O.O.........................
......OOO.O.........................
.....O....OO.O......................
.....O.OO...OO......OO..............
....OO.O.OO.........O.O.............
.........O.OOOOO......O..O.OO.......
..O.OO.OO.O.....O....OO.O.OO.O......
.....OO.....OOOO........O....O......
O...O.O..O...O.O....OO.O.OOOO.OO....
O...O.O..OO.O.OO.OO....O.O....O.O...
.....OO...OOO.OO.O.OOO.O..OOO...O...
..O.OO.OO.OO.............O.O..O.O.OO
...........O......O.O.O.O..OO.O.O.O.
....OO.O.O.OO......OO.O.O.O...O.O.O.
.....O.OO.O..O.......O.OO..OOOO.OO..
.....O....O.O........O...OO.........
....OO....OO........OO...O..O.......
...........................OO.......

:hybrid grey ship A grey ship containing more than one type of region of density 1/2, usually a combination of a with-the-grain grey ship and an against-the-grain grey ship.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_v.htm0000644000175000017500000001134312536111364016414 00000000000000 Life Lexicon (V)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:vacuum Empty space. That is, space containing only dead cells.

:Venetian blinds The p2 agar obtained by using the pattern O..O to tile the plane.

:very long = long long

:very long house The following induction coil.

.OOOOO.
O..O..O
OO...OO

:volatility The volatility of an oscillator is the size (in cells) of its rotor divided by the sum of the sizes of its rotor and its stator. In other words, it is the proportion of cells involved in the oscillator which actually oscillate. For many periods there are known oscillators with volatility 1, see for example Achim's p16, figure-8, Kok's galaxy, mazing, pentadecathlon, phoenix, relay, smiley and tumbler. The smallest period for which the existence of such statorless oscillators is undecided is 3, although Dean Hickerson showed in 1994 that there are p3 oscillators with volatility arbitrarily close to 1 (as is the case for all but finitely many periods, because of the possibility of feeding the gliders from a true period n gun into an eater).

The term "volatility" is due to Robert Wainwright. See also strict volatility.

:volcano Any of a number of p5 oscillators which produce sparks. See lightweight volcano, middleweight volcano and heavyweight volcano.

:V-pentomino Conway's name for the following pentomino, a loaf predecessor.

O..
O..
OOO

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_k.htm0000644000175000017500000001270012536111364016377 00000000000000 Life Lexicon (K)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:keys See short keys, bent keys and odd keys.

:kickback reaction The following collision of two gliders whose product is a single glider travelling in the opposite direction to one of the original gliders. This is important in the proof of the existence of a universal constructor, and in Bill Gosper's total aperiodic, as well as a number of other constructions.

.....O..
......OO
.OO..OO.
O.O.....
..O.....

:kidney A Gosperism for century. See also diuresis.

:killer toads A pair of toads acting together so that they can eat things. Here, for example, are some killer toads eating a HWSS. Similarly they can eat a MWSS (but not a LWSS). For another example see twirling T-tetsons II. See also candlefrobra.

..OO.......OOO
O....O....OOO.
......O.......
O.....O.......
.OOOOOO.......
..........OOO.
...........OOO

:Klein bottle As an alternative to a torus, it's possible to make a finite Life universe in the form of a Klein bottle. The simplest way to do this is to use an m x n rectangle with the top edge joined to the bottom edge (as for a torus) and the left edge twisted and joined to the right.

:knightship Any spaceship of type (2m,m)/n. Such spaceships do exist (see universal constructor), but no concrete example is known. A knightship must be asymmetric and its period must be at least 6, which makes searching for them using programs like lifesrc very difficult.

By analogy with the corresponding fairy chess pieces, spaceships of types (3m,m)/n, (3m,2m)/n and (4m,m)/n would presumably be called camelships, zebraships and giraffeships, respectively. But no examples of these are known either, and they are even more difficult to search for.

:Kok's galaxy (p8) Found by Jan Kok in 1971. See converter for a use of this sparker.

OOOOOO.OO
OOOOOO.OO
.......OO
OO.....OO
OO.....OO
OO.....OO
OO.......
OO.OOOOOO
OO.OOOOOO

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_p.htm0000644000175000017500000016062512536111364016416 00000000000000 Life Lexicon (P)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:p = period

:p30 shuttle = queen bee shuttle

:p46 shuttle = twin bees shuttle

:p54 shuttle (p54) A surprising variant of the twin bees shuttle found by Dave Buckingham in 1973. See also centinal.

OO.........................OO
.O.........................O.
.O.O.......O.............O.O.
..OO.....O..O.....O......OO..
............O.....OO.........
........O..........OO........
........O...OO....OO.........
.........OOOOO...............
.............................
.........OOOOO...............
........O...OO....OO.........
........O..........OO........
............O.....OO.........
..OO.....O..O.....O......OO..
.O.O.......O.............O.O.
.O.........................O.
OO.........................OO

:p6 shuttle (p6) The following oscillator found by Nicolay Beluchenko in February 2004.

O.............
OOO...........
...O..........
..OO..........
..............
......O.......
.....OOOO.....
......O..O....
.......OOO....
..............
..........OO..
..........O...
...........OOO
.............O
This is extensible in more than one way:
O........................
OOO......................
...O.....................
..OO.....................
.........................
......O..................
.....OOOO................
......O..O...............
.......OOO...............
.........................
..........OOO............
..........O..O...........
...........OOOO..........
.............O...........
.........................
.................O.......
................OOO......
.................O.O.....
.................O.O.....
..................OO.....
.....................OO..
.....................O.O.
.......................O.
.......................OO

:pair of bookends = bookends

:pair of tables = table on table

:paperclip (p1)

..OO.
.O..O
.O.OO
OO.O.
O..O.
.OO..

:parallel grey ship = with-the-grain grey ship

:parent A pattern is said to be a parent of the pattern it gives rise to after one generation. Some patterns have infinitely many parents, but other have none at all (see Garden of Eden).

:parent cells The three cells that cause a new cell to be born.

:PD = pentadecathlon

:pedestle (p5)

.....O.....
....O.O....
.O..OO.....
.OOO.......
.....OOO...
...OO...O..
..O....O..O
.O.O.O.O.OO
.O.O...O.O.
OO.O.O.O.O.
O..O....O..
..O...OO...
...OOO.....
.......OOO.
.....OO..O.
....O.O....
.....O.....

:penny lane (p4) Found by Dave Buckingham, 1972.

...OO.....OO...
...O.......O...
OO.O.......O.OO
OO.O.OOOOO.O.OO
....O..O..O....
.....OOOOO.....
...............
.......O.......
......O.O......
.......O.......

:pentadecathlon (p15) Found in 1970 by Conway while tracking the history of short rows of cells, 10 cells giving this object, which is the most natural oscillator of period greater than 3. In fact it is the fifth or sixth most common oscillator overall, being about as frequent as the clock, but much less frequent than the blinker, toad, beacon or pulsar.

..O....O..
OO.OOOO.OO
..O....O..
The pentadecathlon is the only known oscillator which is a polyomino in more than one phase.

:pentant (p5) Found by Dave Buckingham, July 1976.

OO........
.O........
.O.O......
..OO....OO
.........O
.....OOOO.
.....O....
..O...OOO.
..OOOO..O.
.....O....
....O.....
....OO....

:pentaplet Any 5-cell polyplet.

:pentapole (p2) The barberpole of length 5.

OO......
O.O.....
........
..O.O...
........
....O.O.
.......O
......OO

:pentoad (p5) Found by Bill Gosper, June 1977. This is extensible: if an eater is moved back four spaces then another Z-hexomino can can be inserted. (This extensibility was discovered by Scott Kim.)

...........OO
...........O.
.........O.O.
.........OO..
.....OO......
......O......
......O......
......OO.....
..OO.........
.O.O.........
.O...........
OO...........

:pentomino Any 5-cell polyomino. There are 12 such patterns, and Conway assigned them all letters in the range O to Z, loosely based on their shapes. Only in the case of the R-pentomino has Conway's label remained in common use, but all of them can nonetheless be found in this lexicon.

:period The smallest number of generations it takes for an oscillator or spaceship to reappear in its original form. The term can also be used for a puffer, wick, fuse, superstring, stream of spaceships, factory or gun. In the last case there is a distinction between true period and pseudo period. There is also a somewhat different concept of period for wicktrailers.

:perpendicular grey ship = against-the-grain grey ship

:perturb To change the fate of an object by reacting it with other objects. Typically, the other objects are sparks from spaceships or oscillators, or are eaters or impacting spaceships. Perturbations are typically done to turn a dirty reaction into a clean one, or to change the products of a reaction. In many desirable cases the perturbing objects are not destroyed by the reaction, or else are easily replenished.

:perturbation See perturb.

:phase A representative generation of a periodic object such as an oscillator or spaceship. The number of phases is equal to the period of the object. The phases of an object usually repeat in the same cyclic sequence forever, although some perturbations can cause a phase change.

:phase change A perturbation of a periodic object which causes the object to skip ahead by one or more phases. If the perturbation is repeated indefinitely, this can effectively change the period of the object. An example of this, found by Dean Hickerson in November 1998, is shown below. In this example, the period of the oscillator would be 7 if the mold were removed, but the period is increased to 8 because of the repeated phase changes caused by the mold's spark.

..........O....
.........O.OO..
..OO.........O.
..O......O..O.O
.......O...O..O
OOOOOO.O....OO.
O..............
.OO.OO...OO....
..O.O....O.O...
..O.O......O...
...O.......OO..
The following pattern demonstrates a p4 c/2 spaceship found by Jason Summers, in which the phase is changed as it deletes a forward glider. This phase change allows the spaceship to be used to delete a glider wave produced by a rake whose period is 2 (mod 4).
........O...........................
.......OOO.OO.......................
......OO...O.OO.....................
.....OO..O.....O....................
......O.....O...O.OOO...............
.....OO.....O...O.O..O..............
...OO.O.OO....O.O.O...O.............
....O.O..OO...........O.............
.OO.O..O..O.........O...............
.OO.O.....OO.........O.OOO..........
.O.O.............OOO.O.O.OO.........
OO.OO...........OO.O..O.O.O.........
..............OO.O...OOO..OO.....OO.
.............O...O......O........O.O
............O.....O..OO.O.OO.....O..
...........O..O.O......O.O..........
...........O.....OO....OOO..........
.............O..........O...........
..........O.O...........O...........
.........OO.O.OOO...................
........O.O.O...O...................
.......OO.O.........................
......O...O.....OO..................
....................................
......OO.OO.........................

Phase changing reactions have enabled the construction of spaceships having periods that were otherwise unknown, and also allow the construction of period-doubling and period-tripling convoys to easily produce very high period rakes.

See also blinker puffer.

:phi The following common spark. The name comes from the shape in the generation after the one shown here.

.OOO.
O...O
O...O
.OOO.

:phoenix Any pattern all of whose cells die in every generation, but which never dies as a whole. A spaceship cannot be a phoenix, and in fact every finite phoenix eventually evolves into an oscillator. The following 12-cell oscillator (found by the MIT group in December 1971) is the smallest known phoenix, and is sometimes called simply "the phoenix".

....O...
..O.O...
......O.
OO......
......OO
.O......
...O.O..
...O....
Every known phoenix oscillator has period 2. In January 2000, Stephen Silver showed that a period 3 oscillator cannot be a phoenix. The situation for higher periods is unknown.

:pi = pi-heptomino

:pi-heptomino (stabilizes at time 173) A common pattern. The name is also applied to later generations of this object - in a pi ship, for example, the pi-heptomino itself never arises.

OOO
O.O
O.O

:pincers = great on-off

:pinwheel (p4) Found by Simon Norton, April 1970. Compare clock II.

......OO....
......OO....
............
....OOOO....
OO.O....O...
OO.O..O.O...
...O...OO.OO
...O.O..O.OO
....OOOO....
............
....OO......
....OO......

:pi orbital (p168) Found by Noam Elkies, August 1995. In this oscillator, a pi-heptomino is turned ninety degrees every 42 generations. A second pi can be inserted to reduce the period to 84.

..............OO....OO....OO...............................
.............O..O.O....O.O..O..............................
.............OOO..........OOO..............................
................OO......OO.................................
...............O..OOOOOO..O................................
...............OO........OO................................
...........................................................
........O.............................OO..........O........
.......O...OOO......O.........O.......OO.........O.O.......
........O.OOOOO..........OOO...O...........................
............O...O.....O.OOOOO.O..................O.........
............OO....OOO.....O......................OO........
............OO....OOO....OO...................OOOOO........
...................O.....OO...................OO.OO.....OO.
.................................................O......O.O
.....................................................OO.O.O
.....................................................O.O.O.
.......................................................O...
...................................OOO.........O.O...O..O..
.......OO..........................O..O........O..O.....O..
.......OO..............................O.......O.O..O...O..
...................................O..O.............O...O..
...................................OOO..................O..
.....................................................O..O..
................................................O......O...
.............................................OO.OO...O.O.O.
.............................................OOOOO...OO.O.O
.........O......................................OO......O.O
........O.O.....................................O.......OO.
...........................................................
.OO.......O.....................................O.O........
O.O......OO......................................O.........
O.O.OO...OOOOO.............................................
.O.O.O...OO.OO.............................................
...O......O................................................
..O..O.....................................................
..O........................................................
..O...O....................................................
..O...O..O.O......................................OO.......
..O.....O..O......................................OO.......
..O..O...O.O...............................................
...O.......................................................
.O.O.O.....................................................
O.O.OO.....................................................
O.O......O.................................................
.OO.....OO.OO...................OO.....O...................
........OOOOO...................OO....OOO....OO............
........OO......................O.....OOO....OO............
.........O..................O.OOOOO.O.....O...O............
...........................O...OOO..........OOOOO.O........
.......O.O.........OO.......O.........O......OOO...O.......
........O..........OO.............................O........
...........................................................
................................OO........OO...............
................................O..OOOOOO..O...............
.................................OO......OO................
..............................OOO..........OOO.............
..............................O..O.O....O.O..O.............
...............................OO....OO....OO..............

:pi portraitor (p32) Found by Robert Wainwright in 1984 or 1985. Compare with gourmet and popover.

...........OO...........
......OO.O....O.OO......
......O..........O......
.......OO......OO.......
....OOO..OOOOOO..OOO....
....O..O........O..O....
.OO.O.O..........O.O.OO.
.O.O.O............O.O.O.
...O................O...
.O..O..............O..O.
....O.......OOO....O....
O...O.......O.O....O...O
O...O.......O.O....O...O
....O..............O....
.O..O..............O..O.
...O................O...
.O.O.O............O.O.O.
.OO.O.O..........O.O.OO.
....O..O........O..O....
....OOO..OOOOOO..OOO....
.......OO......OO.......
......O..........O......
......OO.O....O.OO......
...........OO...........

:pipsquirt = pipsquirter

:pipsquirter An oscillator that produces a domino spark that is orientated parallel to the direction from which it is produced (in contrast to domino sparkers like the pentadecathlon and HWSS, which produce domino sparks perpendicular to the direction of production). The following is a small p6 example found by Noam Elkies in November 1997.

.....O.........
.....O.........
...............
...O...O.......
.OOO.O.OOO.....
O...OO....O....
O.OO..OO.O.O...
.O..OO..OO.O...
..OO..OO.O.O.OO
....O..O.O.O.OO
....OOOO.OO....
........O......
......O.O......
......OO.......

:pi ship A growing spaceship in which the back part consists of a pi-heptomino travelling at a speed of 3c/10. The first example was constructed by David Bell. All known pi ships are too large to show here, but the following diagram shows how the pi fuse works.

............O............
...........O.O...........
OO........OO.OO........OO
OO.....................OO

:piston (p2) Found in 1971.

OO.......OO
O.O..O..O.O
..OOOO..O..
O.O..O..O.O
OO.......OO

:pi wave A line of pi-heptominoes stabilizing one another. For example, an infinite line of pi-heptominoes arranged as shown below produces a pi wave that moves at a speed of 3c/10, and leaves no debris.

OOO...............OOO...............OOO...............OOO
O.O...............O.O...............O.O...............O.O
O.O...............O.O...............O.O...............O.O

:pixel = cell

:plet = polyplet

:polyomino A finite collection of orthogonally connected cells. The mathematical study of polyominoes was initiated by Solomon Golomb in 1953. Conway's early investigations of Life and other cellular automata involved tracking the histories of small polyominoes, this being a reasonable way to ascertain the typical behaviour of different cellular automata when the patterns had to be evolved by hand rather than by computer. Polyominoes have no special significance in Life, but their extensive study during the early years lead to a number of important discoveries and has influenced the terminology of Life. (Note on spelling: As with "dominoes" the plural may also be spelt without an e. In this lexicon I have followed Golomb in using the longer form.)

It is possible for a polyomino to be an oscillator. In fact there are infinitely many examples of such polyominoes, namely the cross and its larger analogues. The only other known examples are the block, the blinker, the toad, the star and (in two different phases) the pentadecathlon.

A polyomino can also be a spaceship, as the LWSS, MWSS and HWSS show.

:polyplet A finite collection of orthogonally or diagonally connected cells. This king-wise connectivity is a more natural concept in Life than the orthogonal connectivity of the polyomino.

:pond (p1)

.OO.
O..O
O..O
.OO.

:pond on pond (p1) This term is often used to mean bi-pond, but may also be used of the following pseudo still life.

.OO...OO.
O..O.O..O
O..O.O..O
.OO...OO.

:popover (p32) Found by Robert Wainwright in August 1984. Compare with gourmet and pi portraitor.

.....................O..........
.....................O..........
.....................OOO........
.............OO.......OO........
.............OO..OOO..OO........
...................OOO..........
...................OOO..........
..............OO................
..OOO........O..O...............
..OOO........O.O................
OOO..OO...O...O....OOO..........
.....OO...O.....................
....OOO...O.....................
....O.................OO...OO...
....O...........OOO..O..O..OO...
........O.......O.O...O.O.......
.......O.O......O.O....O........
...OO..O..O................O....
...OO...OO.................O....
.....................O...OOO....
.....................O...OO.....
..........OOO........O...OO..OOO
.................OO........OOO..
................O..O.......OOO..
................O.O.............
..........OOO....O..............
..........OOO...................
........OO..OOO..OO.............
........OO.......OO.............
........OOO.....................
..........O.....................
..........O.....................

:population The number of ON cells.

:P-pentomino Conway's name for the following pentomino, a common spark.

OO
OO
O.

:PPS (c/5 orthogonally, p30) A pre-pulsar spaceship. Any of three different p30 c/5 orthogonal spaceships in which a pre-pulsar is pushed by a pair of spiders. The back sparks of the spaceship can be used to perturb gliders in many different ways, allowing the easy construction of c/5 puffers. The first PPS was found by David Bell in May 1998 based on a p15 pre-pulsar spaceship found by Noam Elkies in December 1997. See also SPPS and APPS.

:pre-beehive The following common parent of the beehive.

OOO
OOO

:pre-block The following common parent of the block. Another such pattern is the grin.

O.
OO

:precursor = predecessor

:predecessor Any pattern that evolves into a given pattern after one or more generations.

:pre-pulsar A common predecessor of the pulsar, such as that shown below. This duplicates itself in 15 generations. (It fails, however, to be a true replicator because of the way the two copies then interact.)

OOO...OOO
O.O...O.O
OOO...OOO

A pair of tubs can be placed to eat half the pre-pulsar as it replicates; this gives the p30 oscillator Eureka where the pre-pulsar's replication becomes a movement back and forth. (See twirling T-tetsons II for a variation on this idea.) By other means the replication of the pre-pulsar can be made to occur in just 14 generations as half of it is eaten; this allows the construction of p28 and p29 oscillators, and is in fact the only known method for creating a p29 oscillator. The pre-pulsar is also a vital component of the only known p47 oscillator.

See also PPS.

:pre-pulsar spaceship See PPS.

:pressure cooker (p3) Found by the MIT group in September 1971. Compare mini pressure cooker.

.....O.....
....O.O....
....O.O....
...OO.OO...
O.O.....O.O
OO.O.O.O.OO
...O...O...
...O...O...
....OOO....
...........
...O.OO....
...OO.O....

:primer A pattern originally constructed by Dean Hickerson in November 1991 that emits a stream of LWSSs representing the prime numbers. Some improvements were found by Jason Summers in October 2005.

:protein (p3) Found by Dave Buckingham, November 1972.

....OO.......
....O........
......O......
..OOOO.O.OO..
.O.....O.O..O
.O..OO.O.O.OO
OO.O.....O...
...O..OO.O...
...O....O....
....OOOO.....
.............
....OO.......
....OO.......

:pseudo Opposite of true. A gun emitting a period n stream of spaceships (or rakes) is said to be a pseudo period n gun if its mechanism oscillates with a period different from n. This period will necessarily be a multiple of n. Pseudo period n glider guns are known to exist for all periods greater than or equal to 14, with smaller periods being impossible. The first pseudo p14 gun was built by Dieter Leithner in 1995.

The same distinction between true and pseudo also exists for puffers.

:pseudo-barberpole (p5) Found by Achim Flammenkamp in August 1994. In terms of its minimum population of 15 this is the smallest known p5 oscillator.

..........OO
...........O
.........O..
.......O.O..
............
.....O.O....
............
...O.O......
............
..OO........
O...........
OO..........

:pseudo-random glider generator An object which emits a random-looking stream of gliders, like the sequence of bits from a pseudo-random number generator. Pseudo-random glider generators contain gliders or other spaceships in a loop with a feedback mechanism which causes later spaceships to interfere with the generation of earlier spaceships. The period can be very high, since a loop of n spaceships has 2n possible states.

The first pseudo-random glider generator was built by Bill Gosper. David Bell built the first moving one in 1997, using c/3 rakes.

:pseudo still life The strict definition of still life rules out such stable patterns as the bi-block. In such patterns there are dead cells which have more than 3 neighbours in total, but fewer than 3 in any component still life. These patterns are called pseudo still lifes. Mark Niemiec has enumerated the pseudo still lifes up to 24 bits, and his figures are shown below.


-------------
Bits   Number
-------------
  8        1
  9        1
 10        7
 11       16
 12       55
 13      110
 14      279
 15      620
 16     1645
 17     4067
 18    10843
 19    27250
 20    70637
 21   179011
 22   462086
 23  1184882
 24  3068984
-------------

:puffer An object that moves like a spaceship, except that it leaves debris behind. The first known puffers were found by Bill Gosper and travelled at c/2 orthogonally (see diagram below for the very first one, found in 1971). Not long afterwards c/12 diagonal puffers were found (see switch engine). Discounting wickstretchers (which are not puffers in the conventional sense), no new velocity was obtained after this until David Bell found the first c/3 orthogonal puffer in April 1996. Since then c/5 orthogonal puffers have also been found, the first by Tim Coe in May 1997. Jason Summers built the first c/4 orthogonal puffer in January 1999, and the first 2c/5 orthogonal puffer in February 1999. Hartmut Holzwart built the first c/4 diagonal puffer (as opposed to a wickstretcher) in February 2004.

.OOO......O.....O......OOO.
O..O.....OOO...OOO.....O..O
...O....OO.O...O.OO....O...
...O...................O...
...O..O.............O..O...
...O..OO...........OO..O...
..O...OO...........OO...O..

:puffer engine A pattern which can be used as the main component of a puffer. The pattern may itself be a puffer (e.g. the classic puffer train), it may be a spaceship (e.g. the Schick engine), or it may even be unstable (e.g. the switch engine).

:puffer train The full name for a puffer, coined by Conway before any examples were known. The term was also applied specifically to the classic puffer train found by Bill Gosper and shown below. This is very dirty, and the tail does not stabilize until generation 5533. It consists of a B-heptomino (shown here one generation before the standard form) escorted by two LWSS. (This was the second known puffer. The first is shown under puffer.)

.OOO...........OOO
O..O..........O..O
...O....OOO......O
...O....O..O.....O
..O....O........O.

:puff suppressor An attachment at the back of a line puffer that suppresses all or some of its puffing action. The example below (by Hartmut Holzwart) has a 3-cell puff suppressor at the back which suppresses the entire puff, making a p2 spaceship. If you delete this puff suppressor then you get a p60 double beehive puffer. Puff suppressors were first recognised by Alan Hensel in April 1994.

............O....................
..........OO.O...................
..........OO...O.................
........O...OO.O.....O...........
........OOOO.OO...OOOO.......O.O.
......O......O....OOO.....O.O..O.
......OOOOOOO...O...O....O..O....
...O.O......OO..O...O.O.OO....O..
..OOOOOOOOO.....O..OO........O...
.OO..............O.OO.OOOO...O..O
OO....OO.O..........O...O..O.O...
.OO....O........OOO......O.O.O..O
.........O......OO......O....OO..
.OO....O........OOO......O.O.O..O
OO....OO.O..........O...O..O.O...
.OO..............O.OO.OOOO...O..O
..OOOOOOOOO.....O..OO........O...
...O.O......OO..O...O.O.OO....O..
......OOOOOOO...O...O....O..O....
......O......O....OOO.....O.O..O.
........OOOO.OO...OOOO.......O.O.
........O...OO.O.....O...........
..........OO...O.................
..........OO.O...................
............O....................

:pulsar (p3) Despite its size, this is the fourth most common oscillator (and by far the most common of period greater than 2) and was found very early on by Conway. See also pre-pulsar and pulsar quadrant.

..OOO...OOO..
.............
O....O.O....O
O....O.O....O
O....O.O....O
..OOO...OOO..
.............
..OOO...OOO..
O....O.O....O
O....O.O....O
O....O.O....O
.............
..OOO...OOO..

:pulsar 18-22-20 = two pulsar quadrants

:pulsar CP 48-56-72 = pulsar (The numbers refer to the populations of the three phases.)

:pulsar quadrant (p3) This consists of a quarter of the outer part of a pulsar stabilized by a cis fuse with two tails. This is reminiscent of mold and jam. Found by Dave Buckingham in July 1973. See also two pulsar quadrants.

.....O..
...OOO..
..O...OO
O..O..O.
O...O.O.
O....O..
........
..OOO...

:pulse A moving object, such as a spaceship or Herschel, which can be used to transmit information. See pulse divider.

Also another name for a pulsar quadrant.

:pulse divider A mechanism that lets every n-th object that reaches it pass through, and deletes all the rest, where n > 1 and the objects are typically spaceships or Herschels.

The following diagram shows a p5 glider pulse divider by Dieter Leithner (February 1998). The first glider moves the centre block and is reflected at 90 degrees. The next glider to come along will not be reflected, but will move the block back to its original position. The small size and low period of this example make it useful for constructing glider guns of certain periods. p7, p22, p36 and p46 versions of this pulse divider are also known.

.....OO...................
.....OO...................
..........................
..................OO......
.................O..O.....
.................O.O..O..O
O...............OO.O.OOOOO
.OO...........O...OO......
OO...............OO..OOO..
.............O...O.O..O.O.
........OO.......OO..OO.O.
........OO....O...OO...O..
................OO.O.OO...
.................O.O.O....
.................O.O..O...
..................O..OO...
..OO......................
...O......................
OOO.......................
O.........................
..........................
............OO............
............O.............
.............OOO..........
...............O..........

:pulshuttle V (p30) Found by Robert Wainwright, May 1985. Compare Eureka.

.............O..............O.............
............O.O.......O....O.O............
.............O......OO.OO...O.............
......................O...................
..OO......OO..................OO......OO..
O....O..O....O..............O....O..O....O
O....O..O....O..............O....O..O....O
O....O..O....O........O.....O....O..O....O
..OO......OO........OO.OO.....OO......OO..
......................O...................
..........................................
..........................................
..OO......OO..................OO......OO..
O....O..O....O........O.....O....O..O....O
O....O..O....O......OO.OO...O....O..O....O
O....O..O....O........O.....O....O..O....O
..OO......OO..................OO......OO..
..........................................
..........................................
......................O...................
..OO......OO........OO.OO.....OO......OO..
O....O..O....O........O.....O....O..O....O
O....O..O....O..............O....O..O....O
O....O..O....O..............O....O..O....O
..OO......OO..................OO......OO..
......................O...................
.............O......OO.OO...O.............
............O.O.......O....O.O............
.............O..............O.............

:pure glider generator A pattern that evolves into one or more gliders, and nothing else. There was some interest in these early on, but they are no longer considered important. Here's a neat example:

..O............
..O............
OOO............
...............
......OOO......
.......O.......
............OOO
............O..
............O..

:pushalong Any tagalong at the front of a spaceship. The following is an example (found by David Bell in 1992) attached to the front of a MWSS.

..OOO.O.....
.OOOO.O.....
OO..........
.O.O........
..OOOO.O....
...OOO......
............
............
......OOOOO.
......O....O
......O.....
.......O...O
.........O..

:pyrotechnecium (p8) Found by Dave Buckingham in 1972.

.......O........
.....OOOOO......
....O.....O.....
.O..O.O.OO.O....
O.O.O.O....O..O.
.O..O....O.O.O.O
....O.OO.O.O..O.
.....O.....O....
......OOOOO.....
........O.......

:pyrotechneczum A common mistaken spelling of pyrotechnecium, caused by a copying error in the early 1990s.

:python = long snake


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_bib.htm0000644000175000017500000001025012536111364016677 00000000000000 Life Lexicon (Bibliography)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

BIBLIOGRAPHY

David I. Bell, Spaceships in Conway's Life. Series of articles posted on comp.theory.cell-automata, Aug-Oct 1992. Now available from his web-site.

David I. Bell, Speed c/3 Technology in Conway's Life, 17 December 1999. Available from his web-site.

Elwyn R. Berlekamp, John H. Conway and Richard K. Guy, Winning Ways for your Mathematical Plays, II: Games in Particular. Academic Press, 1982.

David J Buckingham, Some Facts of Life. BYTE, December 1978.

Dave Buckingham, My Experience with B-heptominos in Oscillators. 12 October 1996. Available from Paul Callahan's web-site.

David J. Buckingham and Paul B. Callahan, Tight Bounds on Periodic Cell Configurations in Life. Experimental Mathematics 7:3 (1998) 221-241. Available at http://www.expmath.org/restricted/7/7.3/callahan.ps.

Noam D. Elkies, The still-Life density problem and its generalizations, pp228-253 of "Voronoi's Impact on Modern Science, Book I", P. Engel, H. Syta (eds), Institute of Mathematics, Kyiv, 1998 = Vol.21 of Proc. Inst. Math. Nat. Acad. Sci. Ukraine, math.CO/9905194.

Martin Gardner, Wheels, Life, and other Mathematical Amusements. W. H. Freeman and Company, 1983.

R. Wm. Gosper, Exploiting Regularities in Large Cellular Spaces. Physica 10D (1984) 75-80.

N. M. Gotts and P. B. Callahan, Emergent structures in sparse fields of Conway's 'Game of Life', in Artificial Life VI: Proceedings of the Sixth International Conference on Artificial Life, MIT Press, 1998.

Mark D Niemiec, Life Algorithms. BYTE, January 1979.

William Poundstone, The Recursive Universe. William Morrow and Company Inc., 1985.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_j.htm0000644000175000017500000001533312536111364016403 00000000000000 Life Lexicon (J)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:J = Herschel

:jack (p4) Found by Robert Wainwright, April 1984.

...O.....O...
...OO...OO...
O..OO...OO..O
OOO..O.O..OOO
.....O.O.....
OOO..O.O..OOO
O..OO...OO..O
...OO...OO...
...O.....O...

:jagged lines A pattern constructed by Dean Hickerson in May 2005 that uses puffers to produce a line of bi-blocks that weaves back and forth in a complicated way.

:jam (p3) Found by Achim Flammenkamp in 1988, but not widely known about until its independent discovery (and naming) by Dean Hickerson in September 1989. Compare with mold. In fact this is really very like caterer. In terms of its 7x7 bounding box it ties with trice tongs as the smallest p3 oscillator.

...OO.
..O..O
O..O.O
O...O.
O.....
...O..
.OO...

:Jaws A breeder constructed by Nick Gotts in February 1997. In the original version Jaws had an initial population of 150, which at the time was the smallest for any known pattern with superlinear growth. In November 1997 Gotts produced a 130-cell Jaws using some switch engine predecessors found by Paul Callahan. Jaws has since been beaten by the even smaller mosquitoes, teeth, catacryst and metacatacryst.

Jaws consists of eight pairs of switch engines which produce a new block-laying switch engine (plus masses of junk) every 10752 generations. It is therefore an MMS breeder.

:JC = dead spark coil

:JHC John Horton Conway. Also another name for monogram.

:J-heptomino = Herschel

:Jolson (p15) Two blocks hassled by two pentadecathlons. Found by Robert Wainwright in November 1984 and named by Bill Gosper. A p9 version using snackers instead of pentadecathlons is also possible.

.OO......OO..
O..O....O..O.
O..O....O..O.
O..O....O..O.
.OO......OO..
.............
.............
.......O.....
.....O..O.OO.
......OO..OO.
.............
.............
......OOOO...
.....OOOOOO..
....OOOOOOOO.
...OO......OO
....OOOOOOOO.
.....OOOOOO..
......OOOO...

:Justyna (stabilizes at time 26458) The following methuselah found by Andrzej Okrasinski in May 2004.

.................O....
................O..O..
.................OOO..
.................O..O.
......................
OO................O...
.O................O...
..................O...
......................
......................
......................
......................
......................
......................
......................
...................OOO
...........OOO........

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_d.htm0000644000175000017500000005210012536111364016366 00000000000000 Life Lexicon (D)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:dart (c/3 orthogonally, p3) Found by David Bell, May 1992.

.......O.......
......O.O......
.....O...O.....
......OOO......
...............
....OO...OO....
..O...O.O...O..
.OO...O.O...OO.
O.....O.O.....O
.O.OO.O.O.OO.O.

:dead spark coil (p1) Compare spark coil.

OO...OO
O.O.O.O
..O.O..
O.O.O.O
OO...OO

:de Bruijn diagram = de Bruijn graph

:de Bruijn graph As applied to Life, a de Bruijn graph is a graph showing which pieces can be linked to which other pieces to form a valid part of a Life pattern of a particular kind.

For example, if we are interested in still lifes, then we could consider 2x3 rectangular pieces and the de Bruijn graph would show which pairs of these can be overlapped to form 3x3 squares in which the centre cell remains unchanged in the next generation.

David Eppstein's search program gfind is based on de Bruijn graphs.

:Deep Cell A pattern by Jared James Prince, based on David Bell's unit Life cell, in which each unit cell simulates two Life cells, in such a way that a Life universe filled with Deep Cells simulates two independent Life universes running in parallel.

In fact, a Life universe filled with Deep Cells can simulate infinitely many Life universes, as follows. Let P1, P2, P3, ... be a sequence of Life patterns. Set the Deep Cells to run a simulation of P1 in parallel with a simulation of a universe filled with Deep Cells, with these simulated Deep Cells running a simulation of P2 in parallel with another simulation of a universe filled with Deep Cells, with these doubly simulated Deep Cells simulating P3 in parallel with yet another universe of Deep Cells, and so on.

Deep Cell is available from http://psychoticdeath.com/life.htm.

:density The density of a pattern is the limit of the proportion of live cells in a (2n+1)x(2n+1) square centred on a particular cell as n tends to infinity, when this limit exists. (Note that it does not make any difference what cell is chosen as the centre cell. Also note that if the pattern is finite then the density is zero.) There are other definitions of density, but this one will do here.

In 1994 Noam Elkies proved that the maximum density of a stable pattern is 1/2, which had been the conjectured value. See the paper listed in the bibliography. Marcus Moore provided a simpler proof in 1995, and in fact proves that a still life with an m x n bounding box has at most (mn+m+n)/2 cells.

But what is the maximum average density of an oscillating pattern? The answer is conjectured to be 1/2 again, but this remains unproved. The best upper bound so far obtained is 8/13 (Hartmut Holzwart, September 1992).

The maximum possible density for a phase of an oscillating pattern is also unknown. An example with a density of 3/4 is known (see agar), but densities arbitrarily close to 1 may perhaps be possible.

:D-heptomino = Herschel

:diamond = tub

:diamond ring (p3) Found by Dave Buckingham in 1972.

......O......
.....O.O.....
....O.O.O....
....O...O....
..OO..O..OO..
.O....O....O.
O.O.OO.OO.O.O
.O....O....O.
..OO..O..OO..
....O...O....
....O.O.O....
.....O.O.....
......O......

:diehard Any pattern that vanishes, but only after a long time. The following example vanishes in 130 generations, which is probably the limit for patterns of 7 or fewer cells. Note that there is no limit for higher numbers of cells - e.g., for 8 cells we could have a glider heading towards an arbitrarily distant blinker.

......O.
OO......
.O...OOO

:dinner table (p12) Found by Robert Wainwright in 1972.

.O...........
.OOO.......OO
....O......O.
...OO....O.O.
.........OO..
.............
.....OOO.....
.....OOO.....
..OO.........
.O.O....OO...
.O......O....
OO.......OOO.
...........O.

:dirty Opposite of clean. A reaction which produces a large amount of complicated junk which is difficult to control or use is said to be dirty. Many basic puffer engines are dirty and need to be tamed by accompanying spaceships in order to produce clean output.

:diuresis (p90) Found by David Eppstein in October 1998. His original stabilization used pentadecathlons. The stabilization with complicated still lifes shown here (in two slightly different forms) was found by Dean Hickerson the following day. The name is due to Bill Gosper (see kidney).

.....OO................OO....
......O................O.....
......O.O............O.O.....
.......OO............OO......
.............................
....OO..................OO...
....O.O..........OO....O.O...
.....O..........O.O.....O....
..O.............OO.........O.
..OOOOOO........O.....OOOOOO.
.......O..............O......
....OO..................OO...
....O....................O...
.....O..................O....
..OOO..O..............O..OOO.
..O..OOO........O.....OOO...O
...O............OO.......OOO.
....OO..........O.O.....O....
......O..........OO....O..OO.
....OO..................OO.O.
.O..O....................O...
O.O.O..OO............OO..O...
.O..O.O.O............O.O.OO..
....O.O................O..O..
.....OO................OO....

:dock The following induction coil.

.OOOO.
O....O
OO..OO

:domino The 2-cell polyomino. A number of objects, such as the HWSS and pentadecathlon, produce domino sparks.

:do-see-do The following reaction, found by David Bell in 1996, in which two gliders appear to circle around each other as they are reflected 90 degrees by a twin bees shuttle. Four copies of the reaction can be used to create a p92 glider loop which repeats the do-see-do reaction forever.

.....................................................O.O
.....................................................OO.
......................................................O.
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
........................................................
................................................OO......
................................................O.......
..............................................O.O.......
..............................................OO........
..............................O.O.......................
..............................OO........................
...............................O........................
........................................................
.......................OOO..............................
OO........OOO........OO.O.OO............................
OO........O...O.....O.....OO............................
..........O....O.....OO.O.OO............................
...........O...O.......OOO..............................
........................................................
...........O...O........................................
..........O....O........................................
OO........O...O............OO...........................
OO........OOO..............OO...........................

:double-barrelled Of a gun, emitting two streams of spaceships (or rakes). See B-52 bomber for an example.

:double block reaction A certain reaction that can be used to stabilize the twin bees shuttle (qv). This was discovered by David Bell in October 1996.

The same reaction sometimes works in other situations, as shown in the following diagram where a pair of blocks eats an R-pentomino and a LWSS. (The LWSS version was known at least as early 1994, when Paul Callahan saw it form spontaneously as a result of firing a LWSS stream at some random junk.)

.OOOO.....OO....
O...O......OO.OO
....O......O..OO
O..O............
................
.............OO.
.............OO.

:double caterer (p3) Found by Dean Hickerson, October 1989. Compare caterer and triple caterer.

.....OO...O........
....O..O..OOO......
....OO.O.....O.....
......O.OOOO.O.....
..OOO.O.O...O.OO...
.O..O..O...O..O.O..
O.O..O...O.OO....O.
.O..........OO.OOO.
..OO.OO.OO...O.....
...O...O.....O.OOO.
...O...O......OO..O
.................OO

:double ewe (p3) Found by Robert Wainwright before September 1971.

......OO............
.......O............
......O.............
......OO............
.........OO.........
......OOO.O.........
O.OO.O..............
OO.O.O..............
.....O...O..........
....O...OO....OO....
....OO....OO...O....
..........O...O.....
..............O.O.OO
..............O.OO.O
.........O.OOO......
.........OO.........
............OO......
.............O......
............O.......
............OO......

:double wing = moose antlers

:dove The following induction coil.

.OO..
O..O.
.O..O
..OOO

:down boat with tail = cis-boat with tail

:dragon (c/6 orthogonally, p6) This spaceship, discovered by Paul Tooke in April 2000, was the first known c/6 spaceship. All other known orthogonal c/6 spaceships are flotillas involving at least two dragons.

.............O..OO......O..OOO
.....O...OOOO.OOOOOO....O..OOO
.OOOOO....O....O....OOO.......
O......OO.O......OO.OOO..O.OOO
.OOOOO.OOO........OOOO...O.OOO
.....O..O..............O......
........OO..........OO.OO.....
........OO..........OO.OO.....
.....O..O..............O......
.OOOOO.OOO........OOOO...O.OOO
O......OO.O......OO.OOO..O.OOO
.OOOOO....O....O....OOO.......
.....O...OOOO.OOOOOO....O..OOO
.............O..OO......O..OOO

:drain trap = paperclip

:drifter A perturbation moving within a stable pattern. Dean Hickerson has written a program to search for drifters, with the hope of finding one which could be moved around a track. Because drifters can be very small, they could be packed more tightly than Herschels, and so allow the creation of oscillators of periods not yet attained, and possibly prove that Life is omniperiodic. Hickerson has found a number of components towards this end, but it has proved difficult to change the direction of movement of a drifter, and so far no complete track has been found. However, Hickerson has had success using the same search program to find eaters with novel properties, such as that used in diuresis.

:dual 1-2-3-4 = Achim's p4


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_z.htm0000644000175000017500000000600212536111364016414 00000000000000 Life Lexicon (Z)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Z-hexomino The following hexomino. The Z-hexomino features in the pentoad, and also in Achim's p144.

OO.
.O.
.O.
.OO

:Z-pentomino Conway's name for the following pentomino, which rapidly dies.

OO.
.O.
.OO

:zweiback (p30) An oscillator in which two HW volcanoes hassle a loaf. This was found by Mark Niemiec in February 1995 and is too big to show here.


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_e.htm0000644000175000017500000006110412536111364016373 00000000000000 Life Lexicon (E)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:early universe Conway's somewhat confusing term for sparse Life.

:eater Any still life that has the ability to interact with certain patterns without suffering any permanent damage. (If it doesn't suffer even temporary damage then it may be referred to as a rock.) The eater1 is a very common eater, and the term "eater" is often used specifically for this object. Other eaters include eater2, eater3, eater4 and even the humble block. (In fact the block was the first known eater, being found capable of eating beehives from a queen bee.) Another useful eater is shown below, feasting on a glider.

...O.....
...O.O...
...OO....
.........
.......OO
...O...OO
..O.O....
.O.O.....
.O.......
OO.......

:eater1 (p1) Usually simply called an eater, and also called a fishhook. Its ability to eat various objects was discovered by Bill Gosper in 1971.

OO..
O.O.
..O.
..OO

:eater2 (p1) This eater was found by Dave Buckingham in the 1970s. Mostly it works like the ordinary eater (see eater1) but with two slight differences that make it useful despite its size: it takes longer to recover from each bite and it acts like an eater in two directions. The first property means that, among other things, it can eat a glider in a position that would destroy a fishhook. This novel glider-eating action is occasionally of use in itself, and combined with the symmetry means that an eater2 can eat gliders along four different paths.

...O.OO
.OOO.OO
O......
.OOO.OO
...O.O.
...O.O.
....O..
The following eater2 variant (Stephen Silver, May 1998) can be useful for obtaining smaller bounding boxes. A more compact variant with the same purpose can be seen under gliderless.
OO....
O.....
..O.OO
.OO.OO
......
.OO.OO
..O.O.
..O.O.
...O..

:eater3 (p1) This large symmetric eater, found by Dave Buckingham, has a very different eating action from the eater1 and eater2. The loaf can take bites out things, being flipped over in the process. The rest of the object merely flips it back again.

.........OO.
....OO..O..O
.O..O....O.O
O.O.O.....O.
.O..O.OO....
....O..O....
.....O....O.
......OOOOO.
............
........O...
.......O.O..
........O...

:eater4 (p1) Another eater by Dave Buckingham, which he found in 1971, but did not recognize as an eater until 1975 or 1976. It can't eat gliders, but it can be used for various other purposes. The four NE-most centre cells regrow in a few generations after being destroyed by taking a bite out of something.

...OO.........
...O..........
OO.O..........
O..OO.........
.OO....O......
...OOOOO......
...O....OO....
....OO..O.....
......O.O.....
......O.O.O..O
.......OO.OOOO
.........O....
.........O.O..
..........OO..

:eater/block frob (p4) Found by Dave Buckingham in 1976 or earlier.

.OO.......
..O.......
..O.O.....
...O.O....
.....OO.OO
........OO
..OO......
...O......
OOO.......
O.........

:eater-bound pond = biting off more than they can chew

:eater-bound Z-hexomino = pentoad

:eater eating eater = two eaters

:eater plug (p2) Found by Robert Wainwright, February 1973.

.......O
.....OOO
....O...
.....O..
..O..O..
.O.OO...
.O......
OO......

:eaters + = French kiss

:eaters plus = French kiss

:ecologist (c/2 orthogonally, p20) This consists of the classic puffer train with a LWSS added to suppress the debris. See also space rake.

OOOO.....OO........
O...O...OO.OO......
O........OOOO......
.O..O.....OO.......
...................
.....O.........OO..
...OOO........OOOOO
..O...O.....O....OO
..O....OOOOO.....OO
..OO.O.OOOO....OO..
....O...OO.OOO.....
.....O.O...........
...................
...................
OOOO...............
O...O..............
O..................
.O..O..............

:edge-repair spaceship A spaceship which has an edge that possesses no spark and yet is able to perturb things because of its ability to repair certain types of damage to itself. The most useful examples are the following two small p3 c/3 spaceships:

..................................O.....
........O.......................OOO.OOO.
.......OOOO....................OO......O
..O...O...OO.OO...........O...O..O...OO.
.OOOO.....O..OO..........OOOO...........
O...O.......O..O........O...O...........
.O.O..O..................O.O..O.........
.....O.......................O..........
These were found by David Bell in 1992, but the usefulness of the edge-repair property wasn't recognised until July 1997. The following diagram (showing an edge-repair spaceship deleting a Herschel) demonstrates the self-repairing action.
................O.......
O..............OOOO.....
O.O.......O...O...OO.OO.
OOO......OOOO.....O..OO.
..O.....O...O.......O..O
.........O.O..O.........
.............O..........
In October 2000, David Bell found that a T-tetromino component of a c/4 spaceship can also be self-repairing. Stephen Silver noticed that it could be used to delete beehives and, in November 2000, found the smallest known c/4 spaceship with this edge-repair component - in fact, two copies of the component:
.OO..........................
O..O.........................
.OO..........................
.............................
.......O.O...................
.......O.....................
.......O.O..O..O.............
..........O..................
...........O.OO.O............
............OOO.O............
...........O....O..O.OO......
........O...OO...O.OOOO......
........OO..O..O.OO....O....O
........O........OO....O..OOO
.............OO...OO...O..OO.
.OO..........................
O..O.........................
.OO..........................

:edge shooter A gun which fires its gliders (or whatever) right at the edge of the pattern, so that it can be used to fire them closely parallel to others. This is useful for constructing complex guns. Compare glider pusher, which can in fact be used for making edge shooters.

The following diagram shows a p46 edge shooter found by Paul Callahan in June 1994.

OO............OO..O....OO..OO.............
OO............O.OO......OO.OO.............
...............O......O.O.................
...............OOO....OO..................
..........................................
...............OOO....OO..................
...............O......O.O.................
OO............O.OO......OO................
OO............OO..O....OO.................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
...............................OOO...OOO..
..............................O...O.O...O.
.............................O...OO.OO...O
.............................O.OO.....OO.O
...............................O.......O..
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
..........................................
...............................OO.....OO..
...............................OO.....OO..

:edge spark A spark at the side of a spaceship that can be used to perturb things as the spaceship passes by.

:edge sparker A spaceship that produces one or more edge sparks.

:egg = non-spark

:E-heptomino Name given by Conway to the following heptomino.

.OOO
OO..
.OO.

:elbow ladder Scot Ellison's name for the type of pattern he created in which one or more gliders shuttle back and forth (using the kickback reaction) deleting the output gliders from a pair of slide guns.

:electric fence (p5) A stabilization of ants. Dean Hickerson, February 1993.

..........O..................................................
.........O.O........................OO.......................
..O....OOO.O.....O...................O...O..O......O.....OO..
.O.O..O....OO...O.O..................O.OOO..OOO...O.O....O...
.O.O..O.OO.......O....................O...OO...O.O..O......O.
OO.OO.O.O.OOOOO.....O..................OO...O..O.O.OO.OO..OO.
.O.O..O...O..O..O.......OO...OO...OO....OO.OO..O.O..O.O.O....
.O..OO....OO......OOO.OO...OO...OO...OOO.....OOOO.OOO.O...OO.
..O..OOO..O..O.OOOO...OO...OO...OO...OOO.OO..O....O.O....O..O
...OO...O.O..O.....OO...OO...OO...OO......O............O...OO
.....OO.O.OO.O.OO..O......................O........OO.O......
.....O.OO.O..O.OO....O.................OO.O.O................
...........OO.......OO..................O..OO................
......................................O.O....................
......................................OO.....................

:elevener (p1)

OO....
O.O...
..O...
..OOO.
.....O
....OO

:Elkies' p5 (p5) Found by Noam Elkies in 1997.

.O.......
O..OOO...
..O......
...O.O..O
..OO.OOOO
....O....
....O.O..
.....OO..

:emu Dave Buckingham's term for a Herschel loop that does not emit gliders (and so is "flightless"). All known Herschel loops of periods 57, 58, 59 and 61 are emus. See also Quetzal.

:emulator Any one of three p4 oscillators that produce sparks similar to those produced by LWSS, MWSS and HWSS. See LW emulator, MW emulator and HW emulator. Larger emulators are also possible, but they require stabilizing objects to suppress their non-sparks and so are of little use. The emulators were discovered by Robert Wainwright in June 1980.

:engine The active portion of an object (usually a puffer or gun) which is considered to actually produce its output, and which generally permits no variation in how it works. The other parts of the object are just there to support the engine. For examples, see puffer train, Schick engine, blinker puffer, frothing puffer and line puffer.

:en retard (p3) Found by Dave Buckingham, August 1972.

.....O.....
....O.O....
OO.O.O.O.OO
.O.O...O.O.
O..O.O.O..O
.OO.....OO.
...OO.OO...
...O.O.O...
....O.O....
..O.O.O.O..
..OO...OO..

:Enterprise (c/4 diagonally, p4) Found by Dean Hickerson, March 1993.

.......OOO...........
.....O.OO............
....OOOO.............
...OO.....O..........
..OOO..O.O.O.........
.OO...O.O..O.........
.O.O.OOOOO...........
OO.O.O...O...........
O........OO..........
.OO..O...O.O.........
....OO..O.OO......O..
...........OO.....OOO
............O..OOO..O
............O..O..OO.
.............O.OO....
............OO.......
............OO.......
...........O.........
............O.O......
...........O..O......
.............O.......

:Eureka (p30) A pre-pulsar shuttle found by Dave Buckingham in August 1980. A variant is obtained by shifting the top half two spaces to either side.

.O..............O.
O.O....O.......O.O
.O...OO.OO......O.
.......O..........
..................
..................
..................
.......O..........
.O...OO.OO......O.
O.O....O.......O.O
.O..............O.

:evolutionary factor For an unstable pattern, the time to stabilization divided by the initial population. For example, the R-pentomino has an evolutionary factor of 220.6, while bunnies has an evolutionary factor of 1925.777... The term is no longer in use.

:exposure = underpopulation

:extensible A pattern is said to be extensible if arbitrarily large patterns of the same type can be made by repeating parts of the original pattern in a regular way.

:extra extra long = long^4

:extra long = long^3

:extremely impressive (p6) Found by Dave Buckingham, August 1976.

....OO......
...O.OOO....
...O....O...
OO.O...OO...
OO.O.....OO.
....OOOOO..O
..........OO
......O.....
.....O.O....
......O.....

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_i.htm0000644000175000017500000003075212536111364016404 00000000000000 Life Lexicon (I)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:I-heptomino Name given by Conway to the following heptomino. After one generation this is the same as the H-heptomino.

OO..
.O..
.OO.
..OO

:IMG = intermitting glider gun

:Immigration A form of colorized Life in which there are two types of ON cell, a newly-born cell taking the type of the majority of its three parent cells and surviving cells remaining of the same type as in the previous generation.

:induction coil Any object used to stabilize an edge (or edges) without touching. The tubs used in the Gray counter are examples, as are the blocks and snakes used in the Hertz oscillator and the heptomino at the bottom of the mathematician.

:inductor Any oscillator with a row of dead cells down the middle and whose two halves are mirror images of one another, both halves being required for the oscillator to work. The classic examples are the pulsar and the tumbler. If still lifes are considered as p1 oscillators then there are numerous simple examples such as table on table, dead spark coil and cis-mirrored R-bee. Some spaceships, such as the brain, the snail and the spider use the same principle.

:infinite glider hotel A pattern by David Bell, named after Hilbert's "infinite hotel" scenario in which a hotel with an infinite number of rooms has room for more guests even if it is already full, simply by shuffling the old guests around.

In this pattern, two pairs of Corderships moving at c/12 are pulling apart such that there is an ever-lengthening glider track between them. Every 128 generations another glider is injected into the glider track, joining the gliders already circulating there. The number of gliders in the track therefore increases without limit.

The tricky part of this construction is that even though all the previously injected gliders are repeatedly flying through the injection point, that point is guaranteed to be empty when it is time for the next glider to be injected.

:infinite growth Growth of a finite pattern such that the population tends to infinity, or at least is unbounded. Sometimes the term is used for growth of something other than population (for example, length), but here we will only consider infinite population growth. The first known pattern with infinite growth in this sense was the Gosper glider gun.

An interesting question is: What is the minimum population of a pattern that exhibits infinite growth? In 1971 Charles Corderman found that a switch engine could be stabilized by a pre-block in a number of different ways, giving 11-cell patterns with infinite growth. This record stood for more than quarter of a century until Paul Callahan found, in November 1997, two 10-cell patterns with infinite growth. The following month he found the one shown below, which is much neater, being a single cluster. This produces a stabilized switch engine of the block-laying type.

......O.
....O.OO
....O.O.
....O...
..O.....
O.O.....
Nick Gotts and Paul Callahan have also shown that there is no infinite growth pattern with fewer than 10 cells, so that the question has now been answered.

Also of interest is the following pattern (again found by Callahan), which is the only 5x5 pattern with infinite growth. This too emits a block-laying switch engine.

OOO.O
O....
...OO
.OO.O
O.O.O

Following a conjecture of Nick Gotts, Stephen Silver produced, in May 1998, a pattern of width 1 which exhibits infinite growth. This pattern was very large (12470x1 in the first version, reduced to 5447x1 the following day). In October 1998 Paul Callahan did an exhaustive search, finding the smallest example, the 39x1 pattern shown below. This produces two block-laying switch engines, stability being achieved at generation 1483.

OOOOOOOO.OOOOO...OOO......OOOOOOO.OOOOO

Although the simplest infinite growth patterns grow at a rate that is (asymptotically) linear, many other types of growth rate are possible, quadratic growth (see breeder) being the fastest. Dean Hickerson has found many patterns with unusual growth rates, such as sawtooths and a caber tosser.

See also Fermat prime calculator.

:initials = monogram

:inline inverter The following reaction in which a p30 gun can be used to invert the presence or absence of gliders in a p30 stream, with the output glider stream being in the same direction as the input glider stream.

................O...................
.................O..................
...............OOO..................
....................................
.......................O.O..........
.....................O...O..........
.............O.......O..............
............OOOO....O....O........OO
...........OO.O.O....O............OO
OO........OOO.O..O...O...O..........
OO.........OO.O.O......O.O..........
............OOOO....................
.............O......................

:integral = integral sign

:integral sign (p1)

...OO
..O.O
..O..
O.O..
OO...

:intentionless = elevener

:interchange (p2) A common formation of six blinkers.

..OOO....OOO..
..............
O............O
O............O
O............O
..............
..OOO....OOO..

:intermitting glider gun Despite the name, an intermitting glider gun (IMG) is more often an oscillator than a gun. There are two basic types. A type 1 IMG consists of two guns firing at one another in such a way that each gun is temporarily disabled on being hit by a glider from the other gun. A type 2 IMG consists of a single gun firing at a 180-degree glider reflector in such a way that returning gliders temporarily disable the gun.

Both types of IMG can be used to make glider guns of periods that are multiples of the base period. This is done by firing another gun across the two-way intermittent glider stream of the IMG in such a way that gliders only occasionally escape.

:island The individual polyplets of which a stable pattern consists are sometimes called islands. So, for example, a boat has only one island, while an aircraft carrier has two, a honey farm has four and the standard form of the eater3 has five.

:Iwona (stabilizes at time 28786) The following methuselah found by Andrzej Okrasinski in August 2004.

..............OOO...
....................
....................
....................
....................
....................
..O.................
...OO...............
...O..............O.
..................O.
..................O.
...................O
..................OO
.......OO...........
........O...........
....................
....................
....................
....................
OO..................
.O..................

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/Lexicon/lex_g.htm0000644000175000017500000007763112536111364016411 00000000000000 Life Lexicon (G)
Introduction | Bibliography

1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

:Gabriel's p138 (p138) The following oscillator found by Gabriel Nivasch in October 2002.

.......OOO.....
......O..O.....
.......O...O...
..O.....OOO....
...O.....O.....
OO.OO..........
O..O.........O.
O.O.........O.O
.O.........O..O
..........OO.OO
.....O.....O...
....OOO.....O..
...O...O.......
.....O..O......
.....OOO.......

:galaxy = Kok's galaxy

:Game of Life = Life

:Game of Life News A blog reporting on new Life discoveries, started by Heinrich Koenig in December 2004. Dave Greene is also a frequent contributor to the blog, which can be found at http://gameoflife-news.blogspot.com.

:Garden of Eden A configuration of ON and OFF cells that can only occur in generation 0. (This term was first used in connection with cellular automata by John W. Tukey, many years before Life.) It was known from the start that there are Gardens of Eden in Life, because of a theorem by Edward Moore that guarantees their existence in a wide class of cellular automata. Explicit examples have since been constructed, the first by Roger Banks, et al. at MIT in 1971. This example was 9 x 33. In 1974 J. Hardouin-Duparc et al. at the University of Bordeaux 1 produced a 6 x 122 example. The following shows a 12 x 12 example found by Nicolay Beluchenko in February 2006, based on a 13 x 12 one found by Achim Flammenkamp in June 2004.

..O.OOO.....
OO.O.OOOOO.O
O.O.OO.O.O..
.OOOO.O.OOO.
O.O.OO.OOO.O
.OOO.OO.O.O.
..O...OOO..O
.O.OO.O.O.O.
OOO.OOOO.O.O
OO.OOOO...O.
.O.O.OO..O..
.OO.O..OO.O.

:generation The fundamental unit of time. The starting pattern is generation 0.

:germ (p3) Found by Dave Buckingham, September 1972.

....OO....
.....O....
...O......
..O.OOOO..
..O....O..
.OO.O.....
..O.O.OOOO
O.O.O....O
OO...OOO..
.......OO.

:gfind A program by David Eppstein which uses de Bruijn graphs to search for new spaceships. It was with gfind that Eppstein found the weekender, and Paul Tooke later used it to find the dragon. It is available at http://www.ics.uci.edu/~eppstein/ca/gfind.c (C source code only).

Compare lifesrc.

:GIG A glider injection gate. This is a device for injecting a glider into a glider stream. The injected glider is synthesized from one or more incoming spaceships assisted by the presence of the GIG. (This contrasts with some other glider injection reactions which do not require a GIG.) Gliders already in the glider stream pass through the GIG without interfering with it. A GIG usually consists of a small number of oscillators.

Glider injection gates are useful for building glider guns with pseudo-periods that are of the form nd, where n is a positive integer, and d is a proper divisor of some convenient base gun period (such as 30 or 46), with d > 13.

:glasses (p2) Compare scrubber and spark coil.

....O........O....
..OOO........OOO..
.O..............O.
.O..OOO....OOO..O.
OO.O...O..O...O.OO
...O...OOOO...O...
...O...O..O...O...
....OOO....OOO....
..................
....OO.O..O.OO....
....O.OO..OO.O....

:glider (c/4 diagonally, p4) The smallest, most common and first discovered spaceship. This was found by Richard Guy in 1970 while Conway's group was attempting to track the evolution of the R-pentomino. The name is due in part to the fact that it is glide symmetric. (It is often stated that Conway discovered the glider, but he himself has said it was Guy. See also the cryptic reference ("some guy") in Winning Ways.)

OOO
O..
.O.
The term "glider" is also occasionally (mis)used to mean "spaceship".

:glider-block cycle An infinite oscillator based on the following reaction (a variant of the rephaser). The oscillator consists of copies of this reaction displaced 2n spaces from one another (for some n>6) with blocks added between the copies in order to cause the reaction to occur again halfway through the period. The period of the resulting infinite oscillator is 8n-20. (Alternatively, in a cylindrical universe of width 2n the oscillator just consists of two gliders and two blocks.)

...OO...
...OO...
........
........
..O..O..
O.O..O.O
.OO..OO.

:glider construction = glider synthesis

:glider duplicator Any reaction in which one input glider is converted into two output gliders. This can be done either by oscillators or by spaceships. The most useful glider duplicators are those with low periods.

The following period 30 glider duplicator demonstrates a simple glider duplicating mechanism found by Dieter Leithner. The input glider stream comes in from the upper left, and the output glider streams leave at the upper and lower right. One of the output glider streams is inverted, so an inline inverter is required to complete the duplicator.

..........O.O.......................
...........OO.......................
...........O........................
....................................
....................................
....................................
........................OO....O.....
..................O.....OO....OO....
...................OO........O.O....
..................OO................
....................................
....................................
....................................
....................................
......................OO............
.......................OO...........
............O.........O.............
............O.O.....................
.............O.O.........OO.........
OO...........O..O.......OOO.........
OO...........O.O.....O.OO...........
............O.O......O..O...........
............O........O.OO...........
........................OOO.....OO..
.........................OO.....O.O.
..................................O.
..................................OO

Spaceship convoys which can duplicate gliders are very useful since they (along with glider turners) provide a means to clean up many dirty puffers by duplicating and turning output gliders so as to impact into the exhaust to clean it up.

Glider duplicators (and turners) are known for backward gliders using p2 c/2 spaceships, and for forward gliders using p3 c/3 spaceships. These are the most general duplicators for these speeds.

:glider gun A gun which fires gliders.

:glider injection gate = GIG

:gliderless A gun is said to be gliderless if it does not use gliders. The purist definition would insist that a glider does not appear anywhere, even incidentally. For a long time the only known way to construct LWSS, MWSS and HWSS guns involved gliders, and it was not until April 1996 that Dieter Leithner constructed the first gliderless gun (a p46 LWSS gun).

The following diagram shows the p44 MWSS gun that Dieter Leithner discovered (in a somewhat larger form) in April 1997. This is the smallest known gliderless gun, and also the smallest known MWSS gun. It is based on an important p44 oscillator discovered by Dave Buckingham in early 1992, shown here in an improved form found in January 2005 by Jason Summers using a new p4 sparker by Nicolay Beluchenko. Note that a glider shape appears in this gun for three consecutive generations, but always as part of a larger cluster, so even a purist would regard this gun as gliderless.

.......O..........................................
..OO...O.O....O...................................
..O..OO..O.O.OO.O..OOO..OO........................
....OO.......OO.O.O.OO..OO........................
...OOO.......O.......OOO.........O................
.......................O.......OOO................
.......................O......O........OOO........
..............................OO.......O..O.......
.........OO..............O.............O..........
.........OO.............O..............O...O......
.........................OO............O..........
........................O.O.............O.O.......
..................................................
.......................O.O.....OOO................
........................O.....O..O..............OO
OO............OOO.......O......OO...........OO.O.O
OO...........O...O..........................OO.O..
.............OO.OO..............................O.
.................................OO.........OO.OO.
..............................OO.............O.O..
.............................................O.O..
..............................................O...
.............OO.OO.............O.O................
OO...........O...O.............OO.................
OO............OOO.................................
...........................OO.....................
...........................O.O....................
.............................O....................
.............................OO...................
..................................................
.........OO.......................................
.........OO.......................................
..................................................
.......................O..........................
.......................O..........................
...OOO.......O.......OOO..........................
....OO.......OO.O.O.OO..OO........................
..O..OO..O.O.OO.O..OOO..OO........................
..OO...O.O....O...................................
.......O..........................................

:glider pusher An arrangement of a queen bee shuttle and a pentadecathlon that can push the path of a passing glider out by one half-diagonal space. This was found by Dieter Leithner in December 1993 and is shown below. It is useful for constructing complex guns where it may be necessary to produce a number of gliders travelling on close parallel paths. See also edge shooter.

.........OO..............
.........OO..............
.........................
..........O..............
.........O.O.............
.........O.O.............
..........O..............
.........................
.........................
.......OO.O.OO...........
.......O.....O...........
........O...O............
.O.......OOO.............
..O......................
OOO......................
.........................
.........................
.................O....O..
...............OO.OOOO.OO
.................O....O..

:gliders by the dozen (stabilizes at time 184) In early references this is usually shown in a larger form whose generation 1 is generation 8 of the form shown here.

OO..O
O...O
O..OO

:glider synthesis Construction of an object by means of glider collisions. It is generally assumed that the gliders should be arranged so that they could come from infinity - that is, gliders should not have had to pass through one another to achieve the initial arrangement.

Glider syntheses for all still lifes and known oscillators with at most 14 cells were found by Dave Buckingham.

Perhaps the most interesting glider syntheses are those of spaceships, because these can be used to create corresponding guns and rakes. Many of the c/2 spaceships that are based on standard spaceships have been synthesized, mostly by Mark Niemiec. In June 1998 Stephen Silver found syntheses for some of the Corderships (although it was not until July 1999 that Jason Summers used this to build a Cordership gun). In May 2000, Noam Elkies suggested that a 2c/5 spaceship found by Tim Coe in May 1996 might be a candidate for glider synthesis. Initial attempts to construct a synthesis for this spaceship got fairly close, but it was only in March 2003 that Summers and Elkies managed to find a way perform the crucial last step. Summers then used the new synthesis to build a c/2 forward rake for the 2c/5 spaceship; this was the first example in Life of a rake which fires spaceships that travel in the same direction as the rake but more slowly.

A 3-glider synthesis of a pentadecathlon is shown in the diagram below. This was found in April 1997 by Heinrich Koenig and came as a surprise, as it was widely assumed that anything using just three gliders would already be known.

......O...
......O.O.
......OO..
..........
OOO.......
..O.......
.O.....OO.
........OO
.......O..

:glider train A certain puffer that produces two rows of blocks and two backward glider waves. Ten of these were used to make the first breeder.

:glider turner An reaction in which a glider is turned by an oscillator or a spaceship. In the former case, the glider turner is usually called a reflector.

Glider turners are easily built using standard spaceships. The following diagram shows a convoy which turns a forward glider 90 degrees, with the new glider also moving forwards.

.........OO.........
........OO.OOOO.....
.O.......OOOOOO.....
O.........OOOO......
OOO.................
....................
....................
....................
....................
...O................
.O...O..............
O...................
O....O..............
OOOOO...............
....................
....................
.............OOOOOO.
.............O.....O
.............O......
..............O....O
................OO..
Small rearrangements of the back two spaceships can alternatively send the output glider into any of the other three directions.

See also glider duplicator and reflector.

:glide symmetric Undergoing simultaneous reflection and translation. A glide symmetric spaceship is sometimes called a flipper.

:gnome = fox

:GoE = Garden of Eden

:GoL = Game of Life

:Golly A cross-platform open source Life program by Andrew Trevorrow and Tomas Rokicki. Unlike most Life programs it includes the ability to run patterns using the hashlife algorithm. It is available from http://golly.sourceforge.net.

:Gosper glider gun The first known gun, and indeed the first known finite pattern with unbounded growth, found by Bill Gosper in November 1970. It remains by far the smallest known gun. Gosper has since found other guns, see new gun and the p144 gun shown under factory.

........................O...........
......................O.O...........
............OO......OO............OO
...........O...O....OO............OO
OO........O.....O...OO..............
OO........O...O.OO....O.O...........
..........O.....O.......O...........
...........O...O....................
............OO......................

:gourmet (p32) Found by Dave Buckingham in March 1978. Compare with pi portraitor and popover.

..........OO........
..........O.........
....OO.OO.O....OO...
..O..O.O.O.....O....
..OO....O........O..
................OO..
....................
................OO..
O.........OOO..O.O..
OOO.......O.O...O...
...O......O.O....OOO
..O.O..............O
..OO................
....................
..OO................
..O........O....OO..
....O.....O.O.O..O..
...OO....O.OO.OO....
.........O..........
........OO..........

:grammar A set of rules for connecting components together to make an object such as a spaceship, oscillator or still life.

:grandfather = grandparent

:grandparent A pattern is said to be a grandparent of the pattern it gives rise to after two generations. See also parent.

:Gray counter (p4) Found in 1971. If you look at this in the right way you will see that it cycles through the Gray codes from 0 to 3. Compare with R2D2.

......O......
.....O.O.....
....O.O.O....
.O..O...O..O.
O.O.O...O.O.O
.O..O...O..O.
....O.O.O....
.....O.O.....
......O......

:gray ship = grey ship

:great on-off (p2)

..OO....
.O..O...
.O.O....
OO.O..O.
....OO.O
.......O
....OOO.
....O...

:grey counter = Gray counter (This form is erroneous, as Gray is surname, not a colour.)

:grey ship A spaceship that contains a region with a density of 1/2, and which is extensible in such a way that the region of density 1/2 can be made larger than any given square region.

See also with-the-grain grey ship, against-the-grain grey ship and hybrid grey ship.

:grin The following common parent of the block. This name relates to the infamous Cheshire cat. See also pre-block.

O..O
.OO.

:grow-by-one object A pattern whose population increases by one cell every generation. The smallest known grow-by-one object is the following 44-cell pattern (David Bell's one-cell improvement of a pattern found by Nicolay Beluchenko, September 2005).

........OO.......
.......OO........
.........O.......
...........OO....
..........O......
.................
.........O..OO...
.OO.....OO....O..
OO.....O.....O...
..O....O.O...OO..
....O..O....OO.O.
....OO.......OO..
........O....O.OO
.......O.O..O.OO.
........O........

:growing/shrinking line ship A line ship in which the line repeatedly grows and shrinks, resulting in a high-period spaceship.

:growing spaceship An object that moves like a spaceship, except that its front part moves faster than its back part and a wick extends between the two. Put another way, a growing spaceship is a puffer whose output is burning cleanly at a slower rate than the puffer is producing it. Examples include blinker ships and pi ships.

:gull = elevener

:gun Any stationary pattern that emits spaceships (or rakes) forever. For examples see double-barrelled, edge shooter, factory, gliderless, Gosper glider gun, new gun and true.

:gunstar Any of a series of glider guns of period 144+72n (for all non-negative integers n) constructed by Dave Buckingham in 1990 based on his transparent block reaction and Robert Wainwright's p72 oscillator (shown under factory).


1-9 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z

golly-2.7-src/gui-common/Help/problems.html0000644000175000017500000000175112536111364015677 00000000000000

Known Problems

This section lists all known bugs and limitations. If you come across any problems not mentioned below then please report them to Andrew Trevorrow (andrew@trevorrow.com).

  • All editing operations are restricted to cells whose coordinates are within +/- 1 billion. Not much of a limitation really!
  • The QuickLife algorithm has a minor bug that can cause selecting a large pattern to appear to be incorrect. The selection is actually correct but the rectangle is slightly offset (by one pixel).

Note that this version of Golly has a number of significant limitations when compared with the desktop version:

  • No scripting.
  • No multiple layers.
  • No timelines.
  • No auto fit mode.
  • No hyperspeed mode.
  • You can't change the colors, base step, nor origin.
Some of these capabilities might be added in future versions. golly-2.7-src/gui-common/Help/settings-android.html0000644000175000017500000000030212536111364017321 00000000000000

Settings Screen

The Settings screen lets you change various options. All of these should be pretty obvious. If not, let us know! golly-2.7-src/gui-common/Help/credits.html0000644000175000017500000000557212536111364015516 00000000000000

Credits

The pioneers

First and foremost, a big thanks to John Conway for creating the Game of Life, and to Martin Gardner for popularizing the topic in his Scientific American column.

The programmers

Tom Rokicki wrote most of the complicated stuff. Golly is essentially the merging of two of Tom's programs (hlife and qlife). The HashLife algorithm is based on an idea by Bill Gosper. The QuickLife algorithm uses some ideas from Alan Hensel. David Eppstein provided the idea on how to emulate B0 rules.

Andrew Trevorrow wrote the cross-platform GUI code for the desktop version of Golly using wxWidgets. Much thanks to Julian Smart and all the other wxWidgets developers. Andrew also wrote the GUI code for the iOS, Android and Web versions of Golly.

Tim Hutton wrote the RuleTable algorithm (now merged into the RuleLoader algorithm) and created the excellent Rule Table Repository.

Various code improvements have been contributed by Dave Greene, Jason Summers, Maks Verver, Robert Munafo and Brenton Bostick.

If you'd like to join us and help make Golly the best Life/CA app in the known universe then please get in touch.

The beta testers

Thanks to all the bug hunters for their reports and suggestions, especially Dave Greene, Gabriel Nivasch, Dean Hickerson, Brice Due, David Eppstein, Tony Smith, Alan Hensel, Dennis Langdeau, Bill Gosper.

Other contributors

Dave Greene and Alan Hensel helped put together the pattern collection. Thanks to everybody who allowed us to distribute their fantastic patterns, especially Nick Gotts, Gabriel Nivasch, David Eppstein, Jason Summers, Stephen Morley, Dean Hickerson, Brice Due, William R. Buckley, David Moore, Mark Owen, Tim Hutton, Renato Nobili and Adam P. Goucher.

Thanks to Stephen Silver for compiling the wonderful Life Lexicon.

Thanks to Nathaniel Johnston for creating the brilliant LifeWiki and for making its patterns available to Golly users via an online archive. golly-2.7-src/gui-common/Help/intro.html0000644000175000017500000000334012536111364015203 00000000000000

Introduction

Golly is a cross-platform application for exploring John Conway's Game of Life and many other types of cellular automata. It's also free and open source. More details are available at the Golly web site:

http://golly.sourceforge.net/

What is Life?

The Game of Life is a simple example of a set of rules more broadly known as a "cellular automaton", or CA for short. CAs were first studied in the mid-1950s by Stanislaw Ulam and John von Neumann but became much more widely known in 1970 when Conway's Life was described by Martin Gardner in his Scientific American column.

Life is played on an arbitrary-sized grid of square cells. Each cell has two states: "dead" or "alive". The state of every cell changes from one "generation" to the next according to the states of its 8 nearest neighbors: a dead cell becomes alive (a "birth") if it has exactly 3 live neighbors; a live cell dies out if it has less than 2 or more than 3 live neighbors. The "game" of Life simply involves starting off with a pattern of live cells and seeing what happens.

Even though the rules for Life are completely deterministic, it is impossible to predict whether an arbitrary starting pattern will die out, or start oscillating, or expand forever. Life and other CAs provide a powerful demonstration of how a very simple system can generate extremely complicated results.

If you'd like to learn more about Life and other cellular automata then check out the links and books mentioned in the References, or start exploring the Life Lexicon. golly-2.7-src/gui-common/Help/refs.html0000644000175000017500000000735412536111364015020 00000000000000

References

Good web sites

Good books and magazine articles

  • "Wheels, Life and Other Mathematical Amusements" by Martin Gardner. W. H. Freeman and Company, 1983. The last three chapters are an updated collection of his superb columns from Scientific American (see below). The last chapter has an excellent bibliography.
  • "The Recursive Universe" by William Poundstone. William Morrow & Company, 1985. An entire book devoted to a discussion of cellular automata and other fascinating topics in physics and mathematics.
  • "Winning Ways", Volume 2 by Elwyn Berlekamp, John Conway and Richard Guy. Academic Press, 1982. Chapter 25 has the title "What is Life?".
  • "Cellular Automata Machines" by Tommaso Toffoli and Norman Margolus. MIT Press, 1987. Describes CAM, a machine for doing sophisticated experiments with cellular automata.
  • "A New Kind of Science" by Stephen Wolfram. Wolfram Media, 2002. Bloated and egotistical, but there is plenty of fascinating stuff.
  • Scientific American articles:
    "Mathematical Games" columns by Martin Gardner: Oct, Nov 1970, Jan, Feb, Mar, Apr, Nov 1971, Jan 1972.
    "Computer Recreations" by Brian Hayes, Mar 1984.
  • BYTE articles:
    "Some Facts of Life" by David Buckingham, Dec 1978.
    "Life Algorithms" by Mark Niemiec, Jan 1979.
golly-2.7-src/gui-common/Help/algos.html0000644000175000017500000000075212536111364015161 00000000000000

Algorithms

Golly can generate patterns using a number of different algorithms:

golly-2.7-src/gui-common/Help/help-android.html0000644000175000017500000000323412536111364016420 00000000000000

Help Screen

The Help screen behaves like a simplified browser and is used to display HTML information on a variety of topics.

Special links

A number of Golly-specific links are used for various purposes:

  • edit:file
    Display the given file in a modal view.
  • get:url
    Download the specified file and process it according to its type:
    • A HTML file (.htm or .html) is displayed in the Help screen. Note that this HTML file can contain get links with partial URLs. For a good example of their use, see the LifeWiki Pattern Archive.
    • A text file (.txt or .doc or a name containing "readme") is displayed in a modal view.
    • A zip file's contents are displayed in the Help screen.
    • A rule file (.rule) is installed into Documents/Rules/ and Golly then switches to the corresponding rule.
    • A pattern file is loaded and displayed in the Golly screen.
  • lexpatt:pattern
    Load the given Life Lexicon pattern and display it in the Golly screen.
  • open:file
    Load the given pattern and display it in the Golly screen.
  • rule:rulename
    Load the given rule and switch to the Golly screen.
  • unzip:zip:file
    Extract a file from the given zip file and process it in the same manner as a get link (see above). Golly creates unzip links when it opens a zip file and displays its contents in the Help screen.
golly-2.7-src/gui-common/Help/pattern-ios.html0000644000175000017500000000352312536111364016320 00000000000000

Pattern Tab

The Pattern tab lets you display, edit and generate patterns. There are three toolbars:

  • The top toolbar has buttons for generating the current pattern, changing the speed (by setting how often the pattern is rendered), and for changing the scale and/or location.
  • The middle toolbar has buttons for editing the current pattern. You can undo or redo all editing changes (and generating changes), select all of the current pattern, perform a variety of actions on the selection, paste, or change the current drawing state. The segmented buttons at the right edge of the toolbar let you choose an editing mode: drawing cells, picking cell states, selecting cells, or moving the viewport (with a one-finger drag).
  • The bottom toolbar has buttons for miscellaneous functions. You can create a new pattern, change the current rule (and/or algorithm), display comment information in the current pattern file, save the current pattern, or switch to full screen mode.

The thin area in between the top two toolbars is used to display status information about the current pattern. It consists of three lines: The 1st line shows the pattern name, the current algorithm, and the current rule. The 2nd line shows the generation count, the population (ie. number of live cells), the current scale (in cells per pixels), the current step size, and the XY location of the cell in the middle of the viewport. The 3rd line is for various messages.

The background color of the status area depends on the current algorithm: pale yellow for QuickLife, pale blue for HashLife, etc.

The large area above the bottom toolbar is for displaying the current pattern. Two-finger pinching can be used to zoom in or out, and two-finger dragging can be used to move the viewport. golly-2.7-src/gui-common/Help/settings-ios.html0000644000175000017500000000027412536111364016503 00000000000000

Settings Tab

The Settings tab lets you change various options. All of these should be pretty obvious. If not, let us know! golly-2.7-src/gui-common/Help/changes-android.html0000644000175000017500000000016012536111364017073 00000000000000

Changes

Version 1.0 released November 2013

golly-2.7-src/gui-common/Help/archives.html0000644000175000017500000000264312536111364015661 00000000000000

Online Archives

Golly can download patterns and rules from these online archives:

golly-2.7-src/gui-common/Help/bounded.html0000644000175000017500000005566512536111364015511 00000000000000

Bounded Grids

Bounded grids with various topologies can be created by adding a special suffix to the usual rule string. For example, B3/S23:T30,20 creates a toroidal Life universe 30 cells wide and 20 cells high. The suffix syntax is best illustrated by these examples:

:P30,20 — plane with width 30 and height 20
:P30,0 — plane with width 30 and infinite height
:T0,20 — tube with infinite width and height 20
:T30,20 — torus with width 30 and height 20
:T30+5,20 — torus with a shift of +5 on the horizontal edges
:T30,20-2 — torus with a shift of -2 on the vertical edges
:K30*,20 — Klein bottle with the horizontal edges twisted
:K30,20* — Klein bottle with the vertical edges twisted
:K30*+1,20 — Klein bottle with a shift on the horizontal edges
:C30,20 — cross-surface (horizontal and vertical edges are twisted)
:S30 — sphere with width 30 and height 30 (must be equal)

Some notes:

  • The first letter indicating the topology can be entered in lowercase but is always uppercase in the canonical string returned by the getrule() script command.
  • If a bounded grid has width w and height h then the cell in the top left corner has coordinates -int(w/2),-int(h/2).
  • The maximum width or height of a bounded grid is 2,000,000,000.
  • Use 0 to specify an infinite width or height (but not possible for a Klein bottle, cross-surface or sphere). Shifting is not allowed if either dimension is infinite.
  • Pattern generation in a bounded grid is slower than in an unbounded grid. This is because all the current algorithms have been designed to work with unbounded grids, so Golly has to do extra work to create the illusion of a bounded grid.

The different topologies are described in the following sections.

Plane

A bounded plane is a simple, flat surface with no curvature. When generating patterns in a plane, Golly ensures that all the cells neighboring the edges are set to state 0 before applying the transition rules, as in this example of a 4 by 3 plane:

 0  0  0  0  0  0 
 0  A  B  C  D  0 
 0  E  F  G  H  0 
 0  I  J  K  L  0 
 0  0  0  0  0  0 
   rule suffix is :P4,3

Torus

If the opposite edges of a bounded plane are joined then the result is a donut-shaped surface called a torus. Before applying the transition rules at each generation, Golly copies the states of edge cells into appropriate neighboring cells outside the grid. The following diagram of a 4 by 3 torus shows how the edges are joined:

 L  I  J  K  L  I 
 D  A  B  C  D  A 
 H  E  F  G  H  E 
 L  I  J  K  L  I 
 D  A  B  C  D  A 
   rule suffix is :T4,3

A torus can have a shift on the horizontal edges or the vertical edges, but not both. These two examples show how shifted edges are joined:

 K  L  I  J  K  L 
 D  A  B  C  D  A 
 H  E  F  G  H  E 
 L  I  J  K  L  I 
 A  B  C  D  A  B 
   :T4+1,3
 H  I  J  K  L  A 
 L  A  B  C  D  E 
 D  E  F  G  H  I 
 H  I  J  K  L  A 
 L  A  B  C  D  E 
   :T4,3+1

Klein bottle

If one pair of opposite edges are twisted 180 degrees (ie. reversed) before being joined then the result is a Klein bottle. Here are examples of a horizontal twist and a vertical twist:

 I  L  K  J  I  L 
 D  A  B  C  D  A 
 H  E  F  G  H  E 
 L  I  J  K  L  I 
 A  D  C  B  A  D 
   :K4*,3   
 D  I  J  K  L  A 
 L  A  B  C  D  I 
 H  E  F  G  H  E 
 D  I  J  K  L  A 
 L  A  B  C  D  I 
   :K4,3*

A Klein bottle can only have a shift on the twisted edges and only if that dimension has an even number of cells. Also, all shift amounts are equivalent to a shift of 1. Here are two examples:

 J  I  L  K  J  I 
 D  A  B  C  D  A 
 H  E  F  G  H  E 
 L  I  J  K  L  I 
 B  A  D  C  B  A 
   :K4*+1,3
 F  J  K  L  D 
 C  A  B  C  A 
 L  D  E  F  J 
 I  G  H  I  G 
 F  J  K  L  D 
 C  A  B  C  A 
   :K3,4*+1

Cross-surface

If both pairs of opposite edges are twisted and joined then the result is a cross-surface (also known as a real projective plane, but Conway prefers the term cross-surface). Here's an example showing how the edges are joined:

 A  L  K  J  I  D 
 L  A  B  C  D  I 
 H  E  F  G  H  E 
 D  I  J  K  L  A 
 I  D  C  B  A  L 
   :C4,3

Note that the corner cells have themselves as one of their neighbors. Shifting is not possible.

Sphere

If adjacent edges are joined rather than opposite edges then the result is a sphere. By convention we join the top edge to the left edge and the right edge to the bottom edge, as shown in this 3 by 3 example:

 A  A  D  G  C 
 A  A  B  C  G 
 B  D  E  F  H 
 C  G  H  I  I 
 G  C  F  I  I 
   :S3

Note that the cells in the top left and bottom right corners (the "poles") have different neighborhoods to the cells in the top right and bottom left corners. Shifting is not possible.

Example patterns using the above topologies can be found in the Open tab's supplied patterns, especially in Generations and Life/Bounded-Grids. golly-2.7-src/gui-common/undo.cpp0000644000175000017500000014775012536111364013761 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include "lifealgo.h" #include "writepattern.h" // for MC_format, XRLE_format #include "select.h" // for Selection #include "view.h" // for OutsideLimits, etc #include "utils.h" // for Warning, Fatal, etc #include "algos.h" // for algo_type #include "layer.h" // for currlayer, numclones, MarkLayerDirty, etc #include "prefs.h" // for allowundo, etc #include "control.h" // for RestorePattern #include "file.h" // for SetPatternTitle #include "undo.h" // ----------------------------------------------------------------------------- const char* lack_of_memory = "Due to lack of memory, some changes can't be undone!"; const char* temp_prefix = "golly_undo_"; // ----------------------------------------------------------------------------- // encapsulate change info stored in undo/redo lists typedef enum { cellstates, // one or more cell states were changed fliptb, // selection was flipped top-bottom fliplr, // selection was flipped left-right rotatecw, // selection was rotated clockwise rotateacw, // selection was rotated anticlockwise rotatepattcw, // pattern was rotated clockwise rotatepattacw, // pattern was rotated anticlockwise namechange, // layer name was changed // WARNING: code in UndoChange/RedoChange assumes only changes < selchange // can alter the layer's dirty state; ie. the olddirty/newdirty flags are // not used for all the following changes selchange, // selection was changed genchange, // pattern was generated setgen, // generation count was changed rulechange, // rule was changed algochange, // algorithm was changed scriptstart, // later changes were made by script scriptfinish // earlier changes were made by script } change_type; class ChangeNode { public: ChangeNode(change_type id); ~ChangeNode(); bool DoChange(bool undo); // do the undo/redo; if it returns false (eg. user has aborted a lengthy // rotate/flip operation) then cancel the undo/redo void ChangeCells(bool undo); // change cell states using cellinfo change_type changeid; // specifies the type of change bool olddirty; // layer's dirty state before change bool newdirty; // layer's dirty state after change // cellstates info cell_change* cellinfo; // dynamic array of cell changes unsigned int cellcount; // number of cell changes in array // rotatecw/rotateacw/selchange info Selection oldsel, newsel; // old and new selections // genchange info std::string oldfile, newfile; // old and new pattern files bigint oldgen, newgen; // old and new generation counts bigint oldx, oldy, newx, newy; // old and new positions int oldmag, newmag; // old and new scales int oldbase, newbase; // old and new base steps int oldexpo, newexpo; // old and new step exponents bool scriptgen; // gen change was done by script? // also uses oldsel, newsel // setgen info bigint oldstartgen, newstartgen; // old and new startgen values bool oldsave, newsave; // old and new savestart states std::string oldtempstart, newtempstart; // old and new tempstart paths std::string oldstartfile, newstartfile; // old and new startfile paths std::string oldcurrfile, newcurrfile; // old and new currfile paths std::string oldclone[MAX_LAYERS]; // old starting names for cloned layers std::string newclone[MAX_LAYERS]; // new starting names for cloned layers // also uses oldgen, newgen // and oldrule, newrule // and oldx, oldy, newx, newy, oldmag, newmag // and oldbase, newbase // and oldexpo, newexpo // and oldsel, newsel // and oldalgo, newalgo // namechange info std::string oldname, newname; // old and new layer names Layer* whichlayer; // which layer was changed // also uses oldsave, newsave // and oldcurrfile, newcurrfile // rulechange info std::string oldrule, newrule; // old and new rules // also uses oldsel, newsel // algochange info algo_type oldalgo, newalgo; // old and new algorithm types // also uses oldrule, newrule // and oldsel, newsel }; // ----------------------------------------------------------------------------- ChangeNode::ChangeNode(change_type id) { changeid = id; cellinfo = NULL; cellcount = 0; oldfile.clear(); newfile.clear(); oldtempstart.clear(); newtempstart.clear(); } // ----------------------------------------------------------------------------- ChangeNode::~ChangeNode() { if (cellinfo) free(cellinfo); if (!oldfile.empty() && FileExists(oldfile)) { RemoveFile(oldfile); } if (!newfile.empty() && FileExists(newfile)) { RemoveFile(newfile); } // only delete oldtempstart/newtempstart if they're not being used to // store the current layer's starting pattern if ( !oldtempstart.empty() && FileExists(oldtempstart) && oldtempstart != currlayer->startfile && oldtempstart != currlayer->currfile ) { RemoveFile(oldtempstart); } if ( !newtempstart.empty() && FileExists(newtempstart) && newtempstart != currlayer->startfile && newtempstart != currlayer->currfile ) { RemoveFile(newtempstart); } } // ----------------------------------------------------------------------------- void ChangeNode::ChangeCells(bool undo) { // change state of cell(s) stored in cellinfo array if (undo) { // we must undo the cell changes in reverse order in case // a script has changed the same cell more than once unsigned int i = cellcount; while (i > 0) { i--; currlayer->algo->setcell(cellinfo[i].x, cellinfo[i].y, cellinfo[i].oldstate); } } else { unsigned int i = 0; while (i < cellcount) { currlayer->algo->setcell(cellinfo[i].x, cellinfo[i].y, cellinfo[i].newstate); i++; } } if (cellcount > 0) currlayer->algo->endofpattern(); } // ----------------------------------------------------------------------------- bool ChangeNode::DoChange(bool undo) { switch (changeid) { case cellstates: if (cellcount > 0) ChangeCells(undo); break; case fliptb: case fliplr: // pass in true so FlipSelection won't save changes or call MarkLayerDirty if (!FlipSelection(changeid == fliptb, true)) return false; break; case rotatepattcw: case rotatepattacw: // pass in true so RotateSelection won't save changes or call MarkLayerDirty if (!RotateSelection(changeid == rotatepattcw ? !undo : undo, true)) return false; break; case rotatecw: case rotateacw: if (cellcount > 0) ChangeCells(undo); // rotate selection edges if (undo) { currlayer->currsel = oldsel; } else { currlayer->currsel = newsel; } DisplaySelectionSize(); break; case selchange: if (undo) { currlayer->currsel = oldsel; } else { currlayer->currsel = newsel; } if (SelectionExists()) DisplaySelectionSize(); break; case genchange: if (undo) { currlayer->currsel = oldsel; RestorePattern(oldgen, oldfile.c_str(), oldx, oldy, oldmag, oldbase, oldexpo); } else { currlayer->currsel = newsel; RestorePattern(newgen, newfile.c_str(), newx, newy, newmag, newbase, newexpo); } break; case setgen: if (undo) { ChangeGenCount(oldgen.tostring(), true); currlayer->startgen = oldstartgen; currlayer->savestart = oldsave; currlayer->tempstart = oldtempstart; currlayer->startfile = oldstartfile; currlayer->currfile = oldcurrfile; if (oldtempstart != newtempstart) { currlayer->startdirty = olddirty; currlayer->startalgo = oldalgo; currlayer->startrule = oldrule; currlayer->startx = oldx; currlayer->starty = oldy; currlayer->startmag = oldmag; currlayer->startbase = oldbase; currlayer->startexpo = oldexpo; currlayer->startsel = oldsel; currlayer->startname = oldname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->startname = oldclone[i]; } } } } } else { ChangeGenCount(newgen.tostring(), true); currlayer->startgen = newstartgen; currlayer->savestart = newsave; currlayer->tempstart = newtempstart; currlayer->startfile = newstartfile; currlayer->currfile = newcurrfile; if (oldtempstart != newtempstart) { currlayer->startdirty = newdirty; currlayer->startalgo = newalgo; currlayer->startrule = newrule; currlayer->startx = newx; currlayer->starty = newy; currlayer->startmag = newmag; currlayer->startbase = newbase; currlayer->startexpo = newexpo; currlayer->startsel = newsel; currlayer->startname = newname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->startname = newclone[i]; } } } } } break; case namechange: if (whichlayer == NULL) { // the layer has been deleted so ignore name change } else { // note that if whichlayer != currlayer then we're changing the // name of a non-active cloned layer if (undo) { whichlayer->currname = oldname; currlayer->currfile = oldcurrfile; currlayer->savestart = oldsave; } else { whichlayer->currname = newname; currlayer->currfile = newcurrfile; currlayer->savestart = newsave; } if (whichlayer == currlayer) { if (olddirty == newdirty) SetPatternTitle(currlayer->currname.c_str()); // if olddirty != newdirty then UndoChange/RedoChange will call // MarkLayerClean/MarkLayerDirty (they call SetPatternTitle) } else { // whichlayer is non-active clone so only update Layer menu items //!!! for (int i = 0; i < numlayers; i++) UpdateLayerItem(i); } } break; case rulechange: if (undo) { RestoreRule(oldrule.c_str()); currlayer->currsel = oldsel; } else { RestoreRule(newrule.c_str()); currlayer->currsel = newsel; } if (cellcount > 0) { ChangeCells(undo); } // switch to default colors for new rule UpdateLayerColors(); break; case algochange: // pass in true so ChangeAlgorithm won't call RememberAlgoChange if (undo) { ChangeAlgorithm(oldalgo, oldrule.c_str(), true); currlayer->currsel = oldsel; } else { ChangeAlgorithm(newalgo, newrule.c_str(), true); currlayer->currsel = newsel; } if (cellcount > 0) { ChangeCells(undo); } // ChangeAlgorithm has called UpdateLayerColors() break; case scriptstart: case scriptfinish: // should never happen Warning("Bug detected in DoChange!"); break; } return true; } // ----------------------------------------------------------------------------- UndoRedo::UndoRedo() { numchanges = 0; // for 1st SaveCellChange maxchanges = 0; // ditto badalloc = false; // true if malloc/realloc fails cellarray = NULL; // play safe savecellchanges = false; // no script cell changes are pending savegenchanges = false; // no script gen changes are pending doingscriptchanges = false; // not undoing/redoing script changes prevfile.clear(); // play safe for ClearUndoRedo startcount = 0; // unfinished RememberGenStart calls fixsetgen = false; // no setgen nodes need fixing // need to remember if script has created a new layer (not a clone) if (inscript) RememberScriptStart(); } // ----------------------------------------------------------------------------- UndoRedo::~UndoRedo() { ClearUndoRedo(); } // ----------------------------------------------------------------------------- void UndoRedo::ClearUndoHistory() { while (!undolist.empty()) { delete undolist.front(); undolist.pop_front(); } } // ----------------------------------------------------------------------------- void UndoRedo::ClearRedoHistory() { while (!redolist.empty()) { delete redolist.front(); redolist.pop_front(); } } // ----------------------------------------------------------------------------- void UndoRedo::SaveCellChange(int x, int y, int oldstate, int newstate) { if (numchanges == maxchanges) { if (numchanges == 0) { // initially allocate room for 1 cell change maxchanges = 1; cellarray = (cell_change*) malloc(maxchanges * sizeof(cell_change)); if (cellarray == NULL) { badalloc = true; return; } // ~ChangeNode or ForgetCellChanges will free cellarray } else { // double size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, maxchanges * 2 * sizeof(cell_change)); if (newptr == NULL) { badalloc = true; return; } cellarray = newptr; maxchanges *= 2; } } cellarray[numchanges].x = x; cellarray[numchanges].y = y; cellarray[numchanges].oldstate = oldstate; cellarray[numchanges].newstate = newstate; numchanges++; } // ----------------------------------------------------------------------------- void UndoRedo::ForgetCellChanges() { if (numchanges > 0) { if (cellarray) { free(cellarray); } else { Warning("Bug detected in ForgetCellChanges!"); } numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto badalloc = false; } } // ----------------------------------------------------------------------------- bool UndoRedo::RememberCellChanges(const char* action, bool olddirty) { if (numchanges > 0) { if (numchanges < maxchanges) { // reduce size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, numchanges * sizeof(cell_change)); if (newptr != NULL) cellarray = newptr; // in the unlikely event that newptr is NULL, cellarray should // still point to valid data } ClearRedoHistory(); // add cellstates node to head of undo list ChangeNode* change = new ChangeNode(cellstates); if (change == NULL) Fatal("Failed to create cellstates node!"); change->cellinfo = cellarray; change->cellcount = numchanges; change->olddirty = olddirty; change->newdirty = true; undolist.push_front(change); numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto if (badalloc) { Warning(lack_of_memory); badalloc = false; } return true; // at least one cell changed state } return false; // no cells changed state (SaveCellChange wasn't called) } // ----------------------------------------------------------------------------- void UndoRedo::RememberFlip(bool topbot, bool olddirty) { ClearRedoHistory(); // add fliptb/fliplr node to head of undo list ChangeNode* change = new ChangeNode(topbot ? fliptb : fliplr); if (change == NULL) Fatal("Failed to create flip node!"); change->olddirty = olddirty; change->newdirty = true; undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::RememberRotation(bool clockwise, bool olddirty) { ClearRedoHistory(); // add rotatepattcw/rotatepattacw node to head of undo list ChangeNode* change = new ChangeNode(clockwise ? rotatepattcw : rotatepattacw); if (change == NULL) Fatal("Failed to create simple rotation node!"); change->olddirty = olddirty; change->newdirty = true; undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::RememberRotation(bool clockwise, Selection& oldsel, Selection& newsel, bool olddirty) { ClearRedoHistory(); // add rotatecw/rotateacw node to head of undo list ChangeNode* change = new ChangeNode(clockwise ? rotatecw : rotateacw); if (change == NULL) Fatal("Failed to create rotation node!"); change->oldsel = oldsel; change->newsel = newsel; change->olddirty = olddirty; change->newdirty = true; // if numchanges == 0 we still need to rotate selection edges if (numchanges > 0) { if (numchanges < maxchanges) { // reduce size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, numchanges * sizeof(cell_change)); if (newptr != NULL) cellarray = newptr; } change->cellinfo = cellarray; change->cellcount = numchanges; numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto if (badalloc) { Warning(lack_of_memory); badalloc = false; } } undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::RememberSelection(const char* action) { if (currlayer->savesel == currlayer->currsel) { // selection has not changed return; } if (generating) { // don't record selection changes while a pattern is generating; // RememberGenStart and RememberGenFinish will remember the overall change return; } ClearRedoHistory(); // add selchange node to head of undo list ChangeNode* change = new ChangeNode(selchange); if (change == NULL) Fatal("Failed to create selchange node!"); change->oldsel = currlayer->savesel; change->newsel = currlayer->currsel; undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::SaveCurrentPattern(const char* tempfile) { const char* err = NULL; //!!! need lifealgo::CanWriteFormat(MC_format) method??? if ( currlayer->algo->hyperCapable() ) { // save hlife pattern in a macrocell file err = WritePattern(tempfile, MC_format, no_compression, 0, 0, 0, 0); } else { // can only save RLE file if edges are within getcell/setcell limits bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( OutsideLimits(top, left, bottom, right) ) { err = "Pattern is too big to save."; } else { // use XRLE format so the pattern's top left location and the current // generation count are stored in the file err = WritePattern(tempfile, XRLE_format, no_compression, top.toint(), left.toint(), bottom.toint(), right.toint()); } } if (err) Warning(err); } // ----------------------------------------------------------------------------- void UndoRedo::RememberGenStart() { startcount++; if (startcount > 1) { // return immediately and ignore next RememberGenFinish call; // this can happen in Linux app if user holds down space bar return; } if (inscript) { if (savegenchanges) return; // ignore consecutive run/step command savegenchanges = true; // we're about to do first run/step command of a (possibly long) // sequence, so save starting info } // save current generation, selection, position, scale, speed, etc prevgen = currlayer->algo->getGeneration(); prevsel = currlayer->currsel; prevx = currlayer->view->x; prevy = currlayer->view->y; prevmag = currlayer->view->getmag(); prevbase = currlayer->currbase; prevexpo = currlayer->currexpo; if (prevgen == currlayer->startgen) { // we can just reset to starting pattern prevfile.clear(); if (fixsetgen) { // SaveStartingPattern has just been called so search undolist for setgen // node that changed tempstart and update the starting info in that node; // yuk -- is there a simpler solution??? std::list::iterator node = undolist.begin(); while (node != undolist.end()) { ChangeNode* change = *node; if (change->changeid == setgen && change->oldtempstart != change->newtempstart) { change->newdirty = currlayer->startdirty; change->newalgo = currlayer->startalgo; change->newrule = currlayer->startrule; change->newx = currlayer->startx; change->newy = currlayer->starty; change->newmag = currlayer->startmag; change->newbase = currlayer->startbase; change->newexpo = currlayer->startexpo; change->newsel = currlayer->startsel; change->newname = currlayer->startname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { change->newclone[i] = cloneptr->startname; } } } // do NOT reset fixsetgen to false here; the gen change might // be removed when clearing the redo list and so we may need // to update this setgen node again after a new gen change break; } node++; } } } else { // save starting pattern in a unique temporary file prevfile = CreateTempFileName(temp_prefix); // if head of undo list is a genchange node then we can copy that // change node's newfile to prevfile; this makes consecutive generating // runs faster (setting prevfile to newfile would be even faster but it's // difficult to avoid the file being deleted if the redo list is cleared) if (!undolist.empty()) { std::list::iterator node = undolist.begin(); ChangeNode* change = *node; if (change->changeid == genchange) { if (CopyFile(change->newfile, prevfile)) { return; } else { Warning("Failed to copy temporary file!"); // continue and call SaveCurrentPattern } } } SaveCurrentPattern(prevfile.c_str()); } } // ----------------------------------------------------------------------------- void UndoRedo::RememberGenFinish() { startcount--; if (startcount > 0) return; if (startcount < 0) { // this can happen if a script has pending gen changes that need // to be remembered (ie. savegenchanges is now false) so reset // startcount for the next RememberGenStart call startcount = 0; } if (inscript && savegenchanges) return; // ignore consecutive run/step command // generation count might not have changed (can happen in Linux app and iOS Golly) if (prevgen == currlayer->algo->getGeneration()) { // delete prevfile created by RememberGenStart if (!prevfile.empty() && FileExists(prevfile)) { RemoveFile(prevfile); } prevfile.clear(); return; } std::string fpath; if (currlayer->algo->getGeneration() == currlayer->startgen) { // this can happen if script called reset() so just use starting pattern fpath.clear(); } else { // save finishing pattern in a unique temporary file fpath = CreateTempFileName(temp_prefix); SaveCurrentPattern(fpath.c_str()); } ClearRedoHistory(); // add genchange node to head of undo list ChangeNode* change = new ChangeNode(genchange); if (change == NULL) Fatal("Failed to create genchange node!"); change->scriptgen = inscript; change->oldgen = prevgen; change->newgen = currlayer->algo->getGeneration(); change->oldfile = prevfile; change->newfile = fpath; change->oldx = prevx; change->oldy = prevy; change->newx = currlayer->view->x; change->newy = currlayer->view->y; change->oldmag = prevmag; change->newmag = currlayer->view->getmag(); change->oldbase = prevbase; change->newbase = currlayer->currbase; change->oldexpo = prevexpo; change->newexpo = currlayer->currexpo; change->oldsel = prevsel; change->newsel = currlayer->currsel; // prevfile has been saved in change->oldfile (~ChangeNode will delete it) prevfile.clear(); undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::AddGenChange() { // add a genchange node to empty undo list if (!undolist.empty()) Warning("AddGenChange bug: undo list NOT empty!"); // use starting pattern info for previous state prevgen = currlayer->startgen; prevsel = currlayer->startsel; prevx = currlayer->startx; prevy = currlayer->starty; prevmag = currlayer->startmag; prevbase = currlayer->startbase; prevexpo = currlayer->startexpo; prevfile.clear(); // play safe and pretend RememberGenStart was called startcount = 1; // avoid RememberGenFinish returning early if inscript is true savegenchanges = false; RememberGenFinish(); if (undolist.empty()) Warning("AddGenChange bug: undo list is empty!"); } // ----------------------------------------------------------------------------- void UndoRedo::SyncUndoHistory() { // synchronize undo history due to a ResetPattern call; // wind back the undo list to just past the genchange node that // matches the current layer's starting gen count std::list::iterator node; ChangeNode* change; while (!undolist.empty()) { node = undolist.begin(); change = *node; // remove node from head of undo list and prepend it to redo list undolist.erase(node); redolist.push_front(change); if (change->changeid == genchange && change->oldgen == currlayer->startgen) { if (change->scriptgen) { // gen change was done by a script so keep winding back the undo list // to just past the scriptstart node, or until the list is empty while (!undolist.empty()) { node = undolist.begin(); change = *node; undolist.erase(node); redolist.push_front(change); if (change->changeid == scriptstart) break; } } return; } } // should never get here Warning("Bug detected in SyncUndoHistory!"); } // ----------------------------------------------------------------------------- void UndoRedo::RememberSetGen(bigint& oldgen, bigint& newgen, bigint& oldstartgen, bool oldsave) { std::string oldtempstart = currlayer->tempstart; std::string oldstartfile = currlayer->startfile; std::string oldcurrfile = currlayer->currfile; if (oldgen > oldstartgen && newgen <= oldstartgen) { // if pattern is generated then tempstart will be clobbered by // SaveStartingPattern, so change tempstart to a new temporary file currlayer->tempstart = CreateTempFileName("golly_setgen_"); // also need to update startfile and currfile (currlayer->savestart is true) currlayer->startfile = currlayer->tempstart; currlayer->currfile.clear(); } ClearRedoHistory(); // add setgen node to head of undo list ChangeNode* change = new ChangeNode(setgen); if (change == NULL) Fatal("Failed to create setgen node!"); change->oldgen = oldgen; change->newgen = newgen; change->oldstartgen = oldstartgen; change->newstartgen = currlayer->startgen; change->oldsave = oldsave; change->newsave = currlayer->savestart; change->oldtempstart = oldtempstart; change->newtempstart = currlayer->tempstart; change->oldstartfile = oldstartfile; change->newstartfile = currlayer->startfile; change->oldcurrfile = oldcurrfile; change->newcurrfile = currlayer->currfile; if (change->oldtempstart != change->newtempstart) { // save extra starting info set by previous SaveStartingPattern so that // Undoing this setgen change will restore the correct info for a Reset change->olddirty = currlayer->startdirty; change->oldalgo = currlayer->startalgo; change->oldrule = currlayer->startrule; change->oldx = currlayer->startx; change->oldy = currlayer->starty; change->oldmag = currlayer->startmag; change->oldbase = currlayer->startbase; change->oldexpo = currlayer->startexpo; change->oldsel = currlayer->startsel; change->oldname = currlayer->startname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { change->oldclone[i] = cloneptr->startname; } } } // following settings will be updated by next RememberGenStart call so that // Redoing this setgen change will restore the correct info for a Reset fixsetgen = true; change->newdirty = currlayer->startdirty; change->newalgo = currlayer->startalgo; change->newrule = currlayer->startrule; change->newx = currlayer->startx; change->newy = currlayer->starty; change->newmag = currlayer->startmag; change->newbase = currlayer->startbase; change->newexpo = currlayer->startexpo; change->newsel = currlayer->startsel; change->newname = currlayer->startname; if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { change->newclone[i] = cloneptr->startname; } } } } undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::RememberNameChange(const char* oldname, const char* oldcurrfile, bool oldsave, bool olddirty) { if (oldname == currlayer->currname && oldcurrfile == currlayer->currfile && oldsave == currlayer->savestart && olddirty == currlayer->dirty) return; ClearRedoHistory(); // add namechange node to head of undo list ChangeNode* change = new ChangeNode(namechange); if (change == NULL) Fatal("Failed to create namechange node!"); change->oldname = oldname; change->newname = currlayer->currname; change->oldcurrfile = oldcurrfile; change->newcurrfile = currlayer->currfile; change->oldsave = oldsave; change->newsave = currlayer->savestart; change->olddirty = olddirty; change->newdirty = currlayer->dirty; // cloned layers share the same undo/redo history but each clone can have // a different name, so we need to remember which layer was changed change->whichlayer = currlayer; undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::DeletingClone(int index) { // the given cloned layer is about to be deleted, so we need to go thru the // undo/redo lists and, for each namechange node, set a matching whichlayer // ptr to NULL so DoChange can ignore later changes involving this layer; // very ugly, but I don't see any better solution if we're going to allow // cloned layers to have different names Layer* cloneptr = GetLayer(index); std::list::iterator node; node = undolist.begin(); while (node != undolist.end()) { ChangeNode* change = *node; if (change->changeid == namechange && change->whichlayer == cloneptr) change->whichlayer = NULL; node++; } node = redolist.begin(); while (node != redolist.end()) { ChangeNode* change = *node; if (change->changeid == namechange && change->whichlayer == cloneptr) change->whichlayer = NULL; node++; } } // ----------------------------------------------------------------------------- void UndoRedo::RememberRuleChange(const char* oldrule) { std::string newrule = currlayer->algo->getrule(); if (oldrule == newrule) return; ClearRedoHistory(); // add rulechange node to head of undo list ChangeNode* change = new ChangeNode(rulechange); if (change == NULL) Fatal("Failed to create rulechange node!"); change->oldrule = oldrule; change->newrule = newrule; // selection might have changed if grid became smaller change->oldsel = currlayer->savesel; change->newsel = currlayer->currsel; // SaveCellChange may have been called if (numchanges > 0) { if (numchanges < maxchanges) { // reduce size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, numchanges * sizeof(cell_change)); if (newptr != NULL) cellarray = newptr; } change->cellinfo = cellarray; change->cellcount = numchanges; numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto if (badalloc) { Warning(lack_of_memory); badalloc = false; } } undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::RememberAlgoChange(algo_type oldalgo, const char* oldrule) { ClearRedoHistory(); // add algochange node to head of undo list ChangeNode* change = new ChangeNode(algochange); if (change == NULL) Fatal("Failed to create algochange node!"); change->oldalgo = oldalgo; change->newalgo = currlayer->algtype; change->oldrule = oldrule; change->newrule = currlayer->algo->getrule(); // selection might have changed if grid became smaller change->oldsel = currlayer->savesel; change->newsel = currlayer->currsel; // SaveCellChange may have been called if (numchanges > 0) { if (numchanges < maxchanges) { // reduce size of cellarray cell_change* newptr = (cell_change*) realloc(cellarray, numchanges * sizeof(cell_change)); if (newptr != NULL) cellarray = newptr; } change->cellinfo = cellarray; change->cellcount = numchanges; numchanges = 0; // reset for next SaveCellChange maxchanges = 0; // ditto if (badalloc) { Warning(lack_of_memory); badalloc = false; } } undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::RememberScriptStart() { if (!undolist.empty()) { std::list::iterator node = undolist.begin(); ChangeNode* change = *node; if (change->changeid == scriptstart) { // ignore consecutive RememberScriptStart calls made by RunScript // due to cloned layers if (numclones == 0) Warning("Unexpected RememberScriptStart call!"); return; } } // add scriptstart node to head of undo list ChangeNode* change = new ChangeNode(scriptstart); if (change == NULL) Fatal("Failed to create scriptstart node!"); undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::RememberScriptFinish() { if (undolist.empty()) { // this can happen if RunScript calls RememberScriptFinish multiple times // due to cloned layers AND the script made no changes if (numclones == 0) { // there should be at least a scriptstart node (see ClearUndoRedo) Warning("Bug detected in RememberScriptFinish!"); } return; } // if head of undo list is a scriptstart node then simply remove it // and return (ie. the script didn't make any changes) std::list::iterator node = undolist.begin(); ChangeNode* change = *node; if (change->changeid == scriptstart) { undolist.erase(node); delete change; return; } else if (change->changeid == scriptfinish) { // ignore consecutive RememberScriptFinish calls made by RunScript // due to cloned layers if (numclones == 0) Warning("Unexpected RememberScriptFinish call!"); return; } // add scriptfinish node to head of undo list change = new ChangeNode(scriptfinish); if (change == NULL) Fatal("Failed to create scriptfinish node!"); undolist.push_front(change); } // ----------------------------------------------------------------------------- bool UndoRedo::CanUndo() { // we need to allow undo if generating even though undo list might be empty // (selecting Undo will stop generating and add genchange node to undo list) if (allowundo && generating) return true; return !undolist.empty() && !inscript; } // ----------------------------------------------------------------------------- bool UndoRedo::CanRedo() { return !redolist.empty() && !inscript && !generating; } // ----------------------------------------------------------------------------- void UndoRedo::UndoChange() { if (!CanUndo()) return; // get change info from head of undo list and do the change std::list::iterator node = undolist.begin(); ChangeNode* change = *node; if (change->changeid == scriptfinish) { // undo all changes between scriptfinish and scriptstart nodes; // first remove scriptfinish node from undo list and add it to redo list undolist.erase(node); redolist.push_front(change); while (change->changeid != scriptstart) { // call UndoChange recursively; temporarily set doingscriptchanges so // UndoChange won't return if DoChange is aborted doingscriptchanges = true; UndoChange(); doingscriptchanges = false; node = undolist.begin(); if (node == undolist.end()) Fatal("Bug in UndoChange!"); change = *node; } // continue below so that scriptstart node is removed from undo list // and added to redo list } else { // user might abort the undo (eg. a lengthy rotate/flip) if (!change->DoChange(true) && !doingscriptchanges) return; } // remove node from head of undo list (doesn't delete node's data) undolist.erase(node); if (change->changeid < selchange && change->olddirty != change->newdirty) { // change dirty flag if (change->olddirty) { currlayer->dirty = false; // make sure it changes MarkLayerDirty(); } else { MarkLayerClean(currlayer->currname.c_str()); } } // add change to head of redo list redolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::RedoChange() { if (!CanRedo()) return; // get change info from head of redo list and do the change std::list::iterator node = redolist.begin(); ChangeNode* change = *node; if (change->changeid == scriptstart) { // redo all changes between scriptstart and scriptfinish nodes; // first remove scriptstart node from redo list and add it to undo list redolist.erase(node); undolist.push_front(change); while (change->changeid != scriptfinish) { // call RedoChange recursively; temporarily set doingscriptchanges so // RedoChange won't return if DoChange is aborted doingscriptchanges = true; RedoChange(); doingscriptchanges = false; node = redolist.begin(); if (node == redolist.end()) Fatal("Bug in RedoChange!"); change = *node; } // continue below so that scriptfinish node is removed from redo list // and added to undo list } else { // user might abort the redo (eg. a lengthy rotate/flip) if (!change->DoChange(false) && !doingscriptchanges) return; } // remove node from head of redo list (doesn't delete node's data) redolist.erase(node); if (change->changeid < selchange && change->olddirty != change->newdirty) { // change dirty flag if (change->newdirty) { currlayer->dirty = false; // make sure it changes MarkLayerDirty(); } else { MarkLayerClean(currlayer->currname.c_str()); } } // add change to head of undo list undolist.push_front(change); } // ----------------------------------------------------------------------------- void UndoRedo::ClearUndoRedo() { // free cellarray in case there were SaveCellChange calls not followed // by ForgetCellChanges or RememberCellChanges ForgetCellChanges(); if (startcount > 0) { // RememberGenStart was not followed by RememberGenFinish if (!prevfile.empty() && FileExists(prevfile)) { RemoveFile(prevfile); } prevfile.clear(); startcount = 0; } // clear the undo/redo lists (and delete each node's data) ClearUndoHistory(); ClearRedoHistory(); fixsetgen = false; if (inscript) { // script has called a command like new() so add a scriptstart node // to the undo list to match the final scriptfinish node RememberScriptStart(); // reset flags to indicate no pending cell/gen changes savecellchanges = false; savegenchanges = false; } } // ----------------------------------------------------------------------------- bool CopyTempFiles(ChangeNode* srcnode, ChangeNode* destnode, const char* tempstart1) { // if srcnode has any existing temporary files then create new // temporary file names in the destnode and copy each file bool allcopied = true; if ( !srcnode->oldfile.empty() && FileExists(srcnode->oldfile) ) { destnode->oldfile = CreateTempFileName("golly_dupe1_"); if ( !CopyFile(srcnode->oldfile, destnode->oldfile) ) allcopied = false; } if ( !srcnode->newfile.empty() && FileExists(srcnode->newfile) ) { destnode->newfile = CreateTempFileName("golly_dupe2_"); if ( !CopyFile(srcnode->newfile, destnode->newfile) ) allcopied = false; } if ( !srcnode->oldtempstart.empty() && FileExists(srcnode->oldtempstart) ) { if (srcnode->oldtempstart == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->oldtempstart = tempstart1; } else { destnode->oldtempstart = CreateTempFileName("golly_dupe3_"); if ( !CopyFile(srcnode->oldtempstart, destnode->oldtempstart) ) allcopied = false; } if (srcnode->oldstartfile == srcnode->oldtempstart) destnode->oldstartfile = destnode->oldtempstart; if (srcnode->oldcurrfile == srcnode->oldtempstart) destnode->oldcurrfile = destnode->oldtempstart; } if ( !srcnode->newtempstart.empty() && FileExists(srcnode->newtempstart) ) { if (srcnode->newtempstart == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->newtempstart = tempstart1; } else { destnode->newtempstart = CreateTempFileName("golly_dupe4_"); if ( !CopyFile(srcnode->newtempstart, destnode->newtempstart) ) allcopied = false; } if (srcnode->newstartfile == srcnode->newtempstart) destnode->newstartfile = destnode->newtempstart; if (srcnode->newcurrfile == srcnode->newtempstart) destnode->newcurrfile = destnode->newtempstart; } return allcopied; } // ----------------------------------------------------------------------------- void UndoRedo::DuplicateHistory(Layer* oldlayer, Layer* newlayer) { UndoRedo* history = oldlayer->undoredo; // clear the undo/redo lists; note that UndoRedo::UndoRedo has added // a scriptstart node to undolist if inscript is true, but we don't // want that here because the old layer's history will already have one ClearUndoHistory(); ClearRedoHistory(); // safer to do our own shallow copy (avoids setting undolist/redolist) savecellchanges = history->savecellchanges; savegenchanges = history->savegenchanges; doingscriptchanges = history->doingscriptchanges; numchanges = history->numchanges; maxchanges = history->maxchanges; badalloc = history->badalloc; prevfile = history->prevfile; prevgen = history->prevgen; prevx = history->prevx; prevy = history->prevy; prevmag = history->prevmag; prevbase = history->prevbase; prevexpo = history->prevexpo; prevsel = history->prevsel; startcount = history->startcount; fixsetgen = history->fixsetgen; // copy existing temporary file to new name if ( !prevfile.empty() && FileExists(prevfile) ) { prevfile = CreateTempFileName(temp_prefix); if ( !CopyFile(history->prevfile, prevfile) ) { Warning("Could not copy prevfile!"); return; } } // do a deep copy of dynamically allocated data cellarray = NULL; if (numchanges > 0 && history->cellarray) { cellarray = (cell_change*) malloc(maxchanges * sizeof(cell_change)); if (cellarray == NULL) { Warning("Could not allocate cellarray!"); return; } // copy history->cellarray data to this cellarray memcpy(cellarray, history->cellarray, numchanges * sizeof(cell_change)); } std::list::iterator node; // build a new undolist using history->undolist node = history->undolist.begin(); while (node != undolist.end()) { ChangeNode* change = *node; ChangeNode* newchange = new ChangeNode(change->changeid); if (newchange == NULL) { Warning("Failed to copy undolist!"); ClearUndoHistory(); return; } // shallow copy the change node *newchange = *change; // deep copy any dynamically allocated data if (change->cellinfo) { int bytes = change->cellcount * sizeof(cell_change); newchange->cellinfo = (cell_change*) malloc(bytes); if (newchange->cellinfo == NULL) { Warning("Could not copy undolist!"); ClearUndoHistory(); return; } memcpy(newchange->cellinfo, change->cellinfo, bytes); } // copy any existing temporary files to new names if (!CopyTempFiles(change, newchange, newlayer->tempstart.c_str())) { Warning("Failed to copy temporary file in undolist!"); ClearUndoHistory(); return; } // if node is a name change then update whichlayer to point to new layer if (newchange->changeid == namechange) { newchange->whichlayer = newlayer; } undolist.push_back(newchange); node++; } // build a new redolist using history->redolist node = history->redolist.begin(); while (node != redolist.end()) { ChangeNode* change = *node; ChangeNode* newchange = new ChangeNode(change->changeid); if (newchange == NULL) { Warning("Failed to copy redolist!"); ClearRedoHistory(); return; } // shallow copy the change node *newchange = *change; // deep copy any dynamically allocated data if (change->cellinfo) { int bytes = change->cellcount * sizeof(cell_change); newchange->cellinfo = (cell_change*) malloc(bytes); if (newchange->cellinfo == NULL) { Warning("Could not copy redolist!"); ClearRedoHistory(); return; } memcpy(newchange->cellinfo, change->cellinfo, bytes); } // copy any existing temporary files to new names if (!CopyTempFiles(change, newchange, newlayer->tempstart.c_str())) { Warning("Failed to copy temporary file in redolist!"); ClearRedoHistory(); return; } // if node is a name change then update whichlayer to point to new layer if (newchange->changeid == namechange) { newchange->whichlayer = newlayer; } redolist.push_back(newchange); node++; } } golly-2.7-src/gui-common/view.h0000644000175000017500000000675612536111364013433 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _VIEW_H_ #define _VIEW_H_ #include "bigint.h" // for bigint #include "lifealgo.h" // for lifealgo #include "utils.h" // for gRect // Data and routines for viewing and editing patterns: extern const char* empty_selection; extern const char* empty_outside; extern const char* no_selection; extern const char* selection_too_big; extern const char* pattern_too_big; extern const char* origin_restored; extern bool widescreen; // is screen wide enough to show all info? extern bool fullscreen; // in full screen mode? extern bool nopattupdate; // disable pattern updates? extern bool waitingforpaste; // waiting for user to decide what to do with paste image? extern gRect pasterect; // bounding box of paste image extern int pastex, pastey; // where user wants to paste clipboard pattern extern bool draw_pending; // delay drawing? extern int pendingx, pendingy; // start of delayed drawing void UpdateEverything(); void UpdatePatternAndStatus(); bool OutsideLimits(bigint& t, bigint& l, bigint& b, bigint& r); void TestAutoFit(); void FitInView(int force); void TouchBegan(int x, int y); void TouchMoved(int x, int y); void TouchEnded(); bool CopyRect(int top, int left, int bottom, int right, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, const char* progmsg); void CopyAllRect(int top, int left, int bottom, int right, lifealgo* srcalgo, lifealgo* destalgo, const char* progmsg); bool SelectionExists(); void SelectAll(); void RemoveSelection(); void FitSelection(); void DisplaySelectionSize(); void SaveCurrentSelection(); void RememberNewSelection(const char* action); void CutSelection(); void CopySelection(); void ClearSelection(); void ClearOutsideSelection(); void ShrinkSelection(bool fit); void RandomFill(); bool FlipSelection(bool topbottom, bool inundoredo = false); bool RotateSelection(bool clockwise, bool inundoredo = false); bool ClipboardContainsRule(); void PasteClipboard(); bool FlipPastePattern(bool topbottom); bool RotatePastePattern(bool clockwise); void DoPaste(bool toselection); void AbortPaste(); void ZoomInPos(int x, int y); void ZoomOutPos(int x, int y); bool PointInView(int x, int y); bool PointInPasteImage(int x, int y); bool PointInSelection(int x, int y); bool PointInGrid(int x, int y); bool CellInGrid(const bigint& x, const bigint& y); void PanUp(int amount); void PanDown(int amount); void PanLeft(int amount); void PanRight(int amount); void PanNE(); void PanNW(); void PanSE(); void PanSW(); int SmallScroll(int xysize); int BigScroll(int xysize); #endif golly-2.7-src/gui-common/prefs.cpp0000644000175000017500000005660412536111364014130 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "lifealgo.h" #include "viewport.h" // for MAX_MAG #include "util.h" // for linereader, lifeerrors #include "utils.h" // for gColor, SetColor, Warning, Fatal, Beep #include "status.h" // for DisplayMessage #include "algos.h" // for NumAlgos, algoinfo, etc #include "layer.h" // for currlayer #include "prefs.h" #ifdef ANDROID_GUI #include "jnicalls.h" // for BeginProgress, etc #endif #ifdef WEB_GUI #include "webcalls.h" // for BeginProgress, etc #endif #ifdef IOS_GUI #import "PatternViewController.h" // for BeginProgress, etc #endif // ----------------------------------------------------------------------------- // Golly's preferences file is a simple text file. const int PREFS_VERSION = 1; // increment if necessary due to changes in syntax/semantics int currversion = PREFS_VERSION; // might be changed by prefs_version const int PREF_LINE_SIZE = 5000; // must be quite long for storing file paths std::string supplieddir; // path of parent directory for supplied help/patterns/rules std::string helpdir; // path of directory for supplied help std::string patternsdir; // path of directory for supplied patterns std::string rulesdir; // path of directory for supplied rules std::string userdir; // path of parent directory for user's rules/patterns/downloads std::string userrules; // path of directory for user's rules std::string savedir; // path of directory for user's saved patterns std::string downloaddir; // path of directory for user's downloaded files std::string tempdir; // path of directory for temporary data std::string clipfile; // path of temporary file for storing clipboard data std::string prefsfile; // path of file for storing user's preferences // initialize exported preferences: int debuglevel = 0; // for displaying debug info if > 0 int helpfontsize = 10; // font size in help window char initrule[256] = "B3/S23"; // initial rule bool initautofit = false; // initial autofit setting bool inithyperspeed = false; // initial hyperspeed setting bool initshowhashinfo = false; // initial showhashinfo setting bool savexrle = true; // save RLE file using XRLE format? bool showtool = true; // show tool bar? bool showlayer = false; // show layer bar? bool showedit = true; // show edit bar? bool showallstates = false; // show all cell states in edit bar? bool showstatus = true; // show status bar? bool showexact = false; // show exact numbers in status bar? bool showtimeline = false; // show timeline bar? bool showtiming = false; // show timing messages? bool showgridlines = true; // display grid lines? bool showicons = false; // display icons for cell states? bool swapcolors = false; // swap colors used for cell states? bool allowundo = true; // allow undo/redo? bool allowbeep = true; // okay to play beep sound? bool restoreview = true; // should reset/undo restore view? int canchangerule = 1; // if > 0 then paste can change rule (1 means change rule only if pattern is empty) int randomfill = 50; // random fill percentage (1..100) int opacity = 80; // percentage opacity of live cells in overlays (1..100) int tileborder = 3; // thickness of tiled window borders int mingridmag = 2; // minimum mag to draw grid lines int boldspacing = 10; // spacing of bold grid lines bool showboldlines = true; // show bold grid lines? bool mathcoords = false; // show Y values increasing upwards? bool syncviews = false; // synchronize viewports? bool syncmodes = true; // synchronize touch modes? bool stacklayers = false; // stack all layers? bool tilelayers = false; // tile all layers? bool asktosave = true; // ask to save changes? int newmag = 5; // mag setting for new pattern bool newremovesel = true; // new pattern removes selection? bool openremovesel = true; // opening pattern removes selection? int mindelay = 250; // minimum millisec delay int maxdelay = 2000; // maximum millisec delay int maxhashmem = 100; // maximum memory (in MB) for hashlife-based algos int numpatterns = 0; // current number of recent pattern files int maxpatterns = 20; // maximum number of recent pattern files std::list recentpatterns; // list of recent pattern files gColor borderrgb; // color for border around bounded grid gColor selectrgb; // color for selected cells gColor pastergb; // color for pasted pattern paste_mode pmode = Or; // logical paste mode // ----------------------------------------------------------------------------- const char* GetPasteMode() { switch (pmode) { case And: return "AND"; case Copy: return "COPY"; case Or: return "OR"; case Xor: return "XOR"; default: return "unknown"; } } // ----------------------------------------------------------------------------- void SetPasteMode(const char* s) { if (strcmp(s, "AND") == 0) { pmode = And; } else if (strcmp(s, "COPY") == 0) { pmode = Copy; } else if (strcmp(s, "OR") == 0) { pmode = Or; } else { pmode = Xor; } } // ----------------------------------------------------------------------------- void CreateDefaultColors() { SetColor(borderrgb, 128, 128, 128); // 50% gray SetColor(selectrgb, 75, 175, 0); // dark green SetColor(pastergb, 255, 0, 0); // red } // ----------------------------------------------------------------------------- void GetColor(const char* value, gColor& rgb) { unsigned int r, g, b; sscanf(value, "%u,%u,%u", &r, &g, &b); SetColor(rgb, r, g, b); } // ----------------------------------------------------------------------------- void SaveColor(FILE* f, const char* name, const gColor rgb) { fprintf(f, "%s=%u,%u,%u\n", name, rgb.r, rgb.g, rgb.b); } // ----------------------------------------------------------------------------- void SavePrefs() { if (currlayer == NULL) { // should never happen but play safe Warning("Bug: currlayer is NULL!"); return; } FILE* f = fopen(prefsfile.c_str(), "w"); if (f == NULL) { Warning("Could not save preferences file!"); return; } fprintf(f, "prefs_version=%d\n", PREFS_VERSION); fprintf(f, "debug_level=%d\n", debuglevel); fprintf(f, "help_font_size=%d (%d..%d)\n", helpfontsize, minfontsize, maxfontsize); fprintf(f, "allow_undo=%d\n", allowundo ? 1 : 0); fprintf(f, "allow_beep=%d\n", allowbeep ? 1 : 0); fprintf(f, "restore_view=%d\n", restoreview ? 1 : 0); fprintf(f, "paste_mode=%s\n", GetPasteMode()); fprintf(f, "can_change_rule=%d (0..2)\n", canchangerule); fprintf(f, "random_fill=%d (1..100)\n", randomfill); fprintf(f, "min_delay=%d (0..%d millisecs)\n", mindelay, MAX_DELAY); fprintf(f, "max_delay=%d (0..%d millisecs)\n", maxdelay, MAX_DELAY); fprintf(f, "auto_fit=%d\n", currlayer->autofit ? 1 : 0); fprintf(f, "hyperspeed=%d\n", currlayer->hyperspeed ? 1 : 0); fprintf(f, "hash_info=%d\n", currlayer->showhashinfo ? 1 : 0); fprintf(f, "max_hash_mem=%d\n", maxhashmem); fputs("\n", f); fprintf(f, "init_algo=%s\n", GetAlgoName(currlayer->algtype)); for (int i = 0; i < NumAlgos(); i++) { fputs("\n", f); fprintf(f, "algorithm=%s\n", GetAlgoName(i)); fprintf(f, "base_step=%d\n", algoinfo[i]->defbase); SaveColor(f, "status_rgb", algoinfo[i]->statusrgb); SaveColor(f, "from_rgb", algoinfo[i]->fromrgb); SaveColor(f, "to_rgb", algoinfo[i]->torgb); fprintf(f, "use_gradient=%d\n", algoinfo[i]->gradient ? 1 : 0); fputs("colors=", f); for (int state = 0; state < algoinfo[i]->maxstates; state++) { // only write out state,r,g,b tuple if color is different to default if (algoinfo[i]->algor[state] != algoinfo[i]->defr[state] || algoinfo[i]->algog[state] != algoinfo[i]->defg[state] || algoinfo[i]->algob[state] != algoinfo[i]->defb[state] ) { fprintf(f, "%d,%d,%d,%d,", state, algoinfo[i]->algor[state], algoinfo[i]->algog[state], algoinfo[i]->algob[state]); } } fputs("\n", f); } fputs("\n", f); fprintf(f, "rule=%s\n", currlayer->algo->getrule()); fprintf(f, "show_tool=%d\n", showtool ? 1 : 0); fprintf(f, "show_layer=%d\n", showlayer ? 1 : 0); fprintf(f, "show_edit=%d\n", showedit ? 1 : 0); fprintf(f, "show_states=%d\n", showallstates ? 1 : 0); fprintf(f, "show_status=%d\n", showstatus ? 1 : 0); fprintf(f, "show_exact=%d\n", showexact ? 1 : 0); fprintf(f, "show_timeline=%d\n", showtimeline ? 1 : 0); fprintf(f, "show_timing=%d\n", showtiming ? 1 : 0); fprintf(f, "grid_lines=%d\n", showgridlines ? 1 : 0); fprintf(f, "min_grid_mag=%d (2..%d)\n", mingridmag, MAX_MAG); fprintf(f, "bold_spacing=%d (2..%d)\n", boldspacing, MAX_SPACING); fprintf(f, "show_bold_lines=%d\n", showboldlines ? 1 : 0); fprintf(f, "math_coords=%d\n", mathcoords ? 1 : 0); fputs("\n", f); fprintf(f, "sync_views=%d\n", syncviews ? 1 : 0); fprintf(f, "sync_modes=%d\n", syncmodes ? 1 : 0); fprintf(f, "stack_layers=%d\n", stacklayers ? 1 : 0); fprintf(f, "tile_layers=%d\n", tilelayers ? 1 : 0); fprintf(f, "tile_border=%d (1..10)\n", tileborder); fprintf(f, "ask_to_save=%d\n", asktosave ? 1 : 0); fputs("\n", f); fprintf(f, "show_icons=%d\n", showicons ? 1 : 0); fprintf(f, "swap_colors=%d\n", swapcolors ? 1 : 0); fprintf(f, "opacity=%d (1..100)\n", opacity); SaveColor(f, "border_rgb", borderrgb); SaveColor(f, "select_rgb", selectrgb); SaveColor(f, "paste_rgb", pastergb); fputs("\n", f); fprintf(f, "new_mag=%d (0..%d)\n", newmag, MAX_MAG); fprintf(f, "new_remove_sel=%d\n", newremovesel ? 1 : 0); fprintf(f, "open_remove_sel=%d\n", openremovesel ? 1 : 0); fprintf(f, "save_xrle=%d\n", savexrle ? 1 : 0); fprintf(f, "max_patterns=%d (1..%d)\n", maxpatterns, MAX_RECENT); if (!recentpatterns.empty()) { fputs("\n", f); std::list::iterator next = recentpatterns.begin(); while (next != recentpatterns.end()) { std::string path = *next; fprintf(f, "recent_pattern=%s\n", path.c_str()); next++; } } fclose(f); } // ----------------------------------------------------------------------------- bool GetKeywordAndValue(linereader& lr, char* line, char** keyword, char** value) { // the linereader class handles all line endings (CR, CR+LF, LF) // and terminates line buffer with \0 while ( lr.fgets(line, PREF_LINE_SIZE) != 0 ) { if ( line[0] == '#' || line[0] == 0 ) { // skip comment line or empty line } else { // line should have format keyword=value *keyword = line; *value = line; while ( **value != '=' && **value != 0 ) *value += 1; **value = 0; // terminate keyword *value += 1; return true; } } return false; } // ----------------------------------------------------------------------------- char* ReplaceDeprecatedAlgo(char* algoname) { if (strcmp(algoname, "RuleTable") == 0 || strcmp(algoname, "RuleTree") == 0) { // RuleTable and RuleTree algos have been replaced by RuleLoader return (char*)"RuleLoader"; } else { return algoname; } } // ----------------------------------------------------------------------------- // let gollybase code call Fatal, Warning, BeginProgress, etc class my_errors : public lifeerrors { public: virtual void fatal(const char* s) { Fatal(s); } virtual void warning(const char* s) { Warning(s); } virtual void status(const char* s) { DisplayMessage(s); } virtual void beginprogress(const char* s) { BeginProgress(s); // init flag for isaborted() calls aborted = false; } virtual bool abortprogress(double f, const char* s) { return AbortProgress(f, s); } virtual void endprogress() { EndProgress(); } virtual const char* getuserrules() { return (const char*) userrules.c_str(); } virtual const char* getrulesdir() { return (const char*) rulesdir.c_str(); } }; static my_errors myerrhandler; // create instance // ----------------------------------------------------------------------------- void GetPrefs() { int algoindex = -1; // unknown algorithm // let gollybase code call Fatal, Warning, BeginProgress, etc lifeerrors::seterrorhandler(&myerrhandler); CreateDefaultColors(); FILE* f = fopen(prefsfile.c_str(), "r"); if (f == NULL) { // should only happen 1st time app is run return; } linereader reader(f); char line[PREF_LINE_SIZE]; char* keyword; char* value; while ( GetKeywordAndValue(reader, line, &keyword, &value) ) { if (strcmp(keyword, "prefs_version") == 0) { sscanf(value, "%d", &currversion); } else if (strcmp(keyword, "debug_level") == 0) { sscanf(value, "%d", &debuglevel); } else if (strcmp(keyword, "help_font_size") == 0) { sscanf(value, "%d", &helpfontsize); if (helpfontsize < minfontsize) helpfontsize = minfontsize; if (helpfontsize > maxfontsize) helpfontsize = maxfontsize; } else if (strcmp(keyword, "allow_undo") == 0) { allowundo = value[0] == '1'; } else if (strcmp(keyword, "allow_beep") == 0) { allowbeep = value[0] == '1'; } else if (strcmp(keyword, "restore_view") == 0) { restoreview = value[0] == '1'; } else if (strcmp(keyword, "paste_mode") == 0) { SetPasteMode(value); } else if (strcmp(keyword, "can_change_rule") == 0) { sscanf(value, "%d", &canchangerule); if (canchangerule < 0) canchangerule = 0; if (canchangerule > 2) canchangerule = 2; } else if (strcmp(keyword, "random_fill") == 0) { sscanf(value, "%d", &randomfill); if (randomfill < 1) randomfill = 1; if (randomfill > 100) randomfill = 100; } else if (strcmp(keyword, "algorithm") == 0) { if (strcmp(value, "RuleTable") == 0) { // use deprecated RuleTable settings for RuleLoader // (deprecated RuleTree settings will simply be ignored) value = (char*)"RuleLoader"; } algoindex = -1; for (int i = 0; i < NumAlgos(); i++) { if (strcmp(value, GetAlgoName(i)) == 0) { algoindex = i; break; } } } else if (strcmp(keyword, "base_step") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) { int base; sscanf(value, "%d", &base); if (base < 2) base = 2; if (base > MAX_BASESTEP) base = MAX_BASESTEP; algoinfo[algoindex]->defbase = base; } } else if (strcmp(keyword, "status_rgb") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) GetColor(value, algoinfo[algoindex]->statusrgb); } else if (strcmp(keyword, "from_rgb") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) GetColor(value, algoinfo[algoindex]->fromrgb); } else if (strcmp(keyword, "to_rgb") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) GetColor(value, algoinfo[algoindex]->torgb); } else if (strcmp(keyword, "use_gradient") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) algoinfo[algoindex]->gradient = value[0] == '1'; } else if (strcmp(keyword, "colors") == 0) { if (algoindex >= 0 && algoindex < NumAlgos()) { int state, r, g, b; while (sscanf(value, "%d,%d,%d,%d,", &state, &r, &g, &b) == 4) { if (state >= 0 && state < algoinfo[algoindex]->maxstates) { algoinfo[algoindex]->algor[state] = r; algoinfo[algoindex]->algog[state] = g; algoinfo[algoindex]->algob[state] = b; } while (*value != ',') value++; value++; while (*value != ',') value++; value++; while (*value != ',') value++; value++; while (*value != ',') value++; value++; } } } else if (strcmp(keyword, "min_delay") == 0) { sscanf(value, "%d", &mindelay); if (mindelay < 0) mindelay = 0; if (mindelay > MAX_DELAY) mindelay = MAX_DELAY; } else if (strcmp(keyword, "max_delay") == 0) { sscanf(value, "%d", &maxdelay); if (maxdelay < 0) maxdelay = 0; if (maxdelay > MAX_DELAY) maxdelay = MAX_DELAY; } else if (strcmp(keyword, "auto_fit") == 0) { initautofit = value[0] == '1'; } else if (strcmp(keyword, "init_algo") == 0) { value = ReplaceDeprecatedAlgo(value); int i = staticAlgoInfo::nameToIndex(value); if (i >= 0 && i < NumAlgos()) initalgo = i; } else if (strcmp(keyword, "hyperspeed") == 0) { inithyperspeed = value[0] == '1'; } else if (strcmp(keyword, "hash_info") == 0) { initshowhashinfo = value[0] == '1'; } else if (strcmp(keyword, "max_hash_mem") == 0) { sscanf(value, "%d", &maxhashmem); if (maxhashmem < MIN_MEM_MB) maxhashmem = MIN_MEM_MB; if (maxhashmem > MAX_MEM_MB) maxhashmem = MAX_MEM_MB; } else if (strcmp(keyword, "rule") == 0) { strncpy(initrule, value, sizeof(initrule)); } else if (strcmp(keyword, "show_tool") == 0) { showtool = value[0] == '1'; } else if (strcmp(keyword, "show_layer") == 0) { showlayer = value[0] == '1'; } else if (strcmp(keyword, "show_edit") == 0) { showedit = value[0] == '1'; } else if (strcmp(keyword, "show_states") == 0) { showallstates = value[0] == '1'; } else if (strcmp(keyword, "show_status") == 0) { showstatus = value[0] == '1'; } else if (strcmp(keyword, "show_exact") == 0) { showexact = value[0] == '1'; } else if (strcmp(keyword, "show_timeline") == 0) { showtimeline = value[0] == '1'; } else if (strcmp(keyword, "show_timing") == 0) { showtiming = value[0] == '1'; } else if (strcmp(keyword, "grid_lines") == 0) { showgridlines = value[0] == '1'; } else if (strcmp(keyword, "min_grid_mag") == 0) { sscanf(value, "%d", &mingridmag); if (mingridmag < 2) mingridmag = 2; if (mingridmag > MAX_MAG) mingridmag = MAX_MAG; } else if (strcmp(keyword, "bold_spacing") == 0) { sscanf(value, "%d", &boldspacing); if (boldspacing < 2) boldspacing = 2; if (boldspacing > MAX_SPACING) boldspacing = MAX_SPACING; } else if (strcmp(keyword, "show_bold_lines") == 0) { showboldlines = value[0] == '1'; } else if (strcmp(keyword, "math_coords") == 0) { mathcoords = value[0] == '1'; } else if (strcmp(keyword, "sync_views") == 0) { syncviews = value[0] == '1'; } else if (strcmp(keyword, "sync_modes") == 0) { syncmodes = value[0] == '1'; } else if (strcmp(keyword, "stack_layers") == 0) { stacklayers = value[0] == '1'; } else if (strcmp(keyword, "tile_layers") == 0) { tilelayers = value[0] == '1'; } else if (strcmp(keyword, "tile_border") == 0) { sscanf(value, "%d", &tileborder); if (tileborder < 1) tileborder = 1; if (tileborder > 10) tileborder = 10; } else if (strcmp(keyword, "ask_to_save") == 0) { asktosave = value[0] == '1'; } else if (strcmp(keyword, "show_icons") == 0) { showicons = value[0] == '1'; } else if (strcmp(keyword, "swap_colors") == 0) { swapcolors = value[0] == '1'; } else if (strcmp(keyword, "opacity") == 0) { sscanf(value, "%d", &opacity); if (opacity < 1) opacity = 1; if (opacity > 100) opacity = 100; } else if (strcmp(keyword, "border_rgb") == 0) { GetColor(value, borderrgb); } else if (strcmp(keyword, "select_rgb") == 0) { GetColor(value, selectrgb); } else if (strcmp(keyword, "paste_rgb") == 0) { GetColor(value, pastergb); } else if (strcmp(keyword, "new_mag") == 0) { sscanf(value, "%d", &newmag); if (newmag < 0) newmag = 0; if (newmag > MAX_MAG) newmag = MAX_MAG; } else if (strcmp(keyword, "new_remove_sel") == 0) { newremovesel = value[0] == '1'; } else if (strcmp(keyword, "open_remove_sel") == 0) { openremovesel = value[0] == '1'; } else if (strcmp(keyword, "save_xrle") == 0) { savexrle = value[0] == '1'; } else if (strcmp(keyword, "max_patterns") == 0) { sscanf(value, "%d", &maxpatterns); if (maxpatterns < 1) maxpatterns = 1; if (maxpatterns > MAX_RECENT) maxpatterns = MAX_RECENT; } else if (strcmp(keyword, "recent_pattern") == 0) { if (numpatterns < maxpatterns && value[0]) { // append path to recentpatterns if file exists std::string path = value; if (path.find("Patterns/") == 0 || FileExists(userdir + path)) { recentpatterns.push_back(path); numpatterns++; } } } } reader.close(); // stacklayers and tilelayers must not both be true if (stacklayers && tilelayers) tilelayers = false; } golly-2.7-src/gui-common/undo.h0000644000175000017500000001407312536111364013415 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _UNDO_H_ #define _UNDO_H_ #include "bigint.h" // for bigint class #include "select.h" // for Selection class #include "algos.h" // for algo_type #include // for std::string #include // for std::list class ChangeNode; class Layer; // Golly supports unlimited undo/redo: typedef struct { int x; // cell's x position int y; // cell's y position int oldstate; // old state int newstate; // new state } cell_change; // stores a single cell change class UndoRedo { public: UndoRedo(); ~UndoRedo(); void SaveCellChange(int x, int y, int oldstate, int newstate); // cell at x,y has changed state void ForgetCellChanges(); // ignore cell changes made by any previous SaveCellChange calls bool RememberCellChanges(const char* action, bool olddirty); // remember cell changes made by any previous SaveCellChange calls, // and the state of the layer's dirty flag BEFORE the change; // the given action string will be appended to the Undo/Redo items; // return true if one or more cells changed state, false otherwise void RememberFlip(bool topbot, bool olddirty); // remember flip's direction void RememberRotation(bool clockwise, bool olddirty); // remember simple rotation (selection includes entire pattern) void RememberRotation(bool clockwise, Selection& oldsel, Selection& newsel, bool olddirty); // remember rotation's direction and old and new selections; // this variant assumes SaveCellChange may have been called void RememberSelection(const char* action); // remember selection change (no-op if selection hasn't changed) void RememberGenStart(); // remember info before generating the current pattern void RememberGenFinish(); // remember generating change after pattern has finished generating void AddGenChange(); // in some situations the undo list is empty but ResetPattern can still // be called because the gen count is > startgen, so this routine adds // a generating change to the undo list so the user can Undo or Reset // (and then Redo if they wish) void SyncUndoHistory(); // called by ResetPattern to synchronize the undo history void RememberSetGen(bigint& oldgen, bigint& newgen, bigint& oldstartgen, bool oldsave); // remember change of generation count void RememberNameChange(const char* oldname, const char* oldcurrfile, bool oldsave, bool olddirty); // remember change to current layer's name void DeletingClone(int index); // the given cloned layer is about to be deleted, so we must ignore // any later name changes involving this layer void RememberRuleChange(const char* oldrule); // remember rule change void RememberAlgoChange(algo_type oldalgo, const char* oldrule); // remember algorithm change, including a possible rule change // and possible cell changes (SaveCellChange may have been called) void RememberScriptStart(); // remember that script is about to start; this allows us to undo/redo // any changes made by the script all at once void RememberScriptFinish(); // remember that script has ended void DuplicateHistory(Layer* oldlayer, Layer* newlayer); // duplicate old layer's undo/redo history in new layer bool savecellchanges; // script's cell changes need to be remembered? bool savegenchanges; // script's gen changes need to be remembered? bool doingscriptchanges; // are script's changes being undone/redone? bool CanUndo(); // can a change be undone? bool CanRedo(); // can an undone change be redone? void UndoChange(); // undo a change void RedoChange(); // redo an undone change void ClearUndoRedo(); // clear all undo/redo history private: std::list undolist; // list of undoable changes std::list redolist; // list of redoable changes cell_change* cellarray; // dynamic array of cell changes unsigned int numchanges; // number of cell changes unsigned int maxchanges; // number allocated bool badalloc; // malloc/realloc failed? std::string prevfile; // for saving pattern at start of gen change bigint prevgen; // generation count at start of gen change bigint prevx, prevy; // viewport position at start of gen change int prevmag; // scale at start of gen change int prevbase; // base step at start of gen change int prevexpo; // step exponent at start of gen change Selection prevsel; // selection at start of gen change int startcount; // unfinished RememberGenStart calls bool fixsetgen; // setgen node needs to be updated? void ClearUndoHistory(); // clear undolist void ClearRedoHistory(); // clear redolist void SaveCurrentPattern(const char* tempfile); // save current pattern to given temporary file }; #endif golly-2.7-src/gui-common/control.h0000644000175000017500000000427512536111364014133 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _CONTROL_H_ #define _CONTROL_H_ #include "bigint.h" // for bigint #include "algos.h" // for algo_type #include // for std::string #include // for std::list // Data and routines for generating patterns: extern bool generating; // currently generating pattern? extern int minexpo; // step exponent at maximum delay (must be <= 0) bool StartGenerating(); void StopGenerating(); void NextGeneration(bool useinc); void ResetPattern(bool resetundo = true); void RestorePattern(bigint& gen, const char* filename, bigint& x, bigint& y, int mag, int base, int expo); void SetMinimumStepExponent(); void SetStepExponent(int newexpo); void SetGenIncrement(); bool CreateBorderCells(lifealgo* curralgo); bool DeleteBorderCells(lifealgo* curralgo); void ClearRect(lifealgo* curralgo, int top, int left, int bottom, int right); const char* ChangeGenCount(const char* genstring, bool inundoredo = false); void ClearOutsideGrid(); void ReduceCellStates(int newmaxstate); void ChangeRule(const std::string& rulestring); void ChangeAlgorithm(algo_type newalgotype, const char* newrule = "", bool inundoredo = false); std::string CreateRuleFiles(std::list& deprecated, std::list& keeprules); #endif golly-2.7-src/gui-common/render.cpp0000644000175000017500000015504712536111364014271 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ /* -------------------- Some notes on Golly's display code --------------------- The rectangular area used to display patterns is called the viewport. All drawing in the viewport is done in this module using OpenGL ES. The main rendering routine is DrawPattern() -- see the end of this module. DrawPattern() does the following tasks: - Calls currlayer->algo->draw() to draw the current pattern. It passes in renderer, an instance of golly_render (derived from liferender) which has these methods: - pixblit() draws a pixmap containing at least one live cell. - getcolors() provides access to the current layer's color arrays. Note that currlayer->algo->draw() does all the hard work of figuring out which parts of the viewport are dead and building all the pixmaps for the live parts. The pixmaps contain suitably shrunken images when the scale is < 1:1 (ie. mag < 0). - Calls DrawGridLines() to overlay grid lines if they are visible. - Calls DrawGridBorder() to draw border around a bounded universe. - Calls DrawSelection() to overlay a translucent selection rectangle if a selection exists and any part of it is visible. - If the user is doing a paste, DrawPasteImage() draws the paste pattern stored in pastealgo. ----------------------------------------------------------------------------- */ #include "bigint.h" #include "lifealgo.h" #include "viewport.h" #include "utils.h" // for Warning, Fatal, etc #include "prefs.h" // for showgridlines, mingridmag, swapcolors, etc #include "algos.h" // for gBitmapPtr #include "layer.h" // currlayer, GetLayer, etc #include "view.h" // nopattupdate, waitingforpaste, pasterect, pastex, pastey, etc #include "render.h" #ifdef ANDROID_GUI // the Android version uses OpenGL ES 1 #include #endif #ifdef IOS_GUI // the iOS version uses OpenGL ES 1 #import #import #endif #ifdef WEB_GUI // the web version uses OpenGL ES 2 #include #endif // ----------------------------------------------------------------------------- // local data used in golly_render routines: static int currwd, currht; // current width and height of viewport, in pixels static unsigned char** icontextures; // pointers to texture data for each icon static GLuint texture8 = 0; // texture for drawing 7x7 icons static GLuint texture16 = 0; // texture for drawing 15x15 icons static GLuint texture32 = 0; // texture for drawing 31x31 icons static GLuint patternTexture = 0; // texture for drawing pattern bitmaps at 1:1 scale // fixed texture coordinates used by glTexCoordPointer static const GLshort texture_coordinates[] = { 0,0, 1,0, 0,1, 1,1 }; // for drawing paste pattern static lifealgo* pastealgo; // universe containing paste pattern static gRect pastebbox; // bounding box in cell coords (not necessarily minimal) static bool drawing_paste = false; // in DrawPasteImage? /*!!! // for drawing multiple layers static int layerwd = -1; // width of layer bitmap static int layerht = -1; // height of layer bitmap static wxBitmap* layerbitmap = NULL; // layer bitmap */ // ----------------------------------------------------------------------------- #ifdef WEB_GUI // the following 2 macros convert x,y positions in Golly's preferred coordinate // system (where 0,0 is top left corner of viewport and bottom right corner is // currwd,currht) into OpenGL ES 2's normalized coordinates (where 0.0,0.0 is in // middle of viewport, top right corner is 1.0,1.0 and bottom left corner is -1.0,-1.0) #define XCOORD(x) (2.0 * (x) / float(currwd) - 1.0) #define YCOORD(y) -(2.0 * (y) / float(currht) - 1.0) #else // the following 2 macros don't need to do anything because we've already // changed the viewport coordinate system to what Golly wants #define XCOORD(x) x #define YCOORD(y) y #endif // ----------------------------------------------------------------------------- #ifdef WEB_GUI static GLuint LoadShader(GLenum type, const char* shader_source) { // create a shader object, load the shader source, and compile the shader GLuint shader = glCreateShader(type); if (shader == 0) return 0; glShaderSource(shader, 1, &shader_source, NULL); glCompileShader(shader); // check the compile status GLint compiled; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { Warning("Error compiling shader!"); glDeleteShader(shader); return 0; } return shader; } // ----------------------------------------------------------------------------- static GLuint pointProgram; // program object for drawing points, lines, rects static GLint positionLoc; // location of v_Position attribute static GLint pointSizeLoc; // location of PointSize uniform static GLint lineColorLoc; // location of LineColor uniform static GLuint textureProgram; // program object for drawing 2D textures static GLint texPosLoc; // location of a_Position attribute static GLint texCoordLoc; // location of a_texCoord attribute static GLint samplerLoc; // location of s_texture uniform bool InitOGLES2() { // initialize the shaders and program objects required by OpenGL ES 2 // (based on OpenGL's Hello_Triangle.c and Simple_Texture2D.c) // vertex shader used in pointProgram GLbyte v1ShaderStr[] = "attribute vec4 v_Position; \n" "uniform float PointSize; \n" "void main() { \n" " gl_Position = v_Position;\n" " gl_PointSize = PointSize;\n" "} \n"; // fragment shader used in pointProgram GLbyte f1ShaderStr[] = "uniform lowp vec4 LineColor; \n" "void main() { \n" " gl_FragColor = LineColor;\n" "} \n"; // vertex shader used in textureProgram GLbyte v2ShaderStr[] = "attribute vec4 a_Position; \n" "attribute vec2 a_texCoord; \n" "varying vec2 v_texCoord; \n" "void main() { \n" " gl_Position = a_Position;\n" " v_texCoord = a_texCoord; \n" "} \n"; // fragment shader used in textureProgram GLbyte f2ShaderStr[] = "precision mediump float; \n" "varying vec2 v_texCoord; \n" "uniform sampler2D s_texture; \n" "void main() \n" "{ \n" " gl_FragColor = texture2D(s_texture, v_texCoord);\n" "} \n"; GLuint vertex1Shader, fragment1Shader; GLuint vertex2Shader, fragment2Shader; // load the vertex/fragment shaders vertex1Shader = LoadShader(GL_VERTEX_SHADER, (const char*) v1ShaderStr); vertex2Shader = LoadShader(GL_VERTEX_SHADER, (const char*) v2ShaderStr); fragment1Shader = LoadShader(GL_FRAGMENT_SHADER, (const char*) f1ShaderStr); fragment2Shader = LoadShader(GL_FRAGMENT_SHADER, (const char*) f2ShaderStr); // create the program objects pointProgram = glCreateProgram(); if (pointProgram == 0) return false; textureProgram = glCreateProgram(); if (textureProgram == 0) return false; glAttachShader(pointProgram, vertex1Shader); glAttachShader(pointProgram, fragment1Shader); glAttachShader(textureProgram, vertex2Shader); glAttachShader(textureProgram, fragment2Shader); // link the program objects glLinkProgram(pointProgram); glLinkProgram(textureProgram); // check the link status GLint plinked; glGetProgramiv(pointProgram, GL_LINK_STATUS, &plinked); if (!plinked) { Warning("Error linking pointProgram!"); glDeleteProgram(pointProgram); return false; } GLint tlinked; glGetProgramiv(textureProgram, GL_LINK_STATUS, &tlinked); if (!tlinked) { Warning("Error linking textureProgram!"); glDeleteProgram(textureProgram); return false; } // get the attribute and uniform locations // (note that for IE 11 we must set the appropriate program???!!!) glUseProgram(pointProgram); positionLoc = glGetAttribLocation(pointProgram, "v_Position"); pointSizeLoc = glGetUniformLocation(pointProgram, "PointSize"); lineColorLoc = glGetUniformLocation(pointProgram, "LineColor"); if (positionLoc == -1 || pointSizeLoc == -1 || lineColorLoc == -1) { Warning("Failed to get a location in pointProgram!"); glDeleteProgram(pointProgram); return false; } glUseProgram(textureProgram); texPosLoc = glGetAttribLocation(textureProgram, "a_Position"); texCoordLoc = glGetAttribLocation(textureProgram, "a_texCoord"); samplerLoc = glGetUniformLocation (textureProgram, "s_texture"); if (texPosLoc == -1 || texCoordLoc == -1 || samplerLoc == -1) { Warning("Failed to get a location in textureProgram!"); glDeleteProgram(textureProgram); return false; } // create buffer for vertex data GLuint vertexPosObject; glGenBuffers(1, &vertexPosObject); glBindBuffer(GL_ARRAY_BUFFER, vertexPosObject); // create buffer for index data GLuint indexObject; GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; glGenBuffers(1, &indexObject); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexObject); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // use the pointProgram initially glUseProgram(pointProgram); return true; } #endif // WEB_GUI // ----------------------------------------------------------------------------- static void SetColor(int r, int g, int b, int a) { #ifdef WEB_GUI GLfloat color[4]; color[0] = r/255.0; color[1] = g/255.0; color[2] = b/255.0; color[3] = a/255.0; glUniform4fv(lineColorLoc, 1, color); #else glColor4ub(r, g, b, a); #endif } // ----------------------------------------------------------------------------- static void SetPointSize(int ptsize) { #ifdef WEB_GUI glUniform1f(pointSizeLoc, float(ptsize)); #else glPointSize(ptsize); #endif } // ----------------------------------------------------------------------------- static void FillRect(int x, int y, int wd, int ht) { GLfloat rect[] = { XCOORD(x), YCOORD(y+ht), // left, bottom XCOORD(x+wd), YCOORD(y+ht), // right, bottom XCOORD(x+wd), YCOORD(y), // right, top XCOORD(x), YCOORD(y), // left, top }; #ifdef WEB_GUI glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), rect, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else glVertexPointer(2, GL_FLOAT, 0, rect); #endif glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } // ----------------------------------------------------------------------------- static void DisableTextures() { #ifdef WEB_GUI // don't do anything (avoid WebGL warnings) #else if (glIsEnabled(GL_TEXTURE_2D)) { glDisable(GL_TEXTURE_2D); }; #endif } // ----------------------------------------------------------------------------- void DrawTexture(unsigned char* rgbdata, int x, int y, int w, int h) { // called from ios_render::pixblit to draw a pattern bitmap at 1:1 scale if (patternTexture == 0) { // only need to create texture name once glGenTextures(1, &patternTexture); } #ifdef WEB_GUI glUseProgram(textureProgram); glActiveTexture(GL_TEXTURE0); // bind our texture glBindTexture(GL_TEXTURE_2D, patternTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); #else if (!glIsEnabled(GL_TEXTURE_2D)) { // restore texture color and enable textures SetColor(255, 255, 255, 255); glEnable(GL_TEXTURE_2D); // bind our texture glBindTexture(GL_TEXTURE_2D, patternTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexCoordPointer(2, GL_SHORT, 0, texture_coordinates); } #endif // update the texture with the new bitmap data (in RGB format) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, rgbdata); #ifdef WEB_GUI GLfloat vertices[] = { XCOORD(x), YCOORD(y), 0.0, // Position 0 = left,top 0.0, 0.0, // TexCoord 0 XCOORD(x), YCOORD(y + h), 0.0, // Position 1 = left,bottom 0.0, 1.0, // TexCoord 1 XCOORD(x + h), YCOORD(y + h), 0.0, // Position 2 = right,bottom 1.0, 1.0, // TexCoord 2 XCOORD(x + h), YCOORD(y), 0.0, // Position 3 = right,top 1.0, 0.0 // TexCoord 3 }; glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(texPosLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (const GLvoid*)(0)); glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (const GLvoid*)(3 * sizeof(GL_FLOAT))); glEnableVertexAttribArray(texPosLoc); glEnableVertexAttribArray(texCoordLoc); glUniform1i(samplerLoc, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); glUseProgram(pointProgram); #else // we assume w and h are powers of 2 GLfloat vertices[] = { x, y, x+w, y, x, y+h, x+w, y+h, }; glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #endif } // ----------------------------------------------------------------------------- void DrawPoints(unsigned char* rgbdata, int x, int y, int w, int h) { // called from golly_render::pixblit to draw pattern at 1:1 scale // if numstates is 2 or we're drawing the paste image const int maxcoords = 1024; // must be multiple of 2 GLfloat points[maxcoords]; int numcoords = 0; DisableTextures(); SetPointSize(1); unsigned char deadr = currlayer->cellr[0]; unsigned char deadg = currlayer->cellg[0]; unsigned char deadb = currlayer->cellb[0]; unsigned char prevr = deadr; unsigned char prevg = deadg; unsigned char prevb = deadb; SetColor(deadr, deadg, deadb, 255); unsigned char r, g, b; int i = 0; for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { r = rgbdata[i++]; g = rgbdata[i++]; b = rgbdata[i++]; if (r != deadr || g != deadg || b != deadb) { // we've got a live pixel bool changecolor = (r != prevr || g != prevg || b != prevb); if (changecolor || numcoords == maxcoords) { if (numcoords > 0) { #ifdef WEB_GUI glBufferData(GL_ARRAY_BUFFER, numcoords * sizeof(GLfloat), points, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_POINTS, 0, numcoords/2); numcoords = 0; } if (changecolor) { prevr = r; prevg = g; prevb = b; SetColor(r, g, b, 255); } } points[numcoords++] = XCOORD(x + col + 0.5); points[numcoords++] = YCOORD(y + row + 0.5); } } } if (numcoords > 0) { #ifdef WEB_GUI glBufferData(GL_ARRAY_BUFFER, numcoords * sizeof(GLfloat), points, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_POINTS, 0, numcoords/2); } } // ----------------------------------------------------------------------------- static int prevsize = 0; void DrawIcons(unsigned char* statedata, int x, int y, int w, int h, int pmscale, int stride) { // called from golly_render::pixblit to draw icons for each live cell; // assume pmscale > 2 (should be 8, 16 or 32 or 64) int iconsize = pmscale; // on high density screens the max scale is 1:64, but instead of // supporting 63x63 icons we simply scale up the 31x31 icons // (leaving a barely noticeable 1px gap at the right and bottom edges) if (pmscale == 64) { iconsize = 32; } // create icon textures once if (texture8 == 0) glGenTextures(1, &texture8); if (texture16 == 0) glGenTextures(1, &texture16); if (texture32 == 0) glGenTextures(1, &texture32); #ifdef WEB_GUI glUseProgram(textureProgram); glActiveTexture(GL_TEXTURE0); prevsize = 0; // always rebind #else if (!glIsEnabled(GL_TEXTURE_2D)) { // restore texture color and enable textures SetColor(255, 255, 255, 255); glEnable(GL_TEXTURE_2D); prevsize = 0; // force rebinding } #endif if (iconsize != prevsize) { prevsize = iconsize; // bind appropriate icon texture if (iconsize == 8) glBindTexture(GL_TEXTURE_2D, texture8); if (iconsize == 16) glBindTexture(GL_TEXTURE_2D, texture16); if (iconsize == 32) glBindTexture(GL_TEXTURE_2D, texture32); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); #ifdef WEB_GUI // no need to do anything here #else glTexCoordPointer(2, GL_SHORT, 0, texture_coordinates); #endif } int prevstate = 0; for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { unsigned char state = statedata[row*stride + col]; if (state > 0 && icontextures[state]) { if (state != prevstate) { prevstate = state; // update the texture with the new icon data (in RGBA format) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iconsize, iconsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, icontextures[state]); } int xpos = x + col * pmscale; int ypos = y + row * pmscale; #ifdef WEB_GUI GLfloat vertices[] = { XCOORD(xpos), YCOORD(ypos), 0.0, // Position 0 = left,top 0.0, 0.0, // TexCoord 0 XCOORD(xpos), YCOORD(ypos + pmscale), 0.0, // Position 1 = left,bottom 0.0, 1.0, // TexCoord 1 XCOORD(xpos + pmscale), YCOORD(ypos + pmscale), 0.0, // Position 2 = right,bottom 1.0, 1.0, // TexCoord 2 XCOORD(xpos + pmscale), YCOORD(ypos), 0.0, // Position 3 = right,top 1.0, 0.0 // TexCoord 3 }; glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(texPosLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (const GLvoid*)(0)); glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (const GLvoid*)(3 * sizeof(GL_FLOAT))); glEnableVertexAttribArray(texPosLoc); glEnableVertexAttribArray(texCoordLoc); glUniform1i(samplerLoc, 0); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); #else GLfloat vertices[] = { xpos, ypos, xpos + pmscale, ypos, xpos, ypos + pmscale, xpos + pmscale, ypos + pmscale, }; glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #endif } } } #ifdef WEB_GUI glUseProgram(pointProgram); #endif } // ----------------------------------------------------------------------------- void DrawMagnifiedTwoStateCells(unsigned char* statedata, int x, int y, int w, int h, int pmscale, int stride) { // called from golly_render::pixblit to draw cells magnified by pmscale (2, 4, ... 2^MAX_MAG) // when number of states is 2 int cellsize = pmscale > 2 ? pmscale - 1 : pmscale; const int maxcoords = 1024; // must be multiple of 2 GLfloat points[maxcoords]; int numcoords = 0; DisableTextures(); SetPointSize(cellsize); // all live cells are in state 1 so only need to set color once SetColor(currlayer->cellr[1], currlayer->cellg[1], currlayer->cellb[1], 255); for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { unsigned char state = statedata[row*stride + col]; if (state > 0) { if (numcoords == maxcoords) { #ifdef WEB_GUI glBufferData(GL_ARRAY_BUFFER, numcoords * sizeof(GLfloat), points, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_POINTS, 0, numcoords/2); numcoords = 0; } // get mid point of cell GLfloat midx = XCOORD(x + col*pmscale + cellsize/2.0); GLfloat midy = YCOORD(y + row*pmscale + cellsize/2.0); #ifdef WEB_GUI if (midx > 1.0 || midy < -1.0) #else if (midx > float(currwd) || midy > float(currht)) #endif { // midx,midy is outside viewport so we need to use FillRect to see partially // visible cell at right/bottom edge FillRect(x + col*pmscale, y + row*pmscale, cellsize, cellsize); } else { points[numcoords++] = midx; points[numcoords++] = midy; } } } } if (numcoords > 0) { #ifdef WEB_GUI glBufferData(GL_ARRAY_BUFFER, numcoords * sizeof(GLfloat), points, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_POINTS, 0, numcoords/2); } } // ----------------------------------------------------------------------------- void DrawMagnifiedCells(unsigned char* statedata, int x, int y, int w, int h, int pmscale, int stride, int numstates) { // called from golly_render::pixblit to draw cells magnified by pmscale (2, 4, ... 2^MAX_MAG) // when numstates is > 2 int cellsize = pmscale > 2 ? pmscale - 1 : pmscale; const int maxcoords = 256; // must be multiple of 2 GLfloat points[256][maxcoords]; int numcoords[256] = {0}; DisableTextures(); SetPointSize(cellsize); // following code minimizes color changes due to state changes for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { unsigned char state = statedata[row*stride + col]; if (state > 0) { if (numcoords[state] == maxcoords) { // this shouldn't happen too often SetColor(currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state], 255); #ifdef WEB_GUI glBufferData(GL_ARRAY_BUFFER, numcoords[state] * sizeof(GLfloat), points[state], GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else glVertexPointer(2, GL_FLOAT, 0, points[state]); #endif glDrawArrays(GL_POINTS, 0, numcoords[state]/2); numcoords[state] = 0; } // get mid point of cell GLfloat midx = XCOORD(x + col*pmscale + cellsize/2.0); GLfloat midy = YCOORD(y + row*pmscale + cellsize/2.0); #ifdef WEB_GUI if (midx > 1.0 || midy < -1.0) #else if (midx > float(currwd) || midy > float(currht)) #endif { // midx,midy is outside viewport so we need to use FillRect to see partially // visible cell at right/bottom edge SetColor(currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state], 255); FillRect(x + col*pmscale, y + row*pmscale, cellsize, cellsize); } else { points[state][numcoords[state]++] = midx; points[state][numcoords[state]++] = midy; } } } } for (int state = 1; state < numstates; state++) { if (numcoords[state] > 0) { SetColor(currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state], 255); #ifdef WEB_GUI glBufferData(GL_ARRAY_BUFFER, numcoords[state] * sizeof(GLfloat), points[state], GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else glVertexPointer(2, GL_FLOAT, 0, points[state]); #endif glDrawArrays(GL_POINTS, 0, numcoords[state]/2); } } } // ----------------------------------------------------------------------------- class golly_render : public liferender { public: golly_render() {} virtual ~golly_render() {} virtual void killrect(int x, int y, int w, int h); virtual void pixblit(int x, int y, int w, int h, char* pm, int pmscale); virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b); }; golly_render renderer; // create instance // ----------------------------------------------------------------------------- void golly_render::killrect(int x, int y, int w, int h) { #if 0 // is Tom's hashdraw code doing unnecessary work??? if (x >= currwd || y >= currht) return; if (x + w <= 0 || y + h <= 0) return; if (w <= 0 || h <= 0) return; // clip given rect so it's within viewport int clipx = x < 0 ? 0 : x; int clipy = y < 0 ? 0 : y; int clipr = x + w; int clipb = y + h; if (clipr > currwd) clipr = currwd; if (clipb > currht) clipb = currht; int clipwd = clipr - clipx; int clipht = clipb - clipy; // use a different pale color each time to see any probs DisableTextures(); SetColor((rand()&127)+128, (rand()&127)+128, (rand()&127)+128, 255); FillRect(clipx, clipy, clipwd, clipht); #else // no need to do anything because background has already been filled by glClear in DrawPattern #endif } // ----------------------------------------------------------------------------- void golly_render::pixblit(int x, int y, int w, int h, char* pmdata, int pmscale) { // is Tom's hashdraw code doing unnecessary work??? if (x >= currwd || y >= currht) return; if (x + w <= 0 || y + h <= 0) return; // stride is the horizontal pixel width of the image data int stride = w/pmscale; // clip data outside viewport if (pmscale > 1) { // pmdata contains 1 byte per `pmscale' pixels, so we must be careful // and adjust x, y, w and h by multiples of `pmscale' only if (x < 0) { int dx = -x/pmscale*pmscale; pmdata += dx/pmscale; w -= dx; x += dx; } if (y < 0) { int dy = -y/pmscale*pmscale; pmdata += dy/pmscale*stride; h -= dy; y += dy; } if (x + w >= currwd + pmscale) w = (currwd - x + pmscale - 1)/pmscale*pmscale; if (y + h >= currht + pmscale) h = (currht - y + pmscale - 1)/pmscale*pmscale; } int numstates = currlayer->algo->NumCellStates(); if (pmscale == 1) { // draw rgb pixel data at scale 1:1 if (drawing_paste || numstates == 2) { // we can't use DrawTexture to draw paste image because glTexImage2D clobbers // any background pattern, so we use DrawPoints which is usually faster than // DrawTexture in a sparsely populated universe with only 2 states (eg. Life) DrawPoints((unsigned char*) pmdata, x, y, w, h); } else { DrawTexture((unsigned char*) pmdata, x, y, w, h); } } else if (showicons && pmscale > 4 && icontextures) { // draw icons at scales 1:8 or above DrawIcons((unsigned char*) pmdata, x, y, w/pmscale, h/pmscale, pmscale, stride); } else { // draw magnified cells, assuming pmdata contains (w/pmscale)*(h/pmscale) bytes // where each byte contains a cell state if (numstates == 2) { DrawMagnifiedTwoStateCells((unsigned char*) pmdata, x, y, w/pmscale, h/pmscale, pmscale, stride); } else { DrawMagnifiedCells((unsigned char*) pmdata, x, y, w/pmscale, h/pmscale, pmscale, stride, numstates); } } } // ----------------------------------------------------------------------------- void golly_render::getcolors(unsigned char** r, unsigned char** g, unsigned char** b) { *r = currlayer->cellr; *g = currlayer->cellg; *b = currlayer->cellb; } // ----------------------------------------------------------------------------- void DrawGridBorder(int wd, int ht) { // universe is bounded so draw any visible border regions pair ltpxl = currlayer->view->screenPosOf(currlayer->algo->gridleft, currlayer->algo->gridtop, currlayer->algo); pair rbpxl = currlayer->view->screenPosOf(currlayer->algo->gridright, currlayer->algo->gridbottom, currlayer->algo); int left = ltpxl.first; int top = ltpxl.second; int right = rbpxl.first; int bottom = rbpxl.second; if (currlayer->algo->gridwd == 0) { left = 0; right = wd-1; } if (currlayer->algo->gridht == 0) { top = 0; bottom = ht-1; } // note that right and/or bottom might be INT_MAX so avoid adding to cause overflow if (currlayer->view->getmag() > 0) { // move to bottom right pixel of cell at gridright,gridbottom if (right < wd) right += (1 << currlayer->view->getmag()) - 1; if (bottom < ht) bottom += (1 << currlayer->view->getmag()) - 1; if (currlayer->view->getmag() == 1) { // there are no gaps at scale 1:2 if (right < wd) right++; if (bottom < ht) bottom++; } } else { if (right < wd) right++; if (bottom < ht) bottom++; } if (left < 0 && right >= wd && top < 0 && bottom >= ht) { // border isn't visible (ie. grid fills viewport) return; } DisableTextures(); SetColor(borderrgb.r, borderrgb.g, borderrgb.b, 255); if (left >= wd || right < 0 || top >= ht || bottom < 0) { // no part of grid is visible so fill viewport with border FillRect(0, 0, wd, ht); return; } // avoid drawing overlapping rects below int rtop = 0; int rheight = ht; if (currlayer->algo->gridht > 0) { if (top > 0) { // top border is visible FillRect(0, 0, wd, top); // reduce size of rect below rtop = top; rheight -= top; } if (bottom < ht) { // bottom border is visible FillRect(0, bottom, wd, ht - bottom); // reduce size of rect below rheight -= ht - bottom; } } if (currlayer->algo->gridwd > 0) { if (left > 0) { // left border is visible FillRect(0, rtop, left, rheight); } if (right < wd) { // right border is visible FillRect(right, rtop, wd - right, rheight); } } } // ----------------------------------------------------------------------------- void DrawSelection(gRect& rect, bool active) { // draw semi-transparent rectangle DisableTextures(); if (active) { SetColor(selectrgb.r, selectrgb.g, selectrgb.b, 128); } else { // use light gray to indicate an inactive selection SetColor(160, 160, 160, 128); } FillRect(rect.x, rect.y, rect.width, rect.height); } // ----------------------------------------------------------------------------- void CreatePasteImage(lifealgo* palgo, gRect& bbox) { // set globals used in DrawPasteImage pastealgo = palgo; pastebbox = bbox; } // ----------------------------------------------------------------------------- void DestroyPasteImage() { // no need to do anything } // ----------------------------------------------------------------------------- int PixelsToCells(int pixels, int mag) { // convert given # of screen pixels to corresponding # of cells if (mag >= 0) { int cellsize = 1 << mag; return (pixels + cellsize - 1) / cellsize; } else { // mag < 0; no need to worry about overflow return pixels << -mag; } } // ----------------------------------------------------------------------------- void SetPasteRect(int wd, int ht) { int x, y, pastewd, pasteht; int mag = currlayer->view->getmag(); // find cell coord of current paste position pair pcell = currlayer->view->at(pastex, pastey); // determine bottom right cell bigint right = pcell.first; right += wd; right -= 1; bigint bottom = pcell.second; bottom += ht; bottom -= 1; // best to use same method as in Selection::Visible pair lt = currlayer->view->screenPosOf(pcell.first, pcell.second, currlayer->algo); pair rb = currlayer->view->screenPosOf(right, bottom, currlayer->algo); if (mag > 0) { // move rb to pixel at bottom right corner of cell rb.first += (1 << mag) - 1; rb.second += (1 << mag) - 1; if (mag > 1) { // avoid covering gaps at scale 1:4 and above rb.first--; rb.second--; } } x = lt.first; y = lt.second; pastewd = rb.first - lt.first + 1; pasteht = rb.second - lt.second + 1; // this should never happen but play safe if (pastewd <= 0) pastewd = 1; if (pasteht <= 0) pasteht = 1; // don't let pasterect get too far beyond left/top edge of viewport if (x + pastewd < 64) { if (pastewd >= 64) x = 64 - pastewd; else if (x < 0) x = 0; pastex = x; } if (y + pasteht < 64) { if (pasteht >= 64) y = 64 - pasteht; else if (y < 0) y = 0; pastey = y; } SetRect(pasterect, x, y, pastewd, pasteht); // NSLog(@"pasterect: x=%d y=%d wd=%d ht=%d", pasterect.x, pasterect.y, pasterect.width, pasterect.height); } // ----------------------------------------------------------------------------- void DrawPasteImage() { // calculate pasterect SetPasteRect(pastebbox.width, pastebbox.height); int pastemag = currlayer->view->getmag(); gRect cellbox = pastebbox; // calculate intersection of pasterect and current viewport for use // as a temporary viewport int itop = pasterect.y; int ileft = pasterect.x; int ibottom = itop + pasterect.height - 1; int iright = ileft + pasterect.width - 1; if (itop < 0) { itop = 0; cellbox.y += PixelsToCells(-pasterect.y, pastemag); } if (ileft < 0) { ileft = 0; cellbox.x += PixelsToCells(-pasterect.x, pastemag); } if (ibottom > currht - 1) ibottom = currht - 1; if (iright > currwd - 1) iright = currwd - 1; int pastewd = iright - ileft + 1; int pasteht = ibottom - itop + 1; // set size of translucent rect before following adjustment int rectwd = pastewd; int rectht = pasteht; if (pastemag > 0) { // make sure pastewd/ht don't have partial cells int cellsize = 1 << pastemag; int gap = 1; // gap between cells if (pastemag == 1) gap = 0; // no gap at scale 1:2 if ((pastewd + gap) % cellsize > 0) pastewd += cellsize - ((pastewd + gap) % cellsize); if ((pasteht + gap) % cellsize != 0) pasteht += cellsize - ((pasteht + gap) % cellsize); } cellbox.width = PixelsToCells(pastewd, pastemag); cellbox.height = PixelsToCells(pasteht, pastemag); // create temporary viewport viewport tempview(pastewd, pasteht); int midx, midy; if (pastemag > 1) { // allow for gap between cells midx = cellbox.x + (cellbox.width - 1) / 2; midy = cellbox.y + (cellbox.height - 1) / 2; } else { midx = cellbox.x + cellbox.width / 2; midy = cellbox.y + cellbox.height / 2; } tempview.setpositionmag(midx, midy, pastemag); // temporarily turn off grid lines bool saveshow = showgridlines; showgridlines = false; // temporarily change currwd and currht int savewd = currwd; int saveht = currht; currwd = tempview.getwidth(); currht = tempview.getheight(); #ifdef WEB_GUI // temporarily change OpenGL viewport's origin and size to match tempview glViewport(ileft, saveht-currht-itop, currwd, currht); #else glTranslatef(ileft, itop, 0); #endif // draw paste pattern drawing_paste = true; pastealgo->draw(tempview, renderer); drawing_paste = false; #ifdef WEB_GUI // restore OpenGL viewport's origin and size glViewport(0, 0, savewd, saveht); #else glTranslatef(-ileft, -itop, 0); #endif showgridlines = saveshow; currwd = savewd; currht = saveht; // overlay translucent rect to show paste area DisableTextures(); SetColor(pastergb.r, pastergb.g, pastergb.b, 64); FillRect(ileft, itop, rectwd, rectht); } // ----------------------------------------------------------------------------- void DrawGridLines(int wd, int ht) { int cellsize = 1 << currlayer->view->getmag(); int h, v, i, topbold, leftbold; if (showboldlines) { // ensure that origin cell stays next to bold lines; // ie. bold lines scroll when pattern is scrolled pair lefttop = currlayer->view->at(0, 0); leftbold = lefttop.first.mod_smallint(boldspacing); topbold = lefttop.second.mod_smallint(boldspacing); if (currlayer->originx != bigint::zero) { leftbold -= currlayer->originx.mod_smallint(boldspacing); } if (currlayer->originy != bigint::zero) { topbold -= currlayer->originy.mod_smallint(boldspacing); } if (mathcoords) topbold--; // show origin cell above bold line } else { // avoid gcc warning topbold = leftbold = 0; } DisableTextures(); glLineWidth(1.0); // set the stroke color depending on current bg color int r = currlayer->cellr[0]; int g = currlayer->cellg[0]; int b = currlayer->cellb[0]; int gray = (int) ((r + g + b) / 3.0); if (gray > 127) { // darker lines SetColor(r > 32 ? r - 32 : 0, g > 32 ? g - 32 : 0, b > 32 ? b - 32 : 0, 255); } else { // lighter lines SetColor(r + 32 < 256 ? r + 32 : 255, g + 32 < 256 ? g + 32 : 255, b + 32 < 256 ? b + 32 : 255, 255); } // draw all plain lines first; // note that we need to subtract 0.5 from each coordinate to avoid uneven spacing i = showboldlines ? topbold : 1; v = 0; while (true) { v += cellsize; if (v >= ht) break; if (showboldlines) i++; if (i % boldspacing != 0 && v >= 0 && v < ht) { #ifdef WEB_GUI GLfloat points[] = { XCOORD(-0.5), YCOORD(v-0.5), XCOORD(wd), YCOORD(v-0.5) }; glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat), points, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else GLfloat points[] = { -0.5, v-0.5, wd-0.5, v-0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_LINES, 0, 2); } } i = showboldlines ? leftbold : 1; h = 0; while (true) { h += cellsize; if (h >= wd) break; if (showboldlines) i++; if (i % boldspacing != 0 && h >= 0 && h < wd) { #ifdef WEB_GUI GLfloat points[] = { XCOORD(h-0.5), YCOORD(-0.5), XCOORD(h-0.5), YCOORD(ht) }; glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat), points, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else GLfloat points[] = { h-0.5, -0.5, h-0.5, ht-0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_LINES, 0, 2); } } if (showboldlines) { // draw bold lines in slightly darker/lighter color if (gray > 127) { // darker lines SetColor(r > 64 ? r - 64 : 0, g > 64 ? g - 64 : 0, b > 64 ? b - 64 : 0, 255); } else { // lighter lines SetColor(r + 64 < 256 ? r + 64 : 255, g + 64 < 256 ? g + 64 : 255, b + 64 < 256 ? b + 64 : 255, 255); } i = topbold; v = 0; while (true) { v += cellsize; if (v >= ht) break; i++; if (i % boldspacing == 0 && v >= 0 && v < ht) { #ifdef WEB_GUI GLfloat points[] = { XCOORD(-0.5), YCOORD(v-0.5), XCOORD(wd), YCOORD(v-0.5) }; glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat), points, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else GLfloat points[] = { -0.5, v-0.5, wd-0.5, v-0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_LINES, 0, 2); } } i = leftbold; h = 0; while (true) { h += cellsize; if (h >= wd) break; i++; if (i % boldspacing == 0 && h >= 0 && h < wd) { #ifdef WEB_GUI GLfloat points[] = { XCOORD(h-0.5), YCOORD(-0.5), XCOORD(h-0.5), YCOORD(ht) }; glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(GLfloat), points, GL_STATIC_DRAW); glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(positionLoc); #else GLfloat points[] = { h-0.5, -0.5, h-0.5, ht-0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_LINES, 0, 2); } } } } // ----------------------------------------------------------------------------- /*!!! void DrawOneLayer(EAGLContext* dc) { wxMemoryDC layerdc; layerdc.SelectObject(*layerbitmap); if (showicons && currlayer->view->getmag() > 2) { // only show icons at scales 1:8 and above if (currlayer->view->getmag() == 3) { icontextures = currlayer->textures7x7; } else if (currlayer->view->getmag() == 4) { icontextures = currlayer->textures15x15; } else { icontextures = currlayer->textures31x31; } } currlayer->algo->draw(*currlayer->view, renderer); layerdc.SelectObject(wxNullBitmap); // make dead pixels 100% transparent; live pixels use opacity setting MaskDeadPixels(layerbitmap, layerwd, layerht, int(2.55 * opacity)); // draw result dc.DrawBitmap(*layerbitmap, 0, 0, true); } // ----------------------------------------------------------------------------- void DrawStackedLayers(EAGLContext* dc) { // check if layerbitmap needs to be created or resized if ( layerwd != currlayer->view->getwidth() || layerht != currlayer->view->getheight() ) { layerwd = currlayer->view->getwidth(); layerht = currlayer->view->getheight(); delete layerbitmap; // create a bitmap with depth 32 so it has an alpha channel layerbitmap = new wxBitmap(layerwd, layerht, 32); if (!layerbitmap) { Fatal(_("Not enough memory for layer bitmap!")); return; } } // temporarily turn off grid lines bool saveshow = showgridlines; showgridlines = false; // draw patterns in layers 1..numlayers-1 for ( int i = 1; i < numlayers; i++ ) { Layer* savelayer = currlayer; currlayer = GetLayer(i); // use real current layer's viewport viewport* saveview = currlayer->view; currlayer->view = savelayer->view; // avoid drawing a cloned layer more than once??? draw first or last clone??? if ( !currlayer->algo->isEmpty() ) { DrawOneLayer(dc); } // draw this layer's selection if necessary wxRect r; if ( currlayer->currsel.Visible(&r) ) { DrawSelection(dc, r, i == currindex); } // restore viewport and currlayer currlayer->view = saveview; currlayer = savelayer; } showgridlines = saveshow; } // ----------------------------------------------------------------------------- void DrawTileFrame(EAGLContext* dc, wxRect& trect, wxBrush& brush, int wd) { trect.Inflate(wd); wxRect r = trect; r.height = wd; FillRect(dc, r, brush); // top edge r.y += trect.height - wd; FillRect(dc, r, brush); // bottom edge r = trect; r.width = wd; FillRect(dc, r, brush); // left edge r.x += trect.width - wd; FillRect(dc, r, brush); // right edge } // ----------------------------------------------------------------------------- void DrawTileBorders(EAGLContext* dc) { if (tileborder <= 0) return; // no borders // draw tile borders in bigview window int wd, ht; bigview->GetClientSize(&wd, &ht); if (wd < 1 || ht < 1) return; wxBrush brush; // most people will choose either a very light or very dark color for dead cells, // so draw mid gray border around non-current tiles brush.SetColour(144, 144, 144); wxRect trect; for ( int i = 0; i < numlayers; i++ ) { if (i != currindex) { trect = GetLayer(i)->tilerect; DrawTileFrame(dc, trect, brush, tileborder); } } // draw green border around current tile trect = GetLayer(currindex)->tilerect; brush.SetColour(0, 255, 0); DrawTileFrame(dc, trect, brush, tileborder); } !!!*/ // ----------------------------------------------------------------------------- void DrawPattern(int tileindex) { gRect r; int colorindex = currindex; /*!!! Layer* savelayer = NULL; viewport* saveview0 = NULL; */ // fill the background with state 0 color glClearColor(currlayer->cellr[0]/255.0, currlayer->cellg[0]/255.0, currlayer->cellb[0]/255.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); // if grid is bounded then ensure viewport's central cell is not outside grid edges if ( currlayer->algo->gridwd > 0) { if ( currlayer->view->x < currlayer->algo->gridleft ) currlayer->view->setpositionmag(currlayer->algo->gridleft, currlayer->view->y, currlayer->view->getmag()); else if ( currlayer->view->x > currlayer->algo->gridright ) currlayer->view->setpositionmag(currlayer->algo->gridright, currlayer->view->y, currlayer->view->getmag()); } if ( currlayer->algo->gridht > 0) { if ( currlayer->view->y < currlayer->algo->gridtop ) currlayer->view->setpositionmag(currlayer->view->x, currlayer->algo->gridtop, currlayer->view->getmag()); else if ( currlayer->view->y > currlayer->algo->gridbottom ) currlayer->view->setpositionmag(currlayer->view->x, currlayer->algo->gridbottom, currlayer->view->getmag()); } if (nopattupdate) { // don't draw incomplete pattern, just draw grid lines and border currwd = currlayer->view->getwidth(); currht = currlayer->view->getheight(); if ( showgridlines && currlayer->view->getmag() >= mingridmag ) { DrawGridLines(currwd, currht); } if ( currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0 ) { DrawGridBorder(currwd, currht); } return; } /*!!! if ( numlayers > 1 && tilelayers ) { if ( tileindex < 0 ) { DrawTileBorders(dc); return; } // tileindex >= 0 so temporarily change some globals to draw this tile if ( syncviews && tileindex != currindex ) { // make sure this layer uses same location and scale as current layer GetLayer(tileindex)->view->setpositionmag(currlayer->view->x, currlayer->view->y, currlayer->view->getmag()); } savelayer = currlayer; currlayer = GetLayer(tileindex); viewptr = currlayer->tilewin; colorindex = tileindex; } else if ( numlayers > 1 && stacklayers ) { // draw all layers starting with layer 0 but using current layer's viewport savelayer = currlayer; if ( currindex != 0 ) { // change currlayer to layer 0 currlayer = GetLayer(0); saveview0 = currlayer->view; currlayer->view = savelayer->view; } colorindex = 0; } */ if (showicons && currlayer->view->getmag() > 2) { // only show icons at scales 1:8 and above if (currlayer->view->getmag() == 3) { icontextures = currlayer->textures7x7; } else if (currlayer->view->getmag() == 4) { icontextures = currlayer->textures15x15; } else { icontextures = currlayer->textures31x31; } } currwd = currlayer->view->getwidth(); currht = currlayer->view->getheight(); // draw pattern using a sequence of pixblit calls currlayer->algo->draw(*currlayer->view, renderer); if ( showgridlines && currlayer->view->getmag() >= mingridmag ) { DrawGridLines(currwd, currht); } // if universe is bounded then draw border regions (if visible) if ( currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0 ) { DrawGridBorder(currwd, currht); } if ( currlayer->currsel.Visible(&r) ) { DrawSelection(r, colorindex == currindex); } /*!!! if ( numlayers > 1 && stacklayers ) { // must restore currlayer before we call DrawStackedLayers currlayer = savelayer; if ( saveview0 ) { // restore layer 0's viewport GetLayer(0)->view = saveview0; } // draw layers 1, 2, ... numlayers-1 DrawStackedLayers(dc); } */ if (waitingforpaste) { DrawPasteImage(); } /*!!! if ( numlayers > 1 && tilelayers ) { // restore globals changed above currlayer = savelayer; viewptr = currlayer->tilewin; } */ } golly-2.7-src/gui-common/layer.cpp0000644000175000017500000021327212536111364014121 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "viewport.h" #include "util.h" // for linereader #include "utils.h" // for gRect, Warning, etc #include "prefs.h" // for initrule, swapcolors, userrules, rulesdir, etc #include "algos.h" // for algo_type, initalgo, algoinfo, CreateNewUniverse, etc #include "control.h" // for generating #include "select.h" // for Selection #include "file.h" // for SetPatternTitle #include "view.h" // for OutsideLimits, CopyRect #include "undo.h" // for UndoRedo #include "layer.h" #include // for std::map // ----------------------------------------------------------------------------- bool inscript = false; // move to script.cpp if we ever support scripting!!! int numlayers = 0; // number of existing layers int numclones = 0; // number of cloned layers int currindex = -1; // index of current layer Layer* currlayer = NULL; // pointer to current layer Layer* layer[MAX_LAYERS]; // array of layers bool cloneavail[MAX_LAYERS]; // for setting unique cloneid bool cloning = false; // adding a cloned layer? bool duplicating = false; // adding a duplicated layer? algo_type oldalgo; // algorithm in old layer std::string oldrule; // rule in old layer int oldmag; // scale in old layer bigint oldx; // X position in old layer bigint oldy; // Y position in old layer TouchModes oldmode; // touch mode in old layer // ----------------------------------------------------------------------------- void CalculateTileRects(int bigwd, int bight) { // set tilerect in each layer gRect r; bool portrait = (bigwd <= bight); int rows, cols; // try to avoid the aspect ratio of each tile becoming too large switch (numlayers) { case 4: rows = 2; cols = 2; break; case 9: rows = 3; cols = 3; break; case 3: case 5: case 7: rows = portrait ? numlayers / 2 + 1 : 2; cols = portrait ? 2 : numlayers / 2 + 1; break; case 6: case 8: case 10: rows = portrait ? numlayers / 2 : 2; cols = portrait ? 2 : numlayers / 2; break; default: // numlayers == 2 or > 10 rows = portrait ? numlayers : 1; cols = portrait ? 1 : numlayers; break; } int tilewd = bigwd / cols; int tileht = bight / rows; if ( float(tilewd) > float(tileht) * 2.5 ) { rows = 1; cols = numlayers; tileht = bight; tilewd = bigwd / numlayers; } else if ( float(tileht) > float(tilewd) * 2.5 ) { cols = 1; rows = numlayers; tilewd = bigwd; tileht = bight / numlayers; } for ( int i = 0; i < rows; i++ ) { for ( int j = 0; j < cols; j++ ) { r.x = j * tilewd; r.y = i * tileht; r.width = tilewd; r.height = tileht; if (i == rows - 1) { // may need to increase height of bottom-edge tile r.height += bight - (rows * tileht); } if (j == cols - 1) { // may need to increase width of right-edge tile r.width += bigwd - (cols * tilewd); } int index = i * cols + j; if (index == numlayers) { // numlayers == 3,5,7 layer[index - 1]->tilerect.width += r.width; } else { layer[index]->tilerect = r; } } } if (tileborder > 0) { // make tilerects smaller to allow for equal-width tile borders for ( int i = 0; i < rows; i++ ) { for ( int j = 0; j < cols; j++ ) { int index = i * cols + j; if (index == numlayers) { // numlayers == 3,5,7 layer[index - 1]->tilerect.width -= tileborder; } else { layer[index]->tilerect.x += tileborder; layer[index]->tilerect.y += tileborder; layer[index]->tilerect.width -= tileborder; layer[index]->tilerect.height -= tileborder; if (j == cols - 1) layer[index]->tilerect.width -= tileborder; if (i == rows - 1) layer[index]->tilerect.height -= tileborder; } } } } } // ----------------------------------------------------------------------------- void ResizeTiles(int bigwd, int bight) { // set tilerect for each layer so they tile bigview's client area CalculateTileRects(bigwd, bight); /*!!! // set size of each tile window for ( int i = 0; i < numlayers; i++ ) layer[i]->tilewin->SetSize( layer[i]->tilerect ); // set viewport size for each tile; this is currently the same as the // tilerect size because tile windows are created with wxNO_BORDER for ( int i = 0; i < numlayers; i++ ) { int wd, ht; layer[i]->tilewin->GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; layer[i]->view->resize(wd, ht); } */ } // ----------------------------------------------------------------------------- void ResizeLayers(int wd, int ht) { // this is called whenever the size of the bigview window changes; // wd and ht are the dimensions of bigview's client area if (tilelayers && numlayers > 1) { ResizeTiles(wd, ht); } else { // resize viewport in each layer to bigview's client area for (int i = 0; i < numlayers; i++) layer[i]->view->resize(wd, ht); } } // ----------------------------------------------------------------------------- /*!!! void CreateTiles() { // create tile windows for ( int i = 0; i < numlayers; i++ ) { layer[i]->tilewin = new PatternView(bigview, // correct size will be set below by ResizeTiles 0, 0, 0, 0, // we draw our own tile borders wxNO_BORDER | // needed for wxGTK wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS); if (layer[i]->tilewin == NULL) Fatal(_("Failed to create tile window!")); // set tileindex >= 0; this must always match the layer index, so we'll need to // destroy and recreate all tiles whenever a tile is added, deleted or moved layer[i]->tilewin->tileindex = i; #if wxUSE_DRAG_AND_DROP // let user drop file onto any tile (but file will be loaded into current tile) layer[i]->tilewin->SetDropTarget(mainptr->NewDropTarget()); #endif } // init tilerects, tile window sizes and their viewport sizes int wd, ht; bigview->GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; ResizeTiles(wd, ht); // change viewptr to tile window for current layer viewptr = currlayer->tilewin; if (mainptr->IsActive()) viewptr->SetFocus(); } // ----------------------------------------------------------------------------- void DestroyTiles() { // reset viewptr to main viewport window viewptr = bigview; if (mainptr->IsActive()) viewptr->SetFocus(); // destroy all tile windows for ( int i = 0; i < numlayers; i++ ) delete layer[i]->tilewin; // resize viewport in each layer to bigview's client area int wd, ht; bigview->GetClientSize(&wd, &ht); // wd or ht might be < 1 on Windows if (wd < 1) wd = 1; if (ht < 1) ht = 1; for ( int i = 0; i < numlayers; i++ ) layer[i]->view->resize(wd, ht); } !!!*/ // ----------------------------------------------------------------------------- void SyncClones() { if (numclones == 0) return; if (currlayer->cloneid > 0) { // make sure clone algo and most other settings are synchronized for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = layer[i]; if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { // universe might have been re-created, or algorithm changed cloneptr->algo = currlayer->algo; cloneptr->algtype = currlayer->algtype; cloneptr->rule = currlayer->rule; // no need to sync undo/redo history // cloneptr->undoredo = currlayer->undoredo; // along with view, don't sync these settings // cloneptr->autofit = currlayer->autofit; // cloneptr->hyperspeed = currlayer->hyperspeed; // cloneptr->showhashinfo = currlayer->showhashinfo; // cloneptr->drawingstate = currlayer->drawingstate; // cloneptr->touchmode = currlayer->touchmode; // cloneptr->originx = currlayer->originx; // cloneptr->originy = currlayer->originy; // cloneptr->currname = currlayer->currname; // sync various flags cloneptr->dirty = currlayer->dirty; cloneptr->savedirty = currlayer->savedirty; cloneptr->stayclean = currlayer->stayclean; // sync step size cloneptr->currbase = currlayer->currbase; cloneptr->currexpo = currlayer->currexpo; // sync selection info cloneptr->currsel = currlayer->currsel; cloneptr->savesel = currlayer->savesel; // sync the stuff needed to reset pattern cloneptr->startalgo = currlayer->startalgo; cloneptr->savestart = currlayer->savestart; cloneptr->startdirty = currlayer->startdirty; cloneptr->startrule = currlayer->startrule; cloneptr->startfile = currlayer->startfile; cloneptr->startgen = currlayer->startgen; cloneptr->currfile = currlayer->currfile; cloneptr->startsel = currlayer->startsel; // clone can have different starting name, pos, scale, step // cloneptr->startname = currlayer->startname; // cloneptr->startx = currlayer->startx; // cloneptr->starty = currlayer->starty; // cloneptr->startmag = currlayer->startmag; // cloneptr->startbase = currlayer->startbase; // cloneptr->startexpo = currlayer->startexpo; // sync timeline settings cloneptr->currframe = currlayer->currframe; cloneptr->autoplay = currlayer->autoplay; cloneptr->tlspeed = currlayer->tlspeed; cloneptr->lastframe = currlayer->lastframe; } } } } // ----------------------------------------------------------------------------- void SaveLayerSettings() { // set oldalgo and oldrule for use in CurrentLayerChanged oldalgo = currlayer->algtype; oldrule = currlayer->algo->getrule(); // we're about to change layer so remember current rule // in case we switch back to this layer currlayer->rule = oldrule; // synchronize clone info (do AFTER setting currlayer->rule) SyncClones(); if (syncviews) { // save scale and location for use in CurrentLayerChanged oldmag = currlayer->view->getmag(); oldx = currlayer->view->x; oldy = currlayer->view->y; } if (syncmodes) { // save touch mode for use in CurrentLayerChanged oldmode = currlayer->touchmode; } } // ----------------------------------------------------------------------------- bool RestoreRule(const char* rule) { const char* err = currlayer->algo->setrule(rule); if (err) { // this can happen if the given rule's table/tree file was deleted // or it was edited and some sort of error introduced, so best to // use algo's default rule (which should never fail) currlayer->algo->setrule( currlayer->algo->DefaultRule() ); std::string msg = "The rule \""; msg += rule; msg += "\" is no longer valid!\nUsing the default rule instead."; Warning(msg.c_str()); return false; } return true; } // ----------------------------------------------------------------------------- /*!!! void CurrentLayerChanged() { // currlayer has changed since SaveLayerSettings was called; // update rule if the new currlayer uses a different algorithm or rule if ( currlayer->algtype != oldalgo || !currlayer->rule.IsSameAs(oldrule,false) ) { RestoreRule(currlayer->rule); } if (syncviews) currlayer->view->setpositionmag(oldx, oldy, oldmag); if (syncmodes) currlayer->touchmode = oldmode; // select current layer button (also deselects old button) layerbarptr->SelectButton(currindex, true); if (tilelayers && numlayers > 1) { // switch to new tile viewptr = currlayer->tilewin; if (mainptr->IsActive()) viewptr->SetFocus(); } if (allowundo) { // update Undo/Redo items so they show the correct action currlayer->undoredo->UpdateUndoRedoItems(); } else { // undo/redo is disabled so clear history; // this also removes action from Undo/Redo items currlayer->undoredo->ClearUndoRedo(); } mainptr->SetStepExponent(currlayer->currexpo); // SetStepExponent calls SetGenIncrement mainptr->SetPatternTitle(currlayer->currname); mainptr->UpdateUserInterface(mainptr->IsActive()); mainptr->UpdatePatternAndStatus(); bigview->UpdateScrollBars(); } !!!*/ // ----------------------------------------------------------------------------- static gBitmapPtr* CopyIcons(gBitmapPtr* srcicons, int maxstate) { gBitmapPtr* iconptr = (gBitmapPtr*) malloc(256 * sizeof(gBitmapPtr)); if (iconptr) { for (int i = 0; i < 256; i++) iconptr[i] = NULL; for (int i = 0; i <= maxstate; i++) { if (srcicons && srcicons[i]) { gBitmapPtr icon = (gBitmapPtr) malloc(sizeof(gBitmap)); if (icon) { icon->wd = srcicons[i]->wd; icon->ht = srcicons[i]->ht; if (srcicons[i]->pxldata == NULL) { icon->pxldata = NULL; } else { int iconbytes = icon->wd * icon->ht * 4; icon->pxldata = (unsigned char*) malloc(iconbytes); if (icon->pxldata) { memcpy(icon->pxldata, srcicons[i]->pxldata, iconbytes); } } } iconptr[i] = icon; } } } return iconptr; } // ----------------------------------------------------------------------------- static unsigned char** CreateIconTextures(gBitmapPtr* srcicons, int maxstate) { bool multicolor = currlayer->multicoloricons; unsigned char deadr = currlayer->cellr[0]; unsigned char deadg = currlayer->cellg[0]; unsigned char deadb = currlayer->cellb[0]; if (swapcolors) { deadr = 255 - deadr; deadg = 255 - deadg; deadb = 255 - deadb; } unsigned char** texturesptr = (unsigned char**) malloc(256 * sizeof(unsigned char*)); if (texturesptr) { for (int state = 0; state < 256; state++) texturesptr[state] = NULL; for (int state = 0; state <= maxstate; state++) { if (srcicons && srcicons[state]) { int wd = srcicons[state]->wd; int ht = srcicons[state]->ht; unsigned char* icondata = srcicons[state]->pxldata; // allocate enough memory to store texture data for this icon; // wd = ht = 7, 15 or 31, but Open GL ES 1 requires texture sizes to be powers of 2 int texbytes = (wd+1) * (ht+1) * 4; texturesptr[state] = (unsigned char*) calloc(texbytes, 1); if (texturesptr[state] && icondata) { unsigned char liver = currlayer->cellr[state]; unsigned char liveg = currlayer->cellg[state]; unsigned char liveb = currlayer->cellb[state]; if (swapcolors) { liver = 255 - liver; liveg = 255 - liveg; liveb = 255 - liveb; } unsigned char* texdata = texturesptr[state]; int tpos = 0; int ipos = 0; for (int row = 0; row < ht; row++) { for (int col = 0; col < wd; col++) { unsigned char r = icondata[ipos]; unsigned char g = icondata[ipos+1]; unsigned char b = icondata[ipos+2]; if (r || g || b) { // non-black pixel if (multicolor) { // use non-black pixel in multi-colored icon if (swapcolors) { texdata[tpos] = 255 - r; texdata[tpos+1] = 255 - g; texdata[tpos+2] = 255 - b; } else { texdata[tpos] = r; texdata[tpos+1] = g; texdata[tpos+2] = b; } } else { // grayscale icon (r = g = b) if (r == 255) { // replace white pixel with live cell color texdata[tpos] = liver; texdata[tpos+1] = liveg; texdata[tpos+2] = liveb; } else { // replace gray pixel with appropriate shade between // live and dead cell colors float frac = (float)r / 255.0; texdata[tpos] = (int)(deadr + frac * (liver - deadr) + 0.5); texdata[tpos+1] = (int)(deadg + frac * (liveg - deadg) + 0.5); texdata[tpos+2] = (int)(deadb + frac * (liveb - deadb) + 0.5); } } texdata[tpos+3] = 255; // alpha channel is opaque } else { // replace black pixel with transparent pixel texdata[tpos] = deadr; texdata[tpos+1] = deadg; texdata[tpos+2] = deadb; texdata[tpos+3] = 0; // alpha channel is transparent } tpos += 4; ipos += 4; } // add transparent pixel at right edge of texture texdata[tpos++] = deadr; texdata[tpos++] = deadg; texdata[tpos++] = deadb; texdata[tpos++] = 0; } // add row of transparent pixels at bottom of texture for (int col = 0; col < wd+1; col++) { texdata[tpos++] = deadr; texdata[tpos++] = deadg; texdata[tpos++] = deadb; texdata[tpos++] = 0; } } } } } return texturesptr; } // ----------------------------------------------------------------------------- void AddLayer() { if (numlayers >= MAX_LAYERS) return; if (generating) Warning("Bug detected in AddLayer!"); if (numlayers == 0) { // creating the very first layer currindex = 0; } else { //!!! if (tilelayers && numlayers > 1) DestroyTiles(); SaveLayerSettings(); // insert new layer after currindex currindex++; if (currindex < numlayers) { // shift right one or more layers for (int i = numlayers; i > currindex; i--) layer[i] = layer[i-1]; } } Layer* oldlayer = NULL; if (cloning || duplicating) oldlayer = currlayer; currlayer = new Layer(); if (currlayer == NULL) Fatal("Failed to create new layer!"); layer[currindex] = currlayer; if (cloning || duplicating) { // copy old layer's colors to new layer currlayer->fromrgb = oldlayer->fromrgb; currlayer->torgb = oldlayer->torgb; for (int n = 0; n < currlayer->algo->NumCellStates(); n++) { currlayer->cellr[n] = oldlayer->cellr[n]; currlayer->cellg[n] = oldlayer->cellg[n]; currlayer->cellb[n] = oldlayer->cellb[n]; } if (cloning) { // use same icon pointers currlayer->icons7x7 = oldlayer->icons7x7; currlayer->icons15x15 = oldlayer->icons15x15; currlayer->icons31x31 = oldlayer->icons31x31; // use same texture data currlayer->textures7x7 = oldlayer->textures7x7; currlayer->textures15x15 = oldlayer->textures15x15; currlayer->textures31x31 = oldlayer->textures31x31; } else { // duplicate icons from old layer int maxstate = currlayer->algo->NumCellStates() - 1; currlayer->icons7x7 = CopyIcons(oldlayer->icons7x7, maxstate); currlayer->icons15x15 = CopyIcons(oldlayer->icons15x15, maxstate); currlayer->icons31x31 = CopyIcons(oldlayer->icons31x31, maxstate); // create icon texture data currlayer->textures7x7 = CreateIconTextures(oldlayer->icons7x7, maxstate); currlayer->textures15x15 = CreateIconTextures(oldlayer->icons15x15, maxstate); currlayer->textures31x31 = CreateIconTextures(oldlayer->icons31x31, maxstate); } } else { // set new layer's colors+icons to default colors+icons for current algo+rule UpdateLayerColors(); } numlayers++; if (numlayers > 1) { //!!! if (tilelayers && numlayers > 1) CreateTiles(); //!!! CurrentLayerChanged(); } } // ----------------------------------------------------------------------------- void CloneLayer() { if (numlayers >= MAX_LAYERS) return; if (generating) Warning("Bug detected in CloneLayer!"); cloning = true; AddLayer(); cloning = false; } // ----------------------------------------------------------------------------- void DuplicateLayer() { if (numlayers >= MAX_LAYERS) return; if (generating) Warning("Bug detected in DuplicateLayer!"); duplicating = true; AddLayer(); duplicating = false; } // ----------------------------------------------------------------------------- /*!!! void DeleteLayer() { if (numlayers <= 1) return; if (generating) Warning("Bug detected in DeleteLayer!"); // note that we don't need to ask to delete a clone if (currlayer->dirty && currlayer->cloneid == 0 && asktosave && !SaveCurrentLayer()) return; // numlayers > 1 if (tilelayers) DestroyTiles(); SaveLayerSettings(); delete currlayer; numlayers--; if (currindex < numlayers) { // shift left one or more layers for (int i = currindex; i < numlayers; i++) layer[i] = layer[i+1]; } if (currindex > 0) currindex--; currlayer = layer[currindex]; // remove toggle button at end of layer bar togglebutt[numlayers]->Show(false); layerbarptr->ResizeLayerButtons(); // remove item from end of Layer menu mainptr->RemoveLayerItem(); if (tilelayers && numlayers > 1) CreateTiles(); CurrentLayerChanged(); } // ----------------------------------------------------------------------------- void SetLayer(int index) { if (currindex == index) return; if (index < 0 || index >= numlayers) return; SaveLayerSettings(); currindex = index; currlayer = layer[currindex]; CurrentLayerChanged(); } // ----------------------------------------------------------------------------- bool CanSwitchLayer(int WXUNUSED(index)) { if (inscript) { // user can only switch layers if script has set the appropriate option return canswitch; } else { // user can switch to any layer return true; } } // ----------------------------------------------------------------------------- void SwitchToClickedTile(int index) { if (inscript && !CanSwitchLayer(index)) { Warning("You cannot switch to another layer while this script is running."); return; } // switch current layer to clicked tile SetLayer(index); if (inscript) { // update window title, viewport and status bar inscript = false; mainptr->SetPatternTitle(wxEmptyString); mainptr->UpdatePatternAndStatus(); inscript = true; } } // ----------------------------------------------------------------------------- void MoveLayer(int fromindex, int toindex) { if (fromindex == toindex) return; if (fromindex < 0 || fromindex >= numlayers) return; if (toindex < 0 || toindex >= numlayers) return; SaveLayerSettings(); if (fromindex > toindex) { Layer* savelayer = layer[fromindex]; for (int i = fromindex; i > toindex; i--) layer[i] = layer[i - 1]; layer[toindex] = savelayer; } else { // fromindex < toindex Layer* savelayer = layer[fromindex]; for (int i = fromindex; i < toindex; i++) layer[i] = layer[i + 1]; layer[toindex] = savelayer; } currindex = toindex; currlayer = layer[currindex]; if (tilelayers && numlayers > 1) { DestroyTiles(); CreateTiles(); } CurrentLayerChanged(); } // ----------------------------------------------------------------------------- void MoveLayerDialog() { if (numlayers <= 1) return; wxString msg = _("Move the current layer to a new position:"); if (currindex > 0) { msg += _("\n(enter 0 to make it the first layer)"); } int newindex; if ( GetInteger(_("Move Layer"), msg, currindex, 0, numlayers - 1, &newindex) ) { MoveLayer(currindex, newindex); } } // ----------------------------------------------------------------------------- void NameLayerDialog() { wxString oldname = currlayer->currname; wxString newname; if ( GetString(_("Name Layer"), _("Enter a new name for the current layer:"), oldname, newname) && !newname.IsEmpty() && oldname != newname ) { // inscript is false so no need to call SavePendingChanges // if (allowundo) SavePendingChanges(); // show new name in main window's title bar; // also sets currlayer->currname and updates menu item mainptr->SetPatternTitle(newname); if (allowundo) { // note that currfile and savestart/dirty flags don't change here currlayer->undoredo->RememberNameChange(oldname, currlayer->currfile, currlayer->savestart, currlayer->dirty); } } } !!!*/ // ----------------------------------------------------------------------------- void DeleteOtherLayers() { if (inscript || numlayers <= 1) return; /*!!! if (asktosave) { // keep track of which unique clones have been seen; // we add 1 below to allow for cloneseen[0] (always false) const int maxseen = MAX_LAYERS/2 + 1; bool cloneseen[maxseen]; for (int i = 0; i < maxseen; i++) cloneseen[i] = false; // for each dirty layer, except current layer and all of its clones, // ask user if they want to save changes int cid = layer[currindex]->cloneid; if (cid > 0) cloneseen[cid] = true; int oldindex = currindex; for (int i = 0; i < numlayers; i++) { // only ask once for each unique clone (cloneid == 0 for non-clone) cid = layer[i]->cloneid; if (i != oldindex && !cloneseen[cid]) { if (cid > 0) cloneseen[cid] = true; if (layer[i]->dirty) { // temporarily turn off generating flag for SetLayer bool oldgen = mainptr->generating; mainptr->generating = false; SetLayer(i); if (!SaveCurrentLayer()) { // user hit Cancel so restore current layer and generating flag SetLayer(oldindex); mainptr->generating = oldgen; mainptr->UpdateUserInterface(mainptr->IsActive()); return; } SetLayer(oldindex); mainptr->generating = oldgen; } } } } // numlayers > 1 if (tilelayers) DestroyTiles(); SyncClones(); // delete all layers except current layer; // we need to do this carefully because ~Layer() requires numlayers // and the layer array to be correct when deleting a cloned layer int i = numlayers; while (numlayers > 1) { i--; if (i != currindex) { delete layer[i]; // ~Layer() is called numlayers--; // may need to shift the current layer left one place if (i < numlayers) layer[i] = layer[i+1]; // remove toggle button at end of layer bar togglebutt[numlayers]->Show(false); // remove item from end of Layer menu mainptr->RemoveLayerItem(); } } layerbarptr->ResizeLayerButtons(); currindex = 0; // currlayer doesn't change // update the only layer item mainptr->UpdateLayerItem(0); // update window title (may need to remove "=" prefix) mainptr->SetPatternTitle(wxEmptyString); // select LAYER_0 button (also deselects old button) layerbarptr->SelectButton(LAYER_0, true); mainptr->UpdateMenuItems(mainptr->IsActive()); mainptr->UpdatePatternAndStatus(); */ } // ----------------------------------------------------------------------------- void MarkLayerDirty() { // need to save starting pattern currlayer->savestart = true; // if script has reset dirty flag then don't change it; this makes sense // for scripts that call new() and then construct a pattern if (currlayer->stayclean) return; if (!currlayer->dirty) { currlayer->dirty = true; // pass in currname so UpdateLayerItem(currindex) gets called SetPatternTitle(currlayer->currname.c_str()); if (currlayer->cloneid > 0) { // synchronize other clones for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = layer[i]; if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { // set dirty flag and display asterisk in layer item cloneptr->dirty = true; //!!! UpdateLayerItem(i); } } } } } // ----------------------------------------------------------------------------- void MarkLayerClean(const char* title) { currlayer->dirty = false; // if script is resetting dirty flag -- eg. via new() -- then don't allow // dirty flag to be set true for the remainder of the script; this is // nicer for scripts that construct a pattern (ie. running such a script // is equivalent to loading a pattern file) if (inscript) currlayer->stayclean = true; if (title[0] == 0) { // pass in currname so UpdateLayerItem(currindex) gets called SetPatternTitle(currlayer->currname.c_str()); } else { // set currlayer->currname to title and call UpdateLayerItem(currindex) SetPatternTitle(title); } if (currlayer->cloneid > 0) { // synchronize other clones for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = layer[i]; if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { // reset dirty flag cloneptr->dirty = false; if (inscript) cloneptr->stayclean = true; // always allow clones to have different names // cloneptr->currname = currlayer->currname; // remove asterisk from layer name //!!! UpdateLayerItem(i); } } } } // ----------------------------------------------------------------------------- /*!!! void ToggleSyncViews() { syncviews = !syncviews; mainptr->UpdateUserInterface(mainptr->IsActive()); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void ToggleSyncModes() { syncmodes = !syncmodes; mainptr->UpdateUserInterface(mainptr->IsActive()); mainptr->UpdatePatternAndStatus(); } // ----------------------------------------------------------------------------- void ToggleStackLayers() { stacklayers = !stacklayers; if (stacklayers && tilelayers) { tilelayers = false; layerbarptr->SelectButton(TILE_LAYERS, false); if (numlayers > 1) DestroyTiles(); } layerbarptr->SelectButton(STACK_LAYERS, stacklayers); mainptr->UpdateUserInterface(mainptr->IsActive()); if (inscript) { // always update viewport and status bar inscript = false; mainptr->UpdatePatternAndStatus(); inscript = true; } else { mainptr->UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- void ToggleTileLayers() { tilelayers = !tilelayers; if (tilelayers && stacklayers) { stacklayers = false; layerbarptr->SelectButton(STACK_LAYERS, false); } layerbarptr->SelectButton(TILE_LAYERS, tilelayers); if (tilelayers) { if (numlayers > 1) CreateTiles(); } else { if (numlayers > 1) DestroyTiles(); } mainptr->UpdateUserInterface(mainptr->IsActive()); if (inscript) { // always update viewport and status bar inscript = false; mainptr->UpdatePatternAndStatus(); inscript = true; } else { mainptr->UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- void UpdateCloneColors() { if (currlayer->cloneid > 0) { int maxstate = currlayer->algo->NumCellStates() - 1; for (int i = 0; i < numlayers; i++) { Layer* cloneptr = layer[i]; if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->fromrgb = currlayer->fromrgb; cloneptr->torgb = currlayer->torgb; for (int n = 0; n <= maxstate; n++) { cloneptr->cellr[n] = currlayer->cellr[n]; cloneptr->cellg[n] = currlayer->cellg[n]; cloneptr->cellb[n] = currlayer->cellb[n]; } // use same icon pointers cloneptr->icons7x7 = currlayer->icons7x7; cloneptr->icons15x15 = currlayer->icons15x15; cloneptr->icons31x31 = currlayer->icons31x31; // use same pixel data cloneptr->textures7x7 = currlayer->textures7x7; cloneptr->textures15x15 = currlayer->textures15x15; cloneptr->textures31x31 = currlayer->textures31x31; } } } } !!!*/ // ----------------------------------------------------------------------------- static FILE* FindRuleFile(const std::string& rulename) { const std::string extn = ".rule"; std::string path; // first look for rulename.rule in userrules path = userrules + rulename; path += extn; FILE* f = fopen(path.c_str(), "r"); if (f) return f; // now look for rulename.rule in rulesdir path = rulesdir + rulename; path += extn; return fopen(path.c_str(), "r"); } // ----------------------------------------------------------------------------- static void CheckRuleHeader(char* linebuf, const std::string& rulename) { // check that 1st line of rulename.rule file contains "@RULE rulename" // where rulename must match the file name exactly (to avoid problems on // case-sensitive file systems) if (strncmp(linebuf, "@RULE ", 6) != 0) { std::string msg = "The first line in "; msg += rulename; msg += ".rule does not start with @RULE."; Warning(msg.c_str()); } else if (strcmp(linebuf+6, rulename.c_str()) != 0) { std::string msg = "The rule name on the first line in "; msg += rulename; msg += ".rule does not match the specified rule: "; msg += rulename; Warning(msg.c_str()); } } // ----------------------------------------------------------------------------- static void ParseColors(linereader& reader, char* linebuf, int MAXLINELEN, int* linenum, bool* eof) { // parse @COLORS section in currently open .rule file int state, r, g, b, r1, g1, b1, r2, g2, b2; int maxstate = currlayer->algo->NumCellStates() - 1; while (reader.fgets(linebuf, MAXLINELEN) != 0) { *linenum = *linenum + 1; if (linebuf[0] == '#' || linebuf[0] == 0) { // skip comment or empty line } else if (sscanf(linebuf, "%d%d%d%d%d%d", &r1, &g1, &b1, &r2, &g2, &b2) == 6) { // assume line is like this: // 255 0 0 0 0 255 use a gradient from red to blue SetColor(currlayer->fromrgb, r1, g1, b1); SetColor(currlayer->torgb, r2, g2, b2); CreateColorGradient(); } else if (sscanf(linebuf, "%d%d%d%d", &state, &r, &g, &b) == 4) { // assume line is like this: // 1 0 128 255 state 1 is light blue if (state >= 0 && state <= maxstate) { currlayer->cellr[state] = r; currlayer->cellg[state] = g; currlayer->cellb[state] = b; } } else if (linebuf[0] == '@') { // found next section, so stop parsing *eof = false; return; } // ignore unexpected syntax (better for upward compatibility) } *eof = true; } // ----------------------------------------------------------------------------- static void DeleteXPMData(char** xpmdata, int numstrings) { if (xpmdata) { for (int i = 0; i < numstrings; i++) if (xpmdata[i]) free(xpmdata[i]); free(xpmdata); } } // ----------------------------------------------------------------------------- static void CopyBuiltinIcons(gBitmapPtr* i7x7, gBitmapPtr* i15x15, gBitmapPtr* i31x31) { int maxstate = currlayer->algo->NumCellStates() - 1; if (currlayer->icons7x7) FreeIconBitmaps(currlayer->icons7x7); if (currlayer->icons15x15) FreeIconBitmaps(currlayer->icons15x15); if (currlayer->icons31x31) FreeIconBitmaps(currlayer->icons31x31); currlayer->icons7x7 = CopyIcons(i7x7, maxstate); currlayer->icons15x15 = CopyIcons(i15x15, maxstate); currlayer->icons31x31 = CopyIcons(i31x31, maxstate); } // ----------------------------------------------------------------------------- static void CreateIcons(const char** xpmdata, int size) { int maxstates = currlayer->algo->NumCellStates(); // we only need to call FreeIconBitmaps if .rule file has duplicate XPM data // (unlikely but best to play it safe) if (size == 7) { if (currlayer->icons7x7) FreeIconBitmaps(currlayer->icons7x7); currlayer->icons7x7 = CreateIconBitmaps(xpmdata, maxstates); } else if (size == 15) { if (currlayer->icons15x15) FreeIconBitmaps(currlayer->icons15x15); currlayer->icons15x15 = CreateIconBitmaps(xpmdata, maxstates); } else if (size == 31) { if (currlayer->icons31x31) FreeIconBitmaps(currlayer->icons31x31); currlayer->icons31x31 = CreateIconBitmaps(xpmdata, maxstates); } } // ----------------------------------------------------------------------------- static void ParseIcons(const std::string& rulename, linereader& reader, char* linebuf, int MAXLINELEN, int* linenum, bool* eof) { // parse @ICONS section in currently open .rule file char** xpmdata = NULL; int xpmstarted = 0, xpmstrings = 0, maxstrings = 0; int wd = 0, ht = 0, numcolors = 0, chars_per_pixel = 0; std::map colormap; while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) { *eof = true; break; } *linenum = *linenum + 1; if (linebuf[0] == '#' || linebuf[0] == '/' || linebuf[0] == 0) { // skip comment or empty line } else if (linebuf[0] == '"') { if (xpmstarted) { // we have a "..." string containing XPM data if (xpmstrings == 0) { if (sscanf(linebuf, "\"%d%d%d%d\"", &wd, &ht, &numcolors, &chars_per_pixel) == 4 && wd > 0 && ht > 0 && numcolors > 0 && ht % wd == 0 && chars_per_pixel > 0 && chars_per_pixel < 3) { if (wd != 7 && wd != 15 && wd != 31) { // this version of Golly doesn't support the supplied icon size // so silently ignore the rest of this XPM data xpmstarted = 0; continue; } maxstrings = 1 + numcolors + ht; // create and initialize xpmdata xpmdata = (char**) malloc(maxstrings * sizeof(char*)); if (xpmdata) { for (int i = 0; i < maxstrings; i++) xpmdata[i] = NULL; } else { Warning("Failed to allocate memory for XPM icon data!"); *eof = true; return; } } else { char s[128]; sprintf(s, "The XPM header string on line %d in ", *linenum); std::string msg(s); msg += rulename; msg += ".rule is incorrect"; if (wd > 0 && ht > 0 && ht % wd != 0) msg += " (height must be a multiple of width)."; else if (chars_per_pixel < 1 || chars_per_pixel > 2) msg += " (chars_per_pixel must be 1 or 2)."; else msg += " (4 positive integers are required)."; Warning(msg.c_str()); *eof = true; return; } } // copy data inside "..." to next string in xpmdata int len = strlen(linebuf); while (linebuf[len] != '"') len--; len--; if (xpmstrings > 0 && xpmstrings <= numcolors) { // build colormap so we can validate chars in pixel data std::string pixel; char ch1, ch2; if (chars_per_pixel == 1) { sscanf(linebuf+1, "%c ", &ch1); pixel += ch1; } else { sscanf(linebuf+1, "%c%c ", &ch1, &ch2); pixel += ch1; pixel += ch2; } colormap[pixel] = xpmstrings; } else if (xpmstrings > numcolors) { // check length of string containing pixel data if (len != wd * chars_per_pixel) { DeleteXPMData(xpmdata, maxstrings); char s[128]; sprintf(s, "The XPM data string on line %d in ", *linenum); std::string msg(s); msg += rulename; msg += ".rule has the wrong length."; Warning(msg.c_str()); *eof = true; return; } // now check that chars in pixel data are valid (ie. in colormap) for (int i = 1; i <= len; i += chars_per_pixel) { std::string pixel; pixel += linebuf[i]; if (chars_per_pixel > 1) pixel += linebuf[i+1]; if (colormap.find(pixel) == colormap.end()) { DeleteXPMData(xpmdata, maxstrings); char s[128]; sprintf(s, "The XPM data string on line %d in ", *linenum); std::string msg(s); msg += rulename; msg += ".rule has an unknown pixel: "; msg += pixel; Warning(msg.c_str()); *eof = true; return; } } } char* str = (char*) malloc(len+1); if (str) { strncpy(str, linebuf+1, len); str[len] = 0; xpmdata[xpmstrings] = str; } else { DeleteXPMData(xpmdata, maxstrings); Warning("Failed to allocate memory for XPM string!"); *eof = true; return; } xpmstrings++; if (xpmstrings == maxstrings) { // we've got all the data for this icon size CreateIcons((const char**)xpmdata, wd); DeleteXPMData(xpmdata, maxstrings); xpmdata = NULL; xpmstarted = 0; } } } else if (strcmp(linebuf, "XPM") == 0) { // start parsing XPM data on following lines if (xpmstarted) break; // handle error below xpmstarted = *linenum; xpmstrings = 0; } else if (strcmp(linebuf, "circles") == 0) { // use circular icons CopyBuiltinIcons(circles7x7, circles15x15, circles31x31); } else if (strcmp(linebuf, "diamonds") == 0) { // use diamond-shaped icons CopyBuiltinIcons(diamonds7x7, diamonds15x15, diamonds31x31); } else if (strcmp(linebuf, "hexagons") == 0) { // use hexagonal icons CopyBuiltinIcons(hexagons7x7, hexagons15x15, hexagons31x31); } else if (strcmp(linebuf, "triangles") == 0) { // use triangular icons if (currlayer->algo->NumCellStates() != 4) { char s[128]; sprintf(s, "The triangular icons specified on line %d in ", *linenum); std::string msg(s); msg += rulename; msg += ".rule can only be used with a 4-state rule."; Warning(msg.c_str()); // don't return } else { CopyBuiltinIcons(triangles7x7, triangles15x15, triangles31x31); } } else if (linebuf[0] == '@') { // found next section, so stop parsing *eof = false; break; } // ignore unexpected syntax (better for upward compatibility) } if (xpmstarted) { // XPM data was incomplete DeleteXPMData(xpmdata, maxstrings); char s[128]; sprintf(s, "The XPM icon data starting on line %d in ", xpmstarted); std::string msg(s); msg += rulename; msg += ".rule does not have enough strings."; Warning(msg.c_str()); *eof = true; return; } // create scaled bitmaps if size(s) not supplied if (!currlayer->icons7x7) { if (currlayer->icons15x15) { // scale down 15x15 bitmaps currlayer->icons7x7 = ScaleIconBitmaps(currlayer->icons15x15, 7); } else if (currlayer->icons31x31) { // scale down 31x31 bitmaps currlayer->icons7x7 = ScaleIconBitmaps(currlayer->icons31x31, 7); } } if (!currlayer->icons15x15) { if (currlayer->icons31x31) { // scale down 31x31 bitmaps currlayer->icons15x15 = ScaleIconBitmaps(currlayer->icons31x31, 15); } else if (currlayer->icons7x7) { // scale up 7x7 bitmaps currlayer->icons15x15 = ScaleIconBitmaps(currlayer->icons7x7, 15); } } if (!currlayer->icons31x31) { if (currlayer->icons15x15) { // scale up 15x15 bitmaps currlayer->icons31x31 = ScaleIconBitmaps(currlayer->icons15x15, 31); } else if (currlayer->icons7x7) { // scale up 7x7 bitmaps currlayer->icons31x31 = ScaleIconBitmaps(currlayer->icons7x7, 31); } } } // ----------------------------------------------------------------------------- static void LoadRuleInfo(FILE* rulefile, const std::string& rulename, bool* loadedcolors, bool* loadedicons) { // load any color/icon info from currently open .rule file const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; int linenum = 0; bool eof = false; bool skipget = false; // the linereader class handles all line endings (CR, CR+LF, LF) linereader reader(rulefile); while (true) { if (skipget) { // ParseColors/ParseIcons has stopped at next section // (ie. linebuf contains @...) so skip fgets call skipget = false; } else { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; linenum++; if (linenum == 1) CheckRuleHeader(linebuf, rulename); } // look for @COLORS or @ICONS section if (strcmp(linebuf, "@COLORS") == 0 && !*loadedcolors) { *loadedcolors = true; ParseColors(reader, linebuf, MAXLINELEN, &linenum, &eof); if (eof) break; // otherwise linebuf contains @... so skip next fgets call skipget = true; } else if (strcmp(linebuf, "@ICONS") == 0 && !*loadedicons) { *loadedicons = true; ParseIcons(rulename, reader, linebuf, MAXLINELEN, &linenum, &eof); if (eof) break; // otherwise linebuf contains @... so skip next fgets call skipget = true; } } reader.close(); // closes rulefile } // ----------------------------------------------------------------------------- static void DeleteIcons(Layer* layer) { // delete given layer's existing icons if (layer->icons7x7) { FreeIconBitmaps(layer->icons7x7); layer->icons7x7 = NULL; } if (layer->icons15x15) { FreeIconBitmaps(layer->icons15x15); layer->icons15x15 = NULL; } if (layer->icons31x31) { FreeIconBitmaps(layer->icons31x31); layer->icons31x31 = NULL; } // also delete icon pixel data if (layer->textures7x7) { for (int i = 0; i < 256; i++) if (layer->textures7x7[i]) free(layer->textures7x7[i]); free(layer->textures7x7); layer->textures7x7 = NULL; } if (layer->textures15x15) { for (int i = 0; i < 256; i++) if (layer->textures15x15[i]) free(layer->textures15x15[i]); free(layer->textures15x15); layer->textures15x15 = NULL; } if (layer->textures31x31) { for (int i = 0; i < 256; i++) if (layer->textures31x31[i]) free(layer->textures31x31[i]); free(layer->textures31x31); layer->textures31x31 = NULL; } } // ----------------------------------------------------------------------------- static void UseDefaultIcons(int maxstate) { // icons weren't specified so use default icons if (currlayer->algo->getgridtype() == lifealgo::HEX_GRID) { // use hexagonal icons currlayer->icons7x7 = CopyIcons(hexagons7x7, maxstate); currlayer->icons15x15 = CopyIcons(hexagons15x15, maxstate); currlayer->icons31x31 = CopyIcons(hexagons31x31, maxstate); } else if (currlayer->algo->getgridtype() == lifealgo::VN_GRID) { // use diamond-shaped icons for 4-neighbor von Neumann neighborhood currlayer->icons7x7 = CopyIcons(diamonds7x7, maxstate); currlayer->icons15x15 = CopyIcons(diamonds15x15, maxstate); currlayer->icons31x31 = CopyIcons(diamonds31x31, maxstate); } else { // otherwise use default icons from current algo AlgoData* ad = algoinfo[currlayer->algtype]; currlayer->icons7x7 = CopyIcons(ad->icons7x7, maxstate); currlayer->icons15x15 = CopyIcons(ad->icons15x15, maxstate); currlayer->icons31x31 = CopyIcons(ad->icons31x31, maxstate); } } // ----------------------------------------------------------------------------- void CreateColorGradient() { int maxstate = currlayer->algo->NumCellStates() - 1; unsigned char r1 = currlayer->fromrgb.r; unsigned char g1 = currlayer->fromrgb.g; unsigned char b1 = currlayer->fromrgb.b; unsigned char r2 = currlayer->torgb.r; unsigned char g2 = currlayer->torgb.g; unsigned char b2 = currlayer->torgb.b; // set cell colors for states 1..maxstate using a color gradient // starting with r1,g1,b1 and ending with r2,g2,b2 currlayer->cellr[1] = r1; currlayer->cellg[1] = g1; currlayer->cellb[1] = b1; if (maxstate > 2) { int N = maxstate - 1; double rfrac = (double)(r2 - r1) / (double)N; double gfrac = (double)(g2 - g1) / (double)N; double bfrac = (double)(b2 - b1) / (double)N; for (int n = 1; n < N; n++) { currlayer->cellr[n+1] = (int)(r1 + n * rfrac + 0.5); currlayer->cellg[n+1] = (int)(g1 + n * gfrac + 0.5); currlayer->cellb[n+1] = (int)(b1 + n * bfrac + 0.5); } } if (maxstate > 1) { currlayer->cellr[maxstate] = r2; currlayer->cellg[maxstate] = g2; currlayer->cellb[maxstate] = b2; } } // ----------------------------------------------------------------------------- void UpdateCurrentColors() { // set current layer's colors and icons according to current algo and rule AlgoData* ad = algoinfo[currlayer->algtype]; int maxstate = currlayer->algo->NumCellStates() - 1; // copy default colors from current algo currlayer->fromrgb = ad->fromrgb; currlayer->torgb = ad->torgb; if (ad->gradient) { CreateColorGradient(); // state 0 is not part of the gradient currlayer->cellr[0] = ad->algor[0]; currlayer->cellg[0] = ad->algog[0]; currlayer->cellb[0] = ad->algob[0]; } else { for (int n = 0; n <= maxstate; n++) { currlayer->cellr[n] = ad->algor[n]; currlayer->cellg[n] = ad->algog[n]; currlayer->cellb[n] = ad->algob[n]; } } std::string rulename = currlayer->algo->getrule(); // replace any '\' and '/' chars with underscores; // ie. given 12/34/6 we look for 12_34_6.{colors|icons} std::replace(rulename.begin(), rulename.end(), '\\', '_'); std::replace(rulename.begin(), rulename.end(), '/', '_'); // strip off any suffix like ":T100,200" used to specify a bounded grid size_t colonpos = rulename.find(':'); if (colonpos != std::string::npos) rulename = rulename.substr(0, colonpos); // deallocate current layer's old icons DeleteIcons(currlayer); // this flag will change if any icon uses a non-grayscale color currlayer->multicoloricons = false; bool loadedcolors = false; bool loadedicons = false; // look for rulename.rule FILE* rulefile = FindRuleFile(rulename); if (rulefile) { LoadRuleInfo(rulefile, rulename, &loadedcolors, &loadedicons); if (!loadedcolors || !loadedicons) { // if rulename has the form foo-* then look for foo-shared.rule // and load its colors and/or icons size_t hyphenpos = rulename.rfind('-'); if (hyphenpos != std::string::npos && rulename.rfind("-shared") == std::string::npos) { rulename = rulename.substr(0, hyphenpos) + "-shared"; rulefile = FindRuleFile(rulename); if (rulefile) LoadRuleInfo(rulefile, rulename, &loadedcolors, &loadedicons); } } if (!loadedicons) UseDefaultIcons(maxstate); } else { // rulename.rule wasn't found so use default icons UseDefaultIcons(maxstate); } // use the smallest icons to check if they are multi-color if (currlayer->icons7x7) { for (int n = 1; n <= maxstate; n++) { if (MultiColorImage(currlayer->icons7x7[n])) { currlayer->multicoloricons = true; break; } } } // create icon texture data (used for rendering) currlayer->textures7x7 = CreateIconTextures(currlayer->icons7x7, maxstate); currlayer->textures15x15 = CreateIconTextures(currlayer->icons15x15, maxstate); currlayer->textures31x31 = CreateIconTextures(currlayer->icons31x31, maxstate); if (swapcolors) { // invert cell colors in current layer for (int n = 0; n <= maxstate; n++) { currlayer->cellr[n] = 255 - currlayer->cellr[n]; currlayer->cellg[n] = 255 - currlayer->cellg[n]; currlayer->cellb[n] = 255 - currlayer->cellb[n]; } } } // ----------------------------------------------------------------------------- void UpdateLayerColors() { UpdateCurrentColors(); // if current layer has clones then update their colors //!!! UpdateCloneColors(); } // ----------------------------------------------------------------------------- void InvertCellColors() { // invert cell colors in all layers for (int i = 0; i < numlayers; i++) { Layer* layerptr = layer[i]; // do NOT use layerptr->algo->... here -- it might not be correct // for a non-current layer (but we can use layerptr->algtype) for (int n = 0; n < algoinfo[layerptr->algtype]->maxstates; n++) { layerptr->cellr[n] = 255 - layerptr->cellr[n]; layerptr->cellg[n] = 255 - layerptr->cellg[n]; layerptr->cellb[n] = 255 - layerptr->cellb[n]; } } } // ----------------------------------------------------------------------------- Layer* GetLayer(int index) { if (index < 0 || index >= numlayers) { Warning("Bad index in GetLayer!"); return NULL; } else { return layer[index]; } } // ----------------------------------------------------------------------------- int GetUniqueCloneID() { // find first available index (> 0) to use as cloneid for (int i = 1; i < MAX_LAYERS; i++) { if (cloneavail[i]) { cloneavail[i] = false; return i; } } // bug if we get here Warning("Bug in GetUniqueCloneID!"); return 1; } // ----------------------------------------------------------------------------- Layer::Layer() { if (!cloning) { // use a unique temporary file for saving starting patterns tempstart = CreateTempFileName("golly_start_"); } dirty = false; // user has not modified pattern savedirty = false; // in case script created layer stayclean = inscript; // if true then keep the dirty flag false // for the duration of the script savestart = false; // no need to save starting pattern startgen = 0; // initial starting generation startfile.clear(); // no starting pattern currname = "untitled"; // initial window title currfile.clear(); // no pattern file has been loaded originx = 0; // no X origin offset originy = 0; // no Y origin offset icons7x7 = NULL; // no 7x7 icons icons15x15 = NULL; // no 15x15 icons icons31x31 = NULL; // no 31x31 icons textures7x7 = NULL; // no texture data for 7x7 icons textures15x15 = NULL; // no texture data for 15x15 icons textures31x31 = NULL; // no texture data for 31x31 icons currframe = 0; // first frame in timeline autoplay = 0; // not playing tlspeed = 0; // default speed for autoplay lastframe = 0; // no frame displayed // create viewport; the initial size is not important because it will soon change view = new viewport(100,100); if (view == NULL) Fatal("Failed to create viewport!"); if (numlayers == 0) { // creating very first layer (can't be a clone) cloneid = 0; // initialize cloneavail array (cloneavail[0] is never used) cloneavail[0] = false; for (int i = 1; i < MAX_LAYERS; i++) cloneavail[i] = true; // set some options using initial values stored in prefs file algtype = initalgo; hyperspeed = inithyperspeed; showhashinfo = initshowhashinfo; autofit = initautofit; // initial base step and exponent currbase = algoinfo[algtype]->defbase; currexpo = 0; // create empty universe algo = CreateNewUniverse(algtype); // set rule using initrule stored in prefs file const char* err = algo->setrule(initrule); if (err) { // user might have edited rule in prefs file, or deleted table/tree file algo->setrule( algo->DefaultRule() ); } // don't need to remember rule here (SaveLayerSettings will do it) rule.clear(); // initialize undo/redo history undoredo = new UndoRedo(); if (undoredo == NULL) Fatal("Failed to create new undo/redo object!"); touchmode = drawmode; drawingstate = 1; } else { // adding a new layer after currlayer (see AddLayer) // inherit current universe type and other settings algtype = currlayer->algtype; hyperspeed = currlayer->hyperspeed; showhashinfo = currlayer->showhashinfo; autofit = currlayer->autofit; // initial base step and exponent currbase = algoinfo[algtype]->defbase; currexpo = 0; if (cloning) { if (currlayer->cloneid == 0) { // first time this universe is being cloned so need a unique cloneid cloneid = GetUniqueCloneID(); currlayer->cloneid = cloneid; // current layer also becomes a clone numclones += 2; } else { // we're cloning an existing clone cloneid = currlayer->cloneid; numclones++; } // clones share the same universe and undo/redo history algo = currlayer->algo; undoredo = currlayer->undoredo; // clones also share the same timeline currframe = currlayer->currframe; autoplay = currlayer->autoplay; tlspeed = currlayer->tlspeed; lastframe = currlayer->lastframe; // clones use same name for starting file tempstart = currlayer->tempstart; } else { // this layer isn't a clone cloneid = 0; // create empty universe algo = CreateNewUniverse(algtype); // use current rule const char* err = algo->setrule(currlayer->algo->getrule()); if (err) { // table/tree file might have been deleted algo->setrule( algo->DefaultRule() ); } // initialize undo/redo history undoredo = new UndoRedo(); if (undoredo == NULL) Fatal("Failed to create new undo/redo object!"); } // inherit current rule rule = currlayer->algo->getrule(); // inherit current viewport's size, scale and location view->resize( currlayer->view->getwidth(), currlayer->view->getheight() ); view->setpositionmag( currlayer->view->x, currlayer->view->y, currlayer->view->getmag() ); // inherit current touch mode and drawing state touchmode = currlayer->touchmode; drawingstate = currlayer->drawingstate; if (cloning || duplicating) { // duplicate all the other current settings currname = currlayer->currname; dirty = currlayer->dirty; savedirty = currlayer->savedirty; stayclean = currlayer->stayclean; currbase = currlayer->currbase; currexpo = currlayer->currexpo; autofit = currlayer->autofit; hyperspeed = currlayer->hyperspeed; showhashinfo = currlayer->showhashinfo; originx = currlayer->originx; originy = currlayer->originy; // duplicate selection info currsel = currlayer->currsel; savesel = currlayer->savesel; // duplicate the stuff needed to reset pattern savestart = currlayer->savestart; startalgo = currlayer->startalgo; startdirty = currlayer->startdirty; startname = currlayer->startname; startrule = currlayer->startrule; startx = currlayer->startx; starty = currlayer->starty; startbase = currlayer->startbase; startexpo = currlayer->startexpo; startmag = currlayer->startmag; startgen = currlayer->startgen; startfile = currlayer->startfile; currfile = currlayer->currfile; startsel = currlayer->startsel; } if (duplicating) { // first set same gen count algo->setGeneration( currlayer->algo->getGeneration() ); // duplicate pattern if ( !currlayer->algo->isEmpty() ) { bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( OutsideLimits(top, left, bottom, right) ) { Warning("Pattern is too big to duplicate."); } else { CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, algo, false, "Duplicating layer"); } } // tempstart file must remain unique in duplicate layer if ( FileExists(currlayer->tempstart) ) { if ( !CopyFile(currlayer->tempstart, tempstart) ) { Warning("Could not copy tempstart file!"); } } if (currlayer->startfile == currlayer->tempstart) { startfile = tempstart; } if (currlayer->currfile == currlayer->tempstart) { // starting pattern came from clipboard or lexicon pattern currfile = tempstart; } if (allowundo) { // duplicate current undo/redo history in new layer undoredo->DuplicateHistory(currlayer, this); } } } } // ----------------------------------------------------------------------------- Layer::~Layer() { // delete stuff allocated in ctor delete view; if (cloneid > 0) { // this layer is a clone, so count how many layers have the same cloneid int clonecount = 0; for (int i = 0; i < numlayers; i++) { if (layer[i]->cloneid == cloneid) clonecount++; // tell undo/redo which clone is being deleted if (this == layer[i]) undoredo->DeletingClone(i); } if (clonecount > 2) { // only delete this clone numclones--; } else { // first make this cloneid available for the next clone cloneavail[cloneid] = true; // reset the other cloneid to 0 (should only be one such clone) for (int i = 0; i < numlayers; i++) { // careful -- layer[i] might be this layer if (this != layer[i] && layer[i]->cloneid == cloneid) layer[i]->cloneid = 0; } numclones -= 2; } } else { // this layer is not a clone, so delete universe and undo/redo history delete algo; delete undoredo; // delete tempstart file if it exists if (FileExists(tempstart)) RemoveFile(tempstart); // delete any icons DeleteIcons(this); } } golly-2.7-src/gui-common/utils.h0000644000175000017500000000747012536111364013613 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _UTILS_H_ #define _UTILS_H_ #include // for std::string class lifepoll; // Various types and utility routines: typedef struct { unsigned char r; unsigned char g; unsigned char b; } gColor; // a color in RGB space typedef struct { int x; int y; int width; int height; } gRect; // a rectangle void SetColor(gColor& color, unsigned char red, unsigned char green, unsigned char blue); // Set given gColor to given RGB values. void SetRect(gRect& rect, int x, int y, int width, int height); // Set given gRect to given location and size. void Warning(const char* msg); // Beep and display message in a modal dialog. bool YesNo(const char* msg); // Similar to Warning, but there are 2 buttons: Yes and No. // Returns true if Yes button is hit. void Fatal(const char* msg); // Beep, display message in a modal dialog, then exit app. void Beep(); // Play beep sound, depending on user setting. double TimeInSeconds(); // Get time of day, in seconds (accuracy in microsecs). std::string CreateTempFileName(const char* prefix); // Return path to a unique temporary file. bool FileExists(const std::string& filepath); // Does given file exist? void RemoveFile(const std::string& filepath); // Delete given file. bool CopyFile(const std::string& inpath, const std::string& outpath); // Return true if input file is successfully copied to output file. // If the output file existed it is replaced. bool MoveFile(const std::string& inpath, const std::string& outpath); // Return true if input file is successfully moved to output file. // If the output file existed it is replaced. void FixURLPath(std::string& path); // Replace "%..." with suitable chars for a file path (eg. %20 is changed to space). bool IsHTMLFile(const std::string& filename); // Return true if the given file's extension is .htm or .html // (ignoring case). bool IsTextFile(const std::string& filename); // Return true if the given file's extension is .txt or .doc, // or if it's not a HTML file and its name contains "readme" // (ignoring case). bool IsZipFile(const std::string& filename); // Return true if the given file's extension is .zip or .gar // (ignoring case). bool IsRuleFile(const std::string& filename); // Return true if the given file is a rule-related file with // an extension of .rule or .table or .tree or .colors or .icons // (ignoring case). bool IsScriptFile(const std::string& filename); // Return true if the given file is a Perl or Python script. // It simply checks if the file's extension is .pl or .py // (ignoring case). bool EndsWith(const std::string& str, const std::string& suffix); // Return true if given string ends with given suffix. lifepoll* Poller(); void PollerReset(); void PollerInterrupt(); extern int event_checker; // Poller is used by gollybase modules to process events. // If event_checker > 0 then we've been called from the event checking code. #endif golly-2.7-src/gui-common/status.cpp0000644000175000017500000002102012536111364014314 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include "lifealgo.h" #include "utils.h" // for Fatal, Beep #include "prefs.h" // for mindelay, maxdelay, etc #include "algos.h" // for algoinfo #include "layer.h" // for currlayer #include "view.h" // for nopattupdate, widescreen, PointInView, etc #include "status.h" #ifdef ANDROID_GUI #include "jnicalls.h" // for UpdateStatus, GetRuleName #endif #ifdef WEB_GUI #include "webcalls.h" // for UpdateStatus, GetRuleName #include // for fabs #endif #ifdef IOS_GUI #import "PatternViewController.h" // for UpdateStatus #import "RuleViewController.h" // for GetRuleName #endif // ----------------------------------------------------------------------------- std::string status1; // top line std::string status2; // middle line std::string status3; // bottom line // prefixes used when widescreen is true: const char* large_gen_prefix = "Generation="; const char* large_algo_prefix = " Algorithm="; const char* large_rule_prefix = " Rule="; const char* large_pop_prefix = " Population="; const char* large_scale_prefix = " Scale="; const char* large_step_prefix = " "; const char* large_xy_prefix = " XY="; // prefixes used when widescreen is false: const char* small_gen_prefix = "Gen="; const char* small_algo_prefix = " Algo="; const char* small_rule_prefix = " Rule="; const char* small_pop_prefix = " Pop="; const char* small_scale_prefix = " Scale="; const char* small_step_prefix = " "; const char* small_xy_prefix = " XY="; static bigint currx, curry; // cursor location in cell coords static bool showxy = false; // show cursor's XY location? // ----------------------------------------------------------------------------- void UpdateStatusLines() { std::string rule = currlayer->algo->getrule(); status1 = "Pattern="; if (currlayer->dirty) { // display asterisk to indicate pattern has been modified status1 += "*"; } status1 += currlayer->currname; status1 += widescreen ? large_algo_prefix : small_algo_prefix; status1 += GetAlgoName(currlayer->algtype); status1 += widescreen ? large_rule_prefix : small_rule_prefix; status1 += rule; // show rule name if one exists and is not same as rule // (best NOT to remove any suffix like ":T100,200" in case we allow // users to name "B3/S23:T100,200" as "Life on torus") std::string rulename = GetRuleName(rule); if (!rulename.empty() && rulename != rule) { status1 += " ["; status1 += rulename; status1 += "]"; } char scalestr[32]; int mag = currlayer->view->getmag(); if (mag < 0) { sprintf(scalestr, "2^%d:1", -mag); } else { sprintf(scalestr, "1:%d", 1 << mag); } char stepstr[32]; if (currlayer->currexpo < 0) { // show delay in secs sprintf(stepstr, "Delay=%gs", (double)GetCurrentDelay() / 1000.0); } else { sprintf(stepstr, "Step=%d^%d", currlayer->currbase, currlayer->currexpo); } status2 = widescreen ? large_gen_prefix : small_gen_prefix; if (nopattupdate) { status2 += "0"; } else { status2 += Stringify(currlayer->algo->getGeneration()); } status2 += widescreen ? large_pop_prefix : small_pop_prefix; if (nopattupdate) { status2 += "0"; } else { bigint popcount = currlayer->algo->getPopulation(); if (popcount.sign() < 0) { // getPopulation returns -1 if it can't be calculated status2 += "?"; } else { status2 += Stringify(popcount); } } status2 += widescreen ? large_scale_prefix : small_scale_prefix; status2 += scalestr; status2 += widescreen ? large_step_prefix : small_step_prefix; status2 += stepstr; status2 += widescreen ? large_xy_prefix : small_xy_prefix; #ifdef WEB_GUI // in web app we show the cursor's current cell location, // or nothing if the cursor is outside the viewport (ie. showxy is false) if (showxy) { bigint xo, yo; bigint xpos = currx; xpos -= currlayer->originx; bigint ypos = curry; ypos -= currlayer->originy; if (mathcoords) { // Y values increase upwards bigint temp = 0; temp -= ypos; ypos = temp; } status2 += Stringify(xpos); status2 += " "; status2 += Stringify(ypos); } #else // in iOS and Android apps we show location of the cell in middle of viewport status2 += Stringify(currlayer->view->x); status2 += " "; status2 += Stringify(currlayer->view->y); #endif } // ----------------------------------------------------------------------------- void ClearMessage() { if (status3.length() == 0) return; // no need to clear message status3.clear(); UpdateStatus(); } // ----------------------------------------------------------------------------- void DisplayMessage(const char* s) { status3 = s; UpdateStatus(); } // ----------------------------------------------------------------------------- void ErrorMessage(const char* s) { Beep(); DisplayMessage(s); } // ----------------------------------------------------------------------------- void SetMessage(const char* s) { // set message string without displaying it status3 = s; } // ----------------------------------------------------------------------------- int GetCurrentDelay() { int gendelay = mindelay * (1 << (-currlayer->currexpo - 1)); if (gendelay > maxdelay) gendelay = maxdelay; return gendelay; } // ----------------------------------------------------------------------------- char* Stringify(const bigint& b) { static char buf[32]; char* p = buf; double d = b.todouble(); if ( fabs(d) > 1000000000.0 ) { // use e notation for abs value > 10^9 (agrees with min & max_coord) sprintf(p, "%g", d); } else { // show exact value with commas inserted for readability if ( d < 0 ) { d = - d; *p++ = '-'; } sprintf(p, "%.f", d); int len = strlen(p); int commas = ((len + 2) / 3) - 1; int dest = len + commas; int src = len; p[dest] = 0; while (commas > 0) { p[--dest] = p[--src]; p[--dest] = p[--src]; p[--dest] = p[--src]; p[--dest] = ','; commas--; } if ( p[-1] == '-' ) p--; } return p; } // ----------------------------------------------------------------------------- void CheckMouseLocation(int x, int y) { // check if we need to update XY location in status bar bool mouse_in_grid = false; bigint xpos, ypos; if (PointInView(x, y)) { // get mouse location in cell coords pair cellpos = currlayer->view->at(x, y); xpos = cellpos.first; ypos = cellpos.second; // check if xpos,ypos is inside grid (possibly bounded) mouse_in_grid = CellInGrid(xpos, ypos); } if (mouse_in_grid) { if ( xpos != currx || ypos != curry ) { // show new XY location currx = xpos; curry = ypos; showxy = true; UpdateStatus(); } else if (!showxy) { // mouse moved from outside grid and back over currx,curry showxy = true; UpdateStatus(); } } else { // mouse is outside grid so clear XY location if necessary if (showxy) { showxy = false; UpdateStatus(); } } } golly-2.7-src/gui-common/file.cpp0000644000175000017500000011767512536111364013736 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifdef ANDROID_GUI #include "jnicalls.h" // for SwitchToPatternTab, ShowTextFile, ShowHelp, etc #endif #ifdef WEB_GUI #include "webcalls.h" // for SwitchToPatternTab, ShowTextFile, ShowHelp, etc #endif #ifdef IOS_GUI #import "GollyAppDelegate.h" // for SwitchToPatternTab #import "HelpViewController.h" // for ShowHelp #import "InfoViewController.h" // for ShowTextFile #endif // we use MiniZip code for opening zip files and extracting files stored within them #include "zip.h" #include "unzip.h" #include // for std::string #include // for std::list #include // for std::runtime_error and std::exception #include // for std::ostringstream #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "readpattern.h" // for readpattern #include "writepattern.h" // for writepattern, pattern_format #include "utils.h" // for Warning #include "prefs.h" // for SavePrefs, allowundo, userrules, etc #include "status.h" // for SetMessage #include "algos.h" // for CreateNewUniverse, algo_type, algoinfo, etc #include "layer.h" // for currlayer, etc #include "control.h" // for SetGenIncrement, ChangeAlgorithm #include "view.h" // for origin_restored, nopattupdate #include "undo.h" // for UndoRedo #include "file.h" // ----------------------------------------------------------------------------- std::string GetBaseName(const char* path) { // extract basename from given path std::string basename = path; size_t lastsep = basename.rfind('/'); if (lastsep != std::string::npos) { basename = basename.substr(lastsep+1); } return basename; } // ----------------------------------------------------------------------------- void SetPatternTitle(const char* filename) { if ( filename[0] != 0 ) { // remember current file name currlayer->currname = filename; // show currname in current layer's menu item //!!! UpdateLayerItem(currindex); } } // ----------------------------------------------------------------------------- bool SaveCurrentLayer() { if (currlayer->algo->isEmpty()) return true; // no need to save empty universe #ifdef WEB_GUI // show a modal dialog that lets user save their changes return WebSaveChanges(); #else // currently ignored in Android and iOS versions return true; #endif } // ----------------------------------------------------------------------------- void CreateUniverse() { // save current rule std::string oldrule = currlayer->algo->getrule(); // delete old universe and create new one of same type delete currlayer->algo; currlayer->algo = CreateNewUniverse(currlayer->algtype); // ensure new universe uses same rule (and thus same # of cell states) RestoreRule(oldrule.c_str()); // increment has been reset to 1 but that's probably not always desirable // so set increment using current step size SetGenIncrement(); } // ----------------------------------------------------------------------------- void NewPattern(const char* title) { if (generating) Warning("Bug detected in NewPattern!"); if (currlayer->dirty && asktosave && !SaveCurrentLayer()) return; currlayer->savestart = false; currlayer->currfile.clear(); currlayer->startgen = 0; // reset step size before CreateUniverse calls SetGenIncrement currlayer->currbase = algoinfo[currlayer->algtype]->defbase; currlayer->currexpo = 0; // create new, empty universe of same type and using same rule CreateUniverse(); // clear all undo/redo history currlayer->undoredo->ClearUndoRedo(); // possibly clear selection currlayer->currsel.Deselect(); // initially in drawing mode currlayer->touchmode = drawmode; // reset location and scale currlayer->view->setpositionmag(bigint::zero, bigint::zero, MAX_MAG); // no longer use newmag // best to restore true origin if (currlayer->originx != bigint::zero || currlayer->originy != bigint::zero) { currlayer->originx = 0; currlayer->originy = 0; SetMessage(origin_restored); } // restore default colors for current algo/rule UpdateLayerColors(); MarkLayerClean(title); // calls SetPatternTitle } // ----------------------------------------------------------------------------- bool LoadPattern(const char* path, const char* newtitle) { if ( !FileExists(path) ) { std::string msg = "The file does not exist:\n"; msg += path; Warning(msg.c_str()); return false; } // newtitle is only empty if called from ResetPattern/RestorePattern if (newtitle[0] != 0) { if (currlayer->dirty && asktosave && !SaveCurrentLayer()) return false; currlayer->savestart = false; currlayer->currfile = path; // reset step size currlayer->currbase = algoinfo[currlayer->algtype]->defbase; currlayer->currexpo = 0; // clear all undo/redo history currlayer->undoredo->ClearUndoRedo(); } // disable pattern update so we see gen=0 and pop=0; // in particular, it avoids getPopulation being called which would slow down macrocell loading nopattupdate = true; // save current algo and rule algo_type oldalgo = currlayer->algtype; std::string oldrule = currlayer->algo->getrule(); // delete old universe and create new one of same type delete currlayer->algo; currlayer->algo = CreateNewUniverse(currlayer->algtype); const char* err = readpattern(path, *currlayer->algo); if (err) { // cycle thru all other algos until readpattern succeeds for (int i = 0; i < NumAlgos(); i++) { if (i != oldalgo) { currlayer->algtype = i; delete currlayer->algo; currlayer->algo = CreateNewUniverse(currlayer->algtype); // readpattern will call setrule err = readpattern(path, *currlayer->algo); if (!err) break; } } if (err) { // no algo could read pattern so restore original algo and rule currlayer->algtype = oldalgo; delete currlayer->algo; currlayer->algo = CreateNewUniverse(currlayer->algtype); RestoreRule(oldrule.c_str()); // Warning(err); // current error and original error are not necessarily meaningful // so report a more generic error Warning("File could not be loaded by any algorithm\n(probably due to an unknown rule)."); } } // enable pattern update nopattupdate = false; if (newtitle[0] != 0) { MarkLayerClean(newtitle); // calls SetPatternTitle // restore default base step for current algo // (currlayer->currexpo was set to 0 above) currlayer->currbase = algoinfo[currlayer->algtype]->defbase; SetGenIncrement(); // restore default colors for current algo/rule UpdateLayerColors(); currlayer->currsel.Deselect(); // initially in moving mode currlayer->touchmode = movemode; currlayer->algo->fit(*currlayer->view, 1); currlayer->startgen = currlayer->algo->getGeneration(); // might be > 0 UpdateEverything(); } return err == NULL; } // ----------------------------------------------------------------------------- void AddRecentPattern(const char* inpath) { std::string path = inpath; if (path.find(userdir) == 0) { // remove userdir from start of path path.erase(0, userdir.length()); } // check if path is already in recentpatterns if (!recentpatterns.empty()) { std::list::iterator next = recentpatterns.begin(); while (next != recentpatterns.end()) { std::string nextpath = *next; if (path == nextpath) { if (next == recentpatterns.begin()) { // path is in recentpatterns and at top, so we're done return; } // remove this path from recentpatterns (we'll add it below) recentpatterns.erase(next); numpatterns--; break; } next++; } } // put given path at start of recentpatterns recentpatterns.push_front(path); if (numpatterns < maxpatterns) { numpatterns++; } else { // remove the path at end of recentpatterns recentpatterns.pop_back(); } } // ----------------------------------------------------------------------------- bool CopyTextToClipboard(const char* text) { #ifdef ANDROID_GUI return AndroidCopyTextToClipboard(text); #endif #ifdef WEB_GUI return WebCopyTextToClipboard(text); #endif #ifdef IOS_GUI UIPasteboard *pboard = [UIPasteboard generalPasteboard]; pboard.string = [NSString stringWithCString:text encoding:NSUTF8StringEncoding]; return true; #endif } // ----------------------------------------------------------------------------- bool GetTextFromClipboard(std::string& text) { #ifdef ANDROID_GUI return AndroidGetTextFromClipboard(text); #endif #ifdef WEB_GUI return WebGetTextFromClipboard(text); #endif #ifdef IOS_GUI UIPasteboard *pboard = [UIPasteboard generalPasteboard]; NSString *str = pboard.string; if (str == nil) { ErrorMessage("No text in clipboard."); return false; } else { text = [str cStringUsingEncoding:NSUTF8StringEncoding]; return true; } #endif } // ----------------------------------------------------------------------------- void LoadRule(const std::string& rulestring) { // load recently installed .rule file std::string oldrule = currlayer->algo->getrule(); int oldmaxstate = currlayer->algo->NumCellStates() - 1; // selection might change if grid becomes smaller, // so save current selection for RememberRuleChange/RememberAlgoChange SaveCurrentSelection(); const char* err = currlayer->algo->setrule(rulestring.c_str()); if (err) { // try to find another algorithm that supports the given rule for (int i = 0; i < NumAlgos(); i++) { if (i != currlayer->algtype) { lifealgo* tempalgo = CreateNewUniverse(i); err = tempalgo->setrule(rulestring.c_str()); delete tempalgo; if (!err) { // change the current algorithm and switch to the new rule ChangeAlgorithm(i, rulestring.c_str()); if (i != currlayer->algtype) { RestoreRule(oldrule.c_str()); Warning("Algorithm could not be changed (pattern is too big to convert)."); } return; } } } // should only get here if rule/table/tree file contains some sort of error RestoreRule(oldrule.c_str()); std::string msg = "Rule is not valid in any algorithm: " + rulestring; Warning(msg.c_str()); return; } std::string newrule = currlayer->algo->getrule(); if (oldrule != newrule) { // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { ClearOutsideGrid(); } } // new rule might have changed the number of cell states; // if there are fewer states then pattern might change int newmaxstate = currlayer->algo->NumCellStates() - 1; if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { ReduceCellStates(newmaxstate); } // set colors for new rule (loads any .rule file) UpdateLayerColors(); if (oldrule != newrule) { if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberRuleChange(oldrule.c_str()); } } } // ----------------------------------------------------------------------------- bool ExtractZipEntry(const std::string& zippath, const std::string& entryname, const std::string& outfile) { bool found = false; bool ok = false; std::ostringstream oss; int err; char* zipdata = NULL; unzFile zfile = unzOpen(zippath.c_str()); if (zfile == NULL) { std::string msg = "Could not open zip file:\n" + zippath; Warning(msg.c_str()); return false; } try { err = unzGoToFirstFile(zfile); if (err != UNZ_OK) { oss << "Error going to first file in zip file:\n" << zippath.c_str(); throw std::runtime_error(oss.str().c_str()); } do { char filename[256]; unz_file_info file_info; err = unzGetCurrentFileInfo(zfile, &file_info, filename, sizeof(filename), NULL, 0, NULL, 0); if (err != UNZ_OK) { oss << "Error getting current file info in zip file:\n" << zippath.c_str(); throw std::runtime_error(oss.str().c_str()); } std::string thisname = filename; if (thisname == entryname) { found = true; // we've found the desired entry so copy entry data to given outfile zipdata = (char*) malloc(file_info.uncompressed_size); if (zipdata == NULL) { throw std::runtime_error("Failed to allocate memory for zip file entry!"); } err = unzOpenCurrentFilePassword(zfile, NULL); if (err != UNZ_OK) { oss << "Error opening current zip entry:\n" << entryname.c_str(); throw std::runtime_error(oss.str().c_str()); } int bytesRead = unzReadCurrentFile(zfile, zipdata, file_info.uncompressed_size); if (bytesRead < 0) { throw std::runtime_error("Error reading the zip entry data!"); } err = unzCloseCurrentFile(zfile); if (err != UNZ_OK) { oss << "Error closing current zip entry:\n" << entryname.c_str(); throw std::runtime_error(oss.str().c_str()); } if (file_info.uncompressed_size == 0) { Warning("Zip entry is empty!"); } else if (bytesRead == (long)(file_info.uncompressed_size)) { // write zipdata to outfile FILE* f = fopen(outfile.c_str(), "wb"); if (f) { if (fwrite(zipdata, 1, bytesRead, f) != (size_t)bytesRead) { Warning("Could not write data for zip entry!"); } else { ok = true; } fclose(f); } else { Warning("Could not create file for zip entry!"); } } else { Warning("Failed to read all bytes of zip entry!"); } break; } } while (unzGoToNextFile(zfile) == UNZ_OK); } catch(const std::exception& e) { // display message set by throw std::runtime_error(...) Warning(e.what()); } if (zipdata) free(zipdata); err = unzClose(zfile); if (err != UNZ_OK) { Warning("Error closing zip file!"); } if (found && ok) return true; if (!found) { std::string msg = "Could not find zip file entry:\n" + entryname; Warning(msg.c_str()); } else { // outfile is probably incomplete so best to delete it if (FileExists(outfile)) RemoveFile(outfile); } return false; } // ----------------------------------------------------------------------------- void UnzipFile(const std::string& zippath, const std::string& entry) { std::string filename = GetBaseName(entry.c_str()); std::string tempfile = tempdir + filename; if ( IsRuleFile(filename) ) { // rule-related file should have already been extracted and installed // into userrules, so check that file exists and load rule std::string rulefile = userrules + filename; if (FileExists(rulefile)) { // load corresponding rule SwitchToPatternTab(); LoadRule(filename.substr(0, filename.rfind('.'))); } else { std::string msg = "Rule-related file was not installed:\n" + rulefile; Warning(msg.c_str()); } } else if ( ExtractZipEntry(zippath, entry, tempfile) ) { if ( IsHTMLFile(filename) ) { // display html file ShowHelp(tempfile.c_str()); } else if ( IsTextFile(filename) ) { // display text file ShowTextFile(tempfile.c_str()); } else if ( IsScriptFile(filename) ) { // run script depending on safety check; note that because the script is // included in a zip file we don't remember it in the Run Recent submenu //!!! CheckBeforeRunning(tempfile, false, zippath); Warning("This version of Golly cannot run scripts."); } else { // open pattern but don't remember in recentpatterns OpenFile(tempfile.c_str(), false); } } } // ----------------------------------------------------------------------------- static bool RuleInstalled(unzFile zfile, unz_file_info& info, const std::string& outfile) { if (info.uncompressed_size == 0) { Warning("Zip entry is empty!"); return false; } char* zipdata = (char*) malloc(info.uncompressed_size); if (zipdata == NULL) { Warning("Failed to allocate memory for rule file!"); return false; } int err = unzOpenCurrentFilePassword(zfile, NULL); if (err != UNZ_OK) { Warning("Error opening current zip entry!"); free(zipdata); return false; } int bytesRead = unzReadCurrentFile(zfile, zipdata, info.uncompressed_size); if (bytesRead < 0) { // error is detected below } err = unzCloseCurrentFile(zfile); if (err != UNZ_OK) { Warning("Error closing current zip entry!"); // but keep going } bool ok = true; if (bytesRead == (long)(info.uncompressed_size)) { // write zipdata to outfile FILE* f = fopen(outfile.c_str(), "wb"); if (f) { if (fwrite(zipdata, 1, bytesRead, f) != (size_t)bytesRead) { Warning("Could not write data for zip entry!"); ok = false; } fclose(f); } else { Warning("Could not create file for zip entry!"); ok = false; } } else { Warning("Failed to read all bytes of zip entry!"); ok = false; } free(zipdata); return ok; } // ----------------------------------------------------------------------------- void OpenZipFile(const char* zippath) { // Process given zip file in the following manner: // - If it contains any .rule files then extract and install those files // into userrules (the user's rules directory). // - Build a temporary html file with clickable links to each file entry // and show it in the Help tab. const std::string indent = "    "; bool dirseen = false; bool diffdirs = (userrules != rulesdir); std::string firstdir = ""; std::string lastpattern = ""; std::string lastscript = ""; int patternseps = 0; // # of separators in lastpattern int scriptseps = 0; // # of separators in lastscript int patternfiles = 0; int scriptfiles = 0; int textfiles = 0; // includes html files int rulefiles = 0; int deprecated = 0; // # of .table/tree files std::list deplist; // list of installed deprecated files std::list rulelist; // list of installed .rule files int err; // strip off patternsdir or userdir std::string relpath = zippath; size_t pos = relpath.find(patternsdir); if (pos == 0) { relpath.erase(0, patternsdir.length()); } else { pos = relpath.find(userdir); if (pos == 0) relpath.erase(0, userdir.length()); } std::string contents = "

\nContents of "; contents += relpath; contents += ":

\n"; unzFile zfile = unzOpen(zippath); if (zfile == NULL) { std::string msg = "Could not open zip file:\n"; msg += zippath; Warning(msg.c_str()); return; } try { err = unzGoToFirstFile(zfile); if (err != UNZ_OK) { throw std::runtime_error("Error going to first file in zip file!"); } do { // examine each entry in zip file and build contents string; // also install any .rule files char entryname[256]; unz_file_info file_info; err = unzGetCurrentFileInfo(zfile, &file_info, entryname, sizeof(entryname), NULL, 0, NULL, 0); if (err != UNZ_OK) { throw std::runtime_error("Error getting current file info in zip file!"); } std::string name = entryname; if (name.find("__MACOSX") == 0 || name.rfind(".DS_Store") != std::string::npos) { // ignore meta-data stuff in zip file created on Mac } else { // indent depending on # of separators in name unsigned int sepcount = 0; unsigned int i = 0; unsigned int len = name.length(); while (i < len) { if (name[i] == '/') sepcount++; i++; } // check if 1st directory has multiple separators (eg. in jslife.zip) if (name[len-1] == '/' && !dirseen && sepcount > 1) { firstdir = name.substr(0, name.find('/')); contents += firstdir; contents += "
\n"; } for (i = 1; i < sepcount; i++) contents += indent; if (name[len-1] == '/') { // remove terminating separator from directory name name = name.substr(0, name.rfind('/')); name = GetBaseName(name.c_str()); if (dirseen && name == firstdir) { // ignore dir already output earlier (eg. in jslife.zip) } else { contents += name; contents += "
\n"; } dirseen = true; } else { // entry is for some sort of file std::string filename = GetBaseName(name.c_str()); if (dirseen) contents += indent; if ( IsRuleFile(filename) && !EndsWith(filename,".rule") ) { // this is a deprecated .table/tree/colors/icons file if (EndsWith(filename,".colors") || EndsWith(filename,".icons")) { // these files are no longer supported and are simply ignored contents += filename; contents += indent; contents += "[ignored]"; // don't add to deprecated list } else { // .table/.tree file contents += filename; contents += indent; contents += "[deprecated]"; deprecated++; // install it into userrules so it can be used below to create a .rule file std::string outfile = userrules + filename; if (RuleInstalled(zfile, file_info, outfile)) { deplist.push_back(filename); } else { contents += indent; contents += "INSTALL FAILED!"; } } } else { // user can extract file via special "unzip:" link contents += ""; contents += filename; contents += ""; if ( IsRuleFile(filename) ) { // extract and install .rule file into userrules std::string outfile = userrules + filename; if (RuleInstalled(zfile, file_info, outfile)) { // file successfully installed rulelist.push_back(filename); contents += indent; contents += "[installed]"; if (diffdirs) { // check if this file overrides similarly named file in rulesdir std::string clashfile = rulesdir + filename; if (FileExists(clashfile)) { contents += indent; contents += "(overrides file in Rules folder)"; } } #ifdef WEB_GUI // ensure the .rule file persists beyond the current session CopyRuleToLocalStorage(outfile.c_str()); #endif } else { // file could not be installed contents += indent; contents += "[NOT installed]"; // file is probably incomplete so best to delete it if (FileExists(outfile)) RemoveFile(outfile); } rulefiles++; } else if ( IsHTMLFile(filename) || IsTextFile(filename) ) { textfiles++; } else if ( IsScriptFile(filename) ) { scriptfiles++; lastscript = name; scriptseps = sepcount; } else { patternfiles++; lastpattern = name; patternseps = sepcount; } } contents += "
\n"; } } } while (unzGoToNextFile(zfile) == UNZ_OK); } catch(const std::exception& e) { // display message set by throw std::runtime_error(...) Warning(e.what()); } err = unzClose(zfile); if (err != UNZ_OK) { Warning("Error closing zip file!"); } if (rulefiles > 0) { relpath = userrules; pos = relpath.find(userdir); if (pos == 0) relpath.erase(0, userdir.length()); contents += "

Files marked as \"[installed]\" have been stored in "; contents += relpath; contents += "."; } if (deprecated > 0) { std::string newrules = CreateRuleFiles(deplist, rulelist); if (newrules.length() > 0) { contents += "

Files marked as \"[deprecated]\" have been used to create new .rule files:
\n"; contents += newrules; } } contents += "\n
"; // NOTE: The desktop version of Golly will load a pattern if it's in a "simple" zip file // but for the iPad version it's probably less confusing if the zip file's contents are // *always* displayed in the Help tab. We might change this if script support is added. // write contents to a unique temporary html file std::string htmlfile = CreateTempFileName("zip_contents"); htmlfile += ".html"; FILE* f = fopen(htmlfile.c_str(), "w"); if (f) { if (fputs(contents.c_str(), f) == EOF) { fclose(f); Warning("Could not write HTML data to temporary file!"); return; } } else { Warning("Could not create temporary HTML file!"); return; } fclose(f); // display temporary html file in Help tab ShowHelp(htmlfile.c_str()); } // ----------------------------------------------------------------------------- void OpenFile(const char* path, bool remember) { // convert path to a full path if necessary std::string fullpath = path; if (path[0] != '/') { if (fullpath.find("Patterns/") == 0) { // Patterns directory is inside supplieddir fullpath = supplieddir + fullpath; } else { fullpath = userdir + fullpath; } } if (IsHTMLFile(path)) { // show HTML file in Help tab ShowHelp(fullpath.c_str()); return; } if (IsTextFile(path)) { // show text file using InfoViewController ShowTextFile(fullpath.c_str()); return; } if (IsScriptFile(path)) { // execute script /*!!! if (remember) AddRecentScript(path); RunScript(path); */ Warning("This version of Golly cannot run scripts."); return; } if (IsZipFile(path)) { // process zip file if (remember) AddRecentPattern(path); // treat zip file like a pattern file OpenZipFile(fullpath.c_str()); // must use full path return; } if (IsRuleFile(path)) { // switch to rule (.rule file must be in rulesdir or userrules) SwitchToPatternTab(); std::string basename = GetBaseName(path); LoadRule(basename.substr(0, basename.rfind('.'))); return; } // anything else is a pattern file if (remember) AddRecentPattern(path); std::string basename = GetBaseName(path); // best to switch to Pattern tab first in case progress view appears SwitchToPatternTab(); LoadPattern(fullpath.c_str(), basename.c_str()); } // ----------------------------------------------------------------------------- const char* WritePattern(const char* path, pattern_format format, output_compression compression, int top, int left, int bottom, int right) { // if the format is RLE_format and the grid is bounded then force XRLE_format so that // position info is recorded (this position will be used when the file is read) if (format == RLE_format && (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0)) format = XRLE_format; const char* err = writepattern(path, *currlayer->algo, format, compression, top, left, bottom, right); return err; } // ----------------------------------------------------------------------------- void SaveSucceeded(const std::string& path) { // save old info for RememberNameChange std::string oldname = currlayer->currname; std::string oldfile = currlayer->currfile; bool oldsave = currlayer->savestart; bool olddirty = currlayer->dirty; //!!! if (allowundo && !currlayer->stayclean) SavePendingChanges(); if ( currlayer->algo->getGeneration() == currlayer->startgen ) { // no need to save starting pattern (ResetPattern can load currfile) currlayer->currfile = path; currlayer->savestart = false; } // set dirty flag false and update currlayer->currname std::string basename = GetBaseName(path.c_str()); MarkLayerClean(basename.c_str()); if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberNameChange(oldname.c_str(), oldfile.c_str(), oldsave, olddirty); } } // ----------------------------------------------------------------------------- bool SavePattern(const std::string& path, pattern_format format, output_compression compression) { bigint top, left, bottom, right; int itop, ileft, ibottom, iright; currlayer->algo->findedges(&top, &left, &bottom, &right); if (currlayer->algo->hyperCapable()) { // algorithm uses hashlife if ( OutsideLimits(top, left, bottom, right) ) { // too big so only allow saving as MC file if (format != MC_format) { Warning("Pattern is outside +/- 10^9 boundary and can't be saved in RLE format."); return false; } itop = ileft = ibottom = iright = 0; } else { // allow saving as MC or RLE file itop = top.toint(); ileft = left.toint(); ibottom = bottom.toint(); iright = right.toint(); } } else { // allow saving file only if pattern is small enough if ( OutsideLimits(top, left, bottom, right) ) { Warning("Pattern is outside +/- 10^9 boundary and can't be saved."); return false; } itop = top.toint(); ileft = left.toint(); ibottom = bottom.toint(); iright = right.toint(); } const char* err = WritePattern(path.c_str(), format, compression, itop, ileft, ibottom, iright); if (err) { Warning(err); return false; } else { std::string msg = "Pattern saved as "; msg += GetBaseName(path.c_str()); DisplayMessage(msg.c_str()); AddRecentPattern(path.c_str()); SaveSucceeded(path); return true; } } // ----------------------------------------------------------------------------- bool DownloadFile(const std::string& url, const std::string& filepath) { #ifdef ANDROID_GUI return AndroidDownloadFile(url, filepath); #endif #ifdef WEB_GUI return WebDownloadFile(url, filepath); #endif #ifdef IOS_GUI NSURL *nsurl = [NSURL URLWithString:[NSString stringWithCString:url.c_str() encoding:NSUTF8StringEncoding]]; if (nsurl == nil) { std::string msg = "Bad URL: " + url; Warning(msg.c_str()); return false; } NSData *urlData = [NSData dataWithContentsOfURL:nsurl]; if (urlData) { [urlData writeToFile:[NSString stringWithCString:filepath.c_str() encoding:NSUTF8StringEncoding] atomically:YES]; return true; } else { Warning("Failed to download file!"); return false; } #endif } // ----------------------------------------------------------------------------- void GetURL(const std::string& url, const std::string& pageurl) { const char* HTML_PREFIX = "GET-"; // prepended to html filename #ifdef ANDROID_GUI // LOGI("GetURL url=%s\n", url.c_str()); // LOGI("GetURL pageurl=%s\n", pageurl.c_str()); #endif #ifdef IOS_GUI // NSLog(@"GetURL url = %s", url.c_str()); // NSLog(@"GetURL pageurl = %s", pageurl.c_str()); #endif std::string fullurl; if (url.find("http:") == 0) { fullurl = url; } else { // relative get, so prepend full prefix extracted from pageurl std::string urlprefix = GetBaseName(pageurl.c_str()); // replace HTML_PREFIX with "http://" and convert spaces to '/' // (ie. reverse what we do below when building filepath) urlprefix.erase(0, strlen(HTML_PREFIX)); urlprefix = "http://" + urlprefix; std::replace(urlprefix.begin(), urlprefix.end(), ' ', '/'); urlprefix = urlprefix.substr(0, urlprefix.rfind('/')+1); fullurl = urlprefix + url; } std::string filename = GetBaseName(fullurl.c_str()); // remove ugly stuff at start of file names downloaded from ConwayLife.com if (filename.find("download.php?f=") == 0 || filename.find("pattern.asp?p=") == 0 || filename.find("script.asp?s=") == 0) { filename = filename.substr( filename.find('=')+1 ); } // create full path for downloaded file based on given url; // first remove initial "http://" std::string filepath = fullurl.substr( fullurl.find('/')+1 ); while (filepath[0] == '/') filepath.erase(0,1); if (IsHTMLFile(filename)) { // create special name for html file so above code can extract it and set urlprefix std::replace(filepath.begin(), filepath.end(), '/', ' '); #ifdef ANDROID_GUI // replace "?" with something else to avoid problem in Android's WebView.loadUrl std::replace(filepath.begin(), filepath.end(), '?', '$'); #endif filepath = HTML_PREFIX + filepath; } else { // no need for url info in file name filepath = filename; } if (IsRuleFile(filename)) { // create file in user's rules directory filepath = userrules + filename; } else if (IsHTMLFile(filename)) { // nicer to store html files in temporary directory filepath = tempdir + filepath; } else { // all other files are stored in user's download directory filepath = downloaddir + filepath; } // download the file and store it in filepath if (!DownloadFile(fullurl, filepath)) return; if (IsHTMLFile(filename)) { // display html file in Help tab ShowHelp(filepath.c_str()); } else if (IsRuleFile(filename)) { // load corresponding rule SwitchToPatternTab(); LoadRule(filename.substr(0, filename.rfind('.'))); } else if (IsTextFile(filename)) { // open text file in modal view ShowTextFile(filepath.c_str()); } else if (IsScriptFile(filename)) { // run script depending on safety check; if it is allowed to run // then we remember script in the Run Recent submenu //!!! CheckBeforeRunning(filepath, true, wxEmptyString); Warning("This version of Golly cannot run scripts."); } else { // assume it's a pattern/zip file, so open it OpenFile(filepath.c_str()); } } // ----------------------------------------------------------------------------- void LoadLexiconPattern(const std::string& lexpattern) { // copy lexpattern data to tempstart file FILE* f = fopen(currlayer->tempstart.c_str(), "w"); if (f) { if (fputs(lexpattern.c_str(), f) == EOF) { fclose(f); Warning("Could not write lexicon pattern to tempstart file!"); return; } } else { Warning("Could not create tempstart file!"); return; } fclose(f); // avoid any pattern conversion (possibly causing ChangeAlgorithm to beep with a message) NewPattern(); // all Life Lexicon patterns assume we're using Conway's Life so try // switching to B3/S23 or Life; if that fails then switch to QuickLife const char* err = currlayer->algo->setrule("B3/S23"); if (err) { // try "Life" in case current algo is RuleLoader and Life.rule/table/tree exists err = currlayer->algo->setrule("Life"); } if (err) { ChangeAlgorithm(QLIFE_ALGO, "B3/S23"); } // load lexicon pattern SwitchToPatternTab(); LoadPattern(currlayer->tempstart.c_str(), "lexicon"); } golly-2.7-src/gui-common/file.h0000644000175000017500000000410012536111364013355 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _FILE_H_ #define _FILE_H_ #include // for std::string #include "writepattern.h" // for pattern_format, output_compression // Routines for opening, saving, unzipping, downloading files: void NewPattern(const char* title = "untitled"); bool LoadPattern(const char* path, const char* newtitle); void SetPatternTitle(const char* filename); bool SaveCurrentLayer(); void CreateUniverse(); void OpenFile(const char* path, bool remember = true); bool CopyTextToClipboard(const char* text); bool GetTextFromClipboard(std::string& text); bool SavePattern(const std::string& path, pattern_format format, output_compression compression); const char* WritePattern(const char* path, pattern_format format, output_compression compression, int top, int left, int bottom, int right); void UnzipFile(const std::string& zippath, const std::string& entry); void GetURL(const std::string& url, const std::string& pageurl); bool DownloadFile(const std::string& url, const std::string& filepath); void LoadLexiconPattern(const std::string& lexpattern); void LoadRule(const std::string& rulestring); std::string GetBaseName(const char* path); #endif golly-2.7-src/gui-common/control.cpp0000644000175000017500000017163612536111364014474 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include "bigint.h" #include "lifealgo.h" #include "qlifealgo.h" #include "hlifealgo.h" #include "writepattern.h" #include "util.h" // for linereader #include "utils.h" // for Warning, TimeInSeconds, Poller, event_checker, etc #include "prefs.h" // for allowundo, etc #include "status.h" // for ErrorMessage, etc #include "file.h" // for WritePattern, LoadPattern, etc #include "algos.h" // for *_ALGO, algo_type, CreateNewUniverse, etc #include "layer.h" // for currlayer, RestoreRule, etc #include "view.h" // for UpdatePatternAndStatus, draw_pending, etc #include "undo.h" // for UndoRedo #include "control.h" #include // for std::runtime_error and std::exception #include // for std::ostringstream #ifdef ANDROID_GUI #include "jnicalls.h" // for UpdateStatus, BeginProgress, etc #endif #ifdef IOS_GUI #import "PatternViewController.h" // for UpdateStatus, BeginProgress, etc #endif #ifdef WEB_GUI #include "webcalls.h" // for UpdateStatus, BeginProgress, etc #endif // ----------------------------------------------------------------------------- bool generating = false; // currently generating pattern? int minexpo = 0; // step exponent at maximum delay (must be <= 0) double begintime, endtime; // for timing info double begingen, endgen; // ditto const char* empty_pattern = "All cells are dead."; // ----------------------------------------------------------------------------- // macros for checking if a certain string exists in a list of strings #define FOUND(l,s) (std::find(l.begin(),l.end(),s) != l.end()) #define NOT_FOUND(l,s) (std::find(l.begin(),l.end(),s) == l.end()) // ----------------------------------------------------------------------------- bool SaveStartingPattern() { if ( currlayer->algo->getGeneration() > currlayer->startgen ) { // don't do anything if current gen count > starting gen return true; } // save current rule, dirty flag, scale, location, etc currlayer->startname = currlayer->currname; currlayer->startrule = currlayer->algo->getrule(); currlayer->startdirty = currlayer->dirty; currlayer->startmag = currlayer->view->getmag(); currlayer->startx = currlayer->view->x; currlayer->starty = currlayer->view->y; currlayer->startbase = currlayer->currbase; currlayer->startexpo = currlayer->currexpo; currlayer->startalgo = currlayer->algtype; // if this layer is a clone then save some settings in other clones if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->startname = cloneptr->currname; cloneptr->startx = cloneptr->view->x; cloneptr->starty = cloneptr->view->y; cloneptr->startmag = cloneptr->view->getmag(); cloneptr->startbase = cloneptr->currbase; cloneptr->startexpo = cloneptr->currexpo; } } } // save current selection currlayer->startsel = currlayer->currsel; if ( !currlayer->savestart ) { // no need to save pattern; ResetPattern will load currfile currlayer->startfile.clear(); return true; } // save starting pattern in tempstart file if ( currlayer->algo->hyperCapable() ) { // much faster to save pattern in a macrocell file const char* err = WritePattern(currlayer->tempstart.c_str(), MC_format, no_compression, 0, 0, 0, 0); if (err) { ErrorMessage(err); // don't allow user to continue generating return false; } } else { // can only save as RLE if edges are within getcell/setcell limits bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Starting pattern is outside +/- 10^9 boundary."); // don't allow user to continue generating return false; } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); // use XRLE format so the pattern's top left location and the current // generation count are stored in the file const char* err = WritePattern(currlayer->tempstart.c_str(), XRLE_format, no_compression, itop, ileft, ibottom, iright); if (err) { ErrorMessage(err); // don't allow user to continue generating return false; } } currlayer->startfile = currlayer->tempstart; // ResetPattern will load tempstart return true; } // ----------------------------------------------------------------------------- void SetGenIncrement() { if (currlayer->currexpo > 0) { bigint inc = 1; // set increment to currbase^currexpo int i = currlayer->currexpo; while (i > 0) { inc.mul_smallint(currlayer->currbase); i--; } currlayer->algo->setIncrement(inc); } else { currlayer->algo->setIncrement(1); } } // ----------------------------------------------------------------------------- void SetStepExponent(int newexpo) { currlayer->currexpo = newexpo; if (currlayer->currexpo < minexpo) currlayer->currexpo = minexpo; SetGenIncrement(); } // ----------------------------------------------------------------------------- void SetMinimumStepExponent() { // set minexpo depending on mindelay and maxdelay minexpo = 0; if (mindelay > 0) { int d = mindelay; minexpo--; while (d < maxdelay) { d *= 2; minexpo--; } } } // ----------------------------------------------------------------------------- void ResetPattern(bool resetundo) { if (currlayer->algo->getGeneration() == currlayer->startgen) return; if (currlayer->algo->getGeneration() < currlayer->startgen) { // if this happens then startgen logic is wrong Warning("Current gen < starting gen!"); return; } if (currlayer->startfile.length() == 0 && currlayer->currfile.length() == 0) { // if this happens then savestart logic is wrong Warning("Starting pattern cannot be restored!"); return; } // save current algo and rule algo_type oldalgo = currlayer->algtype; std::string oldrule = currlayer->algo->getrule(); // restore pattern and settings saved by SaveStartingPattern; // first restore algorithm currlayer->algtype = currlayer->startalgo; // restore starting pattern if ( currlayer->startfile.length() == 0 ) { // restore pattern from currfile LoadPattern(currlayer->currfile.c_str(), ""); } else { // restore pattern from startfile LoadPattern(currlayer->startfile.c_str(), ""); } if (currlayer->algo->getGeneration() != currlayer->startgen) { // LoadPattern failed to reset the gen count to startgen // (probably because the user deleted the starting pattern) // so best to clear the pattern and reset the gen count CreateUniverse(); currlayer->algo->setGeneration(currlayer->startgen); } // ensure savestart flag is correct currlayer->savestart = currlayer->startfile.length() != 0; // restore settings saved by SaveStartingPattern RestoreRule(currlayer->startrule.c_str()); currlayer->currname = currlayer->startname; currlayer->dirty = currlayer->startdirty; if (restoreview) { currlayer->view->setpositionmag(currlayer->startx, currlayer->starty, currlayer->startmag); } // restore step size and set increment currlayer->currbase = currlayer->startbase; currlayer->currexpo = currlayer->startexpo; SetGenIncrement(); // if this layer is a clone then restore some settings in other clones if (currlayer->cloneid > 0) { for ( int i = 0; i < numlayers; i++ ) { Layer* cloneptr = GetLayer(i); if (cloneptr != currlayer && cloneptr->cloneid == currlayer->cloneid) { cloneptr->currname = cloneptr->startname; if (restoreview) { cloneptr->view->setpositionmag(cloneptr->startx, cloneptr->starty, cloneptr->startmag); } cloneptr->currbase = cloneptr->startbase; cloneptr->currexpo = cloneptr->startexpo; // also synchronize dirty flags and update items in Layer menu cloneptr->dirty = currlayer->dirty; //!!! UpdateLayerItem(i); } } } // restore selection currlayer->currsel = currlayer->startsel; // switch to default colors if algo/rule changed std::string newrule = currlayer->algo->getrule(); if (oldalgo != currlayer->algtype || oldrule != newrule) { UpdateLayerColors(); } // update window title in case currname, rule or dirty flag changed //!!! SetWindowTitle(currlayer->currname); if (allowundo) { if (resetundo) { // wind back the undo history to the starting pattern currlayer->undoredo->SyncUndoHistory(); } } } // ----------------------------------------------------------------------------- void RestorePattern(bigint& gen, const char* filename, bigint& x, bigint& y, int mag, int base, int expo) { // called to undo/redo a generating change if (gen == currlayer->startgen) { // restore starting pattern (false means don't call SyncUndoHistory) ResetPattern(false); } else { // restore pattern in given filename LoadPattern(filename, ""); if (currlayer->algo->getGeneration() != gen) { // filename could not be loaded for some reason, // so best to clear the pattern and set the expected gen count CreateUniverse(); currlayer->algo->setGeneration(gen); } // restore step size and set increment currlayer->currbase = base; currlayer->currexpo = expo; SetGenIncrement(); // restore position and scale, if allowed if (restoreview) currlayer->view->setpositionmag(x, y, mag); UpdatePatternAndStatus(); } } // ----------------------------------------------------------------------------- const char* ChangeGenCount(const char* genstring, bool inundoredo) { // disallow alphabetic chars in genstring for (unsigned int i = 0; i < strlen(genstring); i++) if ( (genstring[i] >= 'a' && genstring[i] <= 'z') || (genstring[i] >= 'A' && genstring[i] <= 'Z') ) return "Alphabetic character is not allowed in generation string."; bigint oldgen = currlayer->algo->getGeneration(); bigint newgen(genstring); if (genstring[0] == '+' || genstring[0] == '-') { // leading +/- sign so make newgen relative to oldgen bigint relgen = newgen; newgen = oldgen; newgen += relgen; if (newgen < bigint::zero) newgen = bigint::zero; } // set stop_after_script BEFORE testing newgen == oldgen so scripts // can call setgen("+0") to prevent further generating //!!! if (inscript) stop_after_script = true; if (newgen == oldgen) return NULL; if (!inundoredo && allowundo && !currlayer->stayclean && inscript) { // script called setgen() //!!! SavePendingChanges(); } // need IsParityShifted() method??? if (currlayer->algtype == QLIFE_ALGO && newgen.odd() != oldgen.odd()) { // qlife stores pattern in different bits depending on gen parity, // so we need to create a new qlife universe, set its gen, copy the // current pattern to the new universe, then switch to that universe bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( OutsideLimits(top, left, bottom, right) ) { return "Pattern is too big to copy."; } // create a new universe of same type and same rule lifealgo* newalgo = CreateNewUniverse(currlayer->algtype); const char* err = newalgo->setrule(currlayer->algo->getrule()); if (err) { delete newalgo; return "Current rule is no longer valid!"; } newalgo->setGeneration(newgen); // copy pattern if ( !CopyRect(top.toint(), left.toint(), bottom.toint(), right.toint(), currlayer->algo, newalgo, false, "Copying pattern") ) { delete newalgo; return "Failed to copy pattern."; } // switch to new universe delete currlayer->algo; currlayer->algo = newalgo; SetGenIncrement(); } else { currlayer->algo->setGeneration(newgen); } if (!inundoredo) { // save some settings for RememberSetGen below bigint oldstartgen = currlayer->startgen; bool oldsave = currlayer->savestart; // may need to change startgen and savestart if (oldgen == currlayer->startgen || newgen <= currlayer->startgen) { currlayer->startgen = newgen; currlayer->savestart = true; } if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberSetGen(oldgen, newgen, oldstartgen, oldsave); } } UpdateStatus(); return NULL; } // ----------------------------------------------------------------------------- static void JoinTwistedEdges(lifealgo* curralgo) { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; if (curralgo->htwist && curralgo->vtwist) { // cross-surface // eg. :C4,3 // a l k j i d // l A B C D i // h E F G H e // d I J K L a // i d c b a l for (int x = gl; x <= gr; x++) { int twistedx = gr - x + gl; int state = curralgo->getcell(twistedx, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(twistedx, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { int twistedy = gb - y + gt; int state = curralgo->getcell(gl, twistedy); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, twistedy); if (state > 0) curralgo->setcell(bl, y, state); } // copy grid's corner cells to SAME corners in border // (these cells are topologically different to non-corner cells) curralgo->setcell(bl, bt, curralgo->getcell(gl, gt)); curralgo->setcell(br, bt, curralgo->getcell(gr, gt)); curralgo->setcell(br, bb, curralgo->getcell(gr, gb)); curralgo->setcell(bl, bb, curralgo->getcell(gl, gb)); } else if (curralgo->htwist) { // Klein bottle with top and bottom edges twisted 180 degrees // eg. :K4*,3 // i l k j i l // d A B C D a // h E F G H e // l I J K L i // a d c b a d for (int x = gl; x <= gr; x++) { int twistedx = gr - x + gl; int state = curralgo->getcell(twistedx, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(twistedx, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no twist int state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(bl, y, state); } // do corner cells curralgo->setcell(bl, bt, curralgo->getcell(gl, gb)); curralgo->setcell(br, bt, curralgo->getcell(gr, gb)); curralgo->setcell(bl, bb, curralgo->getcell(gl, gt)); curralgo->setcell(br, bb, curralgo->getcell(gr, gt)); } else { // curralgo->vtwist // Klein bottle with left and right edges twisted 180 degrees // eg. :K4,3* // d i j k l a // l A B C D i // h E F G H e // d I J K L a // l a b c d i for (int x = gl; x <= gr; x++) { // join top and bottom edges with no twist int state = curralgo->getcell(x, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(x, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { int twistedy = gb - y + gt; int state = curralgo->getcell(gl, twistedy); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, twistedy); if (state > 0) curralgo->setcell(bl, y, state); } // do corner cells curralgo->setcell(bl, bt, curralgo->getcell(gr, gt)); curralgo->setcell(br, bt, curralgo->getcell(gl, gt)); curralgo->setcell(bl, bb, curralgo->getcell(gr, gb)); curralgo->setcell(br, bb, curralgo->getcell(gl, gb)); } } // ----------------------------------------------------------------------------- static void JoinTwistedAndShiftedEdges(lifealgo* curralgo) { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; if (curralgo->hshift != 0) { // Klein bottle with shift by 1 on twisted horizontal edge (with even number of cells) // eg. :K4*+1,3 // j i l k j i // d A B C D a // h E F G H e // l I J K L i // b a d c b a int state, twistedx, shiftedx; for (int x = gl; x <= gr; x++) { // join top and bottom edges with a twist and then shift by 1 twistedx = gr - x + gl; shiftedx = twistedx - 1; if (shiftedx < gl) shiftedx = gr; state = curralgo->getcell(shiftedx, gb); if (state > 0) curralgo->setcell(x, bt, state); state = curralgo->getcell(shiftedx, gt); if (state > 0) curralgo->setcell(x, bb, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no twist or shift state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(bl, y, state); } // do corner cells shiftedx = gl - 1; if (shiftedx < gl) shiftedx = gr; curralgo->setcell(bl, bt, curralgo->getcell(shiftedx, gb)); curralgo->setcell(bl, bb, curralgo->getcell(shiftedx, gt)); shiftedx = gr - 1; if (shiftedx < gl) shiftedx = gr; curralgo->setcell(br, bt, curralgo->getcell(shiftedx, gb)); curralgo->setcell(br, bb, curralgo->getcell(shiftedx, gt)); } else { // curralgo->vshift != 0 // Klein bottle with shift by 1 on twisted vertical edge (with even number of cells) // eg. :K3,4*+1 // f j k l d // c A B C a // l D E F j // i G H I g // f J K L d // c a b c a int state, twistedy, shiftedy; for (int x = gl; x <= gr; x++) { // join top and bottom edges with no twist or shift state = curralgo->getcell(x, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(x, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with a twist and then shift by 1 twistedy = gb - y + gt; shiftedy = twistedy - 1; if (shiftedy < gt) shiftedy = gb; state = curralgo->getcell(gr, shiftedy); if (state > 0) curralgo->setcell(bl, y, state); state = curralgo->getcell(gl, shiftedy); if (state > 0) curralgo->setcell(br, y, state); } // do corner cells shiftedy = gt - 1; if (shiftedy < gt) shiftedy = gb; curralgo->setcell(bl, bt, curralgo->getcell(gr, shiftedy)); curralgo->setcell(br, bt, curralgo->getcell(gl, shiftedy)); shiftedy = gb - 1; if (shiftedy < gt) shiftedy = gb; curralgo->setcell(bl, bb, curralgo->getcell(gr, shiftedy)); curralgo->setcell(br, bb, curralgo->getcell(gl, shiftedy)); } } // ----------------------------------------------------------------------------- static void JoinShiftedEdges(lifealgo* curralgo, int gwd, int ght, // grid wd and ht int hshift, int vshift) // horizontal and vertical shifts { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; if (hshift != 0) { // torus with horizontal shift // eg. :T4+1,3 // k l i j k l // d A B C D a // h E F G H e // l I J K L i // a b c d a b int state, shiftedx; for (int x = gl; x <= gr; x++) { // join top and bottom edges with a horizontal shift shiftedx = x - hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; state = curralgo->getcell(shiftedx, gb); if (state > 0) curralgo->setcell(x, bt, state); shiftedx = x + hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; state = curralgo->getcell(shiftedx, gt); if (state > 0) curralgo->setcell(x, bb, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no shift state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(br, y, state); state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(bl, y, state); } // do corner cells shiftedx = gr - hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; curralgo->setcell(bl, bt, curralgo->getcell(shiftedx, gb)); shiftedx = gl - hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; curralgo->setcell(br, bt, curralgo->getcell(shiftedx, gb)); shiftedx = gr + hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; curralgo->setcell(bl, bb, curralgo->getcell(shiftedx, gt)); shiftedx = gl + hshift; if (shiftedx < gl) shiftedx += gwd; else if (shiftedx > gr) shiftedx -= gwd; curralgo->setcell(br, bb, curralgo->getcell(shiftedx, gt)); } else { // vshift != 0 // torus with vertical shift // eg. :T4,3+1 // h i j k l a // l A B C D e // d E F G H i // h I J K L a // l a b c d e int state, shiftedy; for (int x = gl; x <= gr; x++) { // join top and bottom edges with no shift state = curralgo->getcell(x, gt); if (state > 0) curralgo->setcell(x, bb, state); state = curralgo->getcell(x, gb); if (state > 0) curralgo->setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with a vertical shift shiftedy = y - vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; state = curralgo->getcell(gr, shiftedy); if (state > 0) curralgo->setcell(bl, y, state); shiftedy = y + vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; state = curralgo->getcell(gl, shiftedy); if (state > 0) curralgo->setcell(br, y, state); } // do corner cells shiftedy = gb - vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; curralgo->setcell(bl, bt, curralgo->getcell(gr, shiftedy)); shiftedy = gb + vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; curralgo->setcell(br, bt, curralgo->getcell(gl, shiftedy)); shiftedy = gt - vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; curralgo->setcell(bl, bb, curralgo->getcell(gr, shiftedy)); shiftedy = gt + vshift; if (shiftedy < gt) shiftedy += ght; else if (shiftedy > gb) shiftedy -= ght; curralgo->setcell(br, bb, curralgo->getcell(gl, shiftedy)); } } // ----------------------------------------------------------------------------- static void JoinAdjacentEdges(lifealgo* curralgo, int pt, int pl, int pb, int pr) // pattern edges { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; // sphere // eg. :S3 // a a d g c // a A B C g // b D E F h // c G H I i // g c f i i // copy live cells in top edge to left border for (int x = pl; x <= pr; x++) { int state; int skip = curralgo->nextcell(x, gt, state); if (skip < 0) break; x += skip; if (state > 0) curralgo->setcell(bl, gt + (x - gl), state); } // copy live cells in left edge to top border for (int y = pt; y <= pb; y++) { // no point using nextcell() here -- edge is only 1 cell wide int state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(gl + (y - gt), bt, state); } // copy live cells in bottom edge to right border for (int x = pl; x <= pr; x++) { int state; int skip = curralgo->nextcell(x, gb, state); if (skip < 0) break; x += skip; if (state > 0) curralgo->setcell(br, gt + (x - gl), state); } // copy live cells in right edge to bottom border for (int y = pt; y <= pb; y++) { // no point using nextcell() here -- edge is only 1 cell wide int state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(gl + (y - gt), bb, state); } // copy grid's corner cells to SAME corners in border curralgo->setcell(bl, bt, curralgo->getcell(gl, gt)); curralgo->setcell(br, bt, curralgo->getcell(gr, gt)); curralgo->setcell(br, bb, curralgo->getcell(gr, gb)); curralgo->setcell(bl, bb, curralgo->getcell(gl, gb)); } // ----------------------------------------------------------------------------- static void JoinEdges(lifealgo* curralgo, int gwd, int ght, // grid wd and ht int pt, int pl, int pb, int pr) // pattern edges { // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); // border edges are 1 cell outside grid edges int bl = gl - 1; int bt = gt - 1; int br = gr + 1; int bb = gb + 1; if (ght > 0) { // copy live cells in top edge to bottom border for (int x = pl; x <= pr; x++) { int state; int skip = curralgo->nextcell(x, gt, state); if (skip < 0) break; x += skip; if (state > 0) curralgo->setcell(x, bb, state); } // copy live cells in bottom edge to top border for (int x = pl; x <= pr; x++) { int state; int skip = curralgo->nextcell(x, gb, state); if (skip < 0) break; x += skip; if (state > 0) curralgo->setcell(x, bt, state); } } if (gwd > 0) { // copy live cells in left edge to right border for (int y = pt; y <= pb; y++) { // no point using nextcell() here -- edge is only 1 cell wide int state = curralgo->getcell(gl, y); if (state > 0) curralgo->setcell(br, y, state); } // copy live cells in right edge to left border for (int y = pt; y <= pb; y++) { // no point using nextcell() here -- edge is only 1 cell wide int state = curralgo->getcell(gr, y); if (state > 0) curralgo->setcell(bl, y, state); } } if (gwd > 0 && ght > 0) { // copy grid's corner cells to opposite corners in border curralgo->setcell(bl, bt, curralgo->getcell(gr, gb)); curralgo->setcell(br, bt, curralgo->getcell(gl, gb)); curralgo->setcell(br, bb, curralgo->getcell(gl, gt)); curralgo->setcell(bl, bb, curralgo->getcell(gr, gt)); } } // ----------------------------------------------------------------------------- bool CreateBorderCells(lifealgo* curralgo) { // no need to do anything if there is no pattern or if the grid is a bounded plane if (curralgo->isEmpty() || curralgo->boundedplane) return true; int gwd = curralgo->gridwd; int ght = curralgo->gridht; bigint top, left, bottom, right; curralgo->findedges(&top, &left, &bottom, &right); // no need to do anything if pattern is completely inside grid edges if ( (gwd == 0 || (curralgo->gridleft < left && curralgo->gridright > right)) && (ght == 0 || (curralgo->gridtop < top && curralgo->gridbottom > bottom)) ) { return true; } // if grid has infinite width or height then pattern might be too big to use setcell/getcell if ( (gwd == 0 || ght == 0) && OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Pattern is too big!"); // return false so caller can exit step() loop return false; } if (curralgo->sphere) { // to get a sphere we join top edge with left edge, and right edge with bottom edge; // note that grid must be square (gwd == ght) int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); JoinAdjacentEdges(curralgo, pt, pl, pb, pr); } else if (curralgo->htwist || curralgo->vtwist) { // Klein bottle or cross-surface if ( (curralgo->htwist && curralgo->hshift != 0 && (gwd & 1) == 0) || (curralgo->vtwist && curralgo->vshift != 0 && (ght & 1) == 0) ) { // Klein bottle with shift is only possible if the shift is on the // twisted edge and that edge has an even number of cells JoinTwistedAndShiftedEdges(curralgo); } else { JoinTwistedEdges(curralgo); } } else if (curralgo->hshift != 0 || curralgo->vshift != 0) { // torus with horizontal or vertical shift JoinShiftedEdges(curralgo, gwd, ght, curralgo->hshift, curralgo->vshift); } else { // unshifted torus or infinite tube int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); JoinEdges(curralgo, gwd, ght, pt, pl, pb, pr); } curralgo->endofpattern(); return true; } // ----------------------------------------------------------------------------- void ClearRect(lifealgo* curralgo, int top, int left, int bottom, int right) { int cx, cy, v; for ( cy = top; cy <= bottom; cy++ ) { for ( cx = left; cx <= right; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip + cx > right) skip = -1; // pretend we found no more live cells if (skip >= 0) { // found next live cell so delete it cx += skip; curralgo->setcell(cx, cy, 0); } else { cx = right + 1; // done this row } } } } // ----------------------------------------------------------------------------- bool DeleteBorderCells(lifealgo* curralgo) { // no need to do anything if there is no pattern if (curralgo->isEmpty()) return true; int gwd = curralgo->gridwd; int ght = curralgo->gridht; // need to find pattern edges because pattern may have expanded beyond grid // (typically by 2 cells, but could be more if rule allows births in empty space) bigint top, left, bottom, right; curralgo->findedges(&top, &left, &bottom, &right); // no need to do anything if grid encloses entire pattern if ( (gwd == 0 || (curralgo->gridleft <= left && curralgo->gridright >= right)) && (ght == 0 || (curralgo->gridtop <= top && curralgo->gridbottom >= bottom)) ) { return true; } if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Pattern is too big!"); // return false so caller can exit step() loop return false; } // set pattern edges int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); // set grid edges int gl = curralgo->gridleft.toint(); int gt = curralgo->gridtop.toint(); int gr = curralgo->gridright.toint(); int gb = curralgo->gridbottom.toint(); if (ght > 0 && pt < gt) { // delete live cells above grid ClearRect(curralgo, pt, pl, gt-1, pr); pt = gt; // reduce size of rect below } if (ght > 0 && pb > gb) { // delete live cells below grid ClearRect(curralgo, gb+1, pl, pb, pr); pb = gb; // reduce size of rect below } if (gwd > 0 && pl < gl) { // delete live cells left of grid ClearRect(curralgo, pt, pl, pb, gl-1); } if (gwd > 0 && pr > gr) { // delete live cells right of grid ClearRect(curralgo, pt, gr+1, pb, pr); } curralgo->endofpattern(); return true; } // ----------------------------------------------------------------------------- void DisplayTimingInfo() { endtime = TimeInSeconds(); if (endtime <= begintime) endtime = begintime + 0.000001; endgen = currlayer->algo->getGeneration().todouble(); double secs = endtime - begintime; double gens = endgen - begingen; char s[128]; sprintf(s, "%g gens in %g secs (%g gens/sec).", gens, secs, gens/secs); DisplayMessage(s); } // ----------------------------------------------------------------------------- bool StartGenerating() { if (generating) Warning("Bug detected in StartGenerating!"); lifealgo* curralgo = currlayer->algo; if (curralgo->isEmpty()) { ErrorMessage(empty_pattern); return false; } if (!SaveStartingPattern()) { return false; } if (allowundo) currlayer->undoredo->RememberGenStart(); // only show hashing info while generating lifealgo::setVerbose(currlayer->showhashinfo); // for DisplayTimingInfo begintime = TimeInSeconds(); begingen = curralgo->getGeneration().todouble(); generating = true; PollerReset(); // caller will start a repeating timer return true; } // ----------------------------------------------------------------------------- void StopGenerating() { if (!generating) Warning("Bug detected in StopGenerating!"); generating = false; PollerInterrupt(); if (showtiming) DisplayTimingInfo(); lifealgo::setVerbose(0); if (event_checker > 0) { // we're currently in the event poller somewhere inside step(), so we must let // step() complete and only call RememberGenFinish at the end of NextGeneration } else { if (allowundo) currlayer->undoredo->RememberGenFinish(); } // caller will stop the timer } // ----------------------------------------------------------------------------- void NextGeneration(bool useinc) { lifealgo* curralgo = currlayer->algo; bool boundedgrid = (curralgo->gridwd > 0 || curralgo->gridht > 0); if (generating) { // we were called via timer so StartGenerating has already checked // if the pattern is empty, etc (note that useinc is also true) } else { // we were called via Next/Step button if (curralgo->isEmpty()) { ErrorMessage(empty_pattern); return; } if (!SaveStartingPattern()) { return; } if (allowundo) currlayer->undoredo->RememberGenStart(); // only show hashing info while generating lifealgo::setVerbose(currlayer->showhashinfo); if (useinc && curralgo->getIncrement() > bigint::one) { // for DisplayTimingInfo begintime = TimeInSeconds(); begingen = curralgo->getGeneration().todouble(); } PollerReset(); } if (useinc) { // step by current increment if (boundedgrid) { // temporarily set the increment to 1 so we can call CreateBorderCells() // and DeleteBorderCells() around each step() int savebase = currlayer->currbase; int saveexpo = currlayer->currexpo; bigint inc = curralgo->getIncrement(); curralgo->setIncrement(1); while (inc > 0) { if (Poller()->checkevents()) break; if (savebase != currlayer->currbase || saveexpo != currlayer->currexpo) { // user changed step base/exponent, so reset increment to 1 inc = curralgo->getIncrement(); curralgo->setIncrement(1); } if (!CreateBorderCells(curralgo)) break; curralgo->step(); if (!DeleteBorderCells(curralgo)) break; inc -= 1; } // safe way to restore correct increment in case user altered base/expo in above loop SetGenIncrement(); } else { curralgo->step(); } } else { // step by 1 gen bigint saveinc = curralgo->getIncrement(); curralgo->setIncrement(1); if (boundedgrid) CreateBorderCells(curralgo); curralgo->step(); if (boundedgrid) DeleteBorderCells(curralgo); curralgo->setIncrement(saveinc); } if (!generating) { if (showtiming && useinc && curralgo->getIncrement() > bigint::one) DisplayTimingInfo(); lifealgo::setVerbose(0); if (allowundo) currlayer->undoredo->RememberGenFinish(); } // autofit is only used when doing many gens if (currlayer->autofit && (generating || useinc)) { FitInView(0); } if (draw_pending) { draw_pending = false; TouchBegan(pendingx, pendingy); } } // ----------------------------------------------------------------------------- void ClearOutsideGrid() { // check current pattern and clear any live cells outside bounded grid bool patternchanged = false; bool savechanges = allowundo && !currlayer->stayclean; // might also need to truncate selection currlayer->currsel.CheckGridEdges(); if (currlayer->algo->isEmpty()) return; // check if current pattern is too big to use nextcell/setcell bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Pattern too big to check (outside +/- 10^9 boundary)."); return; } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); // no need to do anything if pattern is entirely within grid int gtop = currlayer->algo->gridtop.toint(); int gleft = currlayer->algo->gridleft.toint(); int gbottom = currlayer->algo->gridbottom.toint(); int gright = currlayer->algo->gridright.toint(); if (currlayer->algo->gridwd == 0) { // grid has infinite width gleft = INT_MIN; gright = INT_MAX; } if (currlayer->algo->gridht == 0) { // grid has infinite height gtop = INT_MIN; gbottom = INT_MAX; } if (itop >= gtop && ileft >= gleft && ibottom <= gbottom && iright <= gright) { return; } int ht = ibottom - itop + 1; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = currlayer->algo->getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; bool abort = false; int v = 0; BeginProgress("Checking cells outside grid"); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { currcount++; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (cx < gleft || cx > gright || cy < gtop || cy > gbottom) { // clear cell outside grid if (savechanges) currlayer->undoredo->SaveCellChange(cx, cy, v, 0); curralgo->setcell(cx, cy, 0); patternchanged = true; } currcount++; } else { cx = iright; // done this row } if (currcount > 1024) { accumcount += currcount; currcount = 0; abort = AbortProgress(accumcount / maxcount, ""); if (abort) break; } } if (abort) break; } curralgo->endofpattern(); EndProgress(); if (patternchanged) { ErrorMessage("Pattern was truncated (live cells were outside grid)."); } } // ----------------------------------------------------------------------------- void ReduceCellStates(int newmaxstate) { // check current pattern and reduce any cell states > newmaxstate bool patternchanged = false; bool savechanges = allowundo && !currlayer->stayclean; // check if current pattern is too big to use nextcell/setcell bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Pattern too big to check (outside +/- 10^9 boundary)."); return; } int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int ht = ibottom - itop + 1; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = currlayer->algo->getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; bool abort = false; int v = 0; BeginProgress("Checking cell states"); lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { currcount++; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (v > newmaxstate) { // reduce cell's current state to largest state if (savechanges) currlayer->undoredo->SaveCellChange(cx, cy, v, newmaxstate); curralgo->setcell(cx, cy, newmaxstate); patternchanged = true; } currcount++; } else { cx = iright; // done this row } if (currcount > 1024) { accumcount += currcount; currcount = 0; abort = AbortProgress(accumcount / maxcount, ""); if (abort) break; } } if (abort) break; } curralgo->endofpattern(); EndProgress(); if (patternchanged) { ErrorMessage("Pattern has changed (new rule has fewer states)."); } } // ----------------------------------------------------------------------------- void ChangeRule(const std::string& rulestring) { // load recently installed .rule/table/tree file std::string oldrule = currlayer->algo->getrule(); int oldmaxstate = currlayer->algo->NumCellStates() - 1; // selection might change if grid becomes smaller, // so save current selection for RememberRuleChange/RememberAlgoChange SaveCurrentSelection(); const char* err = currlayer->algo->setrule( rulestring.c_str() ); if (err) { // try to find another algorithm that supports the given rule for (int i = 0; i < NumAlgos(); i++) { if (i != currlayer->algtype) { lifealgo* tempalgo = CreateNewUniverse(i); err = tempalgo->setrule( rulestring.c_str() ); delete tempalgo; if (!err) { // change the current algorithm and switch to the new rule ChangeAlgorithm(i, rulestring.c_str()); if (i != currlayer->algtype) { RestoreRule(oldrule.c_str()); Warning("Algorithm could not be changed (pattern is too big to convert)."); return; } else { UpdateEverything(); return; } } } } // should only get here if .rule/table/tree file contains some sort of error RestoreRule(oldrule.c_str()); Warning("New rule is not valid in any algorithm!"); return; } std::string newrule = currlayer->algo->getrule(); if (oldrule != newrule) { UpdateStatus(); // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { ClearOutsideGrid(); } } // new table/tree might have changed the number of cell states; // if there are fewer states then pattern might change int newmaxstate = currlayer->algo->NumCellStates() - 1; if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { ReduceCellStates(newmaxstate); } // set colors and icons for new rule UpdateLayerColors(); // pattern might have changed or colors and/or icons might have changed UpdateEverything(); if (oldrule != newrule) { if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberRuleChange(oldrule.c_str()); } } } // ----------------------------------------------------------------------------- void ChangeAlgorithm(algo_type newalgotype, const char* newrule, bool inundoredo) { if (newalgotype == currlayer->algtype) return; // check if current pattern is too big to use nextcell/setcell bigint top, left, bottom, right; if ( !currlayer->algo->isEmpty() ) { currlayer->algo->findedges(&top, &left, &bottom, &right); if ( OutsideLimits(top, left, bottom, right) ) { ErrorMessage("Pattern cannot be converted (outside +/- 10^9 boundary)."); return; } } // save changes if undo/redo is enabled and script isn't constructing a pattern // and we're not undoing/redoing an earlier algo change bool savechanges = allowundo && !currlayer->stayclean && !inundoredo; if (savechanges && inscript) { // note that we must save pending gen changes BEFORE changing algo type // otherwise temporary files won't be the correct type (mc or rle) //!!! SavePendingChanges(); } // selection might change if grid becomes smaller, // so save current selection for RememberAlgoChange if (savechanges) SaveCurrentSelection(); bool rulechanged = false; std::string oldrule = currlayer->algo->getrule(); // change algorithm type, reset step size, and update status bar algo_type oldalgo = currlayer->algtype; currlayer->algtype = newalgotype; currlayer->currbase = algoinfo[newalgotype]->defbase; currlayer->currexpo = 0; UpdateStatus(); // create a new universe of the requested flavor lifealgo* newalgo = CreateNewUniverse(newalgotype); if (inundoredo) { // switch to given newrule const char* err = newalgo->setrule(newrule); if (err) newalgo->setrule(newalgo->DefaultRule()); } else { const char* err; if (newrule[0] == 0) { // try to use same rule err = newalgo->setrule(currlayer->algo->getrule()); } else { // switch to newrule err = newalgo->setrule(newrule); rulechanged = true; } if (err) { std::string defrule = newalgo->DefaultRule(); size_t oldpos = oldrule.find(':'); if (newrule[0] == 0 && oldpos != std::string::npos) { // switch to new algo's default rule, but preserve the topology in oldrule // so we can do things like switch from "LifeHistory:T30,20" in RuleLoader // to "B3/S23:T30,20" in QuickLife size_t defpos = defrule.find(':'); if (defpos != std::string::npos) { // default rule shouldn't have a suffix but play safe and remove it defrule = defrule.substr(0, defpos); } defrule += ":"; defrule += oldrule.substr(oldpos+1); } err = newalgo->setrule(defrule.c_str()); // shouldn't ever fail but play safe if (err) newalgo->setrule( newalgo->DefaultRule() ); rulechanged = true; } } // set same gen count newalgo->setGeneration( currlayer->algo->getGeneration() ); bool patternchanged = false; if ( !currlayer->algo->isEmpty() ) { // copy pattern in current universe to new universe int itop = top.toint(); int ileft = left.toint(); int ibottom = bottom.toint(); int iright = right.toint(); int ht = ibottom - itop + 1; int cx, cy; // for showing accurate progress we need to add pattern height to pop count // in case this is a huge pattern with many blank rows double maxcount = currlayer->algo->getPopulation().todouble() + ht; double accumcount = 0; int currcount = 0; bool abort = false; int v = 0; BeginProgress("Converting pattern"); // set newalgo's grid edges so we can save cells that are outside grid int gtop = newalgo->gridtop.toint(); int gleft = newalgo->gridleft.toint(); int gbottom = newalgo->gridbottom.toint(); int gright = newalgo->gridright.toint(); if (newalgo->gridwd == 0) { // grid has infinite width gleft = INT_MIN; gright = INT_MAX; } if (newalgo->gridht == 0) { // grid has infinite height gtop = INT_MIN; gbottom = INT_MAX; } // need to check for state change if new algo has fewer states than old algo int newmaxstate = newalgo->NumCellStates() - 1; lifealgo* curralgo = currlayer->algo; for ( cy=itop; cy<=ibottom; cy++ ) { currcount++; for ( cx=ileft; cx<=iright; cx++ ) { int skip = curralgo->nextcell(cx, cy, v); if (skip >= 0) { // found next live cell in this row cx += skip; if (cx < gleft || cx > gright || cy < gtop || cy > gbottom) { // cx,cy is outside grid if (savechanges) currlayer->undoredo->SaveCellChange(cx, cy, v, 0); // no need to clear cell from curralgo (that universe will soon be deleted) patternchanged = true; } else { if (v > newmaxstate) { // reduce v to largest state in new algo if (savechanges) currlayer->undoredo->SaveCellChange(cx, cy, v, newmaxstate); v = newmaxstate; patternchanged = true; } newalgo->setcell(cx, cy, v); } currcount++; } else { cx = iright; // done this row } if (currcount > 1024) { accumcount += currcount; currcount = 0; abort = AbortProgress(accumcount / maxcount, ""); if (abort) break; } } if (abort) break; } newalgo->endofpattern(); EndProgress(); } // delete old universe and point current universe to new universe delete currlayer->algo; currlayer->algo = newalgo; SetGenIncrement(); // if new grid is bounded then we might need to truncate the selection if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { currlayer->currsel.CheckGridEdges(); } // switch to default colors for new algo+rule UpdateLayerColors(); if (!inundoredo) { if (rulechanged) { // if pattern exists and is at starting gen then set savestart true // so that SaveStartingPattern will save pattern to suitable file // (and thus ResetPattern will work correctly) if ( currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty() ) { currlayer->savestart = true; } if (newrule[0] == 0) { if (patternchanged) { ErrorMessage("Rule has changed and pattern has changed."); } else { // don't beep DisplayMessage("Rule has changed."); } } else { if (patternchanged) { ErrorMessage("Algorithm has changed and pattern has changed."); } else { // don't beep DisplayMessage("Algorithm has changed."); } } } else if (patternchanged) { ErrorMessage("Pattern has changed."); } } if (savechanges) { currlayer->undoredo->RememberAlgoChange(oldalgo, oldrule.c_str()); } if (!inundoredo && !inscript) { // do this AFTER RememberAlgoChange so Undo button becomes enabled UpdateEverything(); } } // ----------------------------------------------------------------------------- static std::string CreateTABLE(const std::string& tablepath) { std::string contents = "\n@TABLE\n\n"; // append contents of .table file FILE* f = fopen(tablepath.c_str(), "r"); if (f) { const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; linereader reader(f); while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; contents += linebuf; contents += "\n"; } reader.close(); } else { std::ostringstream oss; oss << "Could not read .table file:\n" << tablepath.c_str(); throw std::runtime_error(oss.str().c_str()); } return contents; } // ----------------------------------------------------------------------------- static std::string CreateTREE(const std::string& treepath) { std::string contents = "\n@TREE\n\n"; // append contents of .tree file FILE* f = fopen(treepath.c_str(), "r"); if (f) { const int MAXLINELEN = 4095; char linebuf[MAXLINELEN + 1]; linereader reader(f); while (true) { if (reader.fgets(linebuf, MAXLINELEN) == 0) break; contents += linebuf; contents += "\n"; } reader.close(); } else { std::ostringstream oss; oss << "Could not read .tree file:\n" << treepath.c_str(); throw std::runtime_error(oss.str().c_str()); } return contents; } // ----------------------------------------------------------------------------- static void CreateOneRule(const std::string& rulefile, const std::string& folder, std::list& allfiles, std::string& htmlinfo) { std::string rulename = rulefile.substr(0,rulefile.rfind('.')); std::string tablefile = rulename + ".table"; std::string treefile = rulename + ".tree"; std::string tabledata, treedata; if (FOUND(allfiles,tablefile)) tabledata = CreateTABLE(folder + tablefile); if (FOUND(allfiles,treefile)) treedata = CreateTREE(folder + treefile); std::string contents = "@RULE " + rulename + "\n"; contents += tabledata; contents += treedata; // write contents to .rule file std::string rulepath = folder + rulefile; FILE* outfile = fopen(rulepath.c_str(), "w"); if (outfile) { if (fputs(contents.c_str(), outfile) == EOF) { fclose(outfile); std::ostringstream oss; oss << "Could not write data to rule file:\n" << rulepath.c_str(); throw std::runtime_error(oss.str().c_str()); } fclose(outfile); } else { std::ostringstream oss; oss << "Could not create rule file:\n" << rulepath.c_str(); throw std::runtime_error(oss.str().c_str()); } #ifdef WEB_GUI // ensure the .rule file persists beyond the current session CopyRuleToLocalStorage(rulepath.c_str()); #endif // append created file to htmlinfo htmlinfo += ""; htmlinfo += rulefile; htmlinfo += "
\n"; } // ----------------------------------------------------------------------------- std::string CreateRuleFiles(std::list& deprecated, std::list& keeprules) { // use the given list of deprecated .table/tree files to create new .rule files, // except for those .rule files in keeprules std::string htmlinfo; bool aborted = false; try { // create a list of candidate .rule files to be created std::string rulefile, filename, rulename; std::list candidates; std::list::iterator it; for (it=deprecated.begin(); it!=deprecated.end(); ++it) { filename = *it; rulename = filename.substr(0,filename.rfind('.')); if (EndsWith(filename,".table") || EndsWith(filename,".tree")) { // .table/tree file rulefile = rulename + ".rule"; // add .rule file to candidates if it hasn't been added yet // and if it isn't in the keeprules list if (NOT_FOUND(candidates,rulefile) && NOT_FOUND(keeprules,rulefile)) { candidates.push_back(rulefile); } } } // create the new .rule files (we overwrite any existing .rule files // that aren't in keeprules) for (it=candidates.begin(); it!=candidates.end(); ++it) { CreateOneRule(*it, userrules, deprecated, htmlinfo); } } catch(const std::exception& e) { // display message set by throw std::runtime_error(...) Warning(e.what()); aborted = true; // nice to also show error message in help window htmlinfo += "\n

*** CONVERSION ABORTED DUE TO ERROR ***\n

"; htmlinfo += std::string(e.what()); } if (!aborted) { // delete all the deprecated files std::list::iterator it; for (it=deprecated.begin(); it!=deprecated.end(); ++it) { RemoveFile(userrules + *it); } } return htmlinfo; } golly-2.7-src/gui-common/select.h0000644000175000017500000001475012536111364013731 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _SELECT_H_ #define _SELECT_H_ #include "bigint.h" // for bigint #include "lifealgo.h" // for lifealgo #include "utils.h" // for gRect // Most editing functions operate on the current selection. // The Selection class encapsulates all selection-related operations. class Selection { public: Selection(); Selection(int t, int l, int b, int r); ~Selection(); bool operator==(const Selection& sel) const; bool operator!=(const Selection& sel) const; bool Exists(); // return true if the selection exists void Deselect(); // remove the selection bool TooBig(); // return true if any selection edge is outside the editable limits void DisplaySize(); // display the selection's size in the status bar void SetRect(int x, int y, int wd, int ht); // set the selection to the given rectangle void GetRect(int* x, int* y, int* wd, int* ht); // return the selection rectangle void SetEdges(bigint& t, bigint& l, bigint& b, bigint& r); // set the selection using the given rectangle edges void CheckGridEdges(); // change selection edges if necessary to ensure they are inside a bounded grid bool Contains(bigint& t, bigint& l, bigint& b, bigint& r); // return true if the selection encloses the given rectangle bool Outside(bigint& t, bigint& l, bigint& b, bigint& r); // return true if the selection is completely outside the given rectangle bool ContainsCell(int x, int y); // return true if the given cell is within the selection void Advance(); // advance the pattern inside the selection by one generation void AdvanceOutside(); // advance the pattern outside the selection by one generation void Modify(const int x, const int y, bigint& anchorx, bigint& anchory, bool* forceh, bool* forcev); // modify the existing selection based on where the user tapped (inside) void Move(const bigint& xcells, const bigint& ycells); // move the selection by the given number of cells void SetLeftRight(const bigint& x, const bigint& anchorx); // set the selection's left and right edges void SetTopBottom(const bigint& y, const bigint& anchory); // set the selection's top and bottom edges void Fit(); // fit the selection inside the current viewport void Shrink(bool fit); // shrink the selection so it just encloses all the live cells // and optionally fit the new selection inside the current viewport bool Visible(gRect* visrect); // return true if the selection is visible in the current viewport // and, if visrect is not NULL, set it to the visible rectangle void Clear(); // kill all cells inside the selection void ClearOutside(); // kill all cells outside the selection void CopyToClipboard(bool cut); // copy the selection to the clipboard (using RLE format) and // optionally clear the selection if cut is true bool CanPaste(const bigint& wd, const bigint& ht, bigint& top, bigint& left); // return true if the selection fits inside a rectangle of size ht x wd; // if so then top and left are set to the selection's top left corner void RandomFill(); // randomly fill the selection bool Flip(bool topbottom, bool inundoredo); // return true if selection was successfully flipped bool Rotate(bool clockwise, bool inundoredo); // return true if selection was successfully rotated private: bool SaveOutside(bigint& t, bigint& l, bigint& b, bigint& r); // remember live cells outside the selection void EmptyUniverse(); // kill all cells by creating a new, empty universe void AddRun(int state, int multistate, unsigned int &run, unsigned int &linelen, char* &chptr); void AddEOL(char* &chptr); // these routines are used by CopyToClipboard to create RLE data bool SaveDifferences(lifealgo* oldalgo, lifealgo* newalgo, int itop, int ileft, int ibottom, int iright); // compare same rectangle in the given universes and remember the differences // in cell states; return false only if user aborts lengthy comparison bool FlipRect(bool topbottom, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, int top, int left, int bottom, int right); // called by Flip to flip given rectangle from source universe to // destination universe and optionally kill cells in the source rectangle; // return false only if user aborts lengthy flip bool RotateRect(bool clockwise, lifealgo* srcalgo, lifealgo* destalgo, bool erasesrc, int itop, int ileft, int ibottom, int iright, int ntop, int nleft, int nbottom, int nright); // called by Rotate to rotate given rectangle from source universe to // destination universe and optionally kill cells in the source rectangle; // return false only if user aborts lengthy rotation bool RotatePattern(bool clockwise, bigint& newtop, bigint& newbottom, bigint& newleft, bigint& newright, bool inundoredo); // called by Rotate when the selection encloses the entire pattern; // return false only if user aborts lengthy rotation bigint seltop, selleft, selbottom, selright; // currently we only support a single rectangular selection // which is represented by these edges; eventually we might // support arbitrarily complex selection shapes by maintaining // a list or dynamic array of non-overlapping rectangles bool exists; // does the selection exist? }; #endif golly-2.7-src/gui-android/0000755000175000017500000000000012536111545012503 500000000000000golly-2.7-src/gui-android/Golly/0000755000175000017500000000000012536111546013572 500000000000000golly-2.7-src/gui-android/Golly/src/0000755000175000017500000000000012536111545014360 500000000000000golly-2.7-src/gui-android/Golly/src/net/0000755000175000017500000000000012536111545015146 500000000000000golly-2.7-src/gui-android/Golly/src/net/sf/0000755000175000017500000000000012536111545015556 500000000000000golly-2.7-src/gui-android/Golly/src/net/sf/golly/0000755000175000017500000000000012536111546016705 500000000000000golly-2.7-src/gui-android/Golly/src/net/sf/golly/MainActivity.java0000644000175000017500000015160012536111364022072 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import java.io.File; import android.app.AlertDialog; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Color; import android.graphics.Typeface; import android.media.AudioManager; import android.media.ToneGenerator; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; import android.text.InputType; import android.util.DisplayMetrics; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.PopupMenu; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; public class MainActivity extends BaseActivity { // see jnicalls.cpp for these native routines: private static native void nativeClassInit(); // this MUST be static private native void nativeCreate(); // the rest must NOT be static private native void nativeDestroy(); private native void nativeStartGenerating(); private native void nativeStopGenerating(); private native void nativeStopBeforeNew(); private native void nativePauseGenerating(); private native void nativeResumeGenerating(); private native void nativeResetPattern(); private native void nativeUndo(); private native void nativeRedo(); private native boolean nativeCanReset(); private native boolean nativeAllowUndo(); private native boolean nativeCanUndo(); private native boolean nativeCanRedo(); private native boolean nativeInfoAvailable(); private native boolean nativeIsGenerating(); private native int nativeGetStatusColor(); private native String nativeGetStatusLine(int line); private native String nativeGetPasteMode(); private native String nativeGetRandomFill(); private native void nativeNewPattern(); private native void nativeFitPattern(); private native void nativeGenerate(); private native void nativeStep(); private native void nativeStep1(); private native void nativeFaster(); private native void nativeSlower(); private native void nativeScale1to1(); private native void nativeBigger(); private native void nativeSmaller(); private native void nativeMiddle(); private native void nativeSetMode(int mode); private native int nativeGetMode(); private native int nativeCalculateSpeed(); private native int nativeNumLayers(); private native boolean nativePasteExists(); private native boolean nativeSelectionExists(); private native void nativePaste(); private native void nativeSelectAll(); private native void nativeRemoveSelection(); private native void nativeCutSelection(); private native void nativeCopySelection(); private native void nativeClearSelection(int inside); private native void nativeShrinkSelection(); private native void nativeFitSelection(); private native void nativeRandomFill(); private native void nativeFlipSelection(int y); private native void nativeRotateSelection(int clockwise); private native void nativeAdvanceSelection(int inside); private native void nativeAbortPaste(); private native void nativeDoPaste(int toselection); private native void nativeFlipPaste(int y); private native void nativeRotatePaste(int clockwise); private native void nativeClearMessage(); private native String nativeGetValidExtensions(); private native boolean nativeValidExtension(String filename); private native boolean nativeFileExists(String filename); private native void nativeSavePattern(String filename); private native void nativeOpenFile(String filepath); private native void nativeSetFullScreen(boolean fullscreen); private native void nativeChangeRule(String rule); private native void nativeLexiconPattern(String pattern); private native int nativeDrawingState(); // local fields: private static boolean fullscreen = false; // in full screen mode? private boolean widescreen; // use different layout for wide screens? private Button ssbutton; // Start/Stop button private Button resetbutton; // Reset button (used if wide screen) private Button undobutton; // Undo button private Button redobutton; // Redo button private Button editbutton; // Edit/Paste button private Button statebutton; // button to change drawing state private Button modebutton; // Draw/Pick/Select/Move button private Button drawbutton; // Draw button (used if wide screen) private Button pickbutton; // Pick button (used if wide screen) private Button selectbutton; // Select button (used if wide screen) private Button movebutton; // Move button (used if wide screen) private Button infobutton; // Info button private Button restorebutton; // Restore button private TextView status1, status2, status3; // status bar has 3 lines private int statuscolor = 0xFF000000; // background color of status bar private PatternGLSurfaceView pattView; // OpenGL ES is used to draw patterns private Handler genhandler; // for generating patterns private Runnable generate; // code started/stopped by genhandler private int geninterval; // interval between nativeGenerate calls (in millisecs) private Handler callhandler; // for calling a method again private Runnable callagain; // code that calls method private String methodname; // name of method to call private View currview; // current view parameter private MenuItem curritem; // current menu item parameter private PopupMenu popup; // used for all pop-up menus private boolean stopped = true; // generating is stopped? // ----------------------------------------------------------------------------- // this stuff is used to display a progress bar: private static boolean cancelProgress = false; // cancel progress dialog? private static long progstart, prognext; // for progress timing private static int progresscount = 0; // if > 0 then BeginProgress has been called private TextView progtitle; // title above progress bar private ProgressBar progbar; // progress bar private LinearLayout proglayout; // view containing progress bar // ----------------------------------------------------------------------------- // this stuff is used in other activities: public final static String OPENFILE_MESSAGE = "net.sf.golly.OPENFILE"; public final static String RULE_MESSAGE = "net.sf.golly.RULE"; public final static String LEXICON_MESSAGE = "net.sf.golly.LEXICON"; // ----------------------------------------------------------------------------- // the following stuff allows time consuming code (like nativeGenerate) to periodically // check if any user events need to be processed, but without blocking the UI thread // (thanks to http://stackoverflow.com/questions/4994263/how-can-i-do-non-blocking-events-processing-on-android) private boolean processingevents = false; private Handler evthandler = null; private Runnable doevents = new Runnable() { public void run() { Looper looper = Looper.myLooper(); looper.quit(); evthandler.removeCallbacks(this); evthandler = null; } }; private class IdleHandler implements MessageQueue.IdleHandler { private Looper idlelooper; protected IdleHandler(Looper looper) { idlelooper = looper; } public boolean queueIdle() { evthandler = new Handler(idlelooper); evthandler.post(doevents); return(false); } }; // this method is called from C++ code (see jnicalls.cpp) private void CheckMessageQueue() { // process any pending UI events in message queue if (!processingevents) { Looper.myQueue().addIdleHandler(new IdleHandler(Looper.myLooper())); processingevents = true; try { Looper.loop(); } catch (RuntimeException re) { // looper.quit() in doevents causes an exception } processingevents = false; } } // ----------------------------------------------------------------------------- static { nativeClassInit(); // caches Java method IDs } // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Log.i("Golly","screen density in dpi = " + Integer.toString(metrics.densityDpi)); // eg. densityDpi = 320 on Nexus 7 DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); float dpWidth = displayMetrics.widthPixels / displayMetrics.density; // Log.i("Golly","screen width in dp = " + Integer.toString(config.screenWidthDp)); // eg. on Nexus 7 screenWidthDp = 600 in portrait, 960 in landscape widescreen = dpWidth >= 600; if (widescreen) { // use a layout that has more buttons setContentView(R.layout.main_layout_wide); resetbutton = (Button) findViewById(R.id.reset); drawbutton = (Button) findViewById(R.id.drawmode); pickbutton = (Button) findViewById(R.id.pickmode); selectbutton = (Button) findViewById(R.id.selectmode); movebutton = (Button) findViewById(R.id.movemode); if (dpWidth >= 800) { // show nicer text in some buttons ((Button) findViewById(R.id.slower)).setText("Slower"); ((Button) findViewById(R.id.faster)).setText("Faster"); ((Button) findViewById(R.id.smaller)).setText("Smaller"); ((Button) findViewById(R.id.scale1to1)).setText("Scale=1:1"); ((Button) findViewById(R.id.bigger)).setText("Bigger"); ((Button) findViewById(R.id.middle)).setText("Middle"); } } else { // screen isn't wide enough to have all the buttons we'd like setContentView(R.layout.main_layout); modebutton = (Button) findViewById(R.id.touchmode); } // following stuff is used in both layouts ssbutton = (Button) findViewById(R.id.startstop); undobutton = (Button) findViewById(R.id.undo); redobutton = (Button) findViewById(R.id.redo); editbutton = (Button) findViewById(R.id.edit); statebutton = (Button) findViewById(R.id.state); infobutton = (Button) findViewById(R.id.info); restorebutton = (Button) findViewById(R.id.restore); status1 = (TextView) findViewById(R.id.status1); status2 = (TextView) findViewById(R.id.status2); status3 = (TextView) findViewById(R.id.status3); progbar = (ProgressBar) findViewById(R.id.progress_bar); proglayout = (LinearLayout) findViewById(R.id.progress_layout); progtitle = (TextView) findViewById(R.id.progress_title); nativeCreate(); // must be called every time (to cache this instance) // this will call the PatternGLSurfaceView constructor pattView = (PatternGLSurfaceView) findViewById(R.id.patternview); restorebutton.setVisibility(View.INVISIBLE); proglayout.setVisibility(LinearLayout.INVISIBLE); // create handler and runnable for generating patterns geninterval = nativeCalculateSpeed(); genhandler = new Handler(); generate = new Runnable() { public void run() { if (!stopped) { nativeGenerate(); genhandler.postDelayed(this, geninterval); // nativeGenerate will be called again after given interval } } }; // create handler and runnable for calling a method again when the user // invokes certain events while the next generation is being calculated callhandler = new Handler(); callagain = new Runnable() { public void run() { if (methodname.equals("doStartStop")) doStartStop(currview); else if (methodname.equals("doStep")) doStep(currview); else if (methodname.equals("doNew")) doNewPattern(currview); else if (methodname.equals("doUndo")) doUndo(currview); else if (methodname.equals("doRedo")) doRedo(currview); else if (methodname.equals("doRule")) doRule(currview); else if (methodname.equals("doInfo")) doInfo(currview); else if (methodname.equals("doSave")) doSave(currview); else if (methodname.equals("doReset")) doReset(currview); else if (methodname.equals("doPaste")) doPaste(currview); else if (methodname.equals("doSelItem")) doSelectionItem(curritem); else // string mismatch Log.e("Fix callagain", methodname); } }; } // ----------------------------------------------------------------------------- @Override protected void onNewIntent(Intent intent) { // check for messages sent by other activities String filepath = intent.getStringExtra(OPENFILE_MESSAGE); if (filepath != null) { nativeOpenFile(filepath); } String rule = intent.getStringExtra(RULE_MESSAGE); if (rule != null) { nativeChangeRule(rule); } String pattern = intent.getStringExtra(LEXICON_MESSAGE); if (pattern != null) { nativeLexiconPattern(pattern); } } // ----------------------------------------------------------------------------- @Override public boolean onCreateOptionsMenu(Menu menu) { // add main.xml items to the action bar getMenuInflater().inflate(R.menu.main, menu); return true; } // ----------------------------------------------------------------------------- @Override public boolean onOptionsItemSelected(MenuItem item) { // action bar item has been tapped nativeClearMessage(); Intent intent; switch (item.getItemId()) { case R.id.open: intent = new Intent(this, OpenActivity.class); startActivity(intent); return true; case R.id.settings: intent = new Intent(this, SettingsActivity.class); startActivity(intent); return true; case R.id.help: intent = new Intent(this, HelpActivity.class); startActivity(intent); return true; } return super.onOptionsItemSelected(item); } // ----------------------------------------------------------------------------- @Override protected void onPause() { super.onPause(); pattView.onPause(); stopped = true; } // ----------------------------------------------------------------------------- @Override protected void onResume() { super.onResume(); pattView.onResume(); if (fullscreen) { fullscreen = false; // following will set it true toggleFullScreen(null); } else { updateButtons(); UpdateEditBar(); } if (nativeIsGenerating()) { stopped = false; genhandler.post(generate); } } // ----------------------------------------------------------------------------- @Override protected void onDestroy() { stopped = true; // should have been done in OnPause, but play safe nativeDestroy(); super.onDestroy(); } // ----------------------------------------------------------------------------- private void deleteTempFiles() { File dir = getCacheDir(); File[] files = dir.listFiles(); if (files != null) { for (File file : files) { if (file.getName().startsWith("GET-") || file.getName().endsWith(".html")) { // don't delete files created via "get:" links in HelpActivity } else { file.delete(); } } } } // ----------------------------------------------------------------------------- private void updateButtons() { if (fullscreen) return; if (nativeIsGenerating()) { ssbutton.setText("Stop"); ssbutton.setTextColor(Color.rgb(255,0,0)); if (widescreen) resetbutton.setEnabled(true); undobutton.setEnabled(nativeAllowUndo()); redobutton.setEnabled(false); } else { ssbutton.setText("Start"); ssbutton.setTextColor(Color.rgb(0,255,0)); if (widescreen) resetbutton.setEnabled(nativeCanReset()); undobutton.setEnabled(nativeAllowUndo() && (nativeCanReset() || nativeCanUndo())); redobutton.setEnabled(nativeCanRedo()); } infobutton.setEnabled(nativeInfoAvailable()); } // ----------------------------------------------------------------------------- private void updateGeneratingSpeed() { geninterval = nativeCalculateSpeed(); genhandler.removeCallbacks(generate); stopped = false; if (nativeIsGenerating()) genhandler.post(generate); } // ----------------------------------------------------------------------------- private boolean callAgainAfterDelay(String callname, View view, MenuItem item) { if (processingevents) { // CheckMessageQueue has been called inside a (possibly) lengthy task // so call the given method again after a short delay methodname = callname; if (view != null) currview = view; if (item != null) curritem = item; callhandler.postDelayed(callagain, 5); // call after 5 millisecs return true; } else { return false; } } // ----------------------------------------------------------------------------- // called when the Start/Stop button is tapped public void doStartStop(View view) { nativeClearMessage(); if (callAgainAfterDelay("doStartStop", view, null)) return; if (nativeIsGenerating()) { // stop calling nativeGenerate stopped = true; nativeStopGenerating(); } else { nativeStartGenerating(); // nativeIsGenerating() might still be false (eg. if pattern is empty) if (nativeIsGenerating()) { // start calling nativeGenerate geninterval = nativeCalculateSpeed(); genhandler.removeCallbacks(generate); // probably unnecessary here but play safe stopped = false; genhandler.post(generate); } } updateButtons(); } // ----------------------------------------------------------------------------- private void stopIfGenerating() { if (nativeIsGenerating()) { // note that genhandler.removeCallbacks(generate) doesn't always work if // processingevents is true, so we use a global flag to start/stop // making calls to nativeGenerate stopped = true; nativeStopGenerating(); } } // ----------------------------------------------------------------------------- // called when the Step button is tapped public void doStep(View view) { nativeClearMessage(); stopIfGenerating(); if (callAgainAfterDelay("doStep", view, null)) return; nativeStep(); updateButtons(); } // ----------------------------------------------------------------------------- // called when the Slower button is tapped public void doSlower(View view) { nativeClearMessage(); nativeSlower(); updateGeneratingSpeed(); } // ----------------------------------------------------------------------------- // called when the Step=1 button is tapped public void doStep1(View view) { nativeClearMessage(); nativeStep1(); updateGeneratingSpeed(); } // ----------------------------------------------------------------------------- // called when the Faster button is tapped public void doFaster(View view) { nativeClearMessage(); nativeFaster(); updateGeneratingSpeed(); } // ----------------------------------------------------------------------------- // called when the Reset button is tapped public void doReset(View view) { nativeClearMessage(); stopIfGenerating(); if (callAgainAfterDelay("doReset", view, null)) return; nativeResetPattern(); updateButtons(); } // ----------------------------------------------------------------------------- // called when the Control button is tapped public void doControl(View view) { nativeClearMessage(); // display pop-up menu with these items: Step=1, Faster, Slower, Reset popup = new PopupMenu(this, view); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.control_menu, popup.getMenu()); popup.show(); } // ----------------------------------------------------------------------------- // called when item from control_menu is selected public void doControlItem(MenuItem item) { if (item.getItemId() == R.id.reset) { stopIfGenerating(); if (callAgainAfterDelay("doReset", null, item)) return; } popup.dismiss(); switch (item.getItemId()) { case R.id.step1: nativeStep1(); break; case R.id.faster: nativeFaster(); break; case R.id.slower: nativeSlower(); break; case R.id.reset: nativeResetPattern(); break; default: Log.e("Golly","Fix bug in doControlItem!"); } if (item.getItemId() == R.id.reset) { updateButtons(); } else { updateGeneratingSpeed(); } } // ----------------------------------------------------------------------------- // called when the Fit button is tapped public void doFitPattern(View view) { nativeClearMessage(); nativeFitPattern(); } // ----------------------------------------------------------------------------- // called when the Smaller button is tapped public void doSmaller(View view) { nativeClearMessage(); nativeSmaller(); } // ----------------------------------------------------------------------------- // called when the Scale=1:1 button is tapped public void doScale1to1(View view) { nativeClearMessage(); nativeScale1to1(); } // ----------------------------------------------------------------------------- // called when the Bigger button is tapped public void doBigger(View view) { nativeClearMessage(); nativeBigger(); } // ----------------------------------------------------------------------------- // called when the Middle button is tapped public void doMiddle(View view) { nativeClearMessage(); nativeMiddle(); } // ----------------------------------------------------------------------------- // called when the View button is tapped public void doView(View view) { nativeClearMessage(); // display pop-up menu with these items: Scale=1:1, Bigger, Smaller, Middle popup = new PopupMenu(this, view); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.view_menu, popup.getMenu()); popup.show(); } // ----------------------------------------------------------------------------- // called when item from view_menu is selected public void doViewItem(MenuItem item) { popup.dismiss(); switch (item.getItemId()) { case R.id.scale1to1: nativeScale1to1(); break; case R.id.bigger: nativeBigger(); break; case R.id.smaller: nativeSmaller(); break; case R.id.middle: nativeMiddle(); break; default: Log.e("Golly","Fix bug in doViewItem!"); } } // ----------------------------------------------------------------------------- // called when the Undo button is tapped public void doUndo(View view) { nativeClearMessage(); stopIfGenerating(); if (callAgainAfterDelay("doUndo", view, null)) return; nativeUndo(); updateButtons(); } // ----------------------------------------------------------------------------- // called when the Redo button is tapped public void doRedo(View view) { nativeClearMessage(); // nativeIsGenerating() should never be true here if (callAgainAfterDelay("doRedo", view, null)) return; nativeRedo(); updateButtons(); } // ----------------------------------------------------------------------------- // called when the All button is tapped public void doSelectAll(View view) { nativeClearMessage(); nativeSelectAll(); UpdateEditBar(); } // ----------------------------------------------------------------------------- private void createSelectionMenu(MenuInflater inflater) { Menu menu = popup.getMenu(); inflater.inflate(R.menu.selection_menu, menu); MenuItem item = menu.findItem(R.id.random); item.setTitle("Random Fill (" + nativeGetRandomFill() + "%)"); if (widescreen) { // delete the top 2 items menu.removeItem(R.id.paste); menu.removeItem(R.id.all); } } // ----------------------------------------------------------------------------- // called when the Edit button is tapped (widescreen is true) public void doEdit(View view) { nativeClearMessage(); if (nativeSelectionExists()) { popup = new PopupMenu(this, view); MenuInflater inflater = popup.getMenuInflater(); createSelectionMenu(inflater); popup.show(); } else { // editbutton should be disabled if there's no selection Log.e("Golly","Bug detected in doEdit!"); } } // ----------------------------------------------------------------------------- private void createPasteMenu(MenuInflater inflater) { Menu menu = popup.getMenu(); inflater.inflate(R.menu.paste_menu, menu); MenuItem item = menu.findItem(R.id.pastesel); item.setEnabled(nativeSelectionExists()); item = menu.findItem(R.id.pastemode); item.setTitle("Paste (" + nativeGetPasteMode() + ")"); if (nativeIsGenerating()) { // probably best to stop generating when Paste button is tapped // (consistent with iOS Golly) stopped = true; nativeStopGenerating(); updateButtons(); } } // ----------------------------------------------------------------------------- // called when the Paste button is tapped (widescreen is true) public void doPaste(View view) { nativeClearMessage(); if (nativePasteExists()) { // show pop-up menu with various paste options popup = new PopupMenu(this, view); MenuInflater inflater = popup.getMenuInflater(); createPasteMenu(inflater); popup.show(); } else { // create the paste image stopIfGenerating(); if (callAgainAfterDelay("doPaste", view, null)) return; nativePaste(); UpdateEditBar(); } } // ----------------------------------------------------------------------------- // called when the Edit/Paste button is tapped (widescreen is false) public void doEditPaste(View view) { nativeClearMessage(); // display pop-up menu with items that depend on whether a selection or paste image exists popup = new PopupMenu(this, view); MenuInflater inflater = popup.getMenuInflater(); if (nativePasteExists()) { createPasteMenu(inflater); } else if (nativeSelectionExists()) { createSelectionMenu(inflater); } else { inflater.inflate(R.menu.edit_menu, popup.getMenu()); } popup.show(); } // ----------------------------------------------------------------------------- // called when item from edit_menu is selected public void doEditItem(MenuItem item) { if (item.getItemId() == R.id.paste) { stopIfGenerating(); if (callAgainAfterDelay("doPaste", null, item)) return; } popup.dismiss(); switch (item.getItemId()) { case R.id.paste: nativePaste(); break; case R.id.all: nativeSelectAll(); break; default: Log.e("Golly","Fix bug in doEditItem!"); } UpdateEditBar(); } // ----------------------------------------------------------------------------- // called when item from selection_menu is selected public void doSelectionItem(MenuItem item) { if (item.getItemId() != R.id.remove && item.getItemId() != R.id.copy && item.getItemId() != R.id.shrink && item.getItemId() != R.id.fitsel) { // item can modify the current pattern so we must stop generating, // but nicer if we only stop temporarily and resume when done if (nativeIsGenerating()) { // no need to set stopped = true nativePauseGenerating(); } if (callAgainAfterDelay("doSelItem", null, item)) return; } popup.dismiss(); switch (item.getItemId()) { // doEditItem handles the top 2 items (if widescreen is false) // case R.id.paste: nativePaste(); break; // case R.id.all: nativeSelectAll(); break; case R.id.remove: nativeRemoveSelection(); break; case R.id.cut: nativeCutSelection(); break; case R.id.copy: nativeCopySelection(); break; case R.id.clear: nativeClearSelection(1); break; case R.id.clearo: nativeClearSelection(0); break; case R.id.shrink: nativeShrinkSelection(); break; case R.id.fitsel: nativeFitSelection(); break; case R.id.random: nativeRandomFill(); break; case R.id.flipy: nativeFlipSelection(1); break; case R.id.flipx: nativeFlipSelection(0); break; case R.id.rotatec: nativeRotateSelection(1); break; case R.id.rotatea: nativeRotateSelection(0); break; case R.id.advance: nativeAdvanceSelection(1); break; case R.id.advanceo: nativeAdvanceSelection(0); break; default: Log.e("Golly","Fix bug in doSelectionItem!"); } // resume generating (only if nativePauseGenerating was called) nativeResumeGenerating(); } // ----------------------------------------------------------------------------- // called when item from paste_menu is selected public void doPasteItem(MenuItem item) { popup.dismiss(); switch (item.getItemId()) { case R.id.abort: nativeAbortPaste(); break; case R.id.pastemode: nativeDoPaste(0); break; case R.id.pastesel: nativeDoPaste(1); break; case R.id.pflipy: nativeFlipPaste(1); break; case R.id.pflipx: nativeFlipPaste(0); break; case R.id.protatec: nativeRotatePaste(1); break; case R.id.protatea: nativeRotatePaste(0); break; default: Log.e("Golly","Fix bug in doPasteItem!"); } UpdateEditBar(); } // ----------------------------------------------------------------------------- // called when the Draw/Pick/Select/Move button is tapped public void doSetTouchMode(View view) { nativeClearMessage(); // display pop-up menu with these items: Draw, Pick, Select, Move popup = new PopupMenu(this, view); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.mode_menu, popup.getMenu()); popup.show(); } // ----------------------------------------------------------------------------- // called when item from mode_menu is selected public void doModeItem(MenuItem item) { popup.dismiss(); switch (item.getItemId()) { case R.id.draw: nativeSetMode(0); break; case R.id.pick: nativeSetMode(1); break; case R.id.select: nativeSetMode(2); break; case R.id.move: nativeSetMode(3); break; default: Log.e("Golly","Fix bug in doModeItem!"); } UpdateEditBar(); // update modebutton text } // ----------------------------------------------------------------------------- // called when the Draw button is tapped public void doDrawMode(View view) { nativeClearMessage(); if (nativeGetMode() != 0) { nativeSetMode(0); UpdateEditBar(); } } // ----------------------------------------------------------------------------- // called when the Pick button is tapped public void doPickMode(View view) { nativeClearMessage(); if (nativeGetMode() != 1) { nativeSetMode(1); UpdateEditBar(); } } // ----------------------------------------------------------------------------- // called when the Select button is tapped public void doSelectMode(View view) { nativeClearMessage(); if (nativeGetMode() != 2) { nativeSetMode(2); UpdateEditBar(); } } // ----------------------------------------------------------------------------- // called when the Move button is tapped public void doMoveMode(View view) { nativeClearMessage(); if (nativeGetMode() != 3) { nativeSetMode(3); UpdateEditBar(); } } // ----------------------------------------------------------------------------- // called when the state button is tapped public void doChangeState(View view) { nativeClearMessage(); // let user change the current drawing state Intent intent = new Intent(this, StateActivity.class); startActivity(intent); } // ----------------------------------------------------------------------------- // called when the New button is tapped public void doNewPattern(View view) { nativeClearMessage(); // stopIfGenerating() would work here but we use smarter code that // avoids trying to save the current pattern (potentially very large) if (nativeIsGenerating()) { stopped = true; nativeStopBeforeNew(); } if (callAgainAfterDelay("doNew", view, null)) return; nativeNewPattern(); updateButtons(); UpdateEditBar(); if (nativeNumLayers() == 1) { // delete all files in tempdir deleteTempFiles(); } } // ----------------------------------------------------------------------------- // called when the Rule button is tapped public void doRule(View view) { nativeClearMessage(); stopIfGenerating(); if (callAgainAfterDelay("doRule", view, null)) return; // let user change the current rule and/or algorithm Intent intent = new Intent(this, RuleActivity.class); startActivity(intent); } // ----------------------------------------------------------------------------- // called when the Info button is tapped public void doInfo(View view) { nativeClearMessage(); stopIfGenerating(); if (callAgainAfterDelay("doInfo", view, null)) return; // display any comments in current pattern file Intent intent = new Intent(this, InfoActivity.class); intent.putExtra(InfoActivity.INFO_MESSAGE, "native"); startActivity(intent); } // ----------------------------------------------------------------------------- // called when the Save button is tapped public void doSave(View view) { nativeClearMessage(); stopIfGenerating(); if (callAgainAfterDelay("doSave", view, null)) return; AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle("Save current pattern"); alert.setMessage("Valid file name extensions are\n" + nativeGetValidExtensions()); // or use radio buttons as in iPad Golly??? // might be better to create a new SaveActivity and make it appear in a dialog // by setting its theme to Theme.Holo.Dialog in the manifest element // use an EditText view to get filename final EditText input = new EditText(this); input.setSingleLine(true); input.setHint("enter a file name"); input.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); alert.setView(input); alert.setPositiveButton("SAVE", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // do nothing here (see below) } }); alert.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); // don't call alert.show() here -- instead we use the following stuff // which allows us to prevent the alert dialog from closing if the // given file name is invalid final AlertDialog dialog = alert.create(); dialog.show(); dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener( new View.OnClickListener() { public void onClick(View v) { String filename = input.getText().toString(); if (filename.length() == 0) { PlayBeepSound(); return; } // check for valid extension if (!nativeValidExtension(filename)) { baseapp.Warning("Invalid file extension."); return; } // check if given file already exists if (nativeFileExists(filename)) { String answer = baseapp.YesNo("A file with that name already exists. Do you want to replace that file?"); if (answer.equals("no")) return; } // dismiss dialog first in case SavePattern calls BeginProgress dialog.dismiss(); nativeSavePattern(filename); } }); } // ----------------------------------------------------------------------------- // called when the Full/Restore button is tapped public void toggleFullScreen(View view) { // no need to call nativeClearMessage() LinearLayout topbar = (LinearLayout) findViewById(R.id.top_bar); LinearLayout editbar = (LinearLayout) findViewById(R.id.edit_bar); RelativeLayout bottombar = (RelativeLayout) findViewById(R.id.bottom_bar); if (fullscreen) { fullscreen = false; restorebutton.setVisibility(View.INVISIBLE); status1.setVisibility(View.VISIBLE); status2.setVisibility(View.VISIBLE); status3.setVisibility(View.VISIBLE); topbar.setVisibility(LinearLayout.VISIBLE); editbar.setVisibility(LinearLayout.VISIBLE); bottombar.setVisibility(RelativeLayout.VISIBLE); getActionBar().show(); } else { fullscreen = true; restorebutton.setVisibility(View.VISIBLE); status1.setVisibility(View.GONE); status2.setVisibility(View.GONE); status3.setVisibility(View.GONE); topbar.setVisibility(LinearLayout.GONE); editbar.setVisibility(LinearLayout.GONE); bottombar.setVisibility(RelativeLayout.GONE); getActionBar().hide(); } // need to let native code know (this will update status bar if not fullscreen) nativeSetFullScreen(fullscreen); if (!fullscreen) { updateButtons(); UpdateEditBar(); } } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void StartMainActivity() { Intent intent = new Intent(this, MainActivity.class); startActivity(intent); } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void RefreshPattern() { // this can be called from any thread pattView.requestRender(); } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void ShowStatusLines() { // no need to check fullscreen flag here (caller checks it) // this might be called from a non-UI thread runOnUiThread(new Runnable() { public void run() { int bgcolor = nativeGetStatusColor(); if (statuscolor != bgcolor) { // change background color of status lines statuscolor = bgcolor; status1.setBackgroundColor(statuscolor); status2.setBackgroundColor(statuscolor); status3.setBackgroundColor(statuscolor); } status1.setText(nativeGetStatusLine(1)); status2.setText(nativeGetStatusLine(2)); status3.setText(nativeGetStatusLine(3)); } }); } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void UpdateEditBar() { if (fullscreen) return; // this might be called from a non-UI thread runOnUiThread(new Runnable() { public void run() { undobutton.setEnabled(nativeCanUndo()); redobutton.setEnabled(nativeCanRedo()); // update Edit button if (widescreen) { editbutton.setEnabled(nativeSelectionExists()); } else { if (nativePasteExists()) { editbutton.setText("Paste"); } else { editbutton.setText("Edit"); } } // show current drawing state statebutton.setText("State=" + Integer.toString(nativeDrawingState())); // show current touch mode if (widescreen) { drawbutton.setTypeface(Typeface.DEFAULT); pickbutton.setTypeface(Typeface.DEFAULT); selectbutton.setTypeface(Typeface.DEFAULT); movebutton.setTypeface(Typeface.DEFAULT); drawbutton.setTextColor(Color.rgb(0,0,0)); pickbutton.setTextColor(Color.rgb(0,0,0)); selectbutton.setTextColor(Color.rgb(0,0,0)); movebutton.setTextColor(Color.rgb(0,0,0)); switch (nativeGetMode()) { case 0: drawbutton.setTypeface(Typeface.DEFAULT_BOLD); drawbutton.setTextColor(Color.rgb(0,0,255)); break; case 1: pickbutton.setTypeface(Typeface.DEFAULT_BOLD); pickbutton.setTextColor(Color.rgb(0,0,255)); break; case 2: selectbutton.setTypeface(Typeface.DEFAULT_BOLD); selectbutton.setTextColor(Color.rgb(0,0,255)); break; case 3: movebutton.setTypeface(Typeface.DEFAULT_BOLD); movebutton.setTextColor(Color.rgb(0,0,255)); break; default: Log.e("Golly","Fix bug in UpdateEditBar!"); } } else { switch (nativeGetMode()) { case 0: modebutton.setText("Draw"); break; case 1: modebutton.setText("Pick"); break; case 2: modebutton.setText("Select"); break; case 3: modebutton.setText("Move"); break; default: Log.e("Golly","Fix bug in UpdateEditBar!"); } } } }); } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void PlayBeepSound() { ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100); if (tg != null) { tg.startTone(ToneGenerator.TONE_PROP_BEEP); tg.release(); } } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void RemoveFile(String filepath) { File file = new File(filepath); if (!file.delete()) { Log.e("RemoveFile failed", filepath); } } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private String MoveFile(String oldpath, String newpath) { String result = ""; File oldfile = new File(oldpath); File newfile = new File(newpath); if (!oldfile.renameTo(newfile)) { Log.e("MoveFile failed: old", oldpath); Log.e("MoveFile failed: new", newpath); result = "MoveFile failed"; } return result; } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void CopyTextToClipboard(String text) { ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipData clip = ClipData.newPlainText("RLE data", text); clipboard.setPrimaryClip(clip); // Log.i("CopyTextToClipboard", text); } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private String GetTextFromClipboard() { ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); String text = ""; if (clipboard.hasPrimaryClip()) { ClipData clipData = clipboard.getPrimaryClip(); text = clipData.getItemAt(0).coerceToText(this).toString(); if (text.length() == 0) { baseapp.Warning("Failed to get text from clipboard!"); } } // Log.i("GetTextFromClipboard", text); return text; } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void ShowTextFile(String filepath) { // display file contents Intent intent = new Intent(baseapp.getCurrentActivity(), InfoActivity.class); intent.putExtra(InfoActivity.INFO_MESSAGE, filepath); startActivity(intent); } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void ShowHelp(String filepath) { Intent intent = new Intent(this, HelpActivity.class); intent.putExtra(HelpActivity.SHOWHELP_MESSAGE, filepath); startActivity(intent); } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void BeginProgress(String title) { if (progresscount == 0) { // can we disable interaction with all views outside proglayout??? progtitle.setText(title); progbar.setProgress(0); // proglayout.setVisibility(LinearLayout.VISIBLE); cancelProgress = false; progstart = System.nanoTime(); } progresscount++; // handles nested calls } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private boolean AbortProgress(int percentage, String message) { if (progresscount <= 0) baseapp.Fatal("Bug detected in AbortProgress!"); long nanosecs = System.nanoTime() - progstart; if (proglayout.getVisibility() == LinearLayout.VISIBLE) { if (nanosecs < prognext) return false; prognext = nanosecs + 100000000L; // update progress bar about 10 times per sec updateProgressBar(percentage); return cancelProgress; } else { // note that percentage is not always an accurate estimator for how long // the task will take, especially when we use nextcell for cut/copy if ( (nanosecs > 1000000000L && percentage < 30) || nanosecs > 2000000000L ) { // task is probably going to take a while so show progress bar proglayout.setVisibility(LinearLayout.VISIBLE); updateProgressBar(percentage); } prognext = nanosecs + 10000000L; // 0.01 sec delay until 1st progress update } return false; } // ----------------------------------------------------------------------------- private void updateProgressBar(int percentage) { if (percentage < 0 || percentage > 100) return; progbar.setProgress(percentage); CheckMessageQueue(); } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) private void EndProgress() { if (progresscount <= 0) baseapp.Fatal("Bug detected in EndProgress!"); progresscount--; if (progresscount == 0) { proglayout.setVisibility(LinearLayout.INVISIBLE); } } // ----------------------------------------------------------------------------- // called when the Cancel button is tapped public void doCancel(View view) { cancelProgress = true; } } // MainActivity class golly-2.7-src/gui-android/Golly/src/net/sf/golly/BaseApp.java0000644000175000017500000002604712536111364021012 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import android.app.Activity; import android.app.AlertDialog; import android.app.Application; import android.content.DialogInterface; import android.content.res.AssetManager; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.DisplayMetrics; import android.util.Log; // this class (along with BaseActivity) allows our app to keep track of the current foreground activity // (thanks to http://stackoverflow.com/questions/11411395/how-to-get-current-foreground-activity-context-in-android) public class BaseApp extends Application { // see jnicalls.cpp for these native routines: private static native void nativeClassInit(); // this MUST be static private native void nativeCreate(); // the rest must NOT be static private native void nativeSetUserDirs(String path); private native void nativeSetSuppliedDirs(String prefix); private native void nativeSetTempDir(String path); private native void nativeSetScreenDensity(int dpi); private native void nativeSetWideScreen(boolean widescreen); public File userdir; // directory for user-created data public File supplieddir; // directory for supplied data private Activity currentActivity = null; // ----------------------------------------------------------------------------- static { System.loadLibrary("stlport_shared"); // must agree with Application.mk System.loadLibrary("golly"); // loads libgolly.so nativeClassInit(); // caches Java method IDs } // ----------------------------------------------------------------------------- @Override public void onCreate() { super.onCreate(); DisplayMetrics metrics = getResources().getDisplayMetrics(); nativeSetScreenDensity(metrics.densityDpi); // Log.i("Golly","screen density in dpi = " + Integer.toString(metrics.densityDpi)); // eg. densityDpi = 320 on Nexus 7 DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); float dpWidth = displayMetrics.widthPixels / displayMetrics.density; // Log.i("Golly","screen width in dp = " + Integer.toString(config.screenWidthDp)); // eg. on Nexus 7 screenWidthDp = 600 in portrait, 960 in landscape boolean widescreen = dpWidth >= 600; nativeSetWideScreen(widescreen); initPaths(); // sets userdir, supplieddir, etc (must be BEFORE nativeCreate) nativeCreate(); // cache this instance and initialize lots of Golly stuff } // ----------------------------------------------------------------------------- public Activity getCurrentActivity() { return currentActivity; } // ----------------------------------------------------------------------------- public void setCurrentActivity(Activity a) { currentActivity = a; } // ----------------------------------------------------------------------------- private void initPaths() { // check if external storage is available String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { // use external storage for user's files userdir = getExternalFilesDir(null); // /mnt/sdcard/Android/data/net.sf.golly/files } else { // use internal storage for user's files userdir = getFilesDir(); // /data/data/net.sf.golly/files Log.i("Golly", "External storage is not available, so internal storage will be used."); } // create subdirs in userdir (if they don't exist) File subdir; subdir = new File(userdir, "Rules"); // for user's .rule files subdir.mkdir(); subdir = new File(userdir, "Saved"); // for saved pattern files subdir.mkdir(); subdir = new File(userdir, "Downloads"); // for downloaded files subdir.mkdir(); // set appropriate paths used by C++ code nativeSetUserDirs(userdir.getAbsolutePath()); // create a directory in internal storage for supplied Patterns/Rules/Help then // create sub-directories for each by unzipping .zip files stored in assets supplieddir = new File(getFilesDir(), "Supplied"); supplieddir.mkdir(); unzipAsset("Patterns.zip", supplieddir); unzipAsset("Rules.zip", supplieddir); unzipAsset("Help.zip", supplieddir); // supplieddir = /data/data/net.sf.golly/files/Supplied nativeSetSuppliedDirs(supplieddir.getAbsolutePath()); // set directory path for temporary files File tempdir = getCacheDir(); nativeSetTempDir(tempdir.getAbsolutePath()); // /data/data/net.sf.golly/cache } // ----------------------------------------------------------------------------- private void unzipAsset(String zipname, File destdir) { AssetManager am = getAssets(); try { ZipInputStream zipstream = new ZipInputStream(am.open(zipname)); for (ZipEntry entry = zipstream.getNextEntry(); entry != null; entry = zipstream.getNextEntry()) { File destfile = new File(destdir, entry.getName()); if (entry.isDirectory()) { // create any missing sub-directories destfile.mkdirs(); } else { // create a file final int BUFFSIZE = 8192; BufferedOutputStream buffstream = new BufferedOutputStream(new FileOutputStream(destfile), BUFFSIZE); int count = 0; byte[] data = new byte[BUFFSIZE]; while ((count = zipstream.read(data, 0, BUFFSIZE)) != -1) { buffstream.write(data, 0, count); } buffstream.flush(); buffstream.close(); } zipstream.closeEntry(); } zipstream.close(); } catch (Exception e) { Log.e("Golly", "Failed to unzip asset: " + zipname + "\nException: ", e); Warning("You probably forgot to put " + zipname + " in the assets folder!"); } } // ----------------------------------------------------------------------------- // handler for implementing modal dialogs static class LooperInterrupter extends Handler { public void handleMessage(Message msg) { throw new RuntimeException(); } } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) void Warning(String msg) { // use a handler to get a modal dialog final Handler handler = new LooperInterrupter(); // note that MainActivity might not be the current foreground activity AlertDialog.Builder alert = new AlertDialog.Builder(currentActivity); alert.setTitle("Warning"); alert.setMessage(msg); alert.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); handler.sendMessage(handler.obtainMessage()); } }); alert.show(); // loop until runtime exception is triggered try { Looper.loop(); } catch(RuntimeException re) {} } // ----------------------------------------------------------------------------- // this method is called from C++ code (see jnicalls.cpp) void Fatal(String msg) { // use a handler to get a modal dialog final Handler handler = new LooperInterrupter(); // note that MainActivity might not be the current foreground activity AlertDialog.Builder alert = new AlertDialog.Builder(currentActivity); alert.setTitle("Fatal error!"); alert.setMessage(msg); alert.setNegativeButton("QUIT", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); handler.sendMessage(handler.obtainMessage()); } }); alert.show(); // loop until runtime exception is triggered try { Looper.loop(); } catch(RuntimeException re) {} System.exit(1); } // ----------------------------------------------------------------------------- private String answer; // this method is called from C++ code (see jnicalls.cpp) String YesNo(String query) { // use a handler to get a modal dialog final Handler handler = new LooperInterrupter(); // note that MainActivity might not be the current foreground activity AlertDialog.Builder alert = new AlertDialog.Builder(currentActivity); alert.setTitle("A question..."); alert.setMessage(query); alert.setPositiveButton("YES", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { answer = "yes"; dialog.cancel(); handler.sendMessage(handler.obtainMessage()); } }); alert.setNegativeButton("NO", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { answer = "no"; dialog.cancel(); handler.sendMessage(handler.obtainMessage()); } }); alert.show(); // loop until runtime exception is triggered try { Looper.loop(); } catch(RuntimeException re) {} return answer; } } // BaseApp class golly-2.7-src/gui-android/Golly/src/net/sf/golly/EditActivity.java0000644000175000017500000002415312536111364022075 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.InputStreamReader; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; import android.util.DisplayMetrics; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class EditActivity extends BaseActivity { public final static String EDITFILE_MESSAGE = "net.sf.golly.EDITFILE"; private EditText etext; // the text to be edited private boolean textchanged; // true if user changed text private String filename; // name of file being edited private String fileextn; // filename's extension private String dirpath; // location of filename // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.edit_layout); etext = (EditText) findViewById(R.id.edit_text); // next call prevents long lines wrapping and enables horizontal scrolling etext.setHorizontallyScrolling(true); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); float dpWidth = displayMetrics.widthPixels / displayMetrics.density; if (dpWidth >= 600) { // use bigger font size for wide screens (layout size is 10sp) etext.setTextSize(12); } textchanged = false; getActionBar().hide(); // get full file path sent by other activity Intent intent = getIntent(); String filepath = intent.getStringExtra(EDITFILE_MESSAGE); if (filepath != null) { editTextFile(filepath); } } // ----------------------------------------------------------------------------- private boolean error = false; private void editTextFile(String filepath) { File file = new File(filepath); dirpath = filepath.substring(0, filepath.lastIndexOf('/') + 1); filename = file.getName(); fileextn = ""; int i = filename.lastIndexOf('.'); if (i > 0) fileextn = filename.substring(i); // read contents of supplied file into a string String filecontents; try { FileInputStream instream = new FileInputStream(file); BufferedReader reader = new BufferedReader(new InputStreamReader(instream)); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { sb.append(line); sb.append("\n"); } filecontents = sb.toString(); instream.close(); } catch (Exception e) { filecontents = "Error reading file:\n" + e.toString(); // best to hide Save button if error occurred Button savebutton = (Button) findViewById(R.id.save); savebutton.setVisibility(View.INVISIBLE); error = true; } // display file contents (or error message) etext.setText(filecontents); // following stuff will detect any changes to text etext.addTextChangedListener(new TextWatcher() { public void onTextChanged(CharSequence s, int start, int before, int count) { if (!error) textchanged = true; } public void beforeTextChanged(CharSequence s, int start, int count, int after) { // ignore } public void afterTextChanged(Editable s) { // ignore } }); } // ----------------------------------------------------------------------------- private boolean writeFile(File file, final String contents) { try { FileWriter out = new FileWriter(file); out.write(contents); out.close(); } catch (Exception e) { Toast.makeText(this, "Error writing file: " + e.toString(), Toast.LENGTH_LONG).show(); return false; } return true; } // ----------------------------------------------------------------------------- private int answer; static class LooperInterrupter extends Handler { public void handleMessage(Message msg) { throw new RuntimeException(); } } private boolean ask(String title, String msg) { // use a handler to get a modal dialog final Handler handler = new LooperInterrupter(); AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle(title); alert.setMessage(msg); alert.setPositiveButton("YES", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { answer = 1; dialog.cancel(); handler.sendMessage(handler.obtainMessage()); } }); alert.setNegativeButton("NO", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { answer = 0; dialog.cancel(); handler.sendMessage(handler.obtainMessage()); } }); alert.show(); // loop until runtime exception is triggered try { Looper.loop(); } catch(RuntimeException re) {} return answer == 1; } // ----------------------------------------------------------------------------- // called when the Save button is tapped public void doSave(View view) { AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle("Save file as:"); if (fileextn.length() > 0) alert.setMessage("Extension must be " + fileextn); // use an EditText view to get (possibly new) file name final EditText input = new EditText(this); input.setSingleLine(true); input.setText(filename); input.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); alert.setView(input); alert.setPositiveButton("SAVE", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // do nothing here (see below) } }); alert.setNegativeButton("CANCEL", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dialog.cancel(); } }); // don't call alert.show() here -- instead we use the following stuff // which allows us to prevent the alert dialog from closing if the // given file name is invalid final AlertDialog dialog = alert.create(); dialog.show(); dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener( new View.OnClickListener() { public void onClick(View v) { String newname = input.getText().toString(); if (newname.length() == 0) { Toast.makeText(EditActivity.this, "Enter a file name.", Toast.LENGTH_SHORT).show(); input.setText(filename); return; } // check for valid extension if (fileextn.length() > 0 && !newname.endsWith(fileextn)) { Toast.makeText(EditActivity.this, "File extension must be " + fileextn, Toast.LENGTH_SHORT).show(); return; } // check if given file already exists File newfile = new File(dirpath + newname); if (newfile.exists()) { boolean replace = ask("Replace " + newname + "?", "A file with that name already exists. Do you want to replace that file?"); if (!replace) return; } if (!writeFile(newfile, etext.getText().toString())) { return; } // save succeeded textchanged = false; filename = newname; dialog.dismiss(); } }); } // ----------------------------------------------------------------------------- // called when the Cancel button is tapped public void doCancel(View view) { if (textchanged && ask("Save changes?", "Do you want to save the changes you made?")) { doSave(view); } else { // return to previous activity finish(); } } } // EditActivity class golly-2.7-src/gui-android/Golly/src/net/sf/golly/SettingsActivity.java0000644000175000017500000001663112536111364023012 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.NavUtils; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.CheckBox; import android.widget.EditText; import android.widget.PopupMenu; public class SettingsActivity extends BaseActivity { // see jnicalls.cpp for these native routines: private native void nativeOpenSettings(); private native void nativeCloseSettings(); private native int nativeGetPref(String pref); private native void nativeSetPref(String pref, int val); private native String nativeGetPasteMode(); // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.settings_layout); // show the Up button in the action bar getActionBar().setDisplayHomeAsUpEnabled(true); // initialize check boxes, etc initSettings(); nativeOpenSettings(); } // ----------------------------------------------------------------------------- @Override protected void onPause() { super.onPause(); int rval; try { rval = Integer.parseInt(((EditText) findViewById(R.id.randperc)).getText().toString()); } catch (NumberFormatException e) { rval = 50; // 50% is default value for random fill percentage } int mval; try { mval = Integer.parseInt(((EditText) findViewById(R.id.maxmem)).getText().toString()); } catch (NumberFormatException e) { mval = 100; // 100MB is default value for max hash memory } nativeSetPref("rand", rval); nativeSetPref("maxm", mval); nativeCloseSettings(); } // ----------------------------------------------------------------------------- @Override public boolean onCreateOptionsMenu(Menu menu) { // add main.xml items to the action bar getMenuInflater().inflate(R.menu.main, menu); // disable the item for this activity MenuItem item = menu.findItem(R.id.settings); item.setEnabled(false); return true; } // ----------------------------------------------------------------------------- @Override public boolean onOptionsItemSelected(MenuItem item) { // action bar item has been tapped Intent intent; switch (item.getItemId()) { case android.R.id.home: // the Home or Up button will go back to MainActivity NavUtils.navigateUpFromSameTask(this); return true; case R.id.open: finish(); intent = new Intent(this, OpenActivity.class); startActivity(intent); return true; case R.id.settings: // do nothing break; case R.id.help: finish(); intent = new Intent(this, HelpActivity.class); startActivity(intent); return true; } return super.onOptionsItemSelected(item); } // ----------------------------------------------------------------------------- private void initSettings() { ((EditText) findViewById(R.id.randperc)).setText(Integer.toString(nativeGetPref("rand"))); ((EditText) findViewById(R.id.maxmem)).setText(Integer.toString(nativeGetPref("maxm"))); ((CheckBox) findViewById(R.id.checkbox_hash)).setChecked( nativeGetPref("hash") == 1 ); ((CheckBox) findViewById(R.id.checkbox_time)).setChecked( nativeGetPref("time") == 1 ); ((CheckBox) findViewById(R.id.checkbox_beep)).setChecked( nativeGetPref("beep") == 1 ); ((CheckBox) findViewById(R.id.checkbox_swap)).setChecked( nativeGetPref("swap") == 1 ); ((CheckBox) findViewById(R.id.checkbox_icon)).setChecked( nativeGetPref("icon") == 1 ); ((CheckBox) findViewById(R.id.checkbox_undo)).setChecked( nativeGetPref("undo") == 1 ); ((CheckBox) findViewById(R.id.checkbox_grid)).setChecked( nativeGetPref("grid") == 1 ); showPasteMode(); } // ----------------------------------------------------------------------------- public void onCheckboxClicked(View view) { boolean checked = ((CheckBox) view).isChecked(); switch(view.getId()) { case R.id.checkbox_hash: nativeSetPref("hash", checked ? 1 : 0); break; case R.id.checkbox_time: nativeSetPref("time", checked ? 1 : 0); break; case R.id.checkbox_beep: nativeSetPref("beep", checked ? 1 : 0); break; case R.id.checkbox_swap: nativeSetPref("swap", checked ? 1 : 0); break; case R.id.checkbox_icon: nativeSetPref("icon", checked ? 1 : 0); break; case R.id.checkbox_undo: nativeSetPref("undo", checked ? 1 : 0); break; case R.id.checkbox_grid: nativeSetPref("grid", checked ? 1 : 0); break; } } // ----------------------------------------------------------------------------- // called when the pmode button is tapped public void doPasteMode(View view) { // display pop-up menu with these items: AND, COPY, OR, XOR PopupMenu popup = new PopupMenu(this, view); MenuInflater inflater = popup.getMenuInflater(); inflater.inflate(R.menu.pastemode_menu, popup.getMenu()); popup.show(); } // ----------------------------------------------------------------------------- // called when item from pastemode_menu is selected public void doPasteModeItem(MenuItem item) { switch (item.getItemId()) { case R.id.AND: nativeSetPref("pmode", 0); break; case R.id.COPY: nativeSetPref("pmode", 1); break; case R.id.OR: nativeSetPref("pmode", 2); break; case R.id.XOR: nativeSetPref("pmode", 3); break; default: Log.e("Golly","Fix bug in doPasteModeItem!"); return; } showPasteMode(); } // ----------------------------------------------------------------------------- private void showPasteMode() { // show current paste mode in button ((Button) findViewById(R.id.pmode)).setText("Paste mode: " + nativeGetPasteMode()); } } // SettingsActivity class golly-2.7-src/gui-android/Golly/src/net/sf/golly/OpenActivity.java0000644000175000017500000004000012536111364022076 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import java.io.File; import java.util.Arrays; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.support.v4.app.NavUtils; import android.util.DisplayMetrics; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.webkit.WebSettings.LayoutAlgorithm; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; public class OpenActivity extends BaseActivity { // see jnicalls.cpp for these native routines: private native String nativeGetRecentPatterns(); private native String nativeGetSavedPatterns(String paths); private native String nativeGetDownloadedPatterns(String paths); private native String nativeGetSuppliedPatterns(String paths); private native void nativeToggleDir(String path); private enum PATTERNS { SUPPLIED, RECENT, SAVED, DOWNLOADED; } private static PATTERNS currpatterns = PATTERNS.SUPPLIED; // remember scroll positions for each type of patterns private static int supplied_pos = 0; private static int recent_pos = 0; private static int saved_pos = 0; private static int downloaded_pos = 0; private WebView gwebview; // for displaying html data // ----------------------------------------------------------------------------- // this class lets us intercept link taps and restore the scroll position private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView webview, String url) { if (url.startsWith("open:")) { openFile(url.substring(5)); return true; } if (url.startsWith("toggledir:")) { nativeToggleDir(url.substring(10)); saveScrollPosition(); showSuppliedPatterns(); return true; } if (url.startsWith("delete:")) { removeFile(url.substring(7)); return true; } if (url.startsWith("edit:")) { editFile(url.substring(5)); return true; } return false; } @Override public void onPageFinished(WebView webview, String url) { super.onPageFinished(webview, url); // webview.scrollTo doesn't always work here; // we need to delay until webview.getContentHeight() > 0 final int scrollpos = restoreScrollPosition(); if (scrollpos > 0) { final Handler handler = new Handler(); Runnable runnable = new Runnable() { public void run() { if (gwebview.getContentHeight() > 0) { gwebview.scrollTo(0, scrollpos); } else { // try again a bit later handler.postDelayed(this, 100); } } }; handler.postDelayed(runnable, 100); } /* following also works if we setJavaScriptEnabled(true), but is not quite as nice when a folder is closed because the scroll position can change to force the last line to appear at the bottom of the webview int scrollpos = restoreScrollPosition(); if (scrollpos > 0) { final StringBuilder sb = new StringBuilder("javascript:window.scrollTo(0, "); sb.append(scrollpos); sb.append("/ window.devicePixelRatio);"); webview.loadUrl(sb.toString()); } super.onPageFinished(webview, url); */ } } // ----------------------------------------------------------------------------- private void saveScrollPosition() { switch (currpatterns) { case SUPPLIED: supplied_pos = gwebview.getScrollY(); break; case RECENT: recent_pos = gwebview.getScrollY(); break; case SAVED: saved_pos = gwebview.getScrollY(); break; case DOWNLOADED: downloaded_pos = gwebview.getScrollY(); break; } } // ----------------------------------------------------------------------------- private int restoreScrollPosition() { switch (currpatterns) { case SUPPLIED: return supplied_pos; case RECENT: return recent_pos; case SAVED: return saved_pos; case DOWNLOADED: return downloaded_pos; } return 0; // should never get here } // ----------------------------------------------------------------------------- private void openFile(String filepath) { // switch to main screen and open given file Intent intent = new Intent(this, MainActivity.class); intent.putExtra(MainActivity.OPENFILE_MESSAGE, filepath); startActivity(intent); } // ----------------------------------------------------------------------------- private void removeFile(String filepath) { final String fullpath = baseapp.userdir.getAbsolutePath() + "/" + filepath; final File file = new File(fullpath); // ask user if it's okay to delete given file AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle("Delete file?"); alert.setMessage("Do you really want to delete " + file.getName() + "?"); alert.setPositiveButton("DELETE", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (file.delete()) { // file has been deleted so refresh gwebview saveScrollPosition(); switch (currpatterns) { case SUPPLIED: break; // should never happen case RECENT: break; // should never happen case SAVED: showSavedPatterns(); break; case DOWNLOADED: showDownloadedPatterns(); break; } } else { // should never happen Log.e("removeFile", "Failed to delete file: " + fullpath); } } }); alert.setNegativeButton("CANCEL", null); alert.show(); } // ----------------------------------------------------------------------------- private void editFile(String filepath) { // check if filepath is compressed if (filepath.endsWith(".gz") || filepath.endsWith(".zip")) { if (currpatterns == PATTERNS.SUPPLIED) { Toast.makeText(this, "Reading a compressed file is not supported.", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Editing a compressed file is not supported.", Toast.LENGTH_SHORT).show(); } return; } // let user read/edit given file if (currpatterns == PATTERNS.SUPPLIED) { // read contents of supplied file into a string String fullpath = baseapp.supplieddir.getAbsolutePath() + "/" + filepath; // display filecontents Intent intent = new Intent(this, InfoActivity.class); intent.putExtra(InfoActivity.INFO_MESSAGE, fullpath); startActivity(intent); } else { // let user read or edit a saved or downloaded file String fullpath = baseapp.userdir.getAbsolutePath() + "/" + filepath; Intent intent = new Intent(this, EditActivity.class); intent.putExtra(EditActivity.EDITFILE_MESSAGE, fullpath); startActivity(intent); } } // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.open_layout); gwebview = (WebView) findViewById(R.id.webview); gwebview.setWebViewClient(new MyWebViewClient()); // avoid wrapping long lines -- this doesn't work: // gwebview.getSettings().setUseWideViewPort(true); // this is better: gwebview.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); DisplayMetrics metrics = getResources().getDisplayMetrics(); if (metrics.densityDpi > 300) { // use bigger font size for high density screens (default size is 16) gwebview.getSettings().setDefaultFontSize(24); } // no need for JavaScript??? // gwebview.getSettings().setJavaScriptEnabled(true); // allow zooming??? // gwebview.getSettings().setBuiltInZoomControls(true); // show the Up button in the action bar getActionBar().setDisplayHomeAsUpEnabled(true); // note that onResume will do the initial display } // ----------------------------------------------------------------------------- @Override protected void onPause() { super.onPause(); saveScrollPosition(); } // ----------------------------------------------------------------------------- @Override protected void onResume() { super.onResume(); // update gwebview restoreScrollPosition(); switch (currpatterns) { case SUPPLIED: showSuppliedPatterns(); break; case RECENT: showRecentPatterns(); break; case SAVED: showSavedPatterns(); break; case DOWNLOADED: showDownloadedPatterns(); break; } } // ----------------------------------------------------------------------------- @Override public boolean onCreateOptionsMenu(Menu menu) { // add main.xml items to the action bar getMenuInflater().inflate(R.menu.main, menu); // disable the item for this activity MenuItem item = menu.findItem(R.id.open); item.setEnabled(false); return true; } // ----------------------------------------------------------------------------- @Override public boolean onOptionsItemSelected(MenuItem item) { // action bar item has been tapped Intent intent; switch (item.getItemId()) { case android.R.id.home: // the Home or Up button will go back to MainActivity NavUtils.navigateUpFromSameTask(this); return true; case R.id.open: // do nothing break; case R.id.settings: finish(); intent = new Intent(this, SettingsActivity.class); startActivity(intent); return true; case R.id.help: finish(); intent = new Intent(this, HelpActivity.class); startActivity(intent); return true; } return super.onOptionsItemSelected(item); } // ----------------------------------------------------------------------------- // called when the Supplied button is tapped public void doSupplied(View view) { if (currpatterns != PATTERNS.SUPPLIED) { saveScrollPosition(); currpatterns = PATTERNS.SUPPLIED; showSuppliedPatterns(); } } // ----------------------------------------------------------------------------- // called when the Recent button is tapped public void doRecent(View view) { if (currpatterns != PATTERNS.RECENT) { saveScrollPosition(); currpatterns = PATTERNS.RECENT; showRecentPatterns(); } } // ----------------------------------------------------------------------------- // called when the Saved button is tapped public void doSaved(View view) { if (currpatterns != PATTERNS.SAVED) { saveScrollPosition(); currpatterns = PATTERNS.SAVED; showSavedPatterns(); } } // ----------------------------------------------------------------------------- // called when the Downloaded button is tapped public void doDownloaded(View view) { if (currpatterns != PATTERNS.DOWNLOADED) { saveScrollPosition(); currpatterns = PATTERNS.DOWNLOADED; showDownloadedPatterns(); } } // ----------------------------------------------------------------------------- private String enumerateDirectory(File dir, String prefix) { // return the files and/or sub-directories in the given directory // as a string of paths where: // - paths are relative to to the initial directory // - directory paths end with '/' // - each path is terminated by \n String result = ""; File[] files = dir.listFiles(); if (files != null) { Arrays.sort(files); // sort into alphabetical order for (File file : files) { if (file.isDirectory()) { String dirname = prefix + file.getName() + "/"; result += dirname + "\n"; result += enumerateDirectory(file, dirname); } else { result += prefix + file.getName() + "\n"; } } } return result; } // ----------------------------------------------------------------------------- private void showSuppliedPatterns() { String paths = enumerateDirectory(new File(baseapp.supplieddir, "Patterns"), ""); String htmldata = nativeGetSuppliedPatterns(paths); // use a special base URL so that will extract foo.png from the assets folder gwebview.loadDataWithBaseURL("file:///android_asset/", htmldata, "text/html", "utf-8", null); } // ----------------------------------------------------------------------------- private void showRecentPatterns() { String htmldata = nativeGetRecentPatterns(); gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } // ----------------------------------------------------------------------------- private void showSavedPatterns() { String paths = enumerateDirectory(new File(baseapp.userdir, "Saved"), ""); String htmldata = nativeGetSavedPatterns(paths); gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } // ----------------------------------------------------------------------------- private void showDownloadedPatterns() { String paths = enumerateDirectory(new File(baseapp.userdir, "Downloads"), ""); String htmldata = nativeGetDownloadedPatterns(paths); gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } } // OpenActivity class golly-2.7-src/gui-android/Golly/src/net/sf/golly/StateActivity.java0000644000175000017500000000730512536111364022270 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.CheckBox; public class StateActivity extends BaseActivity { // see jnicalls.cpp for these native routines: private native int nativeNumStates(); private native boolean nativeShowIcons(); private native void nativeToggleIcons(); private StateGLSurfaceView stateView; // OpenGL ES is used to draw states // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.state_layout); ((CheckBox) findViewById(R.id.icons)).setChecked( nativeShowIcons() ); // this will call the PatternGLSurfaceView constructor stateView = (StateGLSurfaceView) findViewById(R.id.stateview); stateView.setCallerActivity(this); // avoid this GL surface being darkened like PatternGLSurfaceView (underneath dialog box) stateView.setZOrderOnTop(true); // change dimensions of stateView (initially 321x321) depending on screen density // and number of states in current rule int numstates = nativeNumStates(); DisplayMetrics metrics = getResources().getDisplayMetrics(); if (metrics.densityDpi > 300) { ViewGroup.LayoutParams params = stateView.getLayoutParams(); params.width = 642; if (numstates <= 90) { params.height = ((numstates + 9) / 10) * 64 + 2; } else { params.height = 642; } stateView.setLayoutParams(params); } else if (numstates <= 90) { ViewGroup.LayoutParams params = stateView.getLayoutParams(); params.height = ((numstates + 9) / 10) * 32 + 1; stateView.setLayoutParams(params); } stateView.requestRender(); // display states } // ----------------------------------------------------------------------------- @Override protected void onPause() { super.onPause(); stateView.onPause(); } // ----------------------------------------------------------------------------- @Override protected void onResume() { super.onResume(); stateView.onResume(); } // ----------------------------------------------------------------------------- // called when the "Show icons" check box is tapped public void doToggleIcons(View view) { nativeToggleIcons(); stateView.requestRender(); } } // StateActivity class golly-2.7-src/gui-android/Golly/src/net/sf/golly/HelpActivity.java0000644000175000017500000004422112536111364022076 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v4.app.NavUtils; import android.util.DisplayMetrics; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Button; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.Toast; public class HelpActivity extends BaseActivity { // see jnicalls.cpp for these native routines: private static native void nativeClassInit(); // this MUST be static private native void nativeCreate(); // the rest must NOT be static private native void nativeDestroy(); private native void nativeGetURL(String url, String pageurl); private native void nativeUnzipFile(String zippath); private native boolean nativeDownloadedFile(String url); // local fields: private static boolean firstcall = true; private static Bundle webbundle = null; // for saving/restoring scroll position and page history private boolean restarted = false; // onRestart was called before OnResume? private boolean clearhistory = false; // tell onPageFinished to clear page history? private WebView gwebview; // for displaying html pages private Button backbutton; // go to previous page private Button nextbutton; // go to next page private static String pageurl; // URL for last displayed page private ProgressBar progbar; // progress bar for downloads private LinearLayout proglayout; // view containing progress bar private boolean cancelled; // download was cancelled? public final static String SHOWHELP_MESSAGE = "net.sf.golly.SHOWHELP"; // ----------------------------------------------------------------------------- static { nativeClassInit(); // caches Java method IDs } // ----------------------------------------------------------------------------- // this class lets us intercept link taps private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView webview, String url) { // look for special prefixes used by Golly and return true if found if (url.startsWith("open:")) { openFile(url.substring(5)); return true; } if (url.startsWith("edit:")) { editFile(url.substring(5)); return true; } if (url.startsWith("rule:")) { changeRule(url.substring(5)); return true; } if (url.startsWith("lexpatt:")) { // user tapped on pattern in Life Lexicon loadLexiconPattern(url.substring(8)); return true; } if (url.startsWith("get:")) { // download file specifed in link (possibly relative to a previous full url) nativeGetURL(url.substring(4), pageurl); return true; } if (url.startsWith("unzip:")) { nativeUnzipFile(url.substring(6)); return true; } // no special prefix, so look for file with .zip/rle/lif/mc extension and download it if (nativeDownloadedFile(url)) { return true; } return false; } @Override public void onPageFinished(WebView webview, String url) { super.onPageFinished(webview, url); if (clearhistory) { // this only works after page is loaded gwebview.clearHistory(); clearhistory = false; } backbutton.setEnabled(gwebview.canGoBack()); nextbutton.setEnabled(gwebview.canGoForward()); // need URL of this page for relative "get:" links pageurl = gwebview.getUrl(); // Log.i("URL", pageurl); } } // ----------------------------------------------------------------------------- private void openFile(String filepath) { // switch to main screen and open given file Intent intent = new Intent(this, MainActivity.class); intent.putExtra(MainActivity.OPENFILE_MESSAGE, filepath); startActivity(intent); } // ----------------------------------------------------------------------------- private void editFile(String filepath) { // let user read/edit given file if (filepath.startsWith("Supplied/")) { // read contents of supplied .rule file into a string String prefix = baseapp.supplieddir.getAbsolutePath(); prefix = prefix.substring(0, prefix.length() - 8); // strip off "Supplied" String fullpath = prefix + filepath; // display filecontents Intent intent = new Intent(this, InfoActivity.class); intent.putExtra(InfoActivity.INFO_MESSAGE, fullpath); startActivity(intent); } else { // let user read or edit user's .rule file String fullpath = baseapp.userdir.getAbsolutePath() + "/" + filepath; Intent intent = new Intent(this, EditActivity.class); intent.putExtra(EditActivity.EDITFILE_MESSAGE, fullpath); startActivity(intent); } } // ----------------------------------------------------------------------------- private void changeRule(String rule) { // switch to main screen and change rule Intent intent = new Intent(this, MainActivity.class); intent.putExtra(MainActivity.RULE_MESSAGE, rule); startActivity(intent); } // ----------------------------------------------------------------------------- private void loadLexiconPattern(String pattern) { // switch to main screen and load given lexicon pattern Intent intent = new Intent(this, MainActivity.class); intent.putExtra(MainActivity.LEXICON_MESSAGE, pattern); startActivity(intent); } // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.help_layout); backbutton = (Button) findViewById(R.id.back); nextbutton = (Button) findViewById(R.id.forwards); progbar = (ProgressBar) findViewById(R.id.progress_bar); proglayout = (LinearLayout) findViewById(R.id.progress_layout); proglayout.setVisibility(LinearLayout.INVISIBLE); // show the Up button in the action bar getActionBar().setDisplayHomeAsUpEnabled(true); nativeCreate(); // cache this instance gwebview = (WebView) findViewById(R.id.webview); gwebview.setWebViewClient(new MyWebViewClient()); // JavaScript is used to detect device type gwebview.getSettings().setJavaScriptEnabled(true); DisplayMetrics metrics = getResources().getDisplayMetrics(); // my Nexus 7 has a density of 320 if (metrics.densityDpi > 300) { // use bigger font size for high density screens (default size is 16) gwebview.getSettings().setDefaultFontSize(24); } if (firstcall) { firstcall = false; backbutton.setEnabled(false); nextbutton.setEnabled(false); showContentsPage(); // pageurl has now been initialized } } // ----------------------------------------------------------------------------- @Override protected void onNewIntent(Intent intent) { setIntent(intent); restarted = true; } // ----------------------------------------------------------------------------- @Override protected void onPause() { super.onPause(); gwebview.onPause(); // save scroll position and back/forward history if (webbundle == null) webbundle = new Bundle(); gwebview.saveState(webbundle); } // ----------------------------------------------------------------------------- @Override protected void onResume() { super.onResume(); gwebview.onResume(); // restore scroll position and back/forward history if (webbundle != null && !restarted) { gwebview.restoreState(webbundle); } restarted = false; // check for messages sent by other activities Intent intent = getIntent(); String filepath = intent.getStringExtra(SHOWHELP_MESSAGE); if (filepath != null) { gwebview.loadUrl("file://" + filepath); } else { gwebview.reload(); } } // ----------------------------------------------------------------------------- @Override protected void onRestart() { super.onRestart(); // set flag to prevent onResume calling gwebview.restoreState // causing app to crash for some unknown reason restarted = true; } // ----------------------------------------------------------------------------- @Override protected void onDestroy() { nativeDestroy(); super.onDestroy(); } // ----------------------------------------------------------------------------- @Override public boolean onCreateOptionsMenu(Menu menu) { // add main.xml items to the action bar getMenuInflater().inflate(R.menu.main, menu); // disable the item for this activity MenuItem item = menu.findItem(R.id.help); item.setEnabled(false); return true; } // ----------------------------------------------------------------------------- @Override public boolean onOptionsItemSelected(MenuItem item) { // action bar item has been tapped Intent intent; switch (item.getItemId()) { case android.R.id.home: // the Home or Up button will go back to MainActivity NavUtils.navigateUpFromSameTask(this); return true; case R.id.open: finish(); intent = new Intent(this, OpenActivity.class); startActivity(intent); return true; case R.id.settings: finish(); intent = new Intent(this, SettingsActivity.class); startActivity(intent); return true; case R.id.help: // do nothing break; } return super.onOptionsItemSelected(item); } // ----------------------------------------------------------------------------- private void showContentsPage() { // display html data in supplieddir/Help/index.html String fullpath = baseapp.supplieddir.getAbsolutePath() + "/Help/index.html"; File htmlfile = new File(fullpath); if (htmlfile.exists()) { gwebview.loadUrl("file://" + fullpath); // fullpath starts with "/" } else { // should never happen String htmldata = "

Failed to find index.html!
"; gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } } // ----------------------------------------------------------------------------- // called when the Contents button is tapped public void doContents(View view) { clearhistory = true; // tell onPageFinished to clear page history showContentsPage(); if (webbundle != null) { webbundle.clear(); webbundle = null; } } // ----------------------------------------------------------------------------- // called when backbutton is tapped public void doBack(View view) { gwebview.goBack(); } // ----------------------------------------------------------------------------- // called when nextbutton is tapped public void doForwards(View view) { gwebview.goForward(); } // ----------------------------------------------------------------------------- // called when Cancel is tapped public void doCancel(View view) { cancelled = true; } // ----------------------------------------------------------------------------- private String downloadURL(String urlstring, String filepath) { // download given url and save data in given file try { File outfile = new File(filepath); final int BUFFSIZE = 8192; FileOutputStream outstream = null; try { outstream = new FileOutputStream(outfile); } catch (FileNotFoundException e) { return "File not found: " + filepath; } long starttime = System.nanoTime(); // Log.i("downloadURL: ", urlstring); URL url = new URL(urlstring); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setAllowUserInteraction(false); connection.setInstanceFollowRedirects(true); connection.setRequestMethod("GET"); connection.connect(); if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { outstream.close(); return "No HTTP_OK response."; } // init info for progress bar int filesize = connection.getContentLength(); int downloaded = 0; int percent; int lastpercent = 0; // stream the data to given file InputStream instream = connection.getInputStream(); byte[] buffer = new byte[BUFFSIZE]; int bufflen = 0; while ((bufflen = instream.read(buffer, 0, BUFFSIZE)) > 0) { outstream.write(buffer, 0, bufflen); downloaded += bufflen; percent = (int) ((downloaded / (float)filesize) * 100); if (percent > lastpercent) { progbar.setProgress(percent); lastpercent = percent; } // show proglayout only if download takes more than 1 second if (System.nanoTime() - starttime > 1000000000L) { runOnUiThread(new Runnable() { public void run() { proglayout.setVisibility(LinearLayout.VISIBLE); } }); starttime = Long.MAX_VALUE; // only show it once } if (cancelled) break; } outstream.close(); connection.disconnect(); if (cancelled) return "Cancelled."; } catch (MalformedURLException e) { return "Bad URL string: " + urlstring; } catch (IOException e) { return "Could not connect to URL: " + urlstring; } return ""; // success } // ----------------------------------------------------------------------------- private String dresult; static class LooperInterrupter extends Handler { public void handleMessage(Message msg) { throw new RuntimeException(); } } // this method is called from C++ code (see jnicalls.cpp) private String DownloadFile(String urlstring, String filepath) { // we cannot do network connections on main thread, so we do the // download on a new thread, but we have to wait for it to finish final Handler handler = new LooperInterrupter(); cancelled = false; progbar.setProgress(0); // don't show proglayout immediately // proglayout.setVisibility(LinearLayout.VISIBLE); dresult = ""; final String durl = urlstring; final String dfile = filepath; Thread download_thread = new Thread(new Runnable() { public void run() { dresult = downloadURL(durl, dfile); handler.sendMessage(handler.obtainMessage()); } }); download_thread.setPriority(Thread.MAX_PRIORITY); download_thread.start(); // wait for thread to finish try { Looper.loop(); } catch(RuntimeException re) {} proglayout.setVisibility(LinearLayout.INVISIBLE); if (dresult.length() > 0 && !cancelled) { Toast.makeText(this, "Download failed! " + dresult, Toast.LENGTH_SHORT).show(); } return dresult; } } // HelpActivity class golly-2.7-src/gui-android/Golly/src/net/sf/golly/RuleActivity.java0000644000175000017500000004411612536111364022120 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import java.io.File; import java.util.Arrays; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.DisplayMetrics; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.EditorInfo; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Button; import android.widget.EditText; import android.widget.PopupMenu; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import android.widget.Toast; public class RuleActivity extends BaseActivity { // see jnicalls.cpp for these native routines: private native void nativeSaveCurrentSelection(); private native int nativeGetAlgoIndex(); private native String nativeGetAlgoName(int algoindex); private native String nativeGetRule(); private native String nativeCheckRule(String rule, int algoindex); private native int nativeCheckAlgo(String rule, int algoindex); private native void nativeSetRule(String rule, int algoindex); // local fields: private static boolean firstcall = true; private static int algoindex = 0; // index of currently displayed algorithm private static int numalgos; // number of algorithms private static int[] scroll_pos; // remember scroll position for each algo private Button algobutton; // for changing current algorithm private EditText ruletext; // for changing current rule private WebView gwebview; // for displaying html data private String bad_rule = "Given rule is not valid in any algorithm."; // ----------------------------------------------------------------------------- // this class lets us intercept link taps and restore the scroll position private class MyWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView webview, String url) { if (url.startsWith("open:")) { openFile(url.substring(5)); return true; } if (url.startsWith("delete:")) { removeFile(url.substring(7)); return true; } if (url.startsWith("edit:")) { editFile(url.substring(5)); return true; } if (url.startsWith("rule:")) { // copy specified rule into ruletext ruletext.setText(url.substring(5)); ruletext.setSelection(ruletext.getText().length()); checkAlgo(); return true; } return false; } @Override public void onPageFinished(WebView webview, String url) { super.onPageFinished(webview, url); // webview.scrollTo doesn't always work here; // we need to delay until webview.getContentHeight() > 0 final int scrollpos = restoreScrollPosition(); if (scrollpos > 0) { final Handler handler = new Handler(); Runnable runnable = new Runnable() { public void run() { if (gwebview.getContentHeight() > 0) { gwebview.scrollTo(0, scrollpos); } else { // try again a bit later handler.postDelayed(this, 100); } } }; handler.postDelayed(runnable, 100); } } } // ----------------------------------------------------------------------------- private void saveScrollPosition() { scroll_pos[algoindex] = gwebview.getScrollY(); } // ----------------------------------------------------------------------------- private int restoreScrollPosition() { return scroll_pos[algoindex]; } // ----------------------------------------------------------------------------- private void openFile(String filepath) { // switch to main screen and open given file Intent intent = new Intent(this, MainActivity.class); intent.putExtra(MainActivity.OPENFILE_MESSAGE, filepath); startActivity(intent); } // ----------------------------------------------------------------------------- private void removeFile(String filepath) { final String fullpath = baseapp.userdir.getAbsolutePath() + "/" + filepath; final File file = new File(fullpath); // ask user if it's okay to delete given file AlertDialog.Builder alert = new AlertDialog.Builder(this); alert.setTitle("Delete file?"); alert.setMessage("Do you really want to delete " + file.getName() + "?"); alert.setPositiveButton("DELETE", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (file.delete()) { // file has been deleted so refresh gwebview saveScrollPosition(); showAlgoHelp(); } else { // should never happen Log.e("removeFile", "Failed to delete file: " + fullpath); } } }); alert.setNegativeButton("CANCEL", null); alert.show(); } // ----------------------------------------------------------------------------- private void editFile(String filepath) { // let user read/edit given file if (filepath.startsWith("Supplied/")) { // read contents of supplied .rule file into a string String prefix = baseapp.supplieddir.getAbsolutePath(); prefix = prefix.substring(0, prefix.length() - 8); // strip off "Supplied" String fullpath = prefix + filepath; // display filecontents Intent intent = new Intent(this, InfoActivity.class); intent.putExtra(InfoActivity.INFO_MESSAGE, fullpath); startActivity(intent); } else { // let user read or edit user's .rule file String fullpath = baseapp.userdir.getAbsolutePath() + "/" + filepath; Intent intent = new Intent(this, EditActivity.class); intent.putExtra(EditActivity.EDITFILE_MESSAGE, fullpath); startActivity(intent); } } // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rule_layout); algobutton = (Button) findViewById(R.id.algo); ruletext = (EditText) findViewById(R.id.rule); gwebview = (WebView) findViewById(R.id.webview); gwebview.setWebViewClient(new MyWebViewClient()); // no need for JavaScript??? // gwebview.getSettings().setJavaScriptEnabled(true); DisplayMetrics metrics = getResources().getDisplayMetrics(); // my Nexus 7 has a density of 320 if (metrics.densityDpi > 300) { // use bigger font size for high density screens (default size is 16) gwebview.getSettings().setDefaultFontSize(24); } getActionBar().hide(); if (firstcall) { firstcall = false; initAlgoInfo(); } algoindex = nativeGetAlgoIndex(); algobutton.setText(nativeGetAlgoName(algoindex)); // onResume will call showAlgoHelp ruletext.setText(nativeGetRule()); ruletext.setSelection(ruletext.getText().length()); // put cursor at end of rule // following listener allows us to detect when user is closing the soft keyboard // (it assumes rule_layout.xml sets android:imeOptions="actionDone") ruletext.setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE) { checkAlgo(); } return false; } }); // selection might change if grid becomes smaller, so save current selection // in case RememberRuleChange/RememberAlgoChange is called later nativeSaveCurrentSelection(); } // ----------------------------------------------------------------------------- @Override protected void onPause() { super.onPause(); saveScrollPosition(); } // ----------------------------------------------------------------------------- @Override protected void onResume() { super.onResume(); restoreScrollPosition(); showAlgoHelp(); } // ----------------------------------------------------------------------------- private void initAlgoInfo() { // initialize number of algorithms and scroll positions numalgos = 0; while (true) { String algoname = nativeGetAlgoName(numalgos); if (algoname.length() == 0) break; numalgos++; } scroll_pos = new int[numalgos]; for (int i = 0; i < numalgos; i++) { scroll_pos[i] = 0; } } // ----------------------------------------------------------------------------- private String createRuleLinks(File dir, String prefix, String title, boolean candelete) { String htmldata = "

" + title + "

"; int rulecount = 0; File[] files = dir.listFiles(); if (files != null) { Arrays.sort(files); // sort into alphabetical order for (File file : files) { if (file.isDirectory()) { // ignore directory } else { String filename = file.getName(); if (filename.endsWith(".rule")) { if (candelete) { // allow user to delete .rule file htmldata += "DELETE   "; // allow user to edit .rule file htmldata += "EDIT   "; } else { // allow user to read supplied .rule file htmldata += "READ   "; } // use "open:" link rather than "rule:" link htmldata += ""; htmldata += filename.substring(0, filename.length() - 5); // strip off .rule htmldata += "
"; rulecount++; } } } } if (rulecount == 0) htmldata += "None."; return htmldata; } // ----------------------------------------------------------------------------- private void showAlgoHelp() { String algoname = nativeGetAlgoName(algoindex); if (algoname.equals("RuleLoader")) { // create html data with links to the user's .rule files and the supplied .rule files File userrules = new File(baseapp.userdir, "Rules"); File rulesdir = new File(baseapp.supplieddir, "Rules"); String htmldata = ""; htmldata += ""; htmldata += "

The RuleLoader algorithm allows CA rules to be specified in .rule files."; htmldata += " Given the rule string \"Foo\", RuleLoader will search for a file called Foo.rule"; htmldata += " in your rules folder, then in the rules folder supplied with Golly."; htmldata += "

"; htmldata += createRuleLinks(userrules, "Rules/", "Your .rule files:", true); htmldata += createRuleLinks(rulesdir, "Supplied/Rules/", "Supplied .rule files:", false); // note that we use a prefix starting with "Supplied/" so editFile can distinguish // between a user rule and a supplied rule htmldata += ""; gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } else { // display html data in supplieddir/Help/Algorithms/algoname.html String fullpath = baseapp.supplieddir.getAbsolutePath() + "/Help/Algorithms/" + algoname + ".html"; File htmlfile = new File(fullpath); if (htmlfile.exists()) { gwebview.loadUrl("file://" + fullpath); // fullpath starts with "/" } else { // should never happen String htmldata = "
Failed to find html file!
"; gwebview.loadDataWithBaseURL(null, htmldata, "text/html", "utf-8", null); } } } // ----------------------------------------------------------------------------- // called when algobutton is tapped public void doAlgo(View view) { // display pop-up menu with algorithm names PopupMenu popup = new PopupMenu(this, view); for (int id = 0; id < numalgos; id++) { String algoname = nativeGetAlgoName(id); popup.getMenu().add(Menu.NONE, id, Menu.NONE, algoname); } popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { int id = item.getItemId(); String algoname = nativeGetAlgoName(id); if (id != algoindex && algoname.length() > 0) { // change algorithm saveScrollPosition(); algoindex = id; algobutton.setText(algoname); showAlgoHelp(); // rule needs to change if it isn't valid in new algo String currentrule = ruletext.getText().toString(); String newrule = nativeCheckRule(currentrule, algoindex); if (!newrule.equals(currentrule)) { ruletext.setText(newrule); ruletext.setSelection(ruletext.getText().length()); } } return true; } }); popup.show(); } // ----------------------------------------------------------------------------- private void checkAlgo() { // check displayed rule and show message if it's not valid in any algo, // or if the rule is valid then displayed algo might need to change String rule = ruletext.getText().toString(); if (rule.length() == 0) { // change empty rule to Life rule = "B3/S23"; ruletext.setText(rule); ruletext.setSelection(ruletext.getText().length()); } int newalgo = nativeCheckAlgo(rule, algoindex); if (newalgo == -1) { Toast.makeText(this, bad_rule, Toast.LENGTH_LONG).show(); } else if (newalgo != algoindex) { // change algorithm saveScrollPosition(); algoindex = newalgo; algobutton.setText(nativeGetAlgoName(algoindex)); showAlgoHelp(); } } // ----------------------------------------------------------------------------- // called when the Done button is tapped (not the soft keyboard's Done button) public void doDone(View view) { String rule = ruletext.getText().toString(); // no need to check for empty rule here int newalgo = nativeCheckAlgo(rule, algoindex); if (newalgo == -1) { Toast.makeText(this, bad_rule, Toast.LENGTH_LONG).show(); } else { // dismiss dialog first in case ChangeAlgorithm calls BeginProgress finish(); nativeSetRule(rule, newalgo); } } // ----------------------------------------------------------------------------- // called when the Cancel button is tapped public void doCancel(View view) { finish(); } } // RuleActivity class golly-2.7-src/gui-android/Golly/src/net/sf/golly/PatternGLSurfaceView.java0000644000175000017500000002377512536111364023510 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.content.Context; import android.graphics.PixelFormat; import android.opengl.GLSurfaceView; import android.util.AttributeSet; // import android.util.Log; import android.view.MotionEvent; import android.view.ScaleGestureDetector; // this class must be public so it can be used in main_layout.xml public class PatternGLSurfaceView extends GLSurfaceView { // see jnicalls.cpp for these native routines: private native void nativeTouchBegan(int x, int y); private native void nativeTouchMoved(int x, int y); private native void nativeTouchEnded(); private native void nativeMoveMode(); private native void nativeRestoreMode(); private native void nativeZoomIn(int x, int y); private native void nativeZoomOut(int x, int y); private native void nativePause(); private native void nativeResume(); private static final int INVALID_POINTER_ID = -1; private int mActivePointerId = INVALID_POINTER_ID; private int beginx, beginy; private boolean callTouchBegan = false; // nativeTouchBegan needs to be called? private boolean multifinger = false; // are we doing multi-finger panning or zooming? private boolean zooming = false; // are we zooming? private int pancount = 0; // prevents panning changing to zooming // ----------------------------------------------------------------------------- // this stuff handles zooming in/out via two-finger pinch gestures private ScaleGestureDetector zoomDetector; private class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener { private float oldscale, newscale; private int zoomx, zoomy; @Override public boolean onScaleBegin(ScaleGestureDetector detector) { zooming = true; oldscale = 1.0f; newscale = 1.0f; // set zoom point at start of pinch zoomx = (int)detector.getFocusX(); zoomy = (int)detector.getFocusY(); // Log.i("onScaleBegin", "zoomx=" + Integer.toString(zoomx) + " zoomy=" + Integer.toString(zoomy)); return true; } @Override public boolean onScale(ScaleGestureDetector detector) { newscale *= detector.getScaleFactor(); // Log.i("onScale", "newscale=" + Float.toString(newscale) + " oldscale=" + Float.toString(oldscale)); if (newscale - oldscale < -0.1f) { // fingers moved closer, so zoom out nativeZoomOut(zoomx, zoomy); oldscale = newscale; } else if (newscale - oldscale > 0.1f) { // fingers moved apart, so zoom in nativeZoomIn(zoomx, zoomy); oldscale = newscale; } return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { // Log.i("onScaleEnd", "---"); oldscale = 1.0f; newscale = 1.0f; // don't reset zooming flag here } } // ----------------------------------------------------------------------------- public PatternGLSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); super.setEGLConfigChooser(8, 8, 8, 8, 0/*no depth*/, 0); getHolder().setFormat(PixelFormat.RGBA_8888); // avoid crash on some devices setRenderer(new PatternRenderer()); setRenderMode(RENDERMODE_WHEN_DIRTY); zoomDetector = new ScaleGestureDetector(context, new ScaleListener()); } // ----------------------------------------------------------------------------- public boolean onTouchEvent(final MotionEvent ev) { if (pancount < 4) { // check for zooming zoomDetector.onTouchEvent(ev); if (zoomDetector.isInProgress()) return true; } final int action = ev.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { // Log.i("onTouchEvent", "ACTION_DOWN"); mActivePointerId = ev.getPointerId(0); beginx = (int)ev.getX(); beginy = (int)ev.getY(); callTouchBegan = true; break; } case MotionEvent.ACTION_MOVE: { // we need to test zooming flag because it's possible to get // ACTION_MOVE after ACTION_POINTER_UP (and after onScaleEnd) if (mActivePointerId != INVALID_POINTER_ID && !zooming) { int pointerIndex = ev.findPointerIndex(mActivePointerId); int x = (int)ev.getX(pointerIndex); int y = (int)ev.getY(pointerIndex); if (callTouchBegan) { nativeTouchBegan(beginx, beginy); callTouchBegan = false; } if (multifinger && ev.getPointerCount() == 1) { // there is only one pointer down so best not to move } else { nativeTouchMoved(x, y); } if (multifinger) { pancount++; } // Log.i("onTouchEvent", "ACTION_MOVE" + " deltax=" + Integer.toString(x - beginx) + // " deltay=" + Integer.toString(y - beginy)); } break; } case MotionEvent.ACTION_UP: { // Log.i("onTouchEvent", "ACTION_UP"); mActivePointerId = INVALID_POINTER_ID; if (callTouchBegan) { nativeTouchBegan(beginx, beginy); callTouchBegan = false; } nativeTouchEnded(); if (multifinger) { nativeRestoreMode(); multifinger = false; } pancount = 0; zooming = false; break; } case MotionEvent.ACTION_CANCEL: { // Log.i("onTouchEvent", "ACTION_CANCEL"); mActivePointerId = INVALID_POINTER_ID; if (callTouchBegan) { nativeTouchBegan(beginx, beginy); callTouchBegan = false; } nativeTouchEnded(); if (multifinger) { nativeRestoreMode(); multifinger = false; } pancount = 0; zooming = false; break; } case MotionEvent.ACTION_POINTER_DOWN: { // Log.i("onTouchEvent", "ACTION_POINTER_DOWN"); // another pointer has gone down if (callTouchBegan) { // ACTION_DOWN has been seen but no ACTION_MOVE as yet, // so switch to panning mode (which might become zooming) nativeMoveMode(); multifinger = true; } break; } case MotionEvent.ACTION_POINTER_UP: { // Log.i("onTouchEvent", "ACTION_POINTER_UP"); // a pointer has gone up (but another pointer is still down) final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; final int pointerId = ev.getPointerId(pointerIndex); if (pointerId == mActivePointerId) { // this was our active pointer going up so choose a new active pointer final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mActivePointerId = ev.getPointerId(newPointerIndex); } break; } } return true; } // ----------------------------------------------------------------------------- @Override public void onPause() { super.onPause(); nativePause(); } // ----------------------------------------------------------------------------- @Override public void onResume() { super.onResume(); nativeResume(); } } // PatternGLSurfaceView class // ================================================================================= class PatternRenderer implements GLSurfaceView.Renderer { // see jnicalls.cpp for these native routines: private native void nativeInit(); private native void nativeResize(int w, int h); private native void nativeRender(); // ----------------------------------------------------------------------------- public void onSurfaceCreated(GL10 gl, EGLConfig config) { nativeInit(); } // ----------------------------------------------------------------------------- public void onSurfaceChanged(GL10 gl, int w, int h) { nativeResize(w, h); } // ----------------------------------------------------------------------------- public void onDrawFrame(GL10 gl) { nativeRender(); } } // PatternRenderer class golly-2.7-src/gui-android/Golly/src/net/sf/golly/StateGLSurfaceView.java0000644000175000017500000001332512536111364023141 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.app.Activity; import android.content.Context; import android.graphics.PixelFormat; import android.opengl.GLSurfaceView; import android.util.AttributeSet; import android.view.MotionEvent; //this class must be public so it can be used in state_layout.xml public class StateGLSurfaceView extends GLSurfaceView { // see jnicalls.cpp for these native routines: private native void nativeTouchBegan(int x, int y); private native boolean nativeTouchMoved(int x, int y); private native boolean nativeTouchEnded(); private static final int INVALID_POINTER_ID = -1; private int mActivePointerId = INVALID_POINTER_ID; private Activity caller; // ----------------------------------------------------------------------------- public StateGLSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); super.setEGLConfigChooser(8, 8, 8, 8, 0/*no depth*/, 0); getHolder().setFormat(PixelFormat.RGBA_8888); // avoid crash on some devices setRenderer(new StateRenderer()); setRenderMode(RENDERMODE_WHEN_DIRTY); } // ----------------------------------------------------------------------------- public void setCallerActivity(Activity activity) { // set caller so we can finish StateActivity caller = activity; } // ----------------------------------------------------------------------------- public boolean onTouchEvent(final MotionEvent ev) { final int action = ev.getAction(); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { mActivePointerId = ev.getPointerId(0); final float x = ev.getX(); final float y = ev.getY(); nativeTouchBegan((int)x, (int)y); break; } case MotionEvent.ACTION_MOVE: { if (mActivePointerId != INVALID_POINTER_ID) { final int pointerIndex = ev.findPointerIndex(mActivePointerId); final float x = ev.getX(pointerIndex); final float y = ev.getY(pointerIndex); if (nativeTouchMoved((int)x, (int)y)) { // states have scrolled requestRender(); } } break; } case MotionEvent.ACTION_UP: { mActivePointerId = INVALID_POINTER_ID; if (nativeTouchEnded()) { // user touched a state box so close dialog caller.finish(); } break; } case MotionEvent.ACTION_CANCEL: { mActivePointerId = INVALID_POINTER_ID; nativeTouchEnded(); break; } case MotionEvent.ACTION_POINTER_UP: { // secondary pointer has gone up final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; final int pointerId = ev.getPointerId(pointerIndex); if (pointerId == mActivePointerId) { // this was our active pointer going up so choose a new active pointer final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mActivePointerId = ev.getPointerId(newPointerIndex); final float x = ev.getX(newPointerIndex); final float y = ev.getY(newPointerIndex); if (nativeTouchMoved((int)x, (int)y)) { // states have scrolled requestRender(); } } break; } } return true; } } // StateGLSurfaceView class //================================================================================= class StateRenderer implements GLSurfaceView.Renderer { // see jnicalls.cpp for these native routines: private native void nativeInit(); private native void nativeResize(int w, int h); private native void nativeRender(); // ----------------------------------------------------------------------------- public void onSurfaceCreated(GL10 gl, EGLConfig config) { nativeInit(); } // ----------------------------------------------------------------------------- public void onSurfaceChanged(GL10 gl, int w, int h) { nativeResize(w, h); } // ----------------------------------------------------------------------------- public void onDrawFrame(GL10 gl) { nativeRender(); } } // StateRenderer class golly-2.7-src/gui-android/Golly/src/net/sf/golly/BaseActivity.java0000644000175000017500000000407512536111364022063 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import android.app.Activity; import android.os.Bundle; //this class (along with BaseApp) allows our app to keep track of the current foreground activity //(thanks to http://stackoverflow.com/questions/11411395/how-to-get-current-foreground-activity-context-in-android) public abstract class BaseActivity extends Activity { protected BaseApp baseapp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); baseapp = (BaseApp) this.getApplicationContext(); baseapp.setCurrentActivity(this); } @Override protected void onResume() { super.onResume(); baseapp.setCurrentActivity(this); } @Override protected void onPause() { clearReferences(); super.onPause(); } @Override protected void onDestroy() { clearReferences(); super.onDestroy(); } private void clearReferences() { Activity curractivity = baseapp.getCurrentActivity(); if (curractivity != null && curractivity.equals(this)) baseapp.setCurrentActivity(null); } } // BaseActivity class golly-2.7-src/gui-android/Golly/src/net/sf/golly/InfoActivity.java0000644000175000017500000000755212536111364022107 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ package net.sf.golly; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import android.content.Intent; import android.os.Bundle; import android.text.method.ScrollingMovementMethod; import android.util.DisplayMetrics; import android.view.View; import android.widget.TextView; public class InfoActivity extends BaseActivity { private native String nativeGetInfo(); // the rest must NOT be static public final static String INFO_MESSAGE = "net.sf.golly.INFO"; // ----------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.info_layout); getActionBar().hide(); String text = null; // get info sent by other activity Intent intent = getIntent(); String infoMsg = intent.getStringExtra(INFO_MESSAGE); if (infoMsg != null) { if (infoMsg.equals("native")) { text = nativeGetInfo(); } else { // read contents of supplied file into a string File file = new File(infoMsg); try { FileInputStream instream = new FileInputStream(file); BufferedReader reader = new BufferedReader(new InputStreamReader(instream)); StringBuilder sb = new StringBuilder(); String line = null; while ((line = reader.readLine()) != null) { sb.append(line); sb.append("\n"); } text = sb.toString(); instream.close(); } catch (Exception e) { text = "Error reading file:\n" + e.toString(); } } } if (text != null) { TextView tv = (TextView) findViewById(R.id.info_text); tv.setMovementMethod(new ScrollingMovementMethod()); // above call enables vertical scrolling; // next call prevents long lines wrapping and enables horizontal scrolling tv.setHorizontallyScrolling(true); tv.setTextIsSelectable(true); tv.setText(text); DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); float dpWidth = displayMetrics.widthPixels / displayMetrics.density; if (dpWidth >= 600) { // use bigger font size for wide screens (layout size is 10sp) tv.setTextSize(12); } } } // ----------------------------------------------------------------------------- // called when the Cancel button is tapped public void doCancel(View view) { // return to previous activity finish(); } } // InfoActivity class golly-2.7-src/gui-android/Golly/ic_launcher-web.png0000755000175000017500000012757412536111364017270 00000000000000‰PNG  IHDRôxÔú IDATx^ì½ p\åy>þìÙ]­Vë†,É–u±m0NŒ$ü`(ÅIJZ˜I‚Í0%ù‡ 4$iBgZÁ@gH¡SÒé¤!tÒÔÉ4í¦Ì¤iL6 M|bG6ØlK¶dK–lɺíýÿ¼ßÙÅ+Y².{‘?é=Ì"i}ÎwÞóœ÷=ïs¾ï½x ›" (Š€" ,8< îŠõ‚E@PEJT E@Pˆ€€xÓõ’E@P%ªŠ€" (ŠÀD@ À¼ézÉŠ€" (Š€ÕE@PE`" `Þt½dE@PE@ €ê€" (Š€"°P°oº^²" (Š€" @u@PE@X€(X€7]/YPE@P : (Š€" ,@”,À›®—¬(Š€" (PPE@P JàM×KVE@P”¨(Š€" ( % ð¦ë%+Š€" (JTE@Pˆ€€xÓõ’E@P%ªŠ€" (ŠÀD@ À¼ézÉŠ€" (Š€ÕE@PE`" `Þt½dE@PE@ €ê€" (Š€"°P°oº^²" (Š€" @u@PE@X€(X€7]/YPE@˜K0þÜs)‹j‚" (Š€"/ãN4þï¼È1N7uÎÉ~Ê…Ï…\y\O¢(Š€"° Hwò©ß'û™€òíhå|éŽ_~w’Wšú9žä=‰" (Š€"#Æ;úxò<òSþ-ýßó6OîüÅÙ§œ¿üžþ·à’"9º:¬" (Š€"WRŽ>åôågê#ÿ–"é„ §ÎH9|ùéÝ·÷ÿ,//DI‰……>ø|<ù”*§ðêàŠ€" (Š_ñéÖ£Ñ8FG£ŒàÌ™Q¬YûãbK#ãgr ]¾\mêí?õÖïçÏàŒ€œÞc\PE`Ž˜„”S¬h’¤ˆ@j çKù&æ­_òã'èQ0Çš©§WE@È)“€jž4’$)"·Y€|€”óàO~ H:•äTïtpE@P9F`°„b…“$@ˆ€Ì¤ÏäTê¹ :^Y! ÀQ%9½Ç:¸" (ŠÀ#0 h¤X£€Ô,@N¥ÎHþ¥¦þ Äù°çï——ûèe —A€ Ìé-×ÁE@Pò€K Œ10Æ À(Ö\ùÛ–$H‘YO*; §bÎçŸ"E$”äôëàŠ€" (sŒÀ$`%ÅN›å€yKdú_œ 9 à%s¬™zzE@Pœ"0 X•FBü=0ïfRÑÿ©·ÿ /¶˜ M @NõNWE@˜c&!—S¬!~Fø Ÿôl€œJÏ%€Tôÿxð{%9½Ç:¸" (ŠÀ#0 ¸"¤¦2r*õ\€¢ä À^%9½Ç:¸" (ŠÀ#0 X›$éq©tÀTiàœI® gÐêÀŠ€" (Š€‹€·Ð‡: ¦¡(Š€"°P `!è¹^£" (ŠÀ8”(P£PE@X€(P°Õ^/YPE@ €µE@Pˆ€% Píõ’E@P”(P+PE@X€(P°Õ^/YPE@ €µE@Pˆ€% Píõ’E@P”(P+PE@X€(P°Õ^/YPE@ €µE@Pˆ€% Píõ’E@P”(P+PE@X€(P°Õ^/YPE@ €µE@Pˆ€% Píõ’E@P”(P+PE@X€(P°Õ^/YPE@ €µE@Pˆ€% Píõ’E@P”(P+PE@X€(X ‘ð s';ÎÍãñÀë?ñ‹FíUÎìÞ Åsaâ™Ý«ÎÝhªŸ¹Ãvº#+˜§`tÔÞ^úNûqút!Þ=XŽ“] ž¤÷¡¼b–/w°¬±¥¥^T”ÇP]=Jbà„|m*gv‘V<&žÙ½êܦú™;lg3²€yF:»‚Ø·¿m¿/ÂÎ7JÐÖ¶ÃC#(* P€ãó€ó&0ÐB$\ÚàÁkúñ7¶£uy «W…PT4:}šö1*ç´¡šÖŽŠç´`šöN¶à9í šãmÁÓ9³u;•ÌÐÛ[Šíÿ[Œ_*ÅŽµÐÒÔJÇ^æåŨk(BI¥…A/—<H çÄ:Ž`ÿ¾n¼³¿§û{ÑÐЉØOjëÖ ¡ `$[ºfÆQ9OÕϬšÔE=˜Ú{ví=Û7[ €å óñ-¿[\„—_®E<± K«qó'›±áê*,YâEi±ƒ€¿8ð82ÅcL@œƒ³ ôõ…ñΡlÛ~{vAß)×M›Ï`ÓíݨªÊ\‰UNÅSõ3s;ʶÈÕxjïÙµ÷\Ý'%€X̃W^-Ã_?Þ„“DZ¸zÖ^QŒOß²Í+‹, 3È/‚D\\îò¾üɵþi€F£ ˆbûö“øõ¶NtuáìàÛ¸ycÝruu³x©œŠ§êgæv”+'íqÕÞ³kïÙ¾?éã)°˜üÇÏ[ðµo$P¼—¡¹¥·~¦ K/-B¡ÃöŒÐÝÇx¿î÷%þùA~àã.ᨇŸ¼öê~ºÐ×Û‹öŽ7¸ІgŸíEIñìUNÅSõ3s;Ê¥#ÈæØjïÙµ÷lÞ›ñc)°Ã~þçKq×]aÔÕÜ‚ÖÖµ(«êÇÆÏÔcesßé#ðúˆÅCæí :ù0úß»ÉRèü Op‚8ëÇöÿiÇÞßõ`¨?Œ÷>xµõƒxã·o¡¤dú$@åTöñ ®¾®_\Vú鿣p*$§ÿ!ôî2õo>çS'Q€„'ÇA(êGç1Û_êDwg!¡ù®¹öwøÉÖaÔÖ„¦ÔM•SñTýÌÜŽ¦4´‹dµ÷ìÚ{¾n«ËÀo_¯Á7ÿ¢Ç:Z¸æ%|>?ªGpÃu þ“}æõÙÈŒó" oï¿Á{~îÂca©„ÑÑ ¼þýØó¦8û ‡Ž¢»÷ר|Ç <þX/**†.¨£*§â©ú™¹åËdzµ÷ìÚ{¦÷cºÇ+°ˆtwñÀCõø¯šPY¾ž~eœêBã²8nº±%E øã›¿Tûc¦_Ò×› þIÿ9E1á€üÙ\*ˆAj„°{熆ݙƒÁ8Þ]Øòð0þôÎãðûI&ØTNoÅSõ3;šîC|®÷S{Ï®½çó~*°ˆüìÙ*lÙÒ„‘è*æç7ÐÑ/‚Ÿ µ5ŽO\[ÏéÿqüâzÒ{zÔ¿;0~Â'^'î'ˆ#æñáðÑvîêAßÀ—Šápi`p`®Ú°ß}êV®dUÁ 6•SñTýÌÜŽòé29—Ú{ví=“{1Óc•XBÚ; ðà·kðâ ë,]Æ©ú µÑû!47pÕU5(,5õþ% `,HMû‹óŸˆÈÞò½¤rA~K¡óxoïîÄ bžGu ÷Ãñ´á‘-ûqï½§ÎÓ7•3‰â©ú9{;šéƒ|®öW{Ï®½çû>*°„¼øÒ"Ü{ß Nǯ†×_nÖõ¾î;žQåùñÑõKXåOÖïe ŒW© H€ `  eS9n"^ŠŽÃ!´í=‰p¤KÈ–B9H¸7ßü{üí“]h\:v@å,OÕÏÌì(ߎ`¶çS{Ï®½Ïö>Ìö8%€þþ"<ùT#¾÷½R®ù¯¡3v‹úðpê¾²ÂÁêÕ‹QVÁïèûMêßD›™˜øßâ’È©x†@Déôß;xGÞ?ƒh,Às²ROꉓD{±¸¦?xú=|r£Ì¸3 *ç9ÐOÕÏÙÚÑlæù>Ní=»öžïû'çS`ho÷ák^‹W¶­â;ø¥Éð2>^øZ.ëõ>KËù©ä’@Œ7UòýÅÕO6ݾª%H¤`ܤ zY0CN¢÷T˜ßK„+‰™Õ–8aþ~ßy¼÷ýÙ ƒnZ ÊyWÅSõs¶v4Ž`6çT{Ï®½ÏædzŒ€‹œÈtü®Ý—àÖ[›ÐÛWÇ)ú*NÏ»‘þž„Lõó'gŠJ¼hj®CE™äüóm]^ÊÏóÿ“ñ‘·Çñš‚PăÎÎ^œèàß:}. 8B¢<'cÌàGqÛmø‡ïD}ýY6P9ÓЧêçÌí(Óz¾ŽW{‹t¦ÏÏ|Ý·ñçQp‘€X̋瞻 wß]Œh¢…ïçtî|Ã7¯ãn~¿4øqø)]DMuÁBÆp —”¾t0Q ¤J˜ý|<Æ‹S§Î¢çÔbQ!|û7Å„B$Ì@!Ç–óvaùŠžv'ÛŸas!•sŒq)žªŸ³°£¹r3=¯Úû8Ä2´÷™âŸ­ý•\ä rðä“Mxâ‰zúáfSÙœà+¹yÀÊT³ã¸ }ž‡¢Â0ÊH‚Á ßÞ™Às·É‹™!É ¢ÑCìçïO½ÄH‘ 0ÃÀáT?+zø½ãô¡¬¬ /¿´aÛ`•s¬I*žªŸ³±£l=Øs=ŽÚ{ví=×÷k²ñ•\ä`tÔƒªÆÓß_誇o"7Ìl~*Úß„è»ßs9ÀïuX'ÀÇ€A‹õÈ>©îãf¤`9ŒM€FØ=¢QFp·sµ’³`T³4â GçÏÓ¬Bø>žûY|KÂá¸Ê©xª~fhGŽãÆï\ì›>—Üçm¶žŸsuß•X@þê*<óÌ•tî­ÌÏç;¶ÔÏø‡…p3+`&ɤ ˜eƒô%¾å'âîh î33 F©ÇÇ ø9û ÝG¹O Iz¹ð¶nõàŽÛßD$ƒÊ©xª~ffG^/g÷,Ø„¨½gÏÞçê¾+°|«Ïü` —ñ]¾0éÔ'©éÏu|÷_ÄñË€øüä[…L图îf– Äá›™Sþ'9¹à–±Mîe ÅM@˜_ñ/YèáØðÏ?ŒâÎ;öpæ€@åT%3q•óµJi*žªŸ©y´éÙ‘Ãjœ6lú\J¿KR~5³çç\Ýw%9ˆ³òÞ /6às·×RÉ60@O®Ó_0u€“oû)M:!óC–&ÊH'ãÙ|påf™`„2Ða! ªšð‹ç»°a}· $T9Ó1¿ÀAñLS2ÕÏt;’b\6lú\GÆÍ®ž{Lïù9W÷] ÀEND‘öì-Á-ò1ôt·2ß¾Ö”êýpK/ï›\ÇO²€´7úäþç¦+ñ$K fNA?i‡‰ð³%ðY’€½Xµö žû×6¬\>`R9OÕÏÌíÈ ö>þ.Ùyß•X@:ŽùñõûðÂ/×Ò·¯3Ýþ$çßíüÃJ}tÊ2IÛ'ŸÞ hlÔÿäÝ'W`&Òù˼˳0ãœâúÿ|îóaüÝPWë•sz@ñTý¼ÙBÔÞ³kïsqß•X@FFýxæ‡5l¼±ÈµL\d¦äÝõ|)ý›$pùŒ%™©•¼ûK@á © h2 ÚQ\´?ÇWîy%Ńæ$*çÔX+žªŸSÙÑÔZtqì¡ö>õ}˜‰½O=Zö÷P`Ûþ«WªpÏW.GgÇŒh¦¦ã`Rü&,üŸm‘U7“€™²à rý?Z[៞>Œ®—n€ç6•ó°+žYQË™¯xf¥Ü¦öž]{ÏÝšxd%–€'KðÈc-ø·Ÿ2 ºž5ûËxG¥\o*?_Šùp9À ÔüŸ±†‰ûg ËÿÆ#ð:ÇQx›7ŸÅ£[:piCϘUΩVÉÊ€q¦zªÝb¿Kõ°£ŸÉ4Î?UÇOÒå#©|© Áô8‰ÌNöðÈ›¾ô Ì“ˆ0ù¯ƒïFÍÒý¸ÿþeøòv1 `è‚z¦r*žªŸ™ÛÑLæs¹¯Ú{ví=_÷R €e@#Îiþ»áÓ·4`dè*¾Y\H¬‚O›. ¸ý¤êŸGJö¦r†@rùÇ.H€Ô²Û4H*ÿ Qðzéä=]sjjãË_]ޝ߳•åǦ¥Ÿ*§â©ú™¹MËØ.‚ÔÞ³kïù¸¥J,$)ÅØµûl¾s):5Ñϯå4}KI’N^jÿ›LÕ“ $$uP:ù7N¿L.•Äð;¶–£½Îiþ¹GíB}Ãa|ñîÕøæ}´sÆz©r*žªŸ™ÛÑŒ oŽP{Ï®½çò6*°˜H=î·Þ®Çwþ¦¿y­ƒg›ùÞ¾‚Kå\˜Â=il–§d6 äV 45ÜEY:Ô ’É‚ÇÓÏ€nþüÁ6¬^;ŒM›Êqß—v"P0»F%*§â©ú™¹åÒdslµ÷ìÚ{6ïÍø±”XLR7³ãX~òãZü÷/ýØw`9"ÑzÄ£Ìݯ3©‚q¾ÕK €'!í|ds €[H(ÌTB¶úËÏ“œ8ÇwµµC¸îzàóŸnºþ½)×ü§£¤*§â©úyáØ™éØ‘-û¨½g×Þsqß•Ì Š12R€7ß*0·m¯Äž=¥,L"¨ãk~9÷ò'kùËò€|ä­#üœåg€Óþ=ðÚQ[ׇ«¯áúÿW€o8ƒ–e'àóMí?S¥T9OÕÏ™Z½û«½g×Þ³­ Jæ H)Æðpï(ÀÁC¶mkľýÕøàHgB‡¹Öoâ¸ÖÏA¯EÁ*« ÐÒèÃuïÆ•WŽ`ÍšÔÖ„ùÖ6Ûúöáx*gv¡U<&žÙ½êܦú™;l3Y À<#)e®€==…ða³ŽÇŽ×ãDw!FGB,%ã[½ƒ¢âB,^Eý’“(/‹ ²2B§Ï´?o8šÑ±*çŒàšrgÅsJˆf´ƒ-xÎè¢æpg[ð´EÎLo¥€yJÆ+F<ÎZþ’VÿÇÃô?‡¥„ÖÈje¶ ´Rå̼ U<&žÙ½êܦú™;l§3²€@„ÍÆbìæ—h—ˆó÷r5ÀëÍfã é¨Üäû¨œ™á7þhÅsaâ™Ý«ÎÝhªŸ¹Ãvº#+˜§`tÔÞ^úNûqút!Þ=XŽ“] ¦ šœÿòŠEX¾ÜÁ²ÆN”–zQQCuõ¨I Ìç¦rfmÅsaâ™Ý«ÎÝhªŸ¹Ãv6#+˜g ³+ÈÀ¿B´ý¾;ß(A[Û  ¨4€@Q€)~l!Ìÿ£Œýï!ÂÿK<¸bM?þàÆv´.aõªŠŠFg£OÓ>Fåœ6TÓÚQñœLÓÞÉ<§}As¼£-xÚ"g¶n§€yBz{K±ý‹ñâK¥Ø±£¡‘ZšZéØëѼ¼u E(©ô£0(¥‚=H çÄ:Ž`ÿ¾n¼³¿§û{ÑÐЉØOjëÖ ¡ `$[ºfÆQ9OÕϬšÔE=˜Ú{ví=Û7[ €å óñ-¿[\„—_®eÞÿ 4,­ÆÍŸlƆ««°d‰¥ÅþBÓÜÇà?鋹E†‡èë ãC#¬p{vAß)×Á¶¿g°éönTUe®Ä*§â©ú™¹eÛäj<µ÷ìÚ{®î“‹ @Œÿ^yµ ýxNoÄâêUX{E1›­@óÊb‹¤ï¼Tù×Ú?ÜäÒ.Ð]ëg“ReQÀ¾¾(¶o?‰_oëDWçξ›7öàÑ-‡QW7û‡—Ê©xª~fnG¹rÙWí=»öžíû“>ž‹ Àü¼_ûF%ÁkÐØxš[Šqëgš°ôÒ"6ò¡ÃöH¥?éPÅpÿ8Ëÿ§~ŸDø¸K8ê᧯½z†Ÿ.ôõö¢½ã .´áÙg{QR<»A•SñTýÌÜŽré²9¶Ú{ví=›÷füXJ,$°ŸÿùRÜuWu5· µu-ʪú±ñ3õXÙ\Áwzóñ…‹³ù´ú•.€ò‘Ž~Mçox‚ÄÀY?¶ÿO;öþ®Cýa¼÷Á먭Ä¿} %%Ó'*§â©ú™¹åÒdslµ÷ìÚ{6ïÍdc)°ŒD¢^¼úê"Üõ¥Rø<Ÿ@Sãutìgñ±qõu%øâ²ÒO7e*$§ÿMóSXrþ'ÊûçA‚ ƒØ6ØñGŠúÙbØÁö—:ÑÝYˆp(„ƒG~…k®ý~²u˜e‚CSê¦Ê©xª~fnGSÚE²ƒÚ{ví=_·U €eà·¯×à›Q‡c-\ó¿’%}ý¨^Á 7Ö1øOVôÇ7î! 0Îßmþ;YÅ?OÂÏ]x¬3,U‚0:Z×ÿ¯{Þgd9á£èîý56ßq?Ö‹ŠŠ w5S9OÕÏÌí(_Ž Óó¨½g×Þ3½Ó=^ €E »;ˆªÇ½Ð„Êòõ ð+ãTÿ—ÅqÓ-(ayó—jÌôKúz·ðÔ¥~M8 ÿcv— b!ìÞ9€¡awæ`p Žw¶<<Œ?½ó8ü~’… 6•ÓÅ[ñTýÌÄŽ¦ûŸëýÔÞ³kïù¼ŸJ,"?{¶ [¶4a$ºŠùù tô‹à'hmã×Ösú?d¿¸žsÛØ¨w&`ü&„!Âpâ~€8b`ç®ô qY¡—ö᪠{ðݧN`åJVœ`S9OÕÏÌí(ŸŽ “s©½g×Þ3¹3=V €% ½£~»/¾°ÁÒeœªÒYû½BsSW]UƒÂÂQSï_¢Æ€Tàž8ÿ‰€ì-ßKz gä·D:'ðöîNœaÑ æ pTÑp?OÙ²÷Þ{ê<}S9S(žªŸ³·£™>Èçjµ÷ìÚ{¾ï£KÀ‹/-½÷­àtüjxýåf]ßáë¾ãePž]¿„Uþdý^fÒ Àx•š€˜Ð :Qf0uã&â¥è8BÛÞ“G !±„l)Ä‘ˆ„ÛqóÍ¿Çß>Ù…Æ¥c—TNÁRñTýÌÌŽòíf{>µ÷ìÚûlïÃlS`èï/“O5â{ß+åšÿ:c·¨§î++¬^½eü޾ߤþM´™‰€‰ÿ-.9€œú‡'lD”Nÿ½ƒ§qäý3ˆÆ<'+ñ¤ž8)@´‹k:ñƒ§ßÃ'7Ê,€;àrž]ñTýœ­ÍöažïãÔÞ³kïù¾r>%€öv¾öçµxeÛ*¾ƒ_š /ãã…¯å²^ï󇱴±œŸJ. ÄxS%ß_\ýdÓýç«Z‚@:ÆMš —U8tà$zO…ù½D¸’˜Ym‰æï À IDATðÇûpߟ@0親œçpUÙ„'ž¨§n6•ýÁ¾’›¬L5;ŽÛЇáy(* £ŒD  òíùü7w›¼’Ü M``0ÄqþÎñÄÑKœ 3 Nõ³b ‡ß;NÊʺðòK{ñ¶ V9Çš¤â©ú9;ÊÖƒ=×㨽g×Þs}¿&_ ÀENFG=xð¡j<ýý5Œªj1qø&rÃÌæ§¢ýMˆ¾û=—ü^‡u| ô°Xì“êþ7n@ ™ÃØh„Ùc ew;WK 9 F5Kƒ!Î@ptþ<Í*„ï㹟EðÇ·´!Ž«œŠ§êg†vä8nüΞésÉ}Þfëù9W÷] €à¯¨Â3Ï\IçÞÊü|q¾cKýŒX0³æa’üHÚ€Y6H_à[~"îŽÆà>3£`”z|¬€Ÿ³Ò]p”û’ —KïaëVî¸ýMD"1¨œŠ§êgfväõrvÏ‚M€Ú{öì}®î»À·*ñÌÖñ±pßå “N}â€>×ñÝÇ/Kâó“o2•oú¸›Y6‡ofÜŠîä‚[Æ6¹—)7Ya~UÄ¿di ‡cÀ?ÿ0Š;ïØÃ™•SñTýÌÈŽ|>‹€Ú{Öì}®î» ÀƒWáûÿx9îåtÑ¥|ÀÈCbâ€>“²Ç7}®â›}\G.ûŠƒ7l`?…¸À}ÿO'r”ö ‘ð°B Ëñ˜Nö"x?úQwlz›ubP9…P)žªŸ³·#ŸE3jïÙ³÷¹ºïJ.r;xêï›ñèc‹éx?BSeœ{*×ìl¡™üO:ù ‚þ¤˜Ï$í€Ý ÂóëöÂæœRˆÀ1ƒ£¨ø]üûO?ú”ÌÄUÎsÔ*¤©xª~¦æÑ¦gG«qÚ°és)ý.IùÕÌžŸsuß•\ä ÎÊ{/¼Ø€ÏÝ^K%ÛÀ½Kd¢>¹N?~ÀÔN¾í§4é„ÌY ˜( 8ŒdóÁe”›e‚IÈ`@‡…€ªj>À/žï†õÝ&PåLÇüÅ3MÉT?ÓíHŠqÙ°ési7»zîI0½çç\Ýw%9EÚ³··üÉÇÐÓÝÊ|ûZSª÷Ã-½¼or?ÉÒÞè“ûŸ˜®Ä“,)˜9qü¤&fÀÏ–ÀgIöbÕÚ3xî_Û°rù€HåTõhÙßC €@nû¯^©Â=_¹W0 ™n˜Ž_H€Iñ›°ðV´EVÜLfÈb€3Èõÿýhm=„zú0n¸^ºžÛTΠîxfE-?d¾â™]”r7šÚ{ví=wwjâ‘•XBNœ,Á#µàß~Ê8€èzÖì/ã•r½©ü|)æÃåC.PóÆ&îŸ,,ÿOŒÀëGAàmlÞ|néÀ¥ =cFT9§XñTýœÚŽ¦Ò¢‹åßÕÞ§º3³÷©FËö¿+°„ÈÿÏ_,Å_~«ÇÚ?Ê´»et˦P4Án|ÒŒ"dš^¶ €ðŒ?£ ]l7¼Ëš>Àc†ðÙÛŽ²Ô°Û 8}S9§0SÅ3»Ï±yŠgvAÊÝhjïÙµ÷ÜÝ©óGV`èë+ÁãO.¿lmFhø6”¥€‹ô$¦sß…ÿÌXÁ8Ëàõó°ƒl2´ ›6GðЧ±li÷„C©œS=Ïs™*3ÖÆó˜§ú™dò2„Ú{ví=/7-y%¹gmû/ÁW¿Ñˆ]op) ¼ž Ú,Ä½Ì =Ö pgd;WÎ×ý;=Ç8ý÷ô©åƒs]=tþñÄ1–~ ë7ôà‘o;ØxÓ~ÎH&ÂěʙÂOñTýtmo6v”OgɹÔÞ³kï™Ü‹™«À2‹ùñÚoÊñ…/V¢û$+Æ™è©v‹ý:,ÕÃŽ~&#Ð8ÿT?I”¤ò¥‚Óã$2;ÙcÀ#oúÒ'@2 xL"Âä¿þ½5K÷ãþû—áË_ØÅ,€¡ ê™Ê©xª~fnG3y˜Ïå¾jïÙµ÷|ÝK%–QŒ8§ùwîZ„OßÒ€‘¡«øfq"± >m ¸,àvô“ª)Ù›ÈÉå»D MRËnÓ ©ü'DÁ륓÷tq̨©=Œ/u9¾~Ï^T–›–~ªœŠ§êgæv4-c»vR{Ï®½çã–*°¤c×îK°ùÎ¥è<ÖD?¿–Óô ,%H:y©ýo>2UO2ÔAéägÜü9ý2¹TCÀïØXŽö:§ùç>µ õ ‡ñÅ»Wã›÷½‹òÒÎë¥Ê©xª~fnG36¼9:@í=»öžËÛ¨Àb õ¸ßz»ßù›züæµr žmæ{û . ”si ` ÷˜öÀfyJfBnÅ@SCÀ]$e©C 9ð,x<ýœèæÏPlÃêµÃØ´©÷}i'³kT¢r*žªŸ™ÛQ.A6ÇV{Ï®½góÞŒK €Å u3;Ž•á'?®ÅÿÒ}–#­GÿYà¦ëß›rÍ:Jªr*žªŸŽ™ŽÙ²Ú{ví=÷] À< ¢##xó­S1pÛöJìÙSʲÁ$‰:¾æ—s ²–¿,ÈGÞú1ÂÏY~8íßo µu}¸úÚ®ÿ¸ñ†3hYv>ßäÑþ3UJ•SñTýœ©ÕØ»¿Ú{ví=Ûš `ž€”b ðî<ä`Û¶FìÛ_Žpv „p˜ký&>€ký ôúGQ ¡²º->\÷ñn\yåÖ¬@mM˜oýg³­oާrfZÅsaâ™Ý«ÎÝhªŸ¹Ã6“‘•Ì3Ré ØÓSˆ9ëxìx=Ntbt$ÄRÂ1¾Õ;(*.ÄâÅQÔ/9‰ò²*+#túLûó†3Ñ©«rή)wV<§„hF;Ø‚çŒ.jw¶O[äÌôV*˜§`¼bÄã¬å/‰iõ7[äÌ%J2Õ!=^P "ÐÙd@r!Ú~_„o” ­m †‡FPT@ (ÀÔc¶6çáQæ$õ‡aâÑ¥ \±¦pc;Z—ǰzUEE£9EÚ9³‚%ÙÒ%GP1ôö–bûÿãÅ—J±cG-B#´4µÒ±×£yy1êŠPRéGaPJ˜{08@ωtÀþ}Ýxg'N÷÷¢¡¡ÿ°ŸþÔÖ­BAÁHV‘¶Eά^4S  Û:¥ã)ŠÀG óñ-¿[\„—_®e=’hXZ›?ÙŒ WWaÉ/J‹ü…¦é˜‡ÁÈÒ¿$s‹• %Ðׯ;‡FX×äöì>‚þ¾S<®ƒíÈÏ`ÓíݨªÊœØ"g®ÔI €€\é–Ž«( ;’¾òjþúñ&œ<ÞˆÅÕ«°öŠb6/[æ•Å…ä'ÕGÅõ¤&™¼‹ò#mLݵ~6O6Q+íë‹bûö“øõ¶NtuáìàÛ¸ycÝruu³'¶È™KR  —ú¥c+ŠÀCà?~Þ‚¯}#’à5hl¼ Í-Ÿõ3MXziŒÑa{¤©tÎc¸œeÉÓ??ÈO¢|Ü%õðS‚×^=ÃOúz{ÑÞñ—Úðì³½()ž]€ -ræR}”(È¥~éØŠ€"°@7êç¾wÝF]Í-hm]‹²ª~lüL=V6WðžEÆ|aÄâlJ&-È¥;©|¤é„€_Óùžà1pÖíÿÓŽ½¿ëÁPï}ð:jëñÆoßBIÉôI€-ræCm”(ȇžé9E`#‰zñê«‹p×—Jáó|M×ѱŸÅÇ>ÄÕו à‹ËJ?Ý|”…ÇèÐ9ýoš’™Òä’ó?QÞ?—ldÆvæŽ?‚PÔÏÖç¶¿Ô‰îÎB„C!<ò+\síïð“­Ã,_ša[äœòB²´ƒ%YR%FP*¿}½ßü‹:ëhášÿ•,5îGõân¸±ŽÁ²¢?¾¡Y€qþnSòÉ*‘z~îÂca©„ÑÑ ¼þýØó¦8û ËœEwﯱùŽxü±^TT\¸Û¢-ræK”(È—®éyE`"ÐÝÄÕã¿^hBeùzø•qªËâ¸éÆ”°¿ˆ¼ùKµ?fú%}½Û˜|êä&ÿ1;€K1H vïÀа;s08ÐÇ» [ÆŸÞy~?É›-ræSE”(ȧ¾é¹E`ž!ð³g«°eKF¢«˜Ÿß@G¿~€ÖÖ8>qm=§ÿCÆñ‹+?·úwgÆoB"l\Z'î'ˆ#æñáðÑvîêAßÀ—Šápi`p`®Ú°ß}êV®dUÁ 6[ä̧z(PO}Ós)ŠÀº~ «üÉú½Ì¤€ñL@Lh(³˜:ÈqñRt¡mïI„#…XB¶âÈ DÂí¸ùæßãoŸìBãұ˶șoµP  ß:§çSy€@ž|ªßû^)×ü×лE}„x8u_Yá`õêÅ(«àwôý&õo¢ÍLLüoqÉäÔ?¹QfÜ[äœ •P `.ôNÏ©(–#ÐÞîÃ×þ¼¯l[ÅwðKÝê}â¦ùZ.ëõ>KËù©ä’@Œoð’ï/®~²éþóIH'À¸Iô² `‡œDï©0¿— ³J qÃüý¾óxîû³Ý´@[äœ uP `.ôNÏ©(# Óñ»v_‚[omBo_§è«8=ïFú{2ÕÏŸœ(*ñ¢©¹e’óÏ·uy)?ÏÿO^ÄGÞúÇkbB:;{q¢s€èôI7!Qž“±fð£¸í¶üÃw¢¾~È,Ø ç\©‚%s¥{z^E@°X̋瞻 wß]Œh¢…ïçtî|Ã7¯ãn~¿4øqø)]DMuÁBÆp —”¾t0Q $0f?ñâÔ©³è95€XTßþM1¡É3Pȱå¼]X¾"‚çŸÝÉöÁgØ\È9çJ ”(˜+ÝÓó*Š€¥„Bž|² O zX¬GöIuÿ7 ƒÌal4ÂŽ€ì12 €»«%œ³¤Ág 8:žfÂ÷ñÜÏ"øã[ÚÇ­ÓqÜøˆ|oJ”ä[çô|Š€"`9Bþê*<óÌ•tî­ÌÏç;¶ÔÏøK.`fŒ³K~$mÀ,¤/ ð-?wGcpŸ™Q0¤`|¬€Ÿ³Ò]p”û’ —KïaëVî¸ýMD"1+äôz9{2›%s vzJE@°C¾U‰g~°Ž—qßå “N}â€>×ñÝÇ/Kâó“o½2•oú¸›Y6‡ofÜŠîä‚›gÜËŠ›,€0¿*â_²4ÐñàŸÅwìáÌ €rú|J>¼ÿy2 w±J @žàÖÓ(ŠÀ|AÀ,<\…ïÿãåtº—ÓE—òÒĉMÐgRöø¦ÏU|³ëÈe_qð† Œ#ò§—¸ïÿé@ŽÀ>$Vdù!ÓÉ^ïàG?JàŽMo³n@Ì 9}:pîþçÉH”ä h=" Ì/ÂaOý}3}l1ïGø†^eœ{*×ìÕšÉÿ¤“Ÿ èOŠùLÒØ *<¿n€i/lÎ)…€HS0è0ŠŠßÅ¿ÿø£OÉ @Ü 9V;œ‹M—t`.ôNÏ©(#gå½^lÀçn¯åëùè]"õÉuúñ˦pòm?uÑI§n~ÈRÀDÙéÄa<¥ 0ä€e‚Mù!2Ða! ªšð‹ç»°a}· $´AN)v4›%s¡wzNE@°={KpËŸ| =Ý­Ì·¯5¥z?ÜÒËû&×ñS¥yϽÑ'÷?/0˜I–Ìœ‚8~Ò3àgKà³${±jí<÷¯mX¹|À d‹œs¡J”Ì…Þé9EÀr:ŽùñõûðÂ/×Ò·¯3Ýþ$çßíüÃJ}tÊ2IÛ'ŸÞ hlÔÿäÝ''L¤ó—y– fa Ç9ÅõÿøÜçÃø»' ®Ö%¶È9ê @ À\èžSP,G`dÔg~XÃvÀË‹\ËTÀEfJÞ]Ï—Ò¿I·‘ÏXÙÅË»¿t^‘ª€&³ ÅE;ððÃq|åž÷QR\0dà5ÿg ª¸²üo<1¯s·±yóY<º¥—6ôŒÑ9g C†(P¡ éኀ"°øÏ_,Å_~«ÇÚ?Ê´»et˦P4Án|ÒÌ'dš^¶ €ðŒ?£ ]l7¼Ëš>Àc†ðÙÛŽ²Ô°Û 8}³EÎ|ê’%ùÔ7=—" Ì3úúJðø“‹ð/[›¾†Me) À"=B¤C €éÜwáÆ?3†…³ ^ï0;È&C»°is=pË–vO8”-r· P  õÑCE@Úö_‚¯~£»ÞàR@x= @µYˆ{™ )z¬àÎÈv®œ¯ûwz|úïé=RËçºzèüã‰c,üÖoèÁ#ßv°ñ¦ýœ L„‰7[äÌ—N)P/]Óó(ŠÀ€ký ôúGQ ¡²º->\÷ñn\yåÖ¬@mM˜oýg3’åBÛ"g¶P  [º¤ã(Š€"pA¤+`OO!|d0ÿ±ãõ8Ñ]ˆÑ‘K ÇøVï ¨¸‹GQ¿ä$ÊË"¨¬ŒÐé3íÏκ¶È™) J”dªCz¼" (³B g-IH«ÿãaúŸÃRÂëŒ-4«Sdå [äœéÅ*X@Øl,Æ®Yq‰ªu-MŒÌËY7¯7› :fª~c÷·EÎÌ®RVAÀ{·EÎÙh•€yJFÙ«»·×ƒ¾Ó~œ>]ˆw–ãdW‚)9ì‘ÍÜÚòŠEX¾ÜÁ²ÆN”–zQQCuõ¨I½Éçf‹œùÄDÏ¥ÌWl±w[äÌTO”Ì3ÐÙd€M!Ú~_„o” ­m †‡FPT@ (ÀT¶êäáQÆØö‡a í¥ \±¦pc;Z—ǰzUEE£™êÖ·EΜ‚ ƒ+ [ìÝ9³¥6Jæ èí-Åöÿ-Æ‹/•bÇŽZ„Fhij¥c¯GóòbÔ5¡¤Ò ”äô`p ž#è8:€ýûºñÎþNœîïECC'6þa?>ý©¬[7„‚‚‘léšÇ9³zÑ:˜"°@°ÅÞm‘3Ûj¤Àrùø–_­?.ÂË/×2¿v–VãæO6cÃÕUX²Ä‹Òb¡i¢!}º¥w,æßJ ¯/Œw0O÷öì>‚þ¾S<®ƒí5Ï`ÓíݨªÊœØ"g¶ LÇS"¶Ø»-ræJ‡”XLbì°õÊ«eøëÇ›pòx#W¯ÂÚ+ŠÙŒcšW#X$ý²¥š–¸þ€ÔØà&ÿ“¶\îZBJo2 0Êâ[}}Qlß~¿ÞÖ‰®Î!œ|7oìÁ£[£®nö$À9sed:®"°°ÅÞm‘3—º£Àbð?oÁ×¾‘@Ið46^†æ–bÜú™&,½´ˆ 3è°=RQK:i1Ü?Î2›ÆéŸä'Q>îŽzø)Ák¯žá§ }½½hïxƒKmxöÙ^”Ï.@Ð9sih:¶"°P°ÅÞm‘3—z£ÀB ÌõùŸ/Å]w…QWs Z[×¢¬ª?S•Í|§gÑ _±8›lHKMé¶%é¬5!à×tþ†'8A œõcûÿ´cïïz0ÔÆ{¼ŽÚúA¼ñÛ·PR2}`‹œ¹40[X(Øbï¶È™½Q`ˆD½xõÕE¸ëK¥ðy>¦ÆëèØÏâcâêëJðÅe¥Ÿn>ÊBtèœþ7M6L©Íq}¸?Ô0.$ؘƒí9¡¨Ÿ­<l©Ý…‡B8xäW¸æÚßá'[‡YŽ34¥nÚ"產;(ŠÀ”Øbï¶È9%àYÚA €eà·¯×à›Q‡c-\ó¿’¥3ý¨`Ñ%Ž IDAT^Á 7Ö1øOVôÇ7È 0Îßm²9Ye-OÂïöçv†¥JFG+ðúÿõcÏ›âìƒ,Ûyݽ¿Ææ;NàñÇzQQÁ:žØl‘3Kv¤Ã( [ìÝ9ó¥LJ,"ÝÝA<ðP=þë…&T–¯g€_§ú‡Ð¸,Ž›nlA ëeË›¿Tû3½¶Íl½Ûhsê’š&Ðôåöp© ©!Âîvg:àxwaËÃÃøÓ;Ãï'Y˜`³EÎ|™žG˜ÏØbï¶È™O]Q`øÙ³Uز¥ #ÑUÌÏo £_? @kkŸ¸¶žÓÿ!ãøÅ•ŸÛÆFýŸ#éj&„!ÂF\pâ~€8b`ç®ô qY¡—ö᪠{ðݧN`åJVœ`³EÎ|šžK˜¯Øbï¶È™O=Q` hï(Àƒß®Á‹/¬C°t§êƒtÖ>Fï‡ÐÜÀUWÕ °pÔÔû—(€± ¸'Ä ¤«š|/éœAßEè<žÀÛ»;q†Eƒ˜'ÀQDÃýpE`>"`‹½Û"ç\èˆ @{»_ûóZ¼²mßÁ/u«÷‰›æk¹¬×ûüa,m,ç§’K1¾ÁK¾¿¼±O6ݾª%H¤`ܤ zY0CN¢÷T˜ßK†‰Y%8aþ~ßy¼÷ýÙ ƒnZ -rÎ…¡é9ù†€-ön‹œs¡J.r Óñ»v_‚[omBo_§è«8=ïFú{2ÕÏŸœ(*ñ¢©¹e’óÏ·uy)?ÏÿO^ÄGÞúÇkbB:;{q¢s€èôI7!Qž“±fð£¸í¶üÃw¢¾~È,Ø ç\™žS˜oØbï¶È9Wú¡à"'±˜Ï=wî¾»ÑD ßÏ èÜù†o^ÇÝü~iðãðSº(ˆšê‚…Œà2@,.)}é,@Þî'ÙÌ~>ãÅ©SgÑsj±¨ ¾ý›bB!’f  cËy»°|EÏ?»“íƒÏ°¹rΕ¡éyù„€-ön‹œs¥J.r 9xòÉ&<ñD=ýp³©ìÎð•Ü™ºw·¡ÃóPTF‰@0äÛ;óøoî6y 3$¹A4šÀÀ`ˆãü㉣—8)f8œêgÅ@¿wœ>”•uáå—öâ#ll‹œsehz^E`>!`‹½Û"ç\醀‹œŒŽzðàCÕxúûká×bâð9ßžŒ»KEû›}÷{.ø½ëø0èa±Ù'ÕýoÜ € 2‡± Ð;²Ç@4Ê(îv®–@rÌCœàèüyšUßÇs?‹àoiC8·BNÇqã#tSÙ# Ï%÷y›­çç\=—”X@þê*<óÌ•tî­ÌÏç;¶ÔÏx3.`fŒ³K~$mÀ,¤/ ð-?wGcpŸ™Q0J=>VÀÏÙé.8Ê}IÐË¥€÷°u«wÜþ&"‘lÓëåì‰nŠ€"Bl°w}.]ø6+°|«Ïü`ïäe|—/L:õ‰ú<\ÇwÿE¿,ˆÏO¾õÊT¾é ànfÙ@¾™9p+º“ nžAr/S(n²ÂüªˆÉÒ@Ç>€þawÞ±‡3$Èéó)Èèɯ+DÀ ì]ŸKJ&CÀ]D·€<øp¾ÿ—Óé^N]J‘ʼnMÐgRöø¦ÏU|³ëÈe_qð† Œ#ò§—¸ïÿé@ŽÀ>$Vdù!ÓÉ^ïàG?JàŽMo³n@ 6ÈéÓu`Š@Ƙ%}.™¦l)8–¤Æ!í…Í9¥ €c FQñ»ø÷Ÿô)™ˆ[!§Ãj‡º)Š@fès)¿ÌŸŸsõ\Rp‘€8+ï½ðb>w{-ôè]"õÉuúñ˦pòmÿœ 7¿™Y ˜( 8Œ§$†°L°)?Ä @:,TUó~ñ|6¬ï6„6È)ÅŽtSÌÐçÒ80nvuÌ Ô4žŸsõ\Rp‘Q¤={KpËŸ| =Ý­Ì·¯5¥z?ÜÒËû&×ñS¥yÏM÷'÷?/0]‰'YRà.2 5&fÀÏ–ÀgIöbÕÚ3xî_Û°rù€È93{ôéÑŠ€"`“½ësir}U`è8æÇ×ïoÀ ¿\Kß¾Îtû“œ·ó+õÑ)Ë$=¾E sl±w[äÌüŽÌ|%€‘Q?žùa Û/G,r-SñN§Öó¥ôo’Àmä3–Ì\)ÆNnI@ û ˜Õ)$™í(.Ú‡Žã+÷¼’âAsˆ-rf†ˆ­(6Ù»>—t`"¬ÈH þ«WªpÏW.GgÇŒh¦¦ã`Rü&,üŸ•§”¬*¸™ÌÅgëÿûÑÚzÿôôaÜp½t<·Ù"gVÀÑAŽ€-ön‹œùV'°`@”âÄÉ<òX þí§Œˆ®gÍþ2~+åzSùùṘˆ \ æÿŒ5LÜ?Yþ7ž×9Ž‚ÀÛØ¼ù,ÝÒKzÆŒh‹œ3†APó°ÅÞm‘3ß*¦À ŠñŸ¿XŠ¿üV-޵”iwËè–+L# h‚Ýø¤™O<È4½lá1:~F$ºØnx?–5}€Ç á³·e©a·púf‹œù66=Ÿ"0°ÅÞm‘3Ÿ:¢À"Ð×W‚ÇŸ\„ÙÚŒÐð5l (Ké ILç¾ 7þ™±‚q–ÁëæaÙdh6mŽà¡NcÙÒî ‡²EÎã (ŠÀyØbï¶È™OS`ÅhÛ ¾úFìzƒKáõ$Õf îeV€¤è±n€; Û¹r¾îßé9ðé¿§÷H-œë"è¡ó'ޱtð[X¿¡|ÛÁÆ›ös6@2&Þl‘3ŸÆ¦çRæ+¶Ø»-ræKO”XFb1?^ûM9¾ðÅJtŸdeÀ8Ó=Õn±_‡¥zØÑÏd矪ã'iƒò‘T¾TÐ`zœ€ÄC&{ xäM_úHfID˜ü×Á¿w£fé~Üÿ2|ù »˜0tAµEÎ|šžG˜ÏØbï¶È™/]Q`ňsšç®Eøô- º ïˆÄ*èµ ¸,àvô“ª)Ù›ÈÉå»D MRËnÓ ©ü'DÁ륓÷tq̨©=Œ/u9¾~Ï^T–›–~Ú"ç´.FwR "`‹½Û"g>ÔM €… ¥»v_‚Íw.Eç±&úùµœ¦o`@`) @ÒÉKíó‘©z’„¤J'?ãæÏé—Éõ“~ǶÀr´×9Í?÷ñ¨]¨o8Œ/޽߼ï]”—vÎX/m‘sƦ(ŠÀyØbï¶È™KS`1zÜo½]ïüM=~óZ9Ï6ó½}—ʹ40…{L{`³œ/³!·b ©!à.Ȳ€Ô¡NxH<ž~Îtóç(¶aõÚalÚTŽû¾´‚Ù5Ò±EÎ\šŽ­,l±w[äÌ¥Þ(°˜¤£ãX~òãZü÷/ýØw`9"ÑzÄ£Ìݯ3©‚q¾ÕK €'!í|ds €[H(ÌTB¶úËÏ“œ8ÇwµµC¸îzàóŸnºþ½)×ü§£¤¶È9kÑ}EàÂØbï¶È™ }S0€(ÆÈHÞ|«RñjÛöJìÙSʲÁ$‰:¾æ—s ²–¿,ÈGÞú1ÂÏY~8íßo µu}¸úÚ®ÿ¸ñ†3hYv>ßäÑþ3UJ[äœéuéþŠ€"p>¶Ø»-rf[Ç”ÌRŒááÞ=P€ƒ‡lÛÖˆ}û«ñÁ‘΄s­ßÄp­Ÿ‚^ÿ(Š‚!TV ¥Ñ‡ë>Þ+¯Áš5¨­ ó­ÿl¶õíÃñl‘3gèÀŠÀBÀ{·EÎl©Ž€yFRŠ!]{z 10àà ƒù¯Ç‰îBŒŽ„XJ8Æ·zEÅ…X¼8Šú%'Q^Aee„NŸiÞp¶ôkÊql‘sÊ ÑE`Jl±w[äœð)vP0O Àøû³–¿$¤Õÿñ0ýÏa)a‡õÆ ÊT­f¼-rÎþ õHE@H!`‹½Û"çL5K À Âfc1vó‹K´¿ËÄù{¹àõf³qÐLÕoìþ¶È™ÙUêÑŠ€" Øbï¶È9­R0O À訽½ôöãôéB¼{°'»L49ÿå‹°|¹ƒe(-õ¢¢<†êêQ“˜ÏÍ9󉉞K˜¯Øbï¶È™©ž(˜g ³+ÈÀ¿B´ý¾;ß(A[Û  ¨4€@Q€)~l!Ìÿ£Œýï!ÂÿK<¸bM?þàÆv´.aõªŠŠF3Õ­ o‹œ9AW¶Ø»-rfKm”ÌÐÛ[Šíÿ[Œ_*ÅŽµÐÒÔJÇ^æåŨk(BI¥…A)ìÁà@='FÐqtû÷uãý8Ýß‹††NlüÃ~|úS#X·n#ÙÒ53Ž-rfõ¢u0E`"`‹½Û"g¶ÕH €å óñ-¿[\„—_®eÞÿ 4,­ÆÍŸlƆ««°d‰¥ÅþBÓÜÇà?鋹E†‡èë ãC#¬p{vAß)×Á¶¿g°éönTUeNl‘3Û¦ã) [ìÝ9s¥CJ,&1vþ{åÕ2üõãM8y¼‹«WaíÅl´Í+‹, 3ÈOªü‰ëHínò?iè®õ'¤$0£, Ø×Åöí'ñëmèêÂÙÁ·qóÆ<ºå0êêfOl‘3WF¦ã* [ìÝ9s©;J,&ÿñó|í ”¯Acãehn)Æ­ŸiÂÒK‹ØÈ‡Û#•þ¤ÃÃýã,ÿkœþùA~àã.ᨇŸ¼öê~ºÐ×Û‹öŽ7¸ІgŸíEIñìm‘3—†¦c+ [ìÝ9s©7J,$Â\ŸÿùRÜuWu5· µu-ʪú±ñ3õXÙ\Áwzóñ…‹³ù´ú•.€ò‘Ž~Mçox‚ÄÀY?¶ÿO;öþ®Cýa¼÷Á먭Ä¿} %%Ó'¶È™KÓ±…‚€-ön‹œùÐ%–€HÔ‹W_]„»¾T Ÿçhj¼ŽŽý,>öñ ®¾®_\Vú鿣,ðC‡ÎéÓüÇ”–œÿ‰òþ¹D`à ¶ vü„¢~¶v°ý¥Ntw" áà‘_ášk‡Ÿlf™àДºi‹œS^ˆî (S"`‹½Û"甀gi%–€ß¾^ƒoþEŽu´pÍÿJ–ôõ£zq7ÜXÇà?YÑ߸‡,À8·ùïdÿ< ?wá±Î°T Âèh^ÿ¿~ìySœ}å„¢»÷ר|Ç <þX/**X_ø›-rfÉŽtE`A#`‹½Û"g¾”I €E »;ˆªÇ½Ð„Êòõ ð+ãTÿ—ÅqÓ-(ayó—jÌôKúz·ðÔ¥~M8 ÿcv— b!ìÞ9€¡awæ`p Žw¶<<Œ?½ó8ü~’… 6[äÌ—‘éyùŒ€-ön‹œùÔ%€Ÿ=[…-[š0]Åüü:úEð“´¶Æñ‰kë9ý2Ž_\ù¹mlÔ¿;0~ÂaƒÀ8q? @1‡F°sWú†¸¬P ‡KƒûpÕ†=øîS'°r%« N°Ù"g> MÏ¥ÌWl±w[ä̧ž(°„´wàÁo×àÅÖ!XºŒSõA:k£÷Chn ફjPX8jêýKÀX Üç?½å{Iä ‚ü–(BçñÞÞ݉3,Ä<Žê î‡ãiÃ#[öãÞ{O§«¶È™O#Ós)ó[ìÝ9ó­'J,!/¾´÷Þ·‚Óñ«áõ—›u}‡¯ûŽg”Ay~|týVù“õ{™H'ãUj`B(èD™ÀÔAŽ›ˆ—¢ãpm{O")„IJ¥GN nÇÍ7ÿûd—Ž]°EÎ|šžO˜Øbï¶È™oQ`èï/“O5â{ß+åšÿ:c·¨§î++¬^½eü޾ߤþM´™‰€‰ÿ-.9€œú‡'lD”Nÿ½ƒ§qäý3ˆÆ<'+ñ¤ž8)@´‹k:ñƒ§ßÃ'7Ê,€;Ã`‹œù62=Ÿ"0°ÅÞm‘s.tD € ½Ý‡¯ýy-^Ù¶Šïà—ºÕûÄMóµ\Öë}þ0–6–óSÉ%ßà%ß_\ýdÓýç«Z‚@:ÆMš —U8tà$zO…ù½d˜U‰æïðÇûpߟ@0è¦Ú"ç\šžS˜oØbï¶È9ú¡à"'2¿k÷%¸õÖ&ôöÕqоŠÓón¤¿'!SýüÉY€¢/ššëPQ&9ÿ|[——òóüÿäE|ä­ßq¼&† ñ ³³':øw€NŸtÃå9{`?ŠÛnÀ?|÷ êë‡Ì² rÎ…‘é9ù†€-ön‹œs¥J.r‹yñÜs—áM´ðý¼€ÎoøæuÜÍï—??¥‹‚¨© XÈø.Äâ’Ò—Î&*”T=³ŸÇxqêÔYôœ@,*ƒoÿ¦˜Pˆäƒ™(äØrÞ.,_ÁóÏîdûà3l.d‡œsehz^E`>!`‹½Û"ç\醀‹œ„Bž|² O zX¬GöIuÿ7 ƒÌal4ÂŽ€ì12 €»«%œ³¤Ág 8:žfÂ÷ñÜÏ"øã[ÚÇ­ÓqÜøÝE`öèsÉ}Þfëù9WÏ%%€¿z  Ï×ñÝÇ/Kâó“o½2•oú¸›Y6‡ofÜŠîä‚›gÜËŠ›,€0¿*â_²4ÐñàŸÅwìáÌ €rú|J2zòëÁŠ0À{×ç’€ÉpÑ- >\…ïÿãåtº—ÓE—Rdqbô™”=¾ésßìã:rÙW¼aã€ü)Àåîû:£„°Ï‰„‡Y~ˆÇt²Á;øÑ¸cÓÛ¬ƒ rút@˜"1f @ŸKæ…)ÏϹz.é ÀENÂaOý}3}l1ïG¨pUƹ§rýÇZ²™üO:ù ‚þ¤˜Ï$í€Ý ÂóëöÂæœRˆÀ1ƒ£¨ø]üûO?ú”ÌÄ­ÓaµCÝE 3ô¹”ŽŸ”_Íìù9WÏ%%9ˆ³òÞ /6às·×RÉ60@O®Ó_0u€“oû)M:uóC–&ÊH'ã) €Qn– 6å‡È`@‡…€ªj>À/žï†õÝ&Ð9¥Ø‘nŠ€"ú\GÆÍ®ž{úNïù9WÏ%%9EÚ³··üÉÇÐÓÝÊ|ûZSª÷Ã-½¼or?Uš÷Ü}rÿó‚Ó•x’%3§ ŽŸ´ÃÄ øÙø,IÀ^¬Z{ÏýkV.0Ù"gf>=ZPl²w}.M®¯J, Çüøúý xá—kéÛ×™n’óïvþa¥>:e™¤‡‡í€“Oo46êòn€“&Òù˼˳0ãœâúÿ|îóaüÝPWë[äÔÇ·" dŽ€-ön‹œ™ß‘™ À02êÇ3?¬a;àåˆE®e*à"ÞéÔz¾”þM¸|Æ€™+ÅØÉ- d³º $³ ÅE;ððÃq|åž÷QRŒ®—n€ç6[äÌ 8:ˆ"°À°ÅÞm‘3ßê¤3̈Rœ8Y‚GkÁ¿ý”qÑõ¬Ù_Æo¥\o*?_Šùp9À ÔüŸ±†‰ûg ËÿÆ#ð:ÇQx›7ŸÅ£[:piCϘm‘sÆ0芀"p¶Ø»-ræ[Å”XBD1þóKñ—ߪűö2ínÝr…iM°Ÿ4󉙦—m <#FÇÏ(ƒDÛ ïDz¦ðØ£!|ö¶£,5ì¶Nßl‘3߯¦çSæ#¶Ø»-ræSG”XDúúJðø“‹ð/[›¾†Me) À"=B¤C €éÜwáÆ?3V0Î2x½Ã<ì › í¦Í<ôÀi,[Ú=áP¶È9côE@8[ìÝ9ó©bJ,"¢mû/ÁW¿Ñˆ]op) ¼ž Ú,Ä½Ì =Ö pgd;WÎ×ý;=>ý÷ô©åƒs]=tþñÄ1–~ ë7ôà‘o;ØxÓ~ÎH&ÂÄ›-ræÓØô\ŠÀ|EÀ{·EÎ|é‰Ë@,æÇk¿)ǾX‰î“¬ gZ §Ú-öë°T;ú™Œ@ãüSuü$mP>’Ê— LxÈd¼éKŸÉ,à1‰“ÿ:ø÷nÔ,Ýûï_†/a³†.¨£¶È™/CÓó(ó[ìÝ9ó¥+J,#¢qNóïܵŸ¾¥#CWÁ㽑X½v—ÜŽ~RõÏ#%{Ó9C ¹üc—¤ @jÙÀm$•ÿ„(x½tòž.޹5µ‡ñå¯.Ç×ïÙ‹ÊòcÓÒO[äœÖÅèNŠ€"pAl±w[ä̇º)°¤c×îK°ùÎ¥è<ÖD?¿–Óô ,%H:y©ýo>2UO2ÔAéägÜü9ý2¹~CÀïØXŽö:§ùç>µ õ ‡ñÅ»Wã›÷½‹òÒÎë¥-rÎøÂôE@8[ìÝ9s©bJ,&Rû­·ëñ¿©Ço^+ÇàÙf¾·¯à’@9—¦pil–óe6 äV 45ÜEY:Ô ’É‚ÇÓÏ€nþüÁ6¬^;ŒM›Êqß—v"P0»F:¶È™KCÓ±…‚€-ön‹œ¹Ô%€”bt+ÃO~\‹ÿþ¥û,G$Zx´‚¹ûu&U0ηz‰ð$¤l.p …™JÈV¿qùy’àø¡¶v×]|þ³ÀM׿7åšÿt”Ô9§s-º" \[ìÝ9s¡oJæÅ)À›o@*^mÛ^‰={JY6˜D QÇ×ürîäOÖò—åùÈ[?Fø9Ëϧý{à ´£¶®W_Ãõÿ¯7Þp-ËNÀç›<Ú¦Ji‹œ3½.Ý_PÎGÀ{·EÎl똀yBRŠ1<À» pðƒmÛ±o5>8ÀÙÂa®õ›ø®õ3@ÐëEQ0„Êê´4úpÝÇ»qå•#X³fµ5a¾õŸÍ¶¾}8ž-ræ XX@Øbï¶È™-ÕQ0Ï@J1¤+`OO!|d0ÿ±ãõ8Ñ]ˆÑ‘K ÇøVï ¨¸‹GQ¿ä$ÊË"¨¬ŒÐé3íÏΖ~M9Ž-rNy!ºƒ" L‰€-ön‹œS>ÅJæ)ßãqÖò—D€´ú?¦ÿ9,%ì°~ÀØ"A™ªÕì·EÎÙ_¡©()l±w[䜩f)X@Øl,Æn~q‰öw€8/W¼Þl6š©úÝß93»J=ZP[ìÝ9g£UJæ)jVv IDATõ£·×ƒ¾Ó~œ>]ˆw–ãdW‚©‚ƒ&翼b–/w°¬±¥¥^T”ÇP]=jRó¹Ù"g>1Ñs)ó[ìÝ93Õ%óŒtvøWˆ¶ßaç%hk[‚á¡•( 0Å-„ù_x”±ÿý!DàiƒW¬éÇÜØŽÖå1¬^BQÑh¦ºuÁãm‘3§ èàŠÀAÀ{·EÎl©€yBz{K±ý‹ñâK¥Ø±£¡‘ZšZéØëѼ¼u E(©ô£0(¥‚=H çÄ:Ž`ÿ¾n¼³¿§û{ÑÐЉØOjëÖ ¡ `$[ºfƱEά^´¦,Pl±w[ä̶)°œDc>¾åW`ë‹ðò˵Ìû_†¥Õ¸ù“ÍØpu–,ñ¢´ØAÀ_hšûxô'}b1·(ÐðP}}a¼sh„õŽ`Ïî#èï;Åã:Øö÷ 6ÝÞªªÌI€-rfÛÀtçH:ºX7dIHXÖÅÛ`H áC)NRÒÂüI°¦$þ@C’&t¦% t†wJ:4@¿\œLÓL`ÊüiÚ“€MC’|ÇŽlðK¶lK–lÝuîÿó®­ƒdɲ¬­#­sÞíÙ>ÒѾ¼ûYkí÷Yïz/1lÚt¿ÙØ£ƒèØŽ[Vwá±uQ[{þ$À9gkéu\BÀ–ñn‹œ³Ùw”XLþóçÍøÊ×’(]ƒ††KÐÔ\„Û>ÕˆE²¶O2ýI…?ºû'˜þ×(ý3üÄ+ ÀC"1÷b¼þÚ)îGÑÓݶö7¹ЊçžëFqÑù9Ú"çl4½¶"+Ø2Þm‘s6û €0×~¾wßAmõ­hiY‰ÒÊ^¬þT–6•sNÏd>â ÿ‘R¿RPv©ø7!à×Tþ†'8!ôõ±éWmØù‡. öF°ÿÀ¨©À›¿ÅÅçNl‘s6˜^[Èlï¶È™‰~£À2ùñÚk p÷Jð} ×S±÷ã#×…põõÅÈ$d¥Ÿj>Æ?Tè4ÿ›â?&°ÄüO÷Ï%‚$ ±l°Œ" ²Ä°ƒM/w ³£‘p{ßÿ5®¹öøñ†!¦ OÙ7m‘sÊÑE`Jlï¶È9%à À2ðû7ªñõ¿©Åáöf®ù_Δ¾AT-ŒâÆ›jéü'+úã ÷åïÿ,ãŸ/ä!<×’,A)Ç¿íÅŽ·DÙ‡˜Nø:»ƒµwÃw£¼œù…ϲÙ"§GãH/£ä4¶Œw[äÌTgR`èì áÁ‡ëðß/6¢¢lüJiêDÃân¾©ÅÌã/3ÉöÇH¿Q]ïž:Õ¯qä?Fp© É!ƶ-}r-}ípü[±î‘!üå]G ’,L°Ù"g¦™ÞGÈflï¶È™É¾¢À"ð³ç*±n]#†cËŸ_OE¿A€––>zmÍÿa£øE•ŸÞÆzý»–€ñ›†( æÁIIˆû8x(Š-[»ÐÓ7Èe…"8\èÛ…+¯Úo?u K—2«à›-rfr é½lEÀ–ñn‹œ™ì'J,!míyxè›ÕxéÅ+*YLS}ˆÊ:@ïý0šóqå•Õ((1ùþÅ `,H9î‰òŸˆÈÑò½„Ò‚ ?% Ñq$‰íÛ:pŠIƒ'À«:ˆEzáøZñèºÝ¸ï¾gôU[äÌä Ó{)ÙŠ€-ãÝ93ÝO”XB^zyî»ÿbšã—Ã,3ëú§ûŽo„NyA|xÕ…Ìò'ë÷bH'ã»Ô$À¸ÐQЉ1 €¡ƒ¼n2Q‚öƒa´î<ŽH´âKÈ’B¼rÑHn¹åøÇõGѰhì2€-rfz éýlDÀ–ñn‹œ™î#J, ½½…XÿT¾ó®ù¯ 2v“úðÑt_Qî`ùò…(-çwÔý&ôo¢Í&þ[Bbiú‡/bDŒJÿÞ“xÿ½SˆÅóyOf âM} R€X7Vwà™§÷ãã«Å àZl‘3ÓƒLï§d#¶Œw[䜋>¢ÀÐÖÀWþº¯n\Æ9øEnö>QÓœ–Ëz} Á¢†2î\ˆs/ñþ¢ê'3÷ŸÙÕ’$R 0aÂý̘ľ=ÇÑ}"Âï%B€ÄÀ¬ˆŸÀÞƒo=уûÿêB!7,Ð9çb é=lCÀ–ñn‹œsÑ?”Ìs æø­Û.Àm·5¢»§–&úJšç]O_RLýü¤ °ØÆ¦Z”—JÌ?gë2)?CÿOžÄGfýŽã7>á¨Ý8ÖÑÇßó©ôI7!1Þ“¾æâ‡pûí}ø—oïE]Ý Y6°AιdzOE Û°e¼Û"ç\õ%óœÄã~<ÿü%¸çž"Ä’ÍœŸçQ¹s†o¦ãn|¿øq¸—,¡º*¡úp ž¾t0Q Ñ®gŽ ð?NœèG׉>ÄcB08û7É„Â$Œ@¯-÷=Š%GñÂs[X>ø‹ Ù!ç\ 4½¯"MØ2Þm‘s®ú†€yNÂaë×7âÉ'먇›LfÐÀ)¹!bºw· ÝóPXA)‰@(âìñü›»MžÈ\’Ü K¢o Ì þÌ뉢?IF84õ3c ß;NJKâ•—wâC,l‹œs5Ðô¾Š@6!`Ëx·EιêJæ9ñᡇ«ðôwWÐÃ¯ÙøáÓÞ>êw—òö7.úî÷\úæ ÐaÐÇd=rLªúß8 €$ 2§±Ð0+²Æ@,F/v:—À¨ŒC´@ðêü<É,„ïáùŸEñç·¶"IX!§ã¸þº)ŠÀù# ï%÷}ëÕûs®ÞKJ, ÷`%ž}ör*÷Æç‹ò›êgü0.`¬FÙî6`– Ò—8ËO&ܫѹÏXL§ï+¤õAª Žð˜üQÐÍ¥€ýذÁ‡;ïx Ñh6Èé÷Óz¢›" Ì!6Œw}/½™•Ø@¾QgŸ¹‚-y çò£J}b‡>×ñÝ¿ˆâ—%Ñù£³^1固îf– DáË›1Ð5.¸q£G™@ áW…üM–ºxí=øþ÷b¸ëδX g  `Fo~=Y †X0Þõ½¤`2ÜEt ÀCTâ»ÿz)•î¥TÑ%Y”ØÄ}&d3}®â›c\E.ÇŠ‚7l`_…¸Àÿ§9Kë Hø˜!é‡xNk¼ƒü ‰;×lgÞ€8l3 U`ŠÀŒ0Kú^2&/ÞŸsõ^R À<'‘ˆƒ§þ¹ =¾Š÷Cìp•F¹§býÇŽdcüUò8ýI2ŸIÊ»N…gæ !å…Í=% €cDaÑ»øéO€?û„XVÈé0Û¡nŠ€"03ô½”ŽŸ¤_Ùûs®ÞKJæ9H0óÞ‹/Õã3wÔ°“]E½ ÄP?ºN?~Àäí§:è¨R7²0Q4@:qO)HLçfš`“~ˆN€tt˜¨²ú~ñÂQ\µªÓ8Ú §$;ÒMPf†€¾—Æ€qÖÕÓoßs{ÎÕ{I À<'Ò‘vì,Æ­ñtu¶0޾Ƥêý`KOï;ºŽŸJÍ{zF?züN€éx’%cSÅOÚa|‚, ÜO°ËVžÂóÿÞŠ¥KúÌ…l‘sf¯>=[Plïú^š¼¿*°€´â«ÔãÅ_®¤n¿ÂTû“˜·ò3õQ)‹‘>–6J>½ÐX¯ÿÉ«NNHå/v¦ fb Ç9ÁõÿÍøÌg#ø§'÷ ¶Æ%¶È©¯oE@˜9¶Œw[äœy‹Lÿ J, Ã#A<û½j–^‚xôZ†.`K§Öó%õï(€[Èg,˜~§k܇@Ö0« ’H" ÚPT¸<’À—î}ÅEæ[äœ"z¶" Ø4Þõ½¤€‰°" %ø¯_­Ä½_ºí—Ñ ‰j˜Š_H€ ñ›0ñ¿'o)YUp#  ‹Î×ÿw£¥eþí郸ñ©xz³ENOÀÑ‹(9Ž€-ãÝ93ÝÔ`@:űãÅxôñfüÇOè[Åœý¥üVÒõ¦âó%™— 8KÎÿi÷0QÿtdaúßDr~çòò·cíÚ~<¶®Õw¹¢-rN=APÎ@À–ñn‹œ™îbJ,!Ò1þë‹ð·ß¨Áá¶3ìn1Õr¹)K²ŸóI„¦ç5ž§â§—Aò(Ë ïÆâÆxü±0>}û!¦vK§o¶È™éÁ¦÷S²[Æ»-rf²(°ˆôôã‰õ ðà M]′Ï$=B¤B €©ÜwöÂ?Óî`´2øýCŠ@6#`Ëx·EÎLõ%–é šù·l]€OÞZáÁ+áó_†h¼œZ;ËnE?Éúç“”½é´H,ÿØ%)Z6p‹Iæ?! ~?•¼ï(¯¹Õ5ñÅ//ÁWïÝ‰Š²ÃçÔ?m‘óœFR³"`Ëx·EÎLt7%€TÇØºí¬½k:7Rϯ¤™¾ž%$£J^rÿ›]Lõ$I ”J~FÍŸî_&ÖO|øËËÙ~ç$Ýų¶¢®þ >Ïr|ýþwQVÒ1í~i‹œÓ~0=APÎ@À–ñn‹œ³ÙÅ”XL$÷ÛÛëð­¨Ãï^/Ã@çísI ŒKù&q)l–óÅv3šî", Hê$ÉdÁç률“ŸjÅò•CX³¦ ÷a òóίŽ-rÎæ@Ók+¹‚€-ãÝ9g³ß(°˜¤:FûáRüøG5øŸ_±kÏDcuHÄÊ»_kBœÕ‹€/)å|ds €›H(ÂPB–úMÈçqöÀ ìCMÍ ®¿øì§›oØ?åšÿ¹tR[ä<—gÑcEàìØ2Þm‘s6ú›€, Ò1†‡óðÖÛyŒW7U`ÇŽ¦ &HÖrš_Æ#Büd.Y]fýæÞϽfÿ.øóÛPSÛƒ«¯ã†åá¦O¡yñ1“{ûO·SÚ"çtŸKW3°e¼Û"§×}L @–€TÇÊÇ»{ò°wŸƒ°kw¼Ÿþ¾0"®õÿ®õÓAÐAa(ŒŠª<47pýu¸üòa¬Xчšêgýý^÷·®g‹œ³€^XÈ!lï¶ÈéU×Qe Õ1¤*`WWúú 3ÿá#u8ÖY€‘á0S Ç9«wPXT€… c¨»ð8ÊJ£¨¨ˆRé3ìÏñªMy[äœòAôE@˜[Æ»-rN ø(ÈR0¾Ý æò—@€´ü?>†ÿ9L%ì0ÀØ$A3íVç¾-ržÿꙊ€"BÀ–ñn‹œÓíYJr€›ÇYÍ/!Þþ.åïçj€ßïeá év¿±ÇÛ"çÌžRÏVE`~   K ÀÈHÝÝ>ôœ âäɼ»· Ç&*8`bþËÊ`É‹:PRâGyYUU#&$0“›-rf½—" (™@@ @–€Ž£!:þ õ…Øòf1Z[/ÄÐà0 Kò‘_˜Ï?–æ¿È}ÿ{ÈÒÁÿ¢z.[Ñ‹?¹© -KâX¾,ŒÂ‘Yí¶È9« èÅE@˜C”d èî.Á¦ÿ-ÂK/—`󿄇óÑÜØBÅ^‡¦%E¨­/DqE!IìÃ@_]džÑ~¨»wuâÝ8ÙÛúú¬þÓ^|òøâŠAäå {Ú=m‘ÓÓ‡Ö‹)Š€"0P`9ˆÅœå—cà ñÊ+5Œû¿õ‹ªpËÇ›pÕÕ•¸ðB?JŠä Lqþ¤N@<î&L¢§'‚wö 3Àûرí}ôöœàyí,û{ kîèDeåÌI€-rÎÃ1ª")Š€"0+(°˜ÄYùïÕ×Jñ÷O4âø‘,¬Z†•—±HÐÅhZZ„Pa„N~’åOT¾äþá&ÿI¹@w­?))écRÀžž6m:ŽßlìÀÑŽAôlÇ-«»ðغƒ¨­=`‹œ³2Âô¢Š€" ÌS”XLþóçÍøÊ×’(]ƒ††KÐÔ\„Û>ÕˆE²¶O2ýI…?ºû'˜þ×(ý3üÄ+ ÀC"1÷b¼þÚ)îGÑÓݶö7¹ЊçžëFqÑù9Ú"ç<£*–" (³‚€ €Ì¨_øù"Ü}wµÕ·¢¥e%J+{±úSuXÚTÎ9=“ù"ˆ'XüGJýJ@Ù¥âß„€_Sùžà„Ð×Ħ_µaçº0ØÁþo ¦noþþmŸ; °EÎYYzQE@Pæ9J,#ј¯½¶w¡ßGÑØp={?>r]W__Œü@BVú©æcLðC…Nó¿)þcRKÌÿDqÿ\"H²`Ë;Á(± K ;Øôr:;  ‡±÷ý_ãškÿ€obšàð”ÝÚ9§|=@P,E@ €eà÷oTãëS‹ÃíÍ\ó¿œ)}ƒ¨ZÅ7ÕÒùOVôÇî! 0Êß-þ;YÆ?_2ÈCx®3$Y‚02RŽ7~Û‹o‰²1ð!tvÿkï<†'ïFy9ó Ÿe³EÎ,×úXŠ€" L‰€‹@gg>\‡ÿ~±e«èàWJSÿ 'póMÍ(f™ùK¶?Fúêz·ðÔ©~; ÿ1:€KqH0¶méÃàk9èk‡ãߊu á/ï:‚`da‚Í9§z€" (YŒ€‹ÀÏž«ÄºuŽ-c|~=ýIZZøèµu4ÿ‡âU~zëõïZÆoB¢,˜'$H î àà¡(¶líBOß —Šàpi` o®¼j¾ýÔ1,]ʬ‚l¶È™ÅãZMP)P` hkÏÃC߬ÆK/^PÉbšêCTÖzï‡ÑÔ˜+¯¬FAÁˆÉ÷/^c @ÊqO”ÿD@Ž–ï%<ù)YˆŽ#IlßÖSLÄ8^ÕA,Ò Ç׊G×íÆ}÷8£ƒÙ"ç”#CPE ËP` xéå¸ïþ‹iŽ_°Ì¬ë;œî;¾:åñáU2ËŸ¬ß‹ ŒïÁã@GA'Æ(†òºÉD چѺó8"ш/!K ñÊID#m¸å–?â×Eâ±Ë¶È™åãZOP)P`èí-Äú§ðï”pÍ•±›ÔG€¦ûŠrË—/Di9¿£î7¡mÆ0ñßHÓ?|C bTúû÷žÄûïB,žÏ{2SoêKĺ±°ºÏ<½_-V×Â`‹œSŽ =@P@@ € ­-€¯üu ^ݸŒsð‹Üì}¢¦9-—õú@0‚E eÜ+¸$ç ^âýEÕOfî?³g'I¤`„ ú™0‰}{Ž£ûD„ßK„‰Y%?!þ¼ßz¢÷ÿÕ1„BnX -ræÀ¸ÖGTE`J”Ìs æø­Û.Àm·5¢»§–&úJšç]O_RLýü¤ °ØÆ¦Z”—JÌ?gë2)?CÿOžÄGfýŽã7>á¨Ý8ÖÑÇßó©ôI7!1Þ“¾æâ‡pûí}ø—oïE]Ý Y6°AÎ)G„ (Š@Ž  `ž€xÜ矿÷ÜS„X²™óó<*wÎðÍtÜï—?÷’!TWå#T@ÿ.ÄÒ—Î&J4ÚÓÍqžãljýè:чxLgÿ&™P˜äƒ‘(àµå¾G±äâ(^xn ËŸbq!;äÌ‘q­©(ŠÀ”(˜ç v°~}#ž|²Žz¸Édö-œ’ ¦{Çq úÐ=…”’„B!ÎÞÀ¿¹ÛäI€Ì%É b±$ú¬˜àϼž(zñ3$A`„CS?3úø½ãô ´ô(^yy'>IJÁ¶È9åˆÐE@È”Ìs02âÃCWáéï® ‡_³ñç½}Ôï.åío\ôÝï¹ô;̠àÉzä˜Tõ¿qIdNc aVdXŒ^<ìt.Q+ †hàÕùy’YßÃó?‹âÏomE$’°BNÇqý#tSE ×P`ø»+ñì³—S¹·0>_”ïØT?ã;±pc0Ênt—°³l¾$ÀY~2á^Î}Æ¢`HÁx_ ­R]p„Çä€n.ìdž >ÜyÇ[ˆFã°AN¿ŸÖÝE@PÌœQ,¿##q ÄqêT +.ÿýJB#¹Þ%Æ[^úî’c^”ÉYÖ‘½ôÜ]×gv?׆nøFž}æ Šz Ñ/m‡‰ú|\Çwÿâ¶•„ºU¹‰)ßÔp7³l ßXÜŒ®qÁ3=Ê$J˜(é…üM–ºxí=øþ÷b¸ëÎìD$È(˜Ù°Ñ³E [P`xè‘J|÷_/¥Ò½”*º„}O”ØÄDÌ„ìq¦ÏU|sŒ«ÈåXQð† Œ#†˜¯‘`ô_z¡KXg€DÂÇ L?Äs:X‹àüàIܹf;óÄaƒœµdË»KŸCPfˆ€€yN"Oýs{|!ï‡8C¯4Ê=ë?¶ýñTÉOàô'É|&)ì:ži|" å…Í=% €cDaÑ»øéO€?û„XVÈé0Û¡nŠ€" (®Û˜.ˆgŒm½{Ñ®ÝYV@1cë R 3ÝdÉõf»%˜yïÅ—êñ™;jØZWÑAï1Ô®Ó_0y€Ggû)ÉF•ºù¥€‰¢Ò‰ÃxJA`ÈÓ›ôCt¤3 ÃD@•Õð‹ŽâªUÆ‘Ð9%Ù‘nŠ€" (Jæ½€tÒ;‹që_|]-Œ·¯›ë?=½ïè:~*5ïéýh´ÀN€éC`’%cSÅOÚa|‚, ÜO°ËVžÂóÿÞŠ¥KúÌ…l‘S¾" (Š€+@ûá ¾ú@=^ü%3“W˜jóïVþa¦>*e1ÒÃÇrÀFɧëõ?y5ÀÉ ƒ©üÅîÀtÁL ä8'¸þ¿ŸùlÿôäÔÖ¸À9uà+Š€" (°‚ ñì÷ªYx âÑk ¸À˜äÝõ|Iý;J­áV<[5Àéu{™ûK@áIÉ h" ÚPT¸<’À—î}ÅE梶È9=ôhE@P²õ˜çN€©n÷ëW+qï—.EGûeôh¢¦â`Bü&LüïI•U7"€‘²à pý7ZZöáßž>ˆoj€§7[äô½ˆ" (# Àpìx1}¼ÿñúÄV1g)»¤ëMÅçK2.2àe®QÿtdúßDr~çòò·cíÚ~<¶®Õwéþ¶Èiñ˜UÑE@ð%–iíÿúÅ"üí7jp¸íà ÝXLµ\n Å’¬Æ'a ‰Ãô¼&Â3âTüô2He¹áÝXÜx?Ƨo?ÄTÃn)àôÍ9=AzE@P,E@ €E §§O¬_€nhBx蔥€|&é ILå¾³þ™v_¥•Áï—¬{Ydh+Ö¬âáObñ¢Î /e‹œÓÆAOPE ‹P`~׺û|ùk Øú&—"«HªÌ2@ÂϨ ÑcÞ× Ûét¾îïé1ðé?§×H-œ®"è£òO$3ÂÛXuUý¦ƒÕ7ï¦5@"&Þl‘3‹Æ²>Š" (ÓB@ €e âõß•ásŸ¯@çqfL0,ÐWå&ûu˜ª‡ýLD Qþ©<~6(»„ò¥œÓý$j`´Æ€OfúR'@" xN2Êà¿vþ¾ Õ‹vã㋟ÛÊ(©1ùf‹œÓ-y¾£i IDATz°" (Y„€Ë€ô½Íü[¶.À'o­Çðà•ðù/C4^N­Çe·¢ŸdýóIÊÞt‡@Z$–ìH-¸Eƒ$󟿟JÞw”×܌ꚃøâ——à«÷îDEÙás¶ÈyN£)Š€"e(°¤úàÖm`í]‹Ðq¸‘z~%Íôõt,!Uò’ûßìbª'HJè Tò3jþtW6±~âCÀïXXÎö;'ùë.žµuõñù{–ãë÷¿‹²’Ži[äœöƒé Š€" XŒ€‹ €Ô x{{¾õuøÝëeèoâ¼ýb. ”qi ß$î1åÍr¾XÂnÆ@“CÀ]$eÉŸ$9ð‘,ø|½´tòóòB­X¾rkÖ”áþ/lA~ÞùÒ±EN‹Ç±Š®(ŠÀ´P`1HµvûáRüøG5øŸ_±kÏDcuHÄÊ»_kBœÕ‹€/)å|ds €›H(ÂPB–úMÈçqöÀ ìCMÍ ®¿øì§›oØ?åšÿ¹ô<[ä<—gÑcE@°%Y@¤çá­·ó ™ø6nªÀŽ%LL"¬å4¿ŒG„øÉ\þ²< »Ìú1̽Ÿ{Íþ]ðç·¡¦¶W_Ç ËÃM7žBóâc¬†8¹·ÿt€-rN÷¹ôxE@PlC@ @–€TÇÊÇ»{ò°wŸƒ°kw¼Ÿþ¾0"®õÿ®õÓAÐAa(ŒŠª<47pýu¸üòa¬Xчšêgýý³ÖŸm‘sÖÐ +Š€"0Ç(È2êOR°««}} Йÿð‘:ë,ÀÈp˜©„ãœÕ;(,*ÀÂ…1Ô]xe¥QTTD©ôöçd¬[Ú"gÆÑ)Š€"!”d)ß æò—@€´ü?>†ÿ9L%ì0ÀØ$Aê}ÜÆ9ç!½³" (Þ   €Ì²ãqVóKˆ·¿ËDùû¹à÷{Y8hfÒ9gö”™;Û>:ýI€xÜM 44˜DOOïìfþ€÷±cÛûèí9ÁóÚYö÷ÖÜщÊÊ™wb[äôz€ÍÖõlÁSåÌÍq¤íîm»ÏÖ{D €Å Îʯ¾VŠ¿¢Ç4`aÕ2¬¼¬ˆE‚.FÓÒ"„ #tò“,¢úó%÷7ùOʺkýII L‡À“öôİiÓqüfcŽv ¢`;nYÝ…ÇÖDmíù“[䜭AæõumÁSåÌÍq¤íîm»{ýþH¿ž‹ Àþ¼_ùZÅ¡kÐÐp šš‹pÛ§±è¢Bò¡ÂöI¦?©ðGwÿÓÿ¥¦“ŸxxH$æã^Œ×_;Åý(zº»ÑÖþ&—ZñÜsÝ(.:?A[äœÍæåµmÁSåÌÍq¤íîm»{ùî-%aØ/ü|î¾;‚Úê[ÑÒ²¥•½Xý©:,m*眞É|Ä,þ#¥~¥  ìRñoBÀ¯©ü OpBèëbÓ¯Ú°ó]ì`ÿ7PS7€7ÿ6Š‹ÏØ"çl0/¯m ž*gnŽ#mwoÛÝËwÇd×R`ˆÆüxíµ¸û %ø>ŠÆ†ë©Øûñ‘ëB¸úúbä²ÒO5c‚vHšÿMñ“Xbþ'ŠûçA’ƒX6Ø FŽYbØÁ¦—;ÐÙQ€H8Œ½ïÿ×\ûüxÃÓ‡§ì›¶È9åƒÌ“lÁSåÌÍq¤íîm»gêµ£À2ðû7ªñõ¿©Åáöf®ù_Δ¾AT-ŒâÆ›jéü'+úã ÷åïÿ,ãŸ/ä!<×’,A)Ç¿íÅŽ·DÙ‡˜Nø:»ƒµwÃw£¼œù…ϲÙ"g¦ÚLïc ž*gnŽ#mwoÛ}¦ï‹s=_ €E ³3„®Ã¿ØˆŠ²Utð+¥© ‹¸ù¦f3¿Ìü%Û#ýFu½[xêT¿ÆÿÀ¥‚8$‡@Û¶ôapȵ ôµÃñoźG†ð—wA0H²0Áf‹œç:Hæú8[ðT9Ýq–kãHÛÝÛvÏäûF €EàgÏUbݺF Ç–1>¿žŠ~‚$-- |ôÚ:šÿÃFñË+èô6ÖëßµŒß„0DY 0N"H@ÜÀÁCQlÙÚ…ž¾A.+ÁáÒÀ@ß.\yÕ|û©cXº”Y'Øl‘3“m&÷²O•37Ç‘¶»·í>“wÅtÏU` hkÏÃC߬ÆK/^PÉbšêCTÖzï‡ÑÔ˜+¯¬FAÁˆÉ÷/^c @ÊqO”ÿD@Ž–ï%<ù)YˆŽ#IlßÖSLÄ8^ÕA,Ò Ç׊G×íÆ}÷8£¿Ù"çtÊ\o ž*gª‡äÖ8Òv÷¶Ý3ýžQ` xéå¸ïþ‹iŽ_°Ì¬ë;œî;¾:åñáU2ËŸ¬ß‹ ŒïRã@GA'Æ(†òºÉD چѺó8"ш/!K ñÊID#m¸å–?â×Eâ±Ë¶È™év¾÷³O•SÆPî#mwoÛý|ßç{ž @oo!Ö?Õ€ï|§„kþ+¨ŒÝ¤>B|4ÝW”;X¾|!JËùu¿ ý›h3†€‰ÿ–@šþá‹£Òß¿÷$Þïbñ|Þ“™‚xS_‚ Ö…Õxæéýøøj±¸[ä<ßÁ’éólÁSå<Ý3rii»{Ûî™~¿Èý”X@ÚÚøÊ_×àÕË8¿hÔ͈jšÓrY¯#XÔPƽ‚Kq6ªÄû‹ªŸÌÜfWK’H%À„ ô3 `ûöG÷‰¿WcÝ?!þ¼ßz¢÷ÿÕ1„BnX -rÎÅ@;Ÿ{Ú‚§Êyºusii»{ÛîçóŽ˜é9Jæ9süÖmà¶ÛÑÝSK}%Íó®§¿/)¦~~Ò PXìGcS-ÊK%柳u™”Ÿ¡ÿ'Oâ#³~Çñ‚pÔ‡ŽŽnëèãïùTú\p„ÄxOú˜‹Âí·÷á_¾½uuƒfÙÀ9g:`2u¾-xªœc{D®Œ#mwoÛ=Sï•ñ÷Q0Ï @<îÇóÏ_‚{î)B,ÙÌùy•;gøf:îÆ÷K‡{É‚ª«ò* —â éKg%íæ¸Ïñãĉ~tèC<&ƒ³“L(LòÁHðÚrߣXrq/<·…åƒO±¸rÎÕ@›î}mÁSåײ92Ž´Ý½m÷é¾¼:^ À<'á°ƒõëñä“uÔÃM&³?hà”Ü19:Ž[Їîy(,ˆ ”D  qöÎxþÍÝ&Od.In‹%Ñ7f…ÀæõDÑ‹Ÿ$ # šú™1ÐÇï§¥¥GñÊË;ñ!– ¶EN¯Îl_ÇÛï“É®¯`ž€‘z¸ Ow=üš¾ñÜ0Öü”·¿qÑw¿çr@Ðï0O@€ƒ>&ë‘cRÕÿÆY$a9E€†Y5b1zð°Ó¹F­`t€¢‚WççIf!|Ïÿ,Š?¿µ‘H 9Çõ˜ï›¶»ÛŸs­Ú2ŽTNoûç\½—”X@þîÁJ<ûìåTî-ŒÏå;6ÕÏxe&\ÀXŒ²Ý%lÀ,¤/ p–ŸL¸W£sŸ±(˜—îx_ ­R]p„Çä€n.ìdž >ÜyÇ[ˆFã°AN¿ŸÖ 6!6àiK»«œÒéso¼ÛÒîsõ^R`øFž}æ àK8—/Uê;ôù¸ŽïþE¿,ȸõŠ)ßÔp7³l ßXÜŒ®qÁMg:z”I”0Q~UÈßdi ‹×Þƒï/†»îÜAË €r ð´¥ÝUÎÜï¶´û\½—”X@z¤ßý×K©t/¥Š.¡%6±CŸ ÙãLŸ«øæW‘˱¢à GäW!.pçÿé@ÎÀ:$>fdú!žÓÁZïà?HâÎ5Û™7 ä Xd°O[Ú]åL€Üï¶´û\½—”Ìs‰8xꟛðØã ©x?Äz¥Qî©Xÿ´¹;§OSò8ýI2ŸIÊ»N…gæ !å…Í=% €cDaÑ»øéO€?û„XVÈé0Û¡ ›¶{z+IzËÜ蟶Œ#•ÓÛþ9Wï%%óœ$˜yïÅ—êñ™;jø¼Šzˆ¡~t~ü2€É<:ÛOuÐQ¥n>d)`¢h€tâ0žR˜—/ÓË¢8ÒÐa" ÊêøÅ GqÕªNãHhƒœ’ìȆMÛ}Ü vœõêtïήþiË8R9½íŸsõ^R0Ï €t³;‹që_|]-Œ·¯1©z?ØÒÓûŽ®ã§RóžžÑ†`z'ždIÁØDñ“vŸ K÷“ìIJ•§ðü¿·bé’>s![ä´Ø„§-í®rææx·¥Ýç⽤ÀÐ~8ˆ¯>P¹’ºý SíObþÝÊ?ÌÔG¥,FzøXØ(ùôb@c½þ'«0©O¹‹˜ÿÅîÀtÁL ä8'¸þ¿ŸùlÿôäÔÖ¸À9çb Ï=mÁSå<7ÅšmãHÛÝÛv?ŸwÄLÏQ` âÙïU³ðÄ£×2p1É»J[Rÿޏ…|Æ€™u™ûK@áIÉ h" ÚPT¸<’À—î}ÅEæ&¶È93D2w¶-xªœS÷‰lGÚîÞ¶ûÔWóþ%iö_¿Z‰{¿t):Ú/£@Õ0¿â7aâOz‹¬*¸‘ŒÅg€ëÿ»ÑÒ²ÿöôAÜxƒT<½Ù"§'àdà"¶à©rž½3dë8Òv÷¶Ý3ðJs %–€cÇ‹ñèãÍøŸÐ ¶Š9ûKÙ’®7Ÿ/É|¸`ÈÀYrþO»‡‰ú§£Óÿ&’Ãð;G—¿k×öã±uí¸¨¾kÌm‘sÚ0ÌÑ ¶à©rNÕA²si»{ÛîS]Íë¿+°„HÃÿ×/áo¿QƒÃmfØÝbªårS(–d5>)B’1LÏk <#NÅO/ƒäQ–ÞÅðøca|úöCL5ì–Nßl‘ÓëÁ4[׳O•sŠ¥ãHÛÝÛvŸ­÷ÈD×U`èé)Æëà‡šº†Ee) ŸIz„H…@S¹ïì…¦ÝÁheðû‡xÚ^ÚŠ5k£xøÁ“X¼¨sÂKÙ"ç´q˜£lÁSåœJdç8Òv÷¶Ý3ùšQ`ŽÑºû|ùk Øú&—"«HªÌ2@ÂϨ ÑcÞ× Ûét¾îïé1ðé?§×H-œ®"è£òO$3uðÛXuUý¦ƒÕ7ï¦5@"&Þl‘3“ƒm&÷²O•35nrki»{Ûî3yWLç\%–€x<ˆ×W†Ï}¾Ç™0Á°@_•›ì×aªVô3Fù§òøIØ ìÊ—rL÷ÈÑ>™éKÚP‰,à9É(ƒÿÚùû6T/ÚXŒ/~n+£ÏÚÏl‘s:ƒe.µO•37Ç‘¶»·íž©wË€tŒÍü[¶.À'o­Çðà•ðù/C4^N­Çe·¢ŸdýóIÊÞt‡@Z$–ìH-¸Eƒ$󟿟JÞw”×܌ꚃøâ——à«÷îDEÙásꟶÈyN3²O•37Ç‘¶»·íž‰WŽ @ªclÝvÖÞµ‡©çWÒL_O‡À€Q%/¹ÿÍ.¦z’¤„J%?£æO÷/£$>üŽeål¿s’¿îâY[QWŸ¿g9¾~ÿ»(+é˜v¿´EÎi?Ø` ž*gnŽ#mwoÛ}6_3J,&’/þííuøÖ?Ôáw¯—a ¿‰óö‹¹$PÆ¥|“¸Ç”6ËSb »Mw‘@–$u’äÀG²àóõÒÐÉÏÈ µbùÊ!¬YS†û¿°ùyçWHÇ9gs yym[ðT9ssi»{Ûî^¾;Æ_K €Å Õ˜í‡KñãÕà~Ä®=KÕ!+gì~­ LpV/>¾¤”ó‘Í%n"¡C Yê7!ŸÇiØ'°55ƒ¸þ೟n¾aÿ”kþçÒIm‘ó\že>c ž*gnŽ#mwoÛ}6Þ9J²€HÇÎÃ[o癌7U`ÇŽ¦ &HÖrš_Æ#Büd.Y]fýæÞϽfÿ.øóÛPSÛƒ«¯ã†åá¦O¡yñ1“{ûO·SÚ"çtŸk®Ž·O•37Ç‘¶»·íîõ{F @–€TÇÊÇ»{ò°wŸƒ°kw¼Ÿþ¾0"®õÿ®õÓAÐAa(ŒŠª<47pýu¸üòa¬Xчšêgýý^÷·®g‹œ³€Ç¶O•ÓÛ†Wµ€,%ã;F"Á\þ–ÿÇÇð?‡©„æ›$h¦ÝêüÏ·EÎóÂÌži ž*§·ýBñÌM<§ûÔJr€Èì g5¿„xû» @”¿Ÿ«~¿—…ƒ¦ÛýÆo‹œ3{ÊÌm ž*§·}BñÌM<Ïç©•d) ¢»Û‡ž“Aœó\Å37ñœéS+È2Ðq4DÇ¿´þ±[Þ,Fkë…FaI>ò óâÇÂü¡ïoQ:ø_TïÃe+zñ'7µ¡eIË—…QX82Ó¾uÖóm‘sVAððâ¶à©rzØè¼”â™›xzõÔJ²„tw—`ÓÿᥗK°ys ÂÃùhnl¡b¯CÓ’"ÔÖ¢¸"ˆ‚¤ öa /‰®cÃh?ԇݻ:ñÎîœìíF}}Vÿi/>ù‰a\qÅ òò†½êkæ:¶ÈééCÏâÅlÁSåÌÍq¤íîm»{ý*Q`9ˆÅœå—cà ñÊ+5Œû¿õ‹ªpËÇ›pÕÕ•¸ðB?JŠä Lqþ¤N@<î&L¢§'‚wö 3Àûرí}ôöœàyí,û{ kîèDeåÌ;±-rz=Àfëz¶à©rææ8Òv÷¶Ýgë=¢Àbgå¿W_+Åß?шãG°°jV^VÄ"A£iiB…R\²ü‰êÏ—Ü?Üä?)è®õ'%%0cL ØÓæMÇñ›8Ú1ˆþí¸eu[wµµçOl‘s¶™××µO•37Ç‘¶»·íîõû#ýzJ,&ÿùóf|åkI‡®ACÃ%hj.ÂmŸjÄ¢‹ Yȇ Û'™þ¤BÝýLÿk”þ™N~âà!‘˜{1^í÷£èéîF[û›\ hÅsÏu£¸èüm‘s6š—×¶O•37Ç‘¶»·íîå»cüµ”XH„a¿ðóE¸ûîj«oEKËJ”Vöbõ§ê°´©œsz&ó DO°ø”ú•*€²KÅ¿ ¿¦ò7<Á ¡¯?ˆM¿jÃÎ?ta°7‚ýÞ@MÝÞüýÛ(.>w`‹œ³9À¼¼¶-xªœ¹9Ž´Ý½mw/ß“]K €e óãµ×àî/” àû(®§bïÇG® áêë‹‘HÈJ?Õ|Œ ~Ø!iþ7ÅL `‰ùŸ(îŸKI bÙ`'E8d‰a›^î@gG"á0ö¾ÿk\síðã CLž²oÚ"ç”2O°O•37Ç‘¶»·íž©×ŽËÀïߨÆ×ÿ¦‡Û›¹æ9SúQµ0Šoª¥óŸ¬è/ÜC`”¿[üw²Œ¾d‡ð\gH²ad¤oü¶;Þeb:áCèìþ ÖÞy O<Þòræ>Ëf‹œ™h3½-xªœ¹9Ž´Ý½m÷™¾/Îõ|%€ÎÎ|¸ÿýb#*ÊVÑÁ¯”¦þA4,Nàæ›šQÌ<þ2ó—lŒôÕõnà©Sýw@þct— âalÛÒ‡Á!×r0Ð×Ç¿ëÂ_ÞuÁ É›-ržë ™ëãlÁSåtÇY®#mwoÛ=“ï%€Ÿ=W‰uë1[Æøüz*ú’´´$ðÑkëhþÅ/¯ ÓÛX¯×0~ÂeÀ<8‰ @q_E±ekzú¹¬P‡K}»påU;ðí§ŽaéRfœ`³EÎL´™ÜË®¼²#&ß¿xŒ%)Ç=Qþ9Z¾—ð@Zä§d!:Ž$±}[N1iãxU±H/_+]·÷ÝwâŒþf‹œÓ(su¼-xªœ©’[ãHÛÝÛvÏô{F €%ॗà¾û/¦9~9üÁ2³®ïpºïøFè”ćW]È,²~/€t0¾KM@Œk£:Èë&%h?FëÎãˆD ¾„,)Ä+'´á–[þˆ\ ‹Æ.Ø"g¦ÚùÞÏŒ`QC÷ . ÄÙ¨ï/ª~2sÿ™]-I •&LÐÏ,€IìÛsÝ'"ü^<\I ŒuSü†øó|ë‰ÜÿWÇ ¹a¶È9í|îi ž*çéÖÍ¥q¤íîm»ŸÏ;b¦ç(˜ç@Ìñ[·]€ÛnkDwO-Mô•4Ï»žþ¾¤˜úùI+@a±Mµ(/•˜ÎÖeR~†þŸ<‰ÌúÇo|ÂQ::ºq¬£¿çSésIÀã=é{`.~·ßÞ‡ùö^ÔÕ šeäœé€ÉÔù¶à©rŽí¹2Ž´Ý½m÷L½WÆßG À<'ñ¸Ï? î¹§±d3ççyTîœá›é¸ß/~î% B¨®ÊG¨€þ\ˆ'$¤/L”h´K˜ã<Ç'úÑu¢ñ˜ ÎþM2¡0É#PÀkË}bÉÅQ¼ðÜ–>ÅâBvÈ9Wmº÷µO•s\ËæÈ8Òv÷¶Ý§û~ðêx%óœ„ÃÖ¯oÄ“OÖQ7™Ìþ €SrCÄäè8nAºç¡° ‚RP(ÄÙ;ãø7w›< ¹$¹A,–Dß@˜ü™×E/~’$Œ0phêgÆ@¿wœ”–Å+/ïćX6Ø9½8³}[ðT9Çö„\GÚîÞ¶ûl¿O&»¾€yNFF|xèá*<ýÝôðk6~øÆsÃXóSÞþÆEßýžËA¿Ã<: ú˜¬GŽIUÿg„Aæ4fE@ÖˆÅèÀÃNçµ€ÑR`ˆ^Ÿ'™…ð=<ÿ³(þüÖVD" +ät×?b¾oÚînεþiË8R9½íŸsõ^R`ø»+ñì³—S¹·0>_”ïØT?ã•™pc0Ênt—°³l¾$ÀY~2á^Î}Æ¢`^ºã}‚´>HuÁ“?Jº¹°6øpço!Ã9ý~ZO,؄؀§-í®rJ§Ï½ñnK»ÏÕ{I € àxö™+8€/á\¾`T©OìÐçã:¾ûQü² ã~tÖ+¦|SÀÝ̲(|c9p3ºÆ7éèQ&PÂDDøU!“¥.^{¾ÿ½îºs-$ÈXD,ÀÓ–vW9ss¼ÛÒîsõ^R`xè‘J|÷_/¥Ò½”*º„JX”ØÄ}&d3}®â›c\E.ÇŠ‚7l`_…¸Àÿ§9Kë Hø˜!é‡xNk¼ƒü ‰;×lgÞ€Ÿ£ çIDAT8l3`‘ÀMÉOàô'É|&)ì:ž™7@„”6÷”D@$ŽIt…Eïâ§?þìbHX!§Ãl‡6lÚîé­$é-s£Ú2ŽTNoûç\½—”Ìs`æ½_ªÇgî¨áKð*:è] †úÑuúñË&ðèl?ÕAG•ºù¥€‰¢Ò‰ÃxJA`^¾L,kˆâHg@‡‰€*«à/ÅU«:#¡ rJ²#6m÷q/ØqÖ«Ó½;»ú§-ãHåô¶ÎÕ{I À<'ÒÍvì,Æ­ñtu¶0޾Ƥêý`KOï;ºŽŸJÍ{zF?züN€éx’%cSÅOÚa|‚, ÜO°ËVžÂóÿÞŠ¥KúÌ…l‘Ó`ž¶´»Ê™›ãÝ–vŸ‹÷’ @ûá ¾ú@=^üåJêö+Lµ?‰ùw+ÿ0S•²éác9`£äÓ‹õúŸ¬À¤>æ.bþ»Ó31ãœàúÿf|æ³üÓ“{P[ã[䜋v>÷´O•óÜk¶#mwoÛý|Þ3=G €`x$ˆg¿WÍrÀK^ËPÀÆ$ï*mIý;JàòKfÖEdî/U…W$%+ ‰,hCQáf<òH_º÷= ˜›Ø"çÌÉÜÙ¶à©rNÝ'²qi»{ÛîS_Íû#”X@¤Ùýj%îýÒ¥èh¿Œ~MTÃTüBLˆß„‰ÿ=é-²ªàF0@œ®ÿïFKË>üÛÓqã R ðôf‹œž€“‹Ø‚§ÊyöέãHÛÝÛvÏÀ+eÌ-”XBŽ/Æ£7ã?~B?€Ø*æì/eCJºÞT|¾$óár€!gÉù?í&꟎VLÿ›HÃïA^þv¬]ÛÇÖµã¢ú®1W´EÎiÃ0G'Ø‚§Ê9UÉÎq¤íîm»Ou5¯ÿ®À ÿ_¿X„¿ýF ·}˜aw‹©–ËM! X’Õø¤I"Ä0=¯ €ðŒ8?½ ’GYnx77Àã…ñéÛ1Õ°[ 8}³EN¯Ól]Ï÷ù tgfÀÃ}Un²_‡©zXÑÏDåŸÊã'aƒ²K(_Êi0ÝO@"Fk ød¦/iC%²€ç$£ þkçïÛP½h7x`1¾ø¹­ŒÔÔ âú€Ï~¸ù†ýS®ùŸK'µEÎsy–ùpŒ-xªœ¹9Ž´Ý½m÷Ùxç(È cx8o½g2nÜT;J˜6˜D YËi~ñ“¹üey@v™õc˜{?÷>šý»àÏoCMm®¾6Ž>–‡›n<…æÅÇLîí?ÝNi‹œÓ}®¹:ÞúûˆD¸Öoü¸ÖOAp…¡0*ªòÐÜÀõ×uâòˇ±bEjª#œõ÷{Ýß>¸ž-rÎ_ØR‡c3•pœ³z…EX¸0†º £¬4ŠŠŠ(•>Ãþü¯ú×”×±EÎ)dž` ž*§·FñÌMòFn[þïo¯ÞYLó(ä /ÏAÀ¯³,Š€" (Ù‡@,žD$’Àð0­\¸îc›s›¼ú«+wŽÎþƒ4ÿ;\(Ð%€ìëøúDŠ€" ä2²àÊ~tÔ 0<ÇÍ«·å6øÅÿ÷¡y4ýç}ðsöï£@vÝE@PlA@¢R‘B"\ ¸íÿÙž³ Ć-úÙOWþQÌþâüç8ÜUùgK×çPE@HC Aàâ çrÀÚ»v^Æ?KÀ0÷¬ð!SQ†üø‡—¶ÅÏ83ó×é¿E@PlD€&±$à—àŸÿBë¥i ÌŸeqϺ0@ L…æóg øýÿ³â”Î7“µdc·×gRE@e€ üáÿ½o×2þšÊ Ê?•@rdU!) À¹þÏ3Ë÷Å* »ü]v! š0ƒ>£" (Ù‹@J™‹b—=eê—5ÿÔì?µþŸ:&«€ÌïÓ³¦gå/»Xä{Ù%k ¯vìúdŠ€" ä2ß….ëú¢àS3}Qú©=eúOOüÁjÁl”)›NR)ÓýDùË>~öŸ)ùf _½®" (Š@n#"BR3ü H_÷O)ÿ”`V€tRô©¿|ŽWþjÈíA£O¯(Š@6 ŠÜdµ¤H€(üÔžú.]ùgo H)}± ¤¯û§”¿Z²¡ûë3(Š€"»¤@j]?}9 ]ñWþYC¤éM”?÷”s_Ê' µÞŸþ}êØÜí2ú䊀" (Ù‚ÀD$ ERŠ?ERÇÎú³gr†®ÔS3üñJ_gþ³ÞäzE@P9@ ¤ûˆâOý.be%H·Œ·Èï©¿)É$9™ƒ¾ ·TE@ÈRæüÔg*ÉOJù§ÿ}ÖMÿ)ÌçBÉŽWð)ü¹+Gú¡>¦" (ŠÀ ®ØÇ‚ñ¿gD¼¹T´ãï=—²dl½‰" (Š€"0jæO"c³þô›ªÒÕ¾¨(Š€" ä Jr°Ñõ‘E@P%ÚE@PD@ @6º>²" (Š€" @û€" (Š€"ƒ(ÈÁF×GVE@P”hPE@Pr%9ØèúÈŠ€" (Š€íŠ€" (Š@"  ]YPE@P }@PE@ÈA”ä`£ë#+Š€" (J´(Š€" (9ˆ€€lt}dE@PE@ €öE@PE Pƒ®¬(Š€" (Ð> (Š€" ä Jr°Ñõ‘E@P%ÚE@PD@ @6º>²" (Š€" @û€" (Š€"ƒ(ÈÁF×GVE@PþcFÿ5™IEND®B`‚golly-2.7-src/gui-android/Golly/assets/0000755000175000017500000000000012536111546015074 500000000000000golly-2.7-src/gui-android/Golly/assets/readme.txt0000644000175000017500000000077612536111364017022 00000000000000Files added to the assets folder are automatically included in Golly.apk. Note that the following zip archives must be added: Help.zip -- compressed copy of golly/gui-common/Help Patterns.zip -- compressed copy of golly/Patterns Rules.zip -- compressed copy of golly/Rules These zip files will be unzipped and copied into appropriate directories in internal storage (see initPaths in BaseApp.java). The zip files are not included in the git repository (it would be an unnecessary waste of space). golly-2.7-src/gui-android/Golly/assets/triangle-right.png0000644000175000017500000000024712536111364020443 00000000000000‰PNG  IHDR &2Ù !tEXtSoftwareGraphicConverter (Intel)w‡úAIDATxœbøO`€P'Nœ _sjŠfRÀ¢™x#pj&Æš!€¾6“ég2C›Ìx¦(…‘ÿÿœ¸7€Ðú{IEND®B`‚golly-2.7-src/gui-android/Golly/assets/triangle-down.png0000644000175000017500000000027512536111364020276 00000000000000‰PNG  IHDR &2Ù !tEXtSoftwareGraphicConverter (Intel)w‡úWIDATxœ¤ÐÁ AK·<ºB>ˆÀA¸¯ÙŒºx°5‰hÇ»§@Nb|íOXÖoî²Oüã9Ëæ·[¬5Yk–N,x…ubÁ+¥×wÿÿá¸7€0\IEND®B`‚golly-2.7-src/gui-android/Golly/jni/0000755000175000017500000000000012536111546014352 500000000000000golly-2.7-src/gui-android/Golly/jni/jnicalls.h0000644000175000017500000000672412536111364016251 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #ifndef _JNICALLS_H_ #define _JNICALLS_H_ #include // for std::string // for displaying info/error messages in LogCat #include #define LOG_TAG "Golly" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) // Routines for calling C++ from Java and vice versa: void UpdatePattern(); // Redraw the current pattern. void UpdateStatus(); // Redraw the status bar info. void PauseGenerating(); // If pattern is generating then temporarily pause. void ResumeGenerating(); // Resume generating pattern if it was paused. std::string GetRuleName(const std::string& rule); // Return name of given rule (empty string if rule is unnamed). void UpdateEditBar(); // Update Undo and Redo buttons, show current drawing state and touch mode. void BeginProgress(const char* title); bool AbortProgress(double fraction_done, const char* message); void EndProgress(); // These calls display a progress bar while a lengthy task is carried out. void SwitchToPatternTab(); // Switch to main screen for displaying/editing/generating patterns. void ShowTextFile(const char* filepath); // Display contents of given text file in a modal view. void ShowHelp(const char* filepath); // Display given HTML file in Help screen. void AndroidWarning(const char* msg); // Beep and display message in a modal dialog. bool AndroidYesNo(const char* msg); // Similar to Warning, but there are 2 buttons: Yes and No. // Returns true if Yes button is hit. void AndroidFatal(const char* msg); // Beep, display message in a modal dialog, then exit app. void AndroidBeep(); // Play beep sound, depending on user setting. void AndroidRemoveFile(const std::string& filepath); // Delete given file. bool AndroidMoveFile(const std::string& inpath, const std::string& outpath); // Return true if input file is successfully moved to output file. // If the output file existed it is replaced. void AndroidFixURLPath(std::string& path); // Replace "%..." with suitable chars for a file path (eg. %20 is changed to space). void AndroidCheckEvents(); // Run main UI thread for a short time so app remains responsive while doing a // lengthy computation. Note that event_checker is > 0 while in this routine. bool AndroidCopyTextToClipboard(const char* text); // Copy given text to the clipboard. bool AndroidGetTextFromClipboard(std::string& text); // Get text from the clipboard. bool AndroidDownloadFile(const std::string& url, const std::string& filepath); // Download given url and create given file. #endif golly-2.7-src/gui-android/Golly/jni/jnicalls.cpp0000644000175000017500000024165512536111364016610 00000000000000/*** / This file is part of Golly, a Game of Life Simulator. Copyright (C) 2013 Andrew Trevorrow and Tomas Rokicki. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Web site: http://sourceforge.net/projects/golly Authors: rokicki@gmail.com andrew@trevorrow.com / ***/ #include // for calling Java from C++ and vice versa #include // for OpenGL ES 1.x calls #include // for usleep #include // for std::string #include // for std::list #include // for std::set #include // for std::count #include "utils.h" // for Warning, etc #include "algos.h" // for InitAlgorithms #include "prefs.h" // for GetPrefs, SavePrefs, userdir, etc #include "layer.h" // for AddLayer, ResizeLayers, currlayer #include "control.h" // for SetMinimumStepExponent #include "file.h" // for NewPattern #include "render.h" // for DrawPattern #include "view.h" // for widescreen, fullscreen, TouchBegan, etc #include "status.h" // for UpdateStatusLines, ClearMessage, etc #include "undo.h" // for ClearUndoRedo #include "jnicalls.h" // ----------------------------------------------------------------------------- // these globals cache info for calling methods in .java files static JavaVM* javavm; static jobject baseapp = NULL; // instance of BaseApp static jmethodID baseapp_Warning; static jmethodID baseapp_Fatal; static jmethodID baseapp_YesNo; static jobject mainobj = NULL; // current instance of MainActivity static jmethodID main_StartMainActivity; static jmethodID main_RefreshPattern; static jmethodID main_ShowStatusLines; static jmethodID main_UpdateEditBar; static jmethodID main_CheckMessageQueue; static jmethodID main_PlayBeepSound; static jmethodID main_RemoveFile; static jmethodID main_MoveFile; static jmethodID main_CopyTextToClipboard; static jmethodID main_GetTextFromClipboard; static jmethodID main_ShowHelp; static jmethodID main_ShowTextFile; static jmethodID main_BeginProgress; static jmethodID main_AbortProgress; static jmethodID main_EndProgress; static jobject helpobj = NULL; // current instance of HelpActivity static jmethodID help_DownloadFile; static bool rendering = false; // in DrawPattern? static bool paused = false; // generating has been paused? static bool touching_pattern = false; // is pattern being touched? static bool highdensity = false; // screen density is > 300dpi? // ----------------------------------------------------------------------------- // XPM data for digits 0 to 9 where each digit is a 10x10 icon // so we can use CreateIconBitmaps static const char* digits[] = { /* width height ncolors chars_per_pixel */ "10 100 16 1", /* colors */ "A c #FFFFFF", "B c #EEEEEE", "C c #DDDDDD", "D c #CCCCCC", "E c #BBBBBB", "F c #AAAAAA", "G c #999999", "H c #888888", "I c #777777", "J c #666666", "K c #555555", "L c #444444", "M c #333333", "N c #222222", "O c #111111", ". c #000000", // black will be transparent /* pixels */ "AAAAAA....", "AGMMBA....", "CMBFKA....", "HIAAOA....", "JFAANB....", "IFAANA....", "FJACLA....", "ALLODA....", "AACAAA....", "AAAAAA....", "AAAAAA....", "AAFIAA....", "AIOIAA....", "AGKIAA....", "AAGIAA....", "AAGIAA....", "AAGIAA....", "AAGIAA....", "AAAAAA....", "AAAAAA....", "AAAAAA....", "AINLFA....", "EMADNA....", "FGAAOB....", "AABIJA....", "AEMGAA....", "ELAAAA....", "IONMNB....", "AAAAAA....", "AAAAAA....", "AAAAAA....", "AKNLDA....", "FKAGJA....", "FDAELA....", "AAJOFA....", "BAAEOA....", "IFABNA....", "CMLLFA....", "AABBAA....", "AAAAAA....", "AAAAAA....", "AABNDA....", "AAJODA....", "AEKLDA....", "BMBKDA....", "KIFMHB....", "EFGMHB....", "AAAKDA....", "AAAAAA....", "AAAAAA....", "AAAAAA....", "ANNNKA....", "BLBBBA....", "DJCBAA....", "FNJLHA....", "ABABNB....", "FFABMA....", "CMKLFA....", "AABAAA....", "AAAAAA....", "AAAAAA....", "AFLMFA....", "BMBCMA....", "GICBCA....", "IMKMHA....", "IJAANB....", "GJAANA....", "AJLLFA....", "AABAAA....", "AAAAAA....", "AAAAAA....", "JNNNND....", "BCCEMB....", "AAAKEA....", "AAEKAA....", "AAMCAA....", "ADLAAA....", "AHHAAA....", "AAAAAA....", "AAAAAA....", "AAAAAA....", "AINLDA....", "DMAGKA....", "EKADLA....", "BMNOFA....", "HJADNA....", "HHAANB....", "BMLLGA....", "AACAAA....", "AAAAAA....", "AAAAAA....", "AINLBA....", "FKBGKA....", "IGABNA....", "FJBFOB....", "AGKIMA....", "EFADKA....", "CLKMCA....", "AABAAA....", "AAAAAA...."}; static gBitmapPtr* digits10x10; // digit bitmaps for displaying state numbers // ----------------------------------------------------------------------------- jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env; javavm = vm; // save in global if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { LOGE("GetEnv failed!"); return -1; } return JNI_VERSION_1_6; } // ----------------------------------------------------------------------------- static JNIEnv* getJNIenv(bool* attached) { // get the JNI environment for the current thread JNIEnv* env; *attached = false; int result = javavm->GetEnv((void **) &env, JNI_VERSION_1_6); if (result == JNI_EDETACHED) { if (javavm->AttachCurrentThread(&env, NULL) != 0) { LOGE("AttachCurrentThread failed!"); return NULL; } *attached = true; } else if (result == JNI_EVERSION) { LOGE("GetEnv: JNI_VERSION_1_6 is not supported!"); return NULL; } return env; } // ----------------------------------------------------------------------------- static std::string ConvertJString(JNIEnv* env, jstring str) { const jsize len = env->GetStringUTFLength(str); const char* strChars = env->GetStringUTFChars(str, 0); std::string result(strChars, len); env->ReleaseStringUTFChars(str, strChars); return result; } // ----------------------------------------------------------------------------- static void CheckIfRendering() { int msecs = 0; while (rendering) { // wait for DrawPattern to finish usleep(1000); // 1 millisec msecs++; } // if (msecs > 0) LOGI("waited for rendering: %d msecs", msecs); } // ----------------------------------------------------------------------------- void UpdatePattern() { // call a Java method that calls GLSurfaceView.requestRender() which calls nativeRender bool attached; JNIEnv* env = getJNIenv(&attached); if (env) env->CallVoidMethod(mainobj, main_RefreshPattern); if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- void UpdateStatus() { if (fullscreen) return; UpdateStatusLines(); // sets status1, status2, status3 // call Java method in MainActivity class to update the status bar info bool attached; JNIEnv* env = getJNIenv(&attached); if (env) env->CallVoidMethod(mainobj, main_ShowStatusLines); if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- void PauseGenerating() { if (generating) { StopGenerating(); // generating is now false paused = true; } } // ----------------------------------------------------------------------------- void ResumeGenerating() { if (paused) { StartGenerating(); // generating is probably true (false if pattern is empty) paused = false; } } // ============================================================================= // these native routines are used in BaseApp.java: extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_BaseApp_nativeClassInit(JNIEnv* env, jclass klass) { // get IDs for Java methods in BaseApp baseapp_Warning = env->GetMethodID(klass, "Warning", "(Ljava/lang/String;)V"); baseapp_Fatal = env->GetMethodID(klass, "Fatal", "(Ljava/lang/String;)V"); baseapp_YesNo = env->GetMethodID(klass, "YesNo", "(Ljava/lang/String;)Ljava/lang/String;"); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_BaseApp_nativeCreate(JNIEnv* env, jobject obj) { // save obj for calling Java methods in instance of BaseApp if (baseapp != NULL) env->DeleteGlobalRef(baseapp); baseapp = env->NewGlobalRef(obj); SetMessage("This is Golly 1.1 for Android. Copyright 2014 The Golly Gang."); if (highdensity) { MAX_MAG = 6; // maximum cell size = 64x64 } else { MAX_MAG = 5; // maximum cell size = 32x32 } InitAlgorithms(); // must initialize algoinfo first GetPrefs(); // load user's preferences SetMinimumStepExponent(); // for slowest speed AddLayer(); // create initial layer (sets currlayer) NewPattern(); // create new, empty universe digits10x10 = CreateIconBitmaps(digits,11); // 1st "digit" is not used } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_BaseApp_nativeSetUserDirs(JNIEnv* env, jobject obj, jstring path) { userdir = ConvertJString(env, path) + "/"; // userdir = /mnt/sdcard/Android/data/net.sf.golly/files if external storage // is available, otherwise /data/data/net.sf.golly/files/ on internal storage // set paths to various subdirs (created by caller) userrules = userdir + "Rules/"; savedir = userdir + "Saved/"; downloaddir = userdir + "Downloads/"; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_BaseApp_nativeSetSuppliedDirs(JNIEnv* env, jobject obj, jstring path) { supplieddir = ConvertJString(env, path) + "/"; // supplieddir = /data/data/net.sf.golly/files/Supplied/ // set paths to various subdirs (created by caller) helpdir = supplieddir + "Help/"; rulesdir = supplieddir + "Rules/"; patternsdir = supplieddir + "Patterns/"; // also set prefsfile here by replacing "Supplied/" with "GollyPrefs" prefsfile = supplieddir.substr(0, supplieddir.length() - 9) + "GollyPrefs"; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_BaseApp_nativeSetTempDir(JNIEnv* env, jobject obj, jstring path) { tempdir = ConvertJString(env, path) + "/"; // tempdir = /data/data/net.sf.golly/cache/ clipfile = tempdir + "golly_clipboard"; /* assume nativeSetTempDir is called last LOGI("userdir = %s", userdir.c_str()); LOGI("savedir = %s", savedir.c_str()); LOGI("downloaddir = %s", downloaddir.c_str()); LOGI("userrules = %s", userrules.c_str()); LOGI("supplieddir = %s", supplieddir.c_str()); LOGI("patternsdir = %s", patternsdir.c_str()); LOGI("rulesdir = %s", rulesdir.c_str()); LOGI("helpdir = %s", helpdir.c_str()); LOGI("tempdir = %s", tempdir.c_str()); LOGI("clipfile = %s", clipfile.c_str()); LOGI("prefsfile = %s", prefsfile.c_str()); */ } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_BaseApp_nativeSetScreenDensity(JNIEnv* env, jobject obj, jint dpi) { highdensity = dpi > 300; // my Nexus 7 has a density of 320dpi } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_BaseApp_nativeSetWideScreen(JNIEnv* env, jobject obj, jboolean iswide) { widescreen = iswide; } // ============================================================================= // these native routines are used in MainActivity.java: extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeClassInit(JNIEnv* env, jclass klass) { // get IDs for Java methods in MainActivity main_StartMainActivity = env->GetMethodID(klass, "StartMainActivity", "()V"); main_RefreshPattern = env->GetMethodID(klass, "RefreshPattern", "()V"); main_ShowStatusLines = env->GetMethodID(klass, "ShowStatusLines", "()V"); main_UpdateEditBar = env->GetMethodID(klass, "UpdateEditBar", "()V"); main_CheckMessageQueue = env->GetMethodID(klass, "CheckMessageQueue", "()V"); main_PlayBeepSound = env->GetMethodID(klass, "PlayBeepSound", "()V"); main_RemoveFile = env->GetMethodID(klass, "RemoveFile", "(Ljava/lang/String;)V"); main_MoveFile = env->GetMethodID(klass, "MoveFile", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); main_CopyTextToClipboard = env->GetMethodID(klass, "CopyTextToClipboard", "(Ljava/lang/String;)V"); main_GetTextFromClipboard = env->GetMethodID(klass, "GetTextFromClipboard", "()Ljava/lang/String;"); main_ShowHelp = env->GetMethodID(klass, "ShowHelp", "(Ljava/lang/String;)V"); main_ShowTextFile = env->GetMethodID(klass, "ShowTextFile", "(Ljava/lang/String;)V"); main_BeginProgress = env->GetMethodID(klass, "BeginProgress", "(Ljava/lang/String;)V"); main_AbortProgress = env->GetMethodID(klass, "AbortProgress", "(ILjava/lang/String;)Z"); main_EndProgress = env->GetMethodID(klass, "EndProgress", "()V"); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeCreate(JNIEnv* env, jobject obj) { // save obj for calling Java methods in this instance of MainActivity if (mainobj != NULL) env->DeleteGlobalRef(mainobj); mainobj = env->NewGlobalRef(obj); UpdateStatus(); // show initial message } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeDestroy(JNIEnv* env) { // the current instance of MainActivity is being destroyed if (mainobj != NULL) { env->DeleteGlobalRef(mainobj); mainobj = NULL; } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_MainActivity_nativeGetStatusLine(JNIEnv* env, jobject obj, jint line) { switch (line) { case 1: return env->NewStringUTF(status1.c_str()); case 2: return env->NewStringUTF(status2.c_str()); case 3: return env->NewStringUTF(status3.c_str()); } return env->NewStringUTF("Fix bug in nativeGetStatusLine!"); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_MainActivity_nativeGetStatusColor(JNIEnv* env) { unsigned char r = algoinfo[currlayer->algtype]->statusrgb.r; unsigned char g = algoinfo[currlayer->algtype]->statusrgb.g; unsigned char b = algoinfo[currlayer->algtype]->statusrgb.b; // return status bar color as int in format 0xAARRGGBB return (0xFF000000 | (r << 16) | (g << 8) | b); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_MainActivity_nativeGetPasteMode(JNIEnv* env) { return env->NewStringUTF(GetPasteMode()); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_MainActivity_nativeGetRandomFill(JNIEnv* env) { char s[4]; // room for 0..100 sprintf(s, "%d", randomfill); return env->NewStringUTF(s); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeAllowUndo(JNIEnv* env) { return allowundo; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeCanUndo(JNIEnv* env) { return currlayer->undoredo->CanUndo(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeCanRedo(JNIEnv* env) { return currlayer->undoredo->CanRedo(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeInfoAvailable(JNIEnv* env) { return currlayer->currname != "untitled"; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeUndo(JNIEnv* env) { if (generating) Warning("Bug: generating is true in nativeUndo!"); CheckIfRendering(); currlayer->undoredo->UndoChange(); UpdateEverything(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeRedo(JNIEnv* env) { if (generating) Warning("Bug: generating is true in nativeRedo!"); CheckIfRendering(); currlayer->undoredo->RedoChange(); UpdateEverything(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeCanReset(JNIEnv* env) { return currlayer->algo->getGeneration() > currlayer->startgen; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeResetPattern(JNIEnv* env) { CheckIfRendering(); ResetPattern(); UpdateEverything(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativePauseGenerating(JNIEnv* env) { PauseGenerating(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeResumeGenerating(JNIEnv* env) { ResumeGenerating(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeStartGenerating(JNIEnv* env) { if (!generating) { StartGenerating(); // generating might still be false (eg. if pattern is empty) // best to reset paused flag in case a PauseGenerating call // wasn't followed by a matching ResumeGenerating call paused = false; } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeStopGenerating(JNIEnv* env) { if (generating) { StopGenerating(); // generating is now false } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeIsGenerating(JNIEnv* env) { return generating; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeGenerate(JNIEnv* env) { if (paused) return; // PauseGenerating has been called if (touching_pattern) return; // avoid jerky pattern updates // play safe and avoid re-entering currlayer->algo->step() if (event_checker > 0) return; // avoid calling NextGeneration while DrawPattern is executing on different thread if (rendering) return; NextGeneration(true); // calls currlayer->algo->step() using current gen increment UpdatePattern(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeStep(JNIEnv* env) { NextGeneration(true); UpdatePattern(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_MainActivity_nativeCalculateSpeed(JNIEnv* env) { // calculate the interval (in millisecs) between nativeGenerate calls int interval = 1000/60; // max speed is 60 fps // increase interval if user wants a delay if (currlayer->currexpo < 0) { interval = GetCurrentDelay(); } return interval; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeStep1(JNIEnv* env) { // reset step exponent to 0 currlayer->currexpo = 0; SetGenIncrement(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeFaster(JNIEnv* env) { // go faster by incrementing step exponent currlayer->currexpo++; SetGenIncrement(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeSlower(JNIEnv* env) { // go slower by decrementing step exponent if (currlayer->currexpo > minexpo) { currlayer->currexpo--; SetGenIncrement(); } else { Beep(); } UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeStopBeforeNew(JNIEnv* env) { // NewPattern is about to clear all undo/redo history so there's no point // saving the current pattern (which might be very large) bool saveundo = allowundo; allowundo = false; // avoid calling RememberGenFinish if (generating) StopGenerating(); allowundo = saveundo; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeNewPattern(JNIEnv* env) { CheckIfRendering(); NewPattern(); UpdatePattern(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeFitPattern(JNIEnv* env) { CheckIfRendering(); FitInView(1); UpdatePattern(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeScale1to1(JNIEnv* env) { CheckIfRendering(); // set scale to 1:1 if (currlayer->view->getmag() != 0) { currlayer->view->setmag(0); UpdatePattern(); UpdateStatus(); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeBigger(JNIEnv* env) { CheckIfRendering(); // zoom in if (currlayer->view->getmag() < MAX_MAG) { currlayer->view->zoom(); UpdatePattern(); UpdateStatus(); } else { Beep(); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeSmaller(JNIEnv* env) { CheckIfRendering(); // zoom out currlayer->view->unzoom(); UpdatePattern(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeMiddle(JNIEnv* env) { if (currlayer->originx == bigint::zero && currlayer->originy == bigint::zero) { currlayer->view->center(); } else { // put cell saved by ChangeOrigin (not yet implemented!!!) in middle currlayer->view->setpositionmag(currlayer->originx, currlayer->originy, currlayer->view->getmag()); } UpdatePattern(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_MainActivity_nativeGetMode(JNIEnv* env) { switch (currlayer->touchmode) { case drawmode: return 0; case pickmode: return 1; case selectmode: return 2; case movemode: return 3; } Warning("Bug detected in nativeGetMode!"); return 0; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeSetMode(JNIEnv* env, jobject obj, jint mode) { switch (mode) { case 0: currlayer->touchmode = drawmode; return; case 1: currlayer->touchmode = pickmode; return; case 2: currlayer->touchmode = selectmode; return; case 3: currlayer->touchmode = movemode; return; } Warning("Bug detected in nativeSetMode!"); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_MainActivity_nativeNumLayers(JNIEnv* env) { return numlayers; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativePasteExists(JNIEnv* env) { return waitingforpaste; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeSelectionExists(JNIEnv* env) { return currlayer->currsel.Exists(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativePaste(JNIEnv* env) { CheckIfRendering(); PasteClipboard(); UpdatePattern(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeSelectAll(JNIEnv* env) { SelectAll(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeRemoveSelection(JNIEnv* env) { RemoveSelection(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeCutSelection(JNIEnv* env) { CheckIfRendering(); CutSelection(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeCopySelection(JNIEnv* env) { CopySelection(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeClearSelection(JNIEnv* env, jobject obj, jint inside) { CheckIfRendering(); if (inside) { ClearSelection(); } else { ClearOutsideSelection(); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeShrinkSelection(JNIEnv* env) { ShrinkSelection(false); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeFitSelection(JNIEnv* env) { FitSelection(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeRandomFill(JNIEnv* env) { CheckIfRendering(); RandomFill(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeFlipSelection(JNIEnv* env, jobject obj, jint y) { CheckIfRendering(); FlipSelection(y); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeRotateSelection(JNIEnv* env, jobject obj, jint clockwise) { CheckIfRendering(); RotateSelection(clockwise); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeAdvanceSelection(JNIEnv* env, jobject obj, jint inside) { CheckIfRendering(); if (inside) { currlayer->currsel.Advance(); } else { currlayer->currsel.AdvanceOutside(); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeAbortPaste(JNIEnv* env) { AbortPaste(); UpdateEverything(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeDoPaste(JNIEnv* env, jobject obj, jint toselection) { // assume caller has stopped generating CheckIfRendering(); DoPaste(toselection); UpdateEverything(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeFlipPaste(JNIEnv* env, jobject obj, jint y) { FlipPastePattern(y); UpdateEverything(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeRotatePaste(JNIEnv* env, jobject obj, jint clockwise) { RotatePastePattern(clockwise); UpdateEverything(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeClearMessage(JNIEnv* env) { ClearMessage(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_MainActivity_nativeGetValidExtensions(JNIEnv* env) { if (currlayer->algo->hyperCapable()) { // .rle format is allowed but .mc format is better return env->NewStringUTF(".mc (the default) or .mc.gz or .rle or .rle.gz"); } else { // only .rle format is allowed return env->NewStringUTF(".rle (the default) or .rle.gz"); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeValidExtension(JNIEnv* env, jobject obj, jstring filename) { std::string fname = ConvertJString(env, filename); size_t dotpos = fname.find('.'); if (dotpos == std::string::npos) return true; // no extension given (default will be added later) if (EndsWith(fname,".rle")) return true; if (EndsWith(fname,".rle.gz")) return true; if (currlayer->algo->hyperCapable()) { if (EndsWith(fname,".mc")) return true; if (EndsWith(fname,".mc.gz")) return true; } return false; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_MainActivity_nativeFileExists(JNIEnv* env, jobject obj, jstring filename) { std::string fname = ConvertJString(env, filename); // append default extension if not supplied size_t dotpos = fname.find('.'); if (dotpos == std::string::npos) { if (currlayer->algo->hyperCapable()) { fname += ".mc"; } else { fname += ".rle"; } } std::string fullpath = savedir + fname; return FileExists(fullpath); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeSavePattern(JNIEnv* env, jobject obj, jstring filename) { std::string fname = ConvertJString(env, filename); // append default extension if not supplied size_t dotpos = fname.find('.'); if (dotpos == std::string::npos) { if (currlayer->algo->hyperCapable()) { fname += ".mc"; } else { fname += ".rle"; } } pattern_format format = XRLE_format; if (EndsWith(fname,".mc") || EndsWith(fname,".mc.gz")) format = MC_format; output_compression compression = no_compression; if (EndsWith(fname,".gz")) compression = gzip_compression; std::string fullpath = savedir + fname; SavePattern(fullpath, format, compression); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeOpenFile(JNIEnv* env, jobject obj, jstring filepath) { std::string fpath = ConvertJString(env, filepath); FixURLPath(fpath); OpenFile(fpath.c_str()); SavePrefs(); // save recentpatterns } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeSetFullScreen(JNIEnv* env, jobject obj, jboolean isfull) { fullscreen = isfull; if (!fullscreen) { // user might have changed scale or position while in fullscreen mode UpdateStatus(); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeChangeRule(JNIEnv* env, jobject obj, jstring rule) { std::string newrule = ConvertJString(env, rule); ChangeRule(newrule); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_MainActivity_nativeLexiconPattern(JNIEnv* env, jobject obj, jstring jpattern) { std::string pattern = ConvertJString(env, jpattern); std::replace(pattern.begin(), pattern.end(), '$', '\n'); LoadLexiconPattern(pattern); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_MainActivity_nativeDrawingState(JNIEnv* env) { return currlayer->drawingstate; } // ============================================================================= // these native routines are used in PatternGLSurfaceView.java: extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativePause(JNIEnv* env) { PauseGenerating(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeResume(JNIEnv* env) { ResumeGenerating(); UpdatePattern(); UpdateStatus(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeTouchBegan(JNIEnv* env, jobject obj, jint x, jint y) { // LOGI("touch began: x=%d y=%d", x, y); ClearMessage(); TouchBegan(x, y); // set flag so we can avoid jerky updates if pattern is generating touching_pattern = true; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeTouchMoved(JNIEnv* env, jobject obj, jint x, jint y) { // LOGI("touch moved: x=%d y=%d", x, y); TouchMoved(x, y); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeTouchEnded(JNIEnv* env) { // LOGI("touch ended"); TouchEnded(); touching_pattern = false; // allow pattern generation } // ----------------------------------------------------------------------------- static TouchModes oldmode; extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeMoveMode(JNIEnv* env) { // temporarily switch touch mode to movemode oldmode = currlayer->touchmode; currlayer->touchmode = movemode; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeRestoreMode(JNIEnv* env) { // restore touch mode saved in nativeMoveMode currlayer->touchmode = oldmode; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeZoomIn(JNIEnv* env, jobject obj, jint x, jint y) { ZoomInPos(x, y); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeZoomOut(JNIEnv* env, jobject obj, jint x, jint y) { ZoomOutPos(x, y); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternRenderer_nativeInit(JNIEnv* env) { // we only do 2D drawing glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glDisable(GL_MULTISAMPLE); glDisable(GL_STENCIL_TEST); glDisable(GL_FOG); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_BLEND); // this blending function seems similar to the one used in desktop Golly // (ie. selected patterns look much the same) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternRenderer_nativeResize(JNIEnv* env, jobject obj, jint w, jint h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0, w, h, 0, -1, 1); // origin is top left and y increases down glViewport(0, 0, w, h); glMatrixMode(GL_MODELVIEW); if (w != currlayer->view->getwidth() || h != currlayer->view->getheight()) { // update size of viewport ResizeLayers(w, h); UpdatePattern(); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternRenderer_nativeRender(JNIEnv* env) { // if NextGeneration is executing (on different thread) then don't call DrawPattern if (event_checker > 0) return; // render the current pattern; note that this occurs on a different thread // so we use rendering flag to prevent calls like NewPattern being called // before DrawPattern has finished rendering = true; DrawPattern(currindex); rendering = false; } // ============================================================================= // these native routines are used in OpenActivity.java: const char* HTML_HEADER = ""; const char* HTML_FOOTER = ""; const char* HTML_INDENT = "      "; static std::set opendirs; // set of open directories in Supplied patterns extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_OpenActivity_nativeGetRecentPatterns(JNIEnv* env) { std::string htmldata = HTML_HEADER; if (recentpatterns.empty()) { htmldata += "There are no recent patterns."; } else { htmldata += "Recently opened/saved patterns:

"; std::list::iterator next = recentpatterns.begin(); while (next != recentpatterns.end()) { std::string path = *next; if (path.find("Patterns/") == 0 || FileExists(userdir + path)) { htmldata += ""; if (path.find("Patterns/") == 0) { // nicer not to show Patterns/ prefix size_t firstsep = path.find('/'); if (firstsep != std::string::npos) { path.erase(0, firstsep+1); } } htmldata += path; htmldata += "
"; } next++; } } htmldata += HTML_FOOTER; return env->NewStringUTF(htmldata.c_str()); } // ----------------------------------------------------------------------------- static void AppendHtmlData(std::string& htmldata, const std::string& paths, const std::string& dir, const std::string& prefix, bool candelete) { int closedlevel = 0; size_t pathstart = 0; size_t pathend = paths.find('\n'); while (pathend != std::string::npos) { std::string path = paths.substr(pathstart, pathend - pathstart); // path is relative to given dir (eg. "Life/Bounded-Grids/agar-p3.rle" if patternsdir) bool isdir = (paths[pathend-1] == '/'); if (isdir) { // strip off terminating '/' path = paths.substr(pathstart, pathend - pathstart - 1); } // set indent level to number of separators in path int indents = std::count(path.begin(), path.end(), '/'); if (indents <= closedlevel) { if (isdir) { // path is to a directory std::string imgname; if (opendirs.find(path) == opendirs.end()) { closedlevel = indents; imgname = "triangle-right.png"; } else { closedlevel = indents+1; imgname = "triangle-down.png"; } for (int i = 0; i < indents; i++) htmldata += HTML_INDENT; htmldata += ""; size_t lastsep = path.rfind('/'); if (lastsep == std::string::npos) { htmldata += path; } else { htmldata += path.substr(lastsep+1); } htmldata += "
"; } else { // path is to a file for (int i = 0; i < indents; i++) htmldata += HTML_INDENT; if (candelete) { // allow user to delete file htmldata += "DELETE   "; // allow user to edit file htmldata += "EDIT   "; } else { // allow user to read file (a supplied pattern) htmldata += "READ   "; } htmldata += ""; size_t lastsep = path.rfind('/'); if (lastsep == std::string::npos) { htmldata += path; } else { htmldata += path.substr(lastsep+1); } htmldata += "
"; } } pathstart = pathend + 1; pathend = paths.find('\n', pathstart); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_OpenActivity_nativeGetSavedPatterns(JNIEnv* env, jobject obj, jstring jpaths) { std::string paths = ConvertJString(env, jpaths); std::string htmldata = HTML_HEADER; if (paths.length() == 0) { htmldata += "There are no saved patterns."; } else { htmldata += "Saved patterns:

"; AppendHtmlData(htmldata, paths, savedir, "Saved/", true); // can delete files } htmldata += HTML_FOOTER; return env->NewStringUTF(htmldata.c_str()); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_OpenActivity_nativeGetDownloadedPatterns(JNIEnv* env, jobject obj, jstring jpaths) { std::string paths = ConvertJString(env, jpaths); std::string htmldata = HTML_HEADER; if (paths.length() == 0) { htmldata += "There are no downloaded patterns."; } else { htmldata += "Downloaded patterns:

"; AppendHtmlData(htmldata, paths, downloaddir, "Downloads/", true); // can delete files } htmldata += HTML_FOOTER; return env->NewStringUTF(htmldata.c_str()); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_OpenActivity_nativeGetSuppliedPatterns(JNIEnv* env, jobject obj, jstring jpaths) { std::string paths = ConvertJString(env, jpaths); std::string htmldata = HTML_HEADER; if (paths.length() == 0) { htmldata += "There are no supplied patterns."; } else { htmldata += "Supplied patterns:

"; AppendHtmlData(htmldata, paths, patternsdir, "Patterns/", false); // can't delete files } htmldata += HTML_FOOTER; return env->NewStringUTF(htmldata.c_str()); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_OpenActivity_nativeToggleDir(JNIEnv* env, jobject obj, jstring jpath) { std::string path = ConvertJString(env, jpath); if (opendirs.find(path) == opendirs.end()) { // add directory path to opendirs opendirs.insert(path); } else { // remove directory path from opendirs opendirs.erase(path); } } // ============================================================================= // these native routines are used in SettingsActivity.java: static bool oldcolors; // detect if user changed swapcolors static bool oldundo; // detect if user changed allowundo static bool oldhashinfo; // detect if user changed currlayer->showhashinfo static int oldhashmem; // detect if user changed maxhashmem extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_SettingsActivity_nativeOpenSettings(JNIEnv* env) { // SettingsActivity is about to appear oldcolors = swapcolors; oldundo = allowundo; oldhashmem = maxhashmem; oldhashinfo = currlayer->showhashinfo; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_SettingsActivity_nativeCloseSettings(JNIEnv* env) { // SettingsActivity is about to disappear if (swapcolors != oldcolors) InvertCellColors(); if (allowundo != oldundo) { if (allowundo) { if (currlayer->algo->getGeneration() > currlayer->startgen) { // undo list is empty but user can Reset, so add a generating change // to undo list so user can Undo or Reset (and then Redo if they wish) currlayer->undoredo->AddGenChange(); } } else { currlayer->undoredo->ClearUndoRedo(); } } if (currlayer->showhashinfo != oldhashinfo) { // we only show hashing info while generating if (generating) lifealgo::setVerbose(currlayer->showhashinfo); } // need to call setMaxMemory if maxhashmem changed if (maxhashmem != oldhashmem) { for (int i = 0; i < numlayers; i++) { Layer* layer = GetLayer(i); if (algoinfo[layer->algtype]->canhash) { layer->algo->setMaxMemory(maxhashmem); } // non-hashing algos (QuickLife) use their default memory setting } } // this is a good place to save the current settings SavePrefs(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_SettingsActivity_nativeGetPref(JNIEnv* env, jobject obj, jstring pref) { std::string name = ConvertJString(env, pref); if (name == "hash") return currlayer->showhashinfo ? 1 : 0; if (name == "time") return showtiming ? 1 : 0; if (name == "beep") return allowbeep ? 1 : 0; if (name == "swap") return swapcolors ? 1 : 0; if (name == "icon") return showicons ? 1 : 0; if (name == "undo") return allowundo ? 1 : 0; if (name == "grid") return showgridlines ? 1 : 0; if (name == "rand") return randomfill; if (name == "maxm") return maxhashmem; LOGE("Fix bug in nativeGetPref! name = %s", name.c_str()); return 0; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_SettingsActivity_nativeSetPref(JNIEnv* env, jobject obj, jstring pref, int val) { std::string name = ConvertJString(env, pref); if (name == "hash") currlayer->showhashinfo = val == 1; else if (name == "time") showtiming = val == 1; else if (name == "beep") allowbeep = val == 1; else if (name == "swap") swapcolors = val == 1; else if (name == "icon") showicons = val == 1; else if (name == "undo") allowundo = val == 1; else if (name == "grid") showgridlines = val == 1; else if (name == "rand") { randomfill = val; if (randomfill < 1) randomfill = 1; if (randomfill > 100) randomfill = 100; } else if (name == "maxm") { maxhashmem = val; if (maxhashmem < MIN_MEM_MB) maxhashmem = MIN_MEM_MB; if (maxhashmem > MAX_MEM_MB) maxhashmem = MAX_MEM_MB; } else if (name == "pmode") { if (val == 0) SetPasteMode("AND"); if (val == 1) SetPasteMode("COPY"); if (val == 2) SetPasteMode("OR"); if (val == 3) SetPasteMode("XOR"); } else LOGE("Fix bug in nativeSetPref! name = %s", name.c_str()); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_SettingsActivity_nativeGetPasteMode(JNIEnv* env) { return env->NewStringUTF(GetPasteMode()); } // ============================================================================= // these native routines are used in HelpActivity.java: extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_HelpActivity_nativeClassInit(JNIEnv* env, jclass klass) { // get IDs for Java methods in HelpActivity help_DownloadFile = env->GetMethodID(klass, "DownloadFile", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_HelpActivity_nativeCreate(JNIEnv* env, jobject obj) { // save obj for calling Java methods in this instance of HelpActivity if (helpobj != NULL) env->DeleteGlobalRef(helpobj); helpobj = env->NewGlobalRef(obj); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_HelpActivity_nativeDestroy(JNIEnv* env) { // the current instance of HelpActivity is being destroyed if (helpobj != NULL) { env->DeleteGlobalRef(helpobj); helpobj = NULL; } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_HelpActivity_nativeGetURL(JNIEnv* env, jobject obj, jstring jurl, jstring jpageurl) { std::string url = ConvertJString(env, jurl); std::string pageurl = ConvertJString(env, jpageurl); // for GetURL to work we need to convert any "%20" in pageurl to " " size_t start_pos = 0; while ((start_pos = pageurl.find("%20", start_pos)) != std::string::npos) { pageurl.replace(start_pos, 3, " "); start_pos += 1; // skip inserted space } GetURL(url, pageurl); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_HelpActivity_nativeUnzipFile(JNIEnv* env, jobject obj, jstring jzippath) { std::string zippath = ConvertJString(env, jzippath); FixURLPath(zippath); std::string entry = zippath.substr(zippath.rfind(':') + 1); zippath = zippath.substr(0, zippath.rfind(':')); UnzipFile(zippath, entry); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT bool JNICALL Java_net_sf_golly_HelpActivity_nativeDownloadedFile(JNIEnv* env, jobject obj, jstring jurl) { std::string path = ConvertJString(env, jurl); path = path.substr(path.rfind('/')+1); size_t dotpos = path.rfind('.'); std::string ext = ""; if (dotpos != std::string::npos) ext = path.substr(dotpos+1); if ( (IsZipFile(path) || strcasecmp(ext.c_str(),"rle") == 0 || strcasecmp(ext.c_str(),"life") == 0 || strcasecmp(ext.c_str(),"mc") == 0) // also check for '?' to avoid opening links like ".../detail?name=foo.zip" && path.find('?') == std::string::npos) { // download file to downloaddir and open it path = downloaddir + path; std::string url = ConvertJString(env, jurl); if (DownloadFile(url, path)) { OpenFile(path.c_str()); } return true; } else { return false; } } // ============================================================================= // these native routines are used in StateActivity.java: extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_StateActivity_nativeNumStates(JNIEnv* env) { return currlayer->algo->NumCellStates(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jboolean JNICALL Java_net_sf_golly_StateActivity_nativeShowIcons() { return showicons; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_StateActivity_nativeToggleIcons() { showicons = !showicons; UpdatePattern(); UpdateEditBar(); SavePrefs(); } // ============================================================================= // these native routines are used in StateGLSurfaceView.java: static int statewd, stateht; static int state_offset = 0; static int max_offset; static int lastx, lasty; static bool touch_moved; extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_StateGLSurfaceView_nativeTouchBegan(JNIEnv* env, jobject obj, jint x, jint y) { // LOGI("TouchBegan x=%d y=%d", x, y); lastx = x; lasty = y; touch_moved = false; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jboolean JNICALL Java_net_sf_golly_StateGLSurfaceView_nativeTouchMoved(JNIEnv* env, jobject obj, jint x, jint y) { // LOGI("TouchMoved x=%d y=%d", x, y); int boxsize = highdensity ? 64 : 32; int oldcol = lastx / boxsize; int oldrow = lasty / boxsize; int col = x / boxsize; int row = y / boxsize; lastx = x; lasty = y; if (col != oldcol || row != oldrow) { // user moved finger to a different state box touch_moved = true; } if (max_offset > 0 && row != oldrow) { // may need to scroll states by changing state_offset int new_offset = state_offset + 10 * (oldrow - row); if (new_offset < 0) new_offset = 0; if (new_offset > max_offset) new_offset = max_offset; if (new_offset != state_offset) { // scroll up/down state_offset = new_offset; return true; } } return false; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jboolean JNICALL Java_net_sf_golly_StateGLSurfaceView_nativeTouchEnded(JNIEnv* env) { if (touch_moved) return false; if (lastx >= 0 && lastx < statewd && lasty >= 0 && lasty < stateht) { // return true if user touched a valid state box int boxsize = highdensity ? 64 : 32; int col = lastx / boxsize; int row = lasty / boxsize; int newstate = row * 10 + col + state_offset; if (newstate >= 0 && newstate < currlayer->algo->NumCellStates()) { currlayer->drawingstate = newstate; return true; } } return false; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_StateRenderer_nativeInit(JNIEnv* env) { // we only do 2D drawing glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glEnableClientState(GL_VERTEX_ARRAY); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_StateRenderer_nativeResize(JNIEnv* env, jobject obj, jint w, jint h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthof(0, w, h, 0, -1, 1); // origin is top left and y increases down glViewport(0, 0, w, h); glMatrixMode(GL_MODELVIEW); statewd = w; stateht = h; max_offset = 0; int numstates = currlayer->algo->NumCellStates(); if (numstates > 100) { max_offset = (((numstates - 100) + 9) / 10) * 10; // 10 if 101 states, 160 if 256 states } if (state_offset > max_offset) state_offset = 0; } // ----------------------------------------------------------------------------- static void DrawGrid(int wd, int ht) { int cellsize = highdensity ? 64 : 32; int h, v; // set the stroke color to white glColor4ub(255, 255, 255, 255); glLineWidth(highdensity ? 2.0 : 1.0); v = 1; while (v <= ht) { GLfloat points[] = {-0.5, v-0.5, wd-0.5, v-0.5}; glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(GL_LINES, 0, 2); v += cellsize; } h = 1; while (h <= wd) { GLfloat points[] = {h-0.5, -0.5, h-0.5, ht-0.5}; glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(GL_LINES, 0, 2); h += cellsize; } } // ----------------------------------------------------------------------------- static void DrawRect(int state, int x, int y, int wd, int ht) { GLfloat rect[] = { x, y+ht, // left, bottom x+wd, y+ht, // right, bottom x+wd, y, // right, top x, y, // left, top }; glColor4ub(currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state], 255); glVertexPointer(2, GL_FLOAT, 0, rect); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } // ----------------------------------------------------------------------------- static void DrawIcon(int state, int x, int y) { gBitmapPtr* icons = currlayer->icons31x31; if (icons == NULL || icons[state] == NULL) return; unsigned char* pxldata = icons[state]->pxldata; if (pxldata == NULL) return; int cellsize = 31; const int maxcoords = 1024; // must be multiple of 2 GLfloat points[maxcoords]; int numcoords = 0; bool multicolor = currlayer->multicoloricons; glPointSize(highdensity ? 2 : 1); unsigned char deadr = currlayer->cellr[0]; unsigned char deadg = currlayer->cellg[0]; unsigned char deadb = currlayer->cellb[0]; unsigned char prevr = deadr; unsigned char prevg = deadg; unsigned char prevb = deadb; glColor4ub(deadr, deadg, deadb, 255); // draw non-black pixels in this icon unsigned char liver = currlayer->cellr[state]; unsigned char liveg = currlayer->cellg[state]; unsigned char liveb = currlayer->cellb[state]; int byte = 0; for (int i = 0; i < cellsize; i++) { for (int j = 0; j < cellsize; j++) { unsigned char r = pxldata[byte++]; unsigned char g = pxldata[byte++]; unsigned char b = pxldata[byte++]; byte++; // skip alpha if (r || g || b) { if (multicolor) { // draw non-black pixel from multi-colored icon if (swapcolors) { r = 255 - r; g = 255 - g; b = 255 - b; } } else { // grayscale icon if (r == 255) { // replace white pixel with current cell color r = liver; g = liveg; b = liveb; } else { // replace gray pixel with appropriate shade between // live and dead cell colors float frac = (float)r / 255.0; r = (int)(deadr + frac * (liver - deadr) + 0.5); g = (int)(deadg + frac * (liveg - deadg) + 0.5); b = (int)(deadb + frac * (liveb - deadb) + 0.5); } } // draw r,g,b pixel bool changecolor = (r != prevr || g != prevg || b != prevb); if (changecolor || numcoords == maxcoords) { if (numcoords > 0) { glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(GL_POINTS, 0, numcoords/2); numcoords = 0; } if (changecolor) { prevr = r; prevg = g; prevb = b; glColor4ub(r, g, b, 255); } } if (highdensity) { points[numcoords++] = x + j*2 + 0.5; points[numcoords++] = y + i*2 + 0.5; } else { points[numcoords++] = x + j + 0.5; points[numcoords++] = y + i + 0.5; } } } } if (numcoords > 0) { glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(GL_POINTS, 0, numcoords/2); } } // ----------------------------------------------------------------------------- static void DrawDigit(int digit, int x, int y) { unsigned char* pxldata = digits10x10[digit+1]->pxldata; int cellsize = 10; const int maxcoords = 128; // must be multiple of 2 GLfloat points[maxcoords]; int numcoords = 0; glPointSize(highdensity ? 2 : 1); unsigned char deadr = currlayer->cellr[0]; unsigned char deadg = currlayer->cellg[0]; unsigned char deadb = currlayer->cellb[0]; unsigned char prevr = deadr; unsigned char prevg = deadg; unsigned char prevb = deadb; glColor4ub(deadr, deadg, deadb, 255); // draw non-black pixels in this icon int byte = 0; for (int i = 0; i < cellsize; i++) { for (int j = 0; j < cellsize; j++) { unsigned char r = pxldata[byte++]; unsigned char g = pxldata[byte++]; unsigned char b = pxldata[byte++]; byte++; // skip alpha if (r || g || b) { // draw non-black pixel bool changecolor = (r != prevr || g != prevg || b != prevb); if (changecolor || numcoords == maxcoords) { if (numcoords > 0) { glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(GL_POINTS, 0, numcoords/2); numcoords = 0; } if (changecolor) { prevr = r; prevg = g; prevb = b; glColor4ub(r, g, b, 255); } } if (highdensity) { points[numcoords++] = x + j*2 + 0.5; points[numcoords++] = y + i*2 + 0.5; } else { points[numcoords++] = x + j + 0.5; points[numcoords++] = y + i + 0.5; } } } } if (numcoords > 0) { glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(GL_POINTS, 0, numcoords/2); } } // ----------------------------------------------------------------------------- static void DrawStateNumber(int state, int x, int y) { // draw state number in top left corner of each cell int digitwd = highdensity ? 12 : 6; if (state < 10) { // state = 0..9 DrawDigit(state, x, y); } else if (state < 100) { // state = 10..99 DrawDigit(state / 10, x, y); DrawDigit(state % 10, x + digitwd, y); } else { // state = 100..255 DrawDigit(state / 100, x, y); DrawDigit((state % 100) / 10, x + digitwd, y); DrawDigit((state % 100) % 10, x + digitwd*2, y); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_StateRenderer_nativeRender(JNIEnv* env) { // fill the background with state 0 color glClearColor(currlayer->cellr[0]/255.0, currlayer->cellg[0]/255.0, currlayer->cellb[0]/255.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); DrawGrid(statewd, stateht); // display state colors or icons int numstates = currlayer->algo->NumCellStates(); int x = 1; int y = 1; int first = state_offset; // might be > 0 if numstates > 100 if (state_offset == 0) { DrawStateNumber(0, 1, 1); // start from state 1 first = 1; x = highdensity ? 65 : 33; } for (int state = first; state < numstates; state++) { if (showicons) { DrawIcon(state, x, y); } else { DrawRect(state, x, y, highdensity ? 63 : 31, highdensity ? 63 : 31); } DrawStateNumber(state, x, y); x += highdensity ? 64 : 32; if (x > (highdensity ? 640 : 320)) { x = 1; y += highdensity ? 64 : 32; if (y > (highdensity ? 640 : 320)) break; } } } // ============================================================================= // these native routines are used in RuleActivity.java: extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_RuleActivity_nativeSaveCurrentSelection(JNIEnv* env) { SaveCurrentSelection(); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_RuleActivity_nativeGetAlgoIndex(JNIEnv* env) { return currlayer->algtype; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_RuleActivity_nativeGetAlgoName(JNIEnv* env, jobject obj, int algoindex) { if (algoindex < 0 || algoindex >= NumAlgos()) { // caller will check for empty string return env->NewStringUTF(""); } else { return env->NewStringUTF(GetAlgoName(algoindex)); } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_RuleActivity_nativeGetRule(JNIEnv* env) { return env->NewStringUTF(currlayer->algo->getrule()); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_RuleActivity_nativeCheckRule(JNIEnv* env, jobject obj, jstring rule, int algoindex) { // if given rule is valid in the given algo then return same rule, // otherwise return the algo's default rule std::string thisrule = ConvertJString(env, rule); if (thisrule.empty()) thisrule = "B3/S23"; lifealgo* tempalgo = CreateNewUniverse(algoindex); const char* err = tempalgo->setrule(thisrule.c_str()); if (err) { // switch to tempalgo's default rule std::string defrule = tempalgo->DefaultRule(); size_t thispos = thisrule.find(':'); if (thispos != std::string::npos) { // preserve valid topology so we can do things like switch from // "LifeHistory:T30,20" in RuleLoader to "B3/S23:T30,20" in QuickLife size_t defpos = defrule.find(':'); if (defpos != std::string::npos) { // default rule shouldn't have a suffix but play safe and remove it defrule = defrule.substr(0, defpos); } defrule += ":"; defrule += thisrule.substr(thispos+1); } thisrule = defrule; } delete tempalgo; return env->NewStringUTF(thisrule.c_str()); } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT int JNICALL Java_net_sf_golly_RuleActivity_nativeCheckAlgo(JNIEnv* env, jobject obj, jstring rule, int algoindex) { std::string thisrule = ConvertJString(env, rule); if (thisrule.empty()) thisrule = "B3/S23"; // 1st check if rule is valid in displayed algo lifealgo* tempalgo = CreateNewUniverse(algoindex); const char* err = tempalgo->setrule(thisrule.c_str()); if (err) { // check rule in other algos for (int newindex = 0; newindex < NumAlgos(); newindex++) { if (newindex != algoindex) { delete tempalgo; tempalgo = CreateNewUniverse(newindex); err = tempalgo->setrule(thisrule.c_str()); if (!err) { delete tempalgo; return newindex; // tell caller to change algorithm } } } } delete tempalgo; if (err) { return -1; // rule is not valid in any algo } else { return algoindex; // no need to change algo } } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_RuleActivity_nativeSetRule(JNIEnv* env, jobject obj, jstring rule, int algoindex) { std::string oldrule = currlayer->algo->getrule(); int oldmaxstate = currlayer->algo->NumCellStates() - 1; std::string newrule = ConvertJString(env, rule); if (newrule.empty()) newrule = "B3/S23"; if (algoindex == currlayer->algtype) { // check if new rule is valid in current algorithm (if not then revert to oldrule) const char* err = currlayer->algo->setrule(newrule.c_str()); if (err) RestoreRule(oldrule.c_str()); // convert newrule to canonical form for comparison with oldrule, then // check if the rule string changed or if the number of states changed newrule = currlayer->algo->getrule(); int newmaxstate = currlayer->algo->NumCellStates() - 1; if (oldrule != newrule || oldmaxstate != newmaxstate) { // if grid is bounded then remove any live cells outside grid edges if (currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0) { ClearOutsideGrid(); } // rule change might have changed the number of cell states; // if there are fewer states then pattern might change if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { ReduceCellStates(newmaxstate); } if (allowundo) { currlayer->undoredo->RememberRuleChange(oldrule.c_str()); } } UpdateLayerColors(); UpdateEverything(); } else { // change the current algorithm and switch to the new rule // (if the new rule is invalid then the algo's default rule will be used); // this also calls UpdateLayerColors, UpdateEverything and RememberAlgoChange ChangeAlgorithm(algoindex, newrule.c_str()); } SavePrefs(); } // ----------------------------------------------------------------------------- // these native routines are used in InfoApp.java: extern "C" JNIEXPORT jstring JNICALL Java_net_sf_golly_InfoActivity_nativeGetInfo(JNIEnv* env) { std::string info; if (currlayer->currfile.empty()) { // should never happen info = "There is no current pattern file!"; } else { // get comments in current pattern file char *commptr = NULL; // readcomments will allocate commptr const char *err = readcomments(currlayer->currfile.c_str(), &commptr); if (err) { info = err; } else if (commptr[0] == 0) { info = "No comments found."; } else { info = commptr; } if (commptr) free(commptr); } return env->NewStringUTF(info.c_str()); } // ============================================================================= std::string GetRuleName(const std::string& rule) { std::string result = ""; // not yet implemented!!! // maybe we should create rule.h and rule.cpp in gui-common??? return result; } // ----------------------------------------------------------------------------- void UpdateEditBar() { if (currlayer->drawingstate >= currlayer->algo->NumCellStates()) { // this can happen after an algo/rule change currlayer->drawingstate = 1; } // call Java method in MainActivity class to update the buttons in the edit bar bool attached; JNIEnv* env = getJNIenv(&attached); if (env) env->CallVoidMethod(mainobj, main_UpdateEditBar); if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- void BeginProgress(const char* title) { bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jtitle = env->NewStringUTF(title); env->CallVoidMethod(mainobj, main_BeginProgress, jtitle); env->DeleteLocalRef(jtitle); } if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- bool AbortProgress(double fraction_done, const char* message) { bool result = true; // abort if getJNIenv fails bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jint percentage = int(fraction_done * 100); jstring jmsg = env->NewStringUTF(message); result = env->CallBooleanMethod(mainobj, main_AbortProgress, percentage, jmsg); env->DeleteLocalRef(jmsg); } if (attached) javavm->DetachCurrentThread(); return result; } // ----------------------------------------------------------------------------- void EndProgress() { bool attached; JNIEnv* env = getJNIenv(&attached); if (env) env->CallVoidMethod(mainobj, main_EndProgress); if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- void SwitchToPatternTab() { // switch to MainActivity bool attached; JNIEnv* env = getJNIenv(&attached); if (env) env->CallVoidMethod(mainobj, main_StartMainActivity); if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- void ShowTextFile(const char* filepath) { // switch to InfoActivity and display contents of text file bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jpath = env->NewStringUTF(filepath); env->CallVoidMethod(mainobj, main_ShowTextFile, jpath); env->DeleteLocalRef(jpath); } if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- void ShowHelp(const char* filepath) { // switch to HelpActivity and display html file bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jpath = env->NewStringUTF(filepath); env->CallVoidMethod(mainobj, main_ShowHelp, jpath); env->DeleteLocalRef(jpath); } if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- void AndroidWarning(const char* msg) { if (generating) paused = true; bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jmsg = env->NewStringUTF(msg); env->CallVoidMethod(baseapp, baseapp_Warning, jmsg); env->DeleteLocalRef(jmsg); } if (attached) javavm->DetachCurrentThread(); if (generating) paused = false; } // ----------------------------------------------------------------------------- void AndroidFatal(const char* msg) { paused = true; bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jmsg = env->NewStringUTF(msg); env->CallVoidMethod(baseapp, baseapp_Fatal, jmsg); env->DeleteLocalRef(jmsg); } if (attached) javavm->DetachCurrentThread(); // main_Fatal calls System.exit(1) // exit(1); } // ----------------------------------------------------------------------------- bool AndroidYesNo(const char* query) { std::string answer; if (generating) paused = true; bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jquery = env->NewStringUTF(query); jstring jresult = (jstring) env->CallObjectMethod(baseapp, baseapp_YesNo, jquery); answer = ConvertJString(env, jresult); env->DeleteLocalRef(jquery); env->DeleteLocalRef(jresult); } if (attached) javavm->DetachCurrentThread(); if (generating) paused = false; return answer == "yes"; } // ----------------------------------------------------------------------------- void AndroidBeep() { bool attached; JNIEnv* env = getJNIenv(&attached); if (env) env->CallVoidMethod(mainobj, main_PlayBeepSound); if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- void AndroidRemoveFile(const std::string& filepath) { // LOGI("AndroidRemoveFile: %s", filepath.c_str()); bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jpath = env->NewStringUTF(filepath.c_str()); env->CallVoidMethod(mainobj, main_RemoveFile, jpath); env->DeleteLocalRef(jpath); } if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- bool AndroidMoveFile(const std::string& inpath, const std::string& outpath) { // LOGE("AndroidMoveFile: %s to %s", inpath.c_str(), outpath.c_str()); std::string error = "env is null"; bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring joldpath = env->NewStringUTF(inpath.c_str()); jstring jnewpath = env->NewStringUTF(outpath.c_str()); jstring jresult = (jstring) env->CallObjectMethod(mainobj, main_MoveFile, joldpath, jnewpath); error = ConvertJString(env, jresult); env->DeleteLocalRef(joldpath); env->DeleteLocalRef(jnewpath); env->DeleteLocalRef(jresult); } if (attached) javavm->DetachCurrentThread(); return error.length() == 0; } // ----------------------------------------------------------------------------- void AndroidFixURLPath(std::string& path) { // replace "%..." with suitable chars for a file path (eg. %20 is changed to space) // LOGI("AndroidFixURLPath: %s", path.c_str()); // no need to do anything???!!! } // ----------------------------------------------------------------------------- bool AndroidCopyTextToClipboard(const char* text) { bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jtext = env->NewStringUTF(text); env->CallVoidMethod(mainobj, main_CopyTextToClipboard, jtext); env->DeleteLocalRef(jtext); } if (attached) javavm->DetachCurrentThread(); return env != NULL; } // ----------------------------------------------------------------------------- bool AndroidGetTextFromClipboard(std::string& text) { text = ""; bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jtext = (jstring) env->CallObjectMethod(mainobj, main_GetTextFromClipboard); text = ConvertJString(env, jtext); env->DeleteLocalRef(jtext); } if (attached) javavm->DetachCurrentThread(); if (text.length() == 0) { ErrorMessage("No text in clipboard."); return false; } else { return true; } } // ----------------------------------------------------------------------------- void AndroidCheckEvents() { // event_checker is > 0 in here (see gui-common/utils.cpp) if (rendering) { // best not to call CheckMessageQueue while DrawPattern is executing // (speeds up generating loop and might help avoid fatal SIGSEGV error) return; } bool attached; JNIEnv* env = getJNIenv(&attached); if (env) env->CallVoidMethod(mainobj, main_CheckMessageQueue); if (attached) javavm->DetachCurrentThread(); } // ----------------------------------------------------------------------------- bool AndroidDownloadFile(const std::string& url, const std::string& filepath) { // LOGI("AndroidDownloadFile: url=%s file=%s", url.c_str(), filepath.c_str()); std::string error = "env is null"; // call DownloadFile method in HelpActivity bool attached; JNIEnv* env = getJNIenv(&attached); if (env) { jstring jurl = env->NewStringUTF(url.c_str()); jstring jfilepath = env->NewStringUTF(filepath.c_str()); jstring jresult = (jstring) env->CallObjectMethod(helpobj, help_DownloadFile, jurl, jfilepath); error = ConvertJString(env, jresult); env->DeleteLocalRef(jurl); env->DeleteLocalRef(jfilepath); env->DeleteLocalRef(jresult); } if (attached) javavm->DetachCurrentThread(); return error.length() == 0; } golly-2.7-src/gui-android/Golly/jni/Android.mk0000644000175000017500000000167112536111364016206 00000000000000LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := golly LOCAL_SRC_FILES := jnicalls.cpp # add .cpp files in gui-common GUI_COMMON := $(wildcard $(LOCAL_PATH)/../../../gui-common/*.cpp) LOCAL_SRC_FILES += $(GUI_COMMON:$(LOCAL_PATH)/%=%) # add .c files in gui-common/MiniZip MINIZIP := $(wildcard $(LOCAL_PATH)/../../../gui-common/MiniZip/*.c) LOCAL_SRC_FILES += $(MINIZIP:$(LOCAL_PATH)/%=%) # add .cpp files in gollybase GOLLYBASE := $(wildcard $(LOCAL_PATH)/../../../gollybase/*.cpp) LOCAL_SRC_FILES += $(GOLLYBASE:$(LOCAL_PATH)/%=%) # include .h files in gui-common LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../gui-common # include .h files in gui-common/MiniZip LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../gui-common/MiniZip # include .h files in gollybase LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../gollybase LOCAL_LDLIBS := -lGLESv1_CM -llog -lz -ljnigraphics include $(BUILD_SHARED_LIBRARY) golly-2.7-src/gui-android/Golly/jni/Application.mk0000644000175000017500000000056512536111364017072 00000000000000APP_PLATFORM := android-17 #??? APP_ABI = all # define ANDROID_GUI used in the shared C++ code in gui-common; # define ZLIB so Golly can read/write .gz files; # set -fexceptions so we can use stdexcept APP_CFLAGS += -DANDROID_GUI -DZLIB -fexceptions # needed for std::string etc APP_STL := stlport_shared # also need System.loadLibrary("stlport_shared") in BaseApp.java golly-2.7-src/gui-android/Golly/proguard-project.txt0000644000175000017500000000141512536111364017541 00000000000000# To enable ProGuard in your project, edit project.properties # to define the proguard.config property as described in that file. # # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in ${sdk.dir}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the ProGuard # include property in project.properties. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} golly-2.7-src/gui-android/Golly/res/0000755000175000017500000000000012536111545014362 500000000000000golly-2.7-src/gui-android/Golly/res/values-sw600dp/0000755000175000017500000000000012536111546017063 500000000000000golly-2.7-src/gui-android/Golly/res/values-sw600dp/dimens.xml0000644000175000017500000000030412536111364020777 00000000000000 golly-2.7-src/gui-android/Golly/res/menu/0000755000175000017500000000000012536111546015327 500000000000000golly-2.7-src/gui-android/Golly/res/menu/edit_menu.xml0000644000175000017500000000046212536111364017742 00000000000000 golly-2.7-src/gui-android/Golly/res/menu/pastemode_menu.xml0000644000175000017500000000110512536111364020771 00000000000000 golly-2.7-src/gui-android/Golly/res/menu/paste_menu.xml0000644000175000017500000000154512536111364020134 00000000000000 golly-2.7-src/gui-android/Golly/res/menu/mode_menu.xml0000644000175000017500000000075112536111364017742 00000000000000 golly-2.7-src/gui-android/Golly/res/menu/control_menu.xml0000644000175000017500000000100012536111364020462 00000000000000 golly-2.7-src/gui-android/Golly/res/menu/view_menu.xml0000644000175000017500000000077712536111364020000 00000000000000 golly-2.7-src/gui-android/Golly/res/menu/main.xml0000644000175000017500000000066212536111364016717 00000000000000 golly-2.7-src/gui-android/Golly/res/menu/selection_menu.xml0000644000175000017500000000356512536111364021011 00000000000000 golly-2.7-src/gui-android/Golly/res/drawable-ldpi/0000755000175000017500000000000012536111546017072 500000000000000golly-2.7-src/gui-android/Golly/res/drawable-ldpi/readme.txt0000644000175000017500000000034512536111364021010 00000000000000This file is just to ensure "git add" adds this directory. Note that there's no need to create ic_launcher.png in this directory because Android will automatically create a suitable 36x36 icon by scaling down a higher-res icon. golly-2.7-src/gui-android/Golly/res/drawable-xxhdpi/0000755000175000017500000000000012536111546017446 500000000000000golly-2.7-src/gui-android/Golly/res/drawable-xxhdpi/ic_launcher.png0000755000175000017500000003303112536111364022351 00000000000000‰PNG  IHDRçF⸠IDATx^í]`åÖ=Ùô„@ ôN Ho!(R¥K(UÛSD” v°‹úì( RÒkè=„лФғÿÜ™ìnv7Ù(²ËcÇ·HîÎ|÷Ι;÷»ÕÎÃ) —ð]çW€@Nü# 8ôÄçü²@N ü# 8ôÄçü²­2¦³õ;NéÞÈ3Z¶ñß-rSä÷–>w§hœ«.J`äÏ‚ŸbH§ü©}Lòw9Š_Q‹uþÞ±$ 'WùSûÈïäïf‡5h@qå7\wnz+°–?J—ö„NçÄcÝ÷Û»šÜÜ<$$dàlt"Ú>8LJgÏÑ4`™\ÐDËxÜä³{ç°äÚþð÷÷„««¦€nïÂgs äää"11gÎ&¢MÛ?JrUÙúÉL Y¦}<îüxìÞ|½v 7äN95cÜêg99yP”†6ì àU2ùÉÒƒÈL Yh<üx@±Ný;7ÌÑÎZ@¹¾t#‰2Ù™Y¦}¼øoè¢@Žv«ÿõPU^%M"M  1r@ŠöÑè¼@ÿÎ s´³Pu#É«Lì!;È’27¿àC ã£Ýêg=T“W¹¥Q±ä©×@¾P´@ÿÎ s´³P-®/Uÿ Ë(®rÈÑîîX@w@ÈÿË—påäè°c§?ÎþDg@9äd§£„Ï_x¸Ë”)#¯RÓãæM7lØX 7ê"Ï͹Ùi…Ò_¾â‰Í›ª!3;y:äd&¢jå“èØñ<=e§iz=V‘{©uUç¢CNV,7:ƒ–-’áâb/4¦ÏÉ˃.ï<Úµ‹Aí@Ù˜Ƽº¸—ENnN¡ôÅ_qy5¦‡Î­H^Íù1ñÝùWXB¢¦Õé™}Ño@m”ñBfF6¶oþˆ­xîÙÕhÖìfþºOöÂôo:¢vPwtîR>Þî&ôãÇ­DýúbǩǦ-e1gnotìüš5/ 77$'eaÅò¤$®Â„—w¢R%Ù,¨Ç’¥Õ°.<}4E­š¾ pùÒ-, ;†Z5–q=Çáå¥n,rr\0ë@Dìí›OŸG;–ˆUË#ñH¯eèÓçrþ¹-ñš›››O?ôÑEõµâb&Ÿ>boiü4£¯Í¼šÉ†N_k¼Z[”]5P65Ïä7šàÈÑþ:¬"Ü=øtç©=ùÿ;ÒpøÐv|÷í*Ô­“Џ«xúÙÎ(_± ºtñ#…hSú¸+kñÓëQ¢DöF–ÂKãû¢K×V¸ÿ~ñ2­úÜ\ü–_ßåøzúî|úW' Aèæ(+¤²ÁÌ#µ Rˆáßf\À#}â•—OX¹O5|û](FŒªkFöl‡Á;o‡¡G÷k°Î«z~¡_¿f¾ûîO…×â"›'ÇôF‹VmæÕ’l¬ñê ßèQOöGíZUж­¯©Ë’ÿŠ9—…mÛ0lÈ&|òñA|úy-|úÅ# öG½zÞé·n‰ÅÇS—bèc±xbLKlØÔ=º–A@9q”'ß·? G_Ã'S—åÓGDv æ€ÎUóÂ«å‹ á‘œpŽÀXвe³Ð»_Wj¿†Hi3úä”<¬Yºµ~#ví)Q¯€Ð¯Zyƒª¼÷Ù|þe/ôì^Þf^­É¦ ¯Y´]5ÐÄ×êóu _74jXšöˆÁÍ”KMô×™dÄ^ICqغq†l†m;ê |Yw¨#ý1èÓÑ¿ßQ¼óÖQ<Ø¡’“Ë*¯¢jÕ$Pl82ùÖ:v”€HÎ2¡¿y3÷7LÑXÚÁ×^j6ŽN@VV&Þ{g'ªUMÅã£;ÂUç J™Ñ_ŽKÃ_§’¸Æ›X¾dÖ®«`•Wш*}²Â뎭›Q®¬¹ýd TÙÙnèÖ3Ûw‹W˲1çõÕWÎZų]4(´5þ\ÖBy¥xº»ÀË› TŒT‚'“¶sZz.Ÿü\d°xá¼øR0ίNÒz¹ÀÃCèUÅb ÏC“&çðö›{1`P7äåù))%>>:Ú?ª¢™‚ôôÞ®z­"¯;®åV.²²y1]6žµ5ãñæÛr~Wž—ÞS#ú‚3•ô¹r!—t|3}6„—·Ì+×c Wyݶy‚['ج„®^sC›nŠlŠËkAzK¼þôC¤cè‰ÑÁø}vÞEíÕ"×ïrŒl!OïKX·zž{¾Ž»¿z´ >ˆ©ìB·îh{”Ó‡óôH39¿¼ñ…þ€>›ôš­¤(DýÚdiòO~ÿÙgÖ¢^Ýë?a0—.¯FíÜéù%j ¾ÿÛ·U±Î«|_϶yݱu)š6I´@©©ny°w²±À«EÙ¨k1æõ›¯¢@ßþP“ZeŸT_=(”;d¸!ª¾àîi6…¯á kŽ_göVìtæô:—lŒ½ŸLÛûãà¡$µL+çvQè—ÙN¯KÀ¿žG­•ˆ‡»¤¦aü°óû–8ƒ ë°wŸ±xõ+!AmÛ1Ï´Ue£ð,ÉñïòúÌSç@Wb½Ñ³w>¢¼ V±A#¹º]¤vÄñ§±u{…I Ñ'ªèKø¢Ñ:;^ÅWßÔÅĉ£Ç<§\É81=d'åWò0Âü™OÿÊÄ'ÃמáüF;=—,Ôo°kV®CÅ iýÔƒøcN?¾di/å¯Ç°—›2d)fΈ@üu÷¢yuÃÔç*¼÷Ùôë÷’nV±™×ÂecàµJe5¢EH›é§yêéPDŸkI‰ájpÔ¹¹^À Ð5´!ö¡´ÿ-åéúáÇ ný£ñT`Æ”Ò}q >ú жDDµO|53fòU–]ÞèÜ¢Îsàís¯¿¾Çϧót',\ÔO± kq¡ÎKGÅÊÜf»½{\TîotŒ7FéA`w1§w¹f-6<ÛÐà>Õž±Î+ÏOún=VbÖ¯Û^‹{ˆlÞ{¿>˜6Ìf^­ÉƯÖÖcW#Z[ÔáÃ¥¨-šbÍÚ`ÄÅ–†«[wY1xlèn<3&þ¥ ê\µŽ;šo¿oÍY3¤${ш5Ð?÷ôY”ô3x¯ÓÒÜ0kv-ü6+ÖEF†+¼½o¡eË£xê©}4à"ÜÝ ÞèøxO|õõý[‚3g艦í_:¾(¼8ö ‰7‘e,µè·ßÕϧ—”àÊUâðÈ#»ðÒØ“tQœ òE^ãJ+¯P~â„ã¨V¥øàÑ$¼ýö{ Í¼”Mf† yM´Ê«%9€´…]¼èƒý|QºL.Þ‹À±¾•ÍÎÖáä)?œ<é‰òrФaµBðà.Ìþ})ªTNg`´Þ˜2ýû×AÍšFþ}ü,|}:âã7cæ/ëóé§~<ÆÑ;nä›"}V– æÍ½Žõ—cú‘Ô~¹x÷ýX±²?†¬lF—ƒ¹sÎá?Ï.f6š±´ÂxuÐ/fÀö‹Ïç+¼÷Ù<>fºvmj3¯Ödc‰W‡ÐÜùeñü‹}ùÎ @pp ³ôý˜˜ ìÝ›„žÝöð&GbÒëõ0ãWj«&%P·®éb[t }Äžë˜üÚüç?çÑoà|u5A‡‡üQ¶œ¶ÃSýLytØŸŠÓ 7ÓŸ8Ñ].7Á[þù©ãÖ-[pãz,5ã T®”îô Æ¬‰Îå7¡’’s°qãuT,kW…3&WÒ:¯¼’ÐoØpݺ¨¼ZJ) T¯M¾¿Ì쌎Ôâ¶òjM6yíÔÑÜŒÐÖbW ôÜóðÓ/-àá¦CPŸbªt½§XÂ117Ys”‰rå®cËÆ­Œz7ç«§üüÜ™kS‚»'‚ÁŒ> Ý»d,ì‰)òå=¹»ñQ«d•P w¹±;s&…Ú/Ý»žÊ§OÏðg<ªÊxæ{cÅVH`퓬'‡6Ëä×ö zÕ›xnlGÊÑô¾&ôé¿›Æ8žì¨R±pþ¬][Ñ*¯ýÒ—+{{vn mfûn,=Ý í;µSdS^-ÉÆ¯ï¾}Ê*ví  ƒZcɲÖÊ⤀Uv$ê“ÇW7HY’¦ÃךŽÞß…óÂ1n|0mšÊï%þä!éúÃ@fÏaÊ›LËè®÷Ï­|GÿŠ$ 22ó˜Ï˺äþ¼ ½Ä×$°«Ó ½NÙÊgd0*'¯LÆÂF ßG_Ôwzðü´ÙLèÕØ–ÄæDËÁ%_}¾‘Ú¨œU^éuºغi-BÚØþ‹‹sEpHw½lŠÇ«ˆÏX6yA^ùy¯cÈ 3 ±8ca(vR½3f=î猅ÙPêyô9caR™Z¬º°½‘þxyB/újBh4øçïÄ\¸ôõ9Å8Y8Þzý0xéJ,lAXu¼ñf_Æ¡‘^Û‰ÑÔÐÓOž¼Š)§GhSå@<¬Ÿ~ÖÓ¿îCc\ò½Ýõ;7±¢RQ©òLy+OŒ:›O?ù|ÿcÚ`Õ¨¿’Ò*çG£Æ»ðÅg›Ñ¾]œb\ºì…Iÿ÷ÛÒÓnss=Ït’-øüÓ= g$+ôÖyUé‡ _‡/>Px-î!²ùþ‡úxsJ¨Í¼Z’5^­­Ç®F´¶¨ÄDwÌ_±°fˆ>[™Æt7>ÉHö téoBˆŽöfnMlÝÚ ±±¥èaN7Ðw"=Ác|DDøcöœ†ˆŒl€¤D/ø—I¡‘z#GžEㆦƪ„HV¬¬ˆE‹3Ù=qWƪ®q«¾#†_äöÝ42•EOôª ùôÙÜ=cîô!„ˆeεi¸Ä˜×˜èJ @5úÁƒ®01ÍÔÓ]\ ‡W9·1}r’g¡¼ZZ‹CÈxa©·ØSˆ¾——6~ä2…Bèݹ»²…^R?E+IU…»»õ8˜vÕŒ d >>Y\“¡rÃÚª„>;‡ôÞé6ùqnqí¢ål¥/JÚïSRÜpèp :'Ý Î,:?“õ;PËgÐè¯_wヘ†š5lOêw8Ù*$'¹nÝrÅœyupõZ;˜áSÂñWS˜…ív㡇ÔvH}ݼAùôžÞnˆ»ÏXá. èŬKÓL‚»B9ñ÷$ 6дãâ•¡Lº«¬zÆ•ÔTÄ2LòÇoò žÏß]Q.p“¡•7Þj…¬ÜþzþÜ…ç9xèÖ¯Ú„)o/Gs£š<'€þÞ½¹+¾µisi<÷Âô넊•¤ÛŽ¡ÂEbŒÛwdáôÉCø}æRVÙ¦pcˆ¯þÛ¡«˜Ñ‹stéÒdøùnÅìYPª¤õ×·óvWÀ£èEŽyº)wƒmXÍQ*ÊfXÕ@²‡Tã~)¸p>Ï?·R¦Ó¹[†rI_ª½YLjÚ¹ýwsI˜ñãj„2M¢3^@E߇§HIqg‡ÔŽ8v¢ üJ¸3™Í“F³¸ XEÝdXíòå4†nrðP»hÆýâáî™úê§Äé%\s#!×®ÒmÂ0ϸ±ûðÙ'G¬ÊÀ ‡‡GÑ Œ»ÊXX›žŒ…ÕVˆ¥àR'Ù“ƒ(—5üŠ7‹šèþŒ¾µC•8ž4U•˜Ÿ)½Ôü+_}#†G2¯{—@E߆»—"3Óí;ö@DdsýkKÏ‹Q œ4i×~>ùh7:tˆ[iU£9?$mB/mj qËñéG‡º{áaÛÊ'MnB¯û£|iÑ€¶«z˜S1ñ•ExgÊôîÛ“-r:¨¤VèÝÜ.шžOC[ݹY:œ¯0ÛîÃS:í‹î=FâÜEæ‰+5jZ'Me£zm¬Ó_Í×XsÐ+aÔã£Xó_£½ú=[§.+˜F³ƒ¡ëN]'€¶/p!ã„/¼8ŒEŒ÷ñKJФjʸ$³¹Ä.¦â†£OïKÊÏ$‰í絕ؙ)=}ãº8fˆnÄ÷ßî@Ã…ç%9dûý¹+(ïÙX˜xR£c<í†R¥ò¿É` ʺKÊoNœôb!¢ŽudEÓßwÿ6-òž‹…Eí÷Çê5Á(Q²óŸË°l9“~ˆã¨¸Ä0åÒP[%¥7«×TFÔX¦Óþ¾Hâ´~àÀ¥bâ^<îÉXXØ"¶=ù£kà›3•@ê¶Ôéß³há%”-½ ¯¿±UªÙL€wÅç_Ü#ÇúbðÚlK'01¥¯_w^yå°>ŸùÞ‘ÈfÊÛ­Økrzô,¯ô‚Tì~â¯çbþœã,6X„1££Ù\aãÑ7§´…¯_ô.ÔìiX»b^·;]/TˆvµöÁà¡ýYP‘b_}C&½áÇ éÙ³9ËϯÄ+N3§§þïô¦Vd ®—Ú¶Eé0%‚Ré7o>‡¾ c‡Wëî÷ÿEX‰l^scaU©Åõ‰sF²‰Ø›Év~"›?Ù¼ú ±`aWôíSÎŒ^âÕk’‘y˜½V jUÝ…½ÿA >ü¸KiÝѼk±$¨ø$$~㢔ݜ9“ŠF÷ŸCøÚíì1ØkÖ5Fjž¸ï>zQõ%:ÆôgI?bØ>î ü/âÄ"Oü8¸Ûè5b} jr™8aeŽDØ& þZ†"›7ß8ŽvlÿW™ô~¦ô¬ NËÈAdÄ ö¸Å ÉÍxæiµ‰¥Ã®象­°`Q%å T)7Æq¤.Œö A$FrüL%~ãᙄ•K·àÙçZr.Ueºé]ÙØ^ÒSÑŒ>­ZÇö͛ȖÝw· 0!Áe=]p&º íEJ»ç:Š’Ne~Xbb6ÅªÊæ·ö¡wŸ.ÜÊûQ¶è¹½OLÊÁÍTÞvyö©ýl¨µß1:¤ ÿÙŽ‹SëµÔÒfõïJìFê°¨e\u×¶pÆaçV6#WÔ”ÔcÉ.M­#3ÐK]ØìÚ±žÝ7lϬ»[Àbiññ ^F²YÒzEC)Öe)²ygÊn íEÀ_:cz‰Ÿba£FîÂ/?ívLMšÜŸ|Þ÷»* “úµ*ÉPê§\ÅSì¸Ï<‚›Ú¨€Ñú* —owï±+–l¶)­ôn޶vIííÖ³+e#… ò?}ÉwAÙðßÝ»oÆ—ŸE m»A¸~£–>f‰^¼Ñ™˜ƒíŠÍ[{²Ü˜µëšÁ­ℾq“ 3°’= m¯-·ù.90¡È¦Oßس¯«µÕ~jA’þoŒm‡¬Á"Öé‹l¢ö—Dèà!ˆ¹ØÒˆ^hÕVËÎxrô|ýEýjÖkÙÕˆ–妤¸âé-X‹Õ-P˜Ï’'Ùt¢>ãP·^>š¶½º_ÎeIϤI±lEV@TV_Fôÿý&œ ä¦Éã|ßoëÒöEùãùú 2Jú ”¡XHÙÜtœCû[ñù'»¹£5´Þ¶½,{Hö4¥wIcÕÊ)Ö¨…ãýwŽ \@á¢Ý¤<T¡{ýØÁ"ˆóÇ+p'‘Éò’ôy$–>"sC8=]‡õáغ­žZÆ2šÂèoë]rð“‰&ZÁk‘û‚”¸Ò¬kÓæ,zöˆ7é5©±aL¯Ö…Å£S§h¶ÄIä}(zëf¤†)bO$Þ,Å*Í,Ü_Ÿ• nZ5„O³³Ùeéyõåv=³Hz¿ï·myRØåGwGYæ6»³æ,­[Æ£zuËÕ®ÆôÙl…P:Ié RºtÑà‘EÛ@b…-®N Ô ­Z7Bzlâ”Τî¿hÞmÂÓOE BCP5)Ù•më"!¡ó€ë²<¹diùôÿy.EÞ¶;æ@'ºpÑ ?üÔ%Kv¢½S=°=p.:™SŽpèËzVâždÛCöØš¿Î ɧ÷õuÇ‘C×pðÀ>öLZ‡nÝb‹äÎîúiF-–‡ÒË\å#ò:Sc[òZ[±ìÒn.gük;‡Ù¬*uÅÿ½Þ×úѬÄvÀât4¥/å·~°×¬¹e‘’¸Ë D6/Ž{e+ôÃí¤Çµ"FÅI+Í´fÏ<‡Ö­àµWO(²9Þ cÇuFƒ†]Íè/Dz=ßï‡ðÂØùèßWí`í°+€œ±°Û‡Zg,Ì ûÛhrÆÂœ±°¿ ùâ= :<óvä»ZíE¨zµV¿ê;\7÷X¬Xºšs0Àé¿$ßWs½›NT¬C³¦Ç°cÛ:xz¿ÏÎ?º“vúrb’Ì ëMÙÔÓ¯@dÖ䤨Cò3E6ï½»“m•9$&/ ½þŸz­Ä&Ÿ|b~üÞAç…}8­.“š媥;ž —ÓP l)~éZµaç6Î ûO0þ\ÚYP¢D–•H™‘^-]ÉÅ Ak0ïvºö¹ì Áõ²1Š…™ÈFm`*²ùòóÎÌuõõµú² ½.•’ùxu‚ƒN,¶ß}©ÈæÒ%/ΠíŽí;»Z gÃ.ïx÷Ýå?öD¡Y vÝÆ‹ˆ¥>)Œ3>ú¸#iL0”æ'^>1èÙsÞ~+ õë©=å¦Hß|ÓßÿÔ= ùÎÏ•aºú©ïG"°Àˆ¥;{+íwµ+±^xçÝ6ì#ù 8[VÆq2ˆp’NÄíìÊqœ Ñ váù ÞŒC ¿Ž@Nš?~+gÞ‡‡{áNY»HwB¢vì`,ÌŸ1˜lö°I@ËÉÊß-çÏ{r O6Oòe,Œ±³"èíw[ïì•Eëf{»È¨rÌBô`H"]à{_½‹…ÆôII¨R%´MàìÛ²@ÎØ±Ógÿb¶¡{9eÜS Ÿ¿˜ü}eʘ¿ŠD m`ç÷„uŒ÷CnvZ¡ôwöÚ÷j—Ym±yS5ÚBtÒ{ '3U+Ÿä¹ c˜§eÓC熜¬X>Œg”‡×–yvhžé_5eP´/G8ÕfÈ‹㸳±}{öEl夛՜fèÕ'#“¦Óµƒº£s—Š º›Ð·’¶==ö½Õ·ÿê{KÓ>싎à b€aiOrRV,AJâ*Lxygþ¨*¹ú&&ôÍ™ÛÛ@ïÊ—na§Õª±Œ²?®4$-ì°+€²©y&¿ÑGŽöÇÐaá.³/ô[I1üvîHã§íœSº uë¤"~¶3ÊWì‚.]´™¦†ú'¡»²?ý¸ž5c¶E“oÿm´ÏE6OŽé­:âþûe2‘Ö\AæÞ»àϰf.Ç×Ów+²ÙY /ï‹.][™Ð‹ÉÂçõ·تx!{nŸÒçª[æË® ßèÏ jî°ª m[¦©š¬1IâYض-ÆlÂ'ħŸ×§_<‚`ÎTõ¶H¿uK,>žº”‘ CêìsKïìUE6ŸÙ =»—GëÂò­Ê2ò°oë®ᓩË0ô±X<1¦%GPµE®eÌè¥õpø†D$'œã 3é©è S›'¾VŸ¯£`n+Ýèk(­LÈÑiµöIÈÚ£ÔIDAT×™dŽLJã8¥8lݸÛÎf´[å˺@¥”ÎZæôéèßï(‰wöÚñjÒÿº[Ï6Ò B­š¾ìÄ!;SÑÉ}ȱ£Dr–"›wÞ:ŠY–œ\Ö=_{©Ù8z8Cö2ñÞ;;•žŠÖ»j ÐÁ­±xi3®MÇ/°™‚”ê(eôù°žé–øyr™¶‘ˆ?nd(#˜ÞÓª¤q¡íÃïHö«^SèóдéyìÚ¶‘;¸¢›•Ûñ¾ß¶K_ã°ÜànŠld&šÔ×¹¹«ú\¢D·ÒòØq_Š5sÙ¼ýf$ |˜¡ ?3zi‡'5a2úRF[~<Š¡Œ}Ž g,ìö`È sÆÂþ1’œ±0g,ìèž…-Z\•ñ­A KÈø&7CU%Å骋E×îáøîë¨V5U©—ÿè“ÆÜ @êÍêŠdVý]vÿïªåÚ]Ilëý»0ï§Úµçë‹)©bÙ\¸˜…¹³#1p@?¯ò†øù×~Œ›µCº’ 媼ã5ú'FÍÃÃß›¥Íö@ž]”™U£ŸjÏÞ‡]™£[RsÑb8´ecËæÃøjúb´{0Çûâɧú²B ´¦ç1?Suš ýÁƒ»0û÷¥LG¸7ò¡íãkÚ@sç—Åó/öå;7€­K˜Æ¶ˆ£˜˜ ìÝ›„žÝö`æ/‘˜ôz=Ìø•ÚªI Ô­« ÜÕš!©ô{®còkkðòø{Ëöž¸¾]ôÜóðÓ/-àÁÑDAA~Œ‰I‹;U›d±Æ;&æ&“¢¸¥,w[6neO›æØUCQT;°wj×-Sú,v#=É*Ž÷Ä ´7“vÐÀA­±d™´"ŸدO­ßãx‘ü•-˜X¿p^8ýÁ´uj*¿—†œ’þ¡? ôÒâîvïØ@߇õ]œ½ÿ¿r}»è‰ÑÁßÝE âP¨ÅÜzPåyz_ºÕ,ëy¾Ž»¿z´ >ˆm›Ö)];œÇ¿+»èÛjâŗز.ÏW aV댨IvdÍšïÁ¦ð5?¡9»Iô–fmVéul¼9zôRöCÞûïJÎyvEvЕXoôì݇„P I—zí®4’«ÛELý ÆŸÆÖíœ0< 7’õuaæô%üN1 j.:wtnåïÆí aPm>õt(¢Ïµ$ˆ$Ó`׸¹^à„5øfú>”ö¿¥Ô9ýðcÓ`c2TYY¡Ð}q >ú ÊfOêòÿò5ì ®3v÷BÌ!¤‰ÏÑba7oºƒ°ÙøÊ¶È¾Ðëty…Ž©ÊéR›J"˜'w’…µÒè³³]‘”¤£ #—»Oë]S5úôt7Ž*ÐÁߟM69\¥¨Cè3L-UÊ6^µó9€)&iËÙ¤òrlsF²«)3;ÒoÅržG½åé7°LÉY¹²R>}.w”·nF㾺û•Št3> òš››mDGzÓÒ‚âÄýä¿cg¶ðm oŸ:LIõDVF7"QèÕó4–šº5ÌéÝÉ뫼Z¡Ý´'Â_ÿ·‚Û¶G‹–~p岕Í⤘£h²”-FN3pª¶½[¸¨*[üöÁ#}[0Ù^ßÀˆ¾WÏz®¨ÎâïeÞÖ‡ÓZ4ýеGej‰³å!›˜Ù¼ùΜ܀W&nà0<µîìÂEOLûèAø—éjDŸ«Ì¦Xòg4|=9e蕽,-V5†9¯tf1OY£¯VyƽtÐf^ Êæçõ¹ú¬KÍ#k“Ò…®TlX» ZNP_SÖ"¼NÿºbÎ÷6¡·Æ«5Ú@—.{`ÈÐ^L9hÍ:/é>oxú$@zêt[ÿžÃ{o/Æc^¦ͥñÜ ¡,½­Íx˜§I·z~û¶c˜õÛB–¢¤DÓ¿ÄÌY¡ì^Q•IérÓ U"Ò=déÒdøùnå$ã ôšçà™çƒi¿u%`˙Рèó°`~Ç)­æ.ò æ ãU¥Ÿ?ÿÞz}¡Í¼šËfÇ=±9»ôÎ6¬]-lß‘…Ó'á÷™R¦“Bðâ«ÿöåDæ*fôy-UÒz}¼]ôÍ·U8ÿ«;*Wôe‡VÅ~P¤RAÇ:ù[¬eº‰ÚaËý]t$6ÂÂÅ!|=x£Þ}2mÎý¡d<ÿÜ|øþÉb(1Ñ»uÀÅ‹Aœ]Àüµ³…r ú²h íÜ~ƒ¡•$Ìøq5ófÒÑg@†aʱIeSz~ïFB&¾Ü`…ÄlX·žcªÊXáUXVéw’>¤õQÛy- ›°ÅmX_*J¹Š^Úšòª¬ß2¯Ÿ~tØ1´ ¬"†x’¾–Òª¶±pèxÃ:uÞÈù_›ðÖÛ ðégCx[8Ô*}&¾²†«u¦-]'“¯ÌÞ}{²mL Î/7ÁÍíèùhÒ8í;ÀÕ«l1c•>öÅa¦¢,Qr½‹âUŒÝÎ7ƒ×‚²! !³×Ì9TÄfS_YÄsGŠÅkèÀ+Ž  ÔTw<6¼#V­–éy2¾I{Nô 4ùDxûc_¿Å<è"we¾iŠÓÑLá\•^µS”ÇŸô•*ïÅš•aTÕÖûúY“Ʋå•0|äh¤ŠRz0:\¨¯ÍTt겂©%;èÊÀÛï6d‡¯aì3(£ª4z­Ë,õªk,&LÇïå¶Ù­p^y~Oï³øuÆ›y-(›î=FâÜE扛¬]ÓFÙ¨^c–/Y­ÈFxõø(ÖÁ×°‰Wk2³« $‹:{Ö ÿy¡ŸüÎú¶³úv-.4ðsÀÜ:Lxé$}#ªOl‰^ˆ§ZtŒâkòÑÓòñrŒ¡ßèïb‹Lû¨ s´¥Q^•§Ðº7¨ó³‚ƒ7r˜ï4l œ>%E‡7Þ ÆO?÷5¥§Ötw;ƒÁƒ×qÄÒÙªßȯâ ú±cWàÃwÅd¯e³0¬:e3ŒsÕ¤²tèP—d6\Ø…é_„£OïKÊτןgÔf—ÜÐô–yuXÉÂd =w~5Ö…5C4‡êzxfp|ÓIN*<.ãÍ£Ñòûì:غµ™:îÉGÆ=éé;‘¾»¯‚‚‘r¡++r~Gc;Èê–ºT¹ÆWË~Ϲ[4mu’•EOôª ùô2ý&(è{ëBè€Xöä1ÍI2æ5&º/Ÿ—O?xÐþ¦žîByµ ›:fgÏiˆÈÈʸ'Ž{ isˆ=Ï¢qCøÆ‡1½:îÉ:¯–@dw ¤-J¼ÌÑ1žl6åË.e`Cì¤BcDr8~܇c¼9Í'·Húâj$?uˆ½Ó ÆÒP³Fá|5zÙÖ7ožB­c½3ˆÆë±c¾tI¸I_\^SRÜ”µËš‚‚²è9O¦íf=¦Ñ_¿îƱh^eéŠÚïÏA÷Á(Q²óŸË0U#“>—㨸ÄPÈæe{¼zMeDxeË6‚€/’2òéŒá+ èà¡5@ÅÆy`öM¹{åËW¤£cµlýˆáÇ‚0ÐÅkAÙHxbμ:¸z­‹-áSÂñWS˜Å)Ž»é 5Í‘’^“óåÓ{z»±Ã›u^RmÜ€/¾€ÁCBP£¦ì Ô‘i4fÿΠd…˜8ñ¨"yrü9µcä¨úÜòÊÀ”þÁ¶³ñÌÓ§Š«pú›,3z…ÎÁšµ²cýAâ‰ã™×=xèÖ¯ÚDßÏr4×÷lÞ{/Âf^ ÊfÚÇqñÊP&ÝUVçÆë]!±q9øã7yÏçïÔ•ðúÆ[­•Ûß@ÏŸ[ãÕ!m g,L½-ZìÌ $ã»{Gptí@oªcwÀ† ^A;caªlœ±0ú×(™˜R,9caªË û› ܆ýiÔX˜O’—¶jç²° Ëã¶üÂH]Xö4Ä”L;½ûÝ@/uaÑŒ„¯g„¼ð“±F\»Î½‘X˜V Cˆi¥wä)±-C,lÔˆ=¨KJ_ýˆNkô´Ÿt霎³Ž%Úå­òšþbójI6ªé¦ÄÂõ&q<½““çÙ¼ÍXØ Á !éy5¦·Äë/?ï¶fÙ·*cÒäFøäó~dRŒgi%ÞdýZPý”«x ;¶®À3φÐm£Z Z-Yzùv÷›ØlS§uM2ñVF ]¿¡}1ĶŒ×#ÞèLLž¼Xq&1ŒÎÏRæôúP‚ÄÂ\\ã°p~vï®X(¯ª-öÀ¶WsÙ„ˆšÊR.нûf|ùYÚ¶D^kéãxš'ß2¯ïN9á˜’ŠŒ>ýF±k“ä0ãÕê\ÒéP\Y3wá˯‚è™f$ù̲måÊàå´is1aÜ_V™¶ô 9߈Qí1o~ož_êÎÌÏ/Æ®¯ï)æë„¡Aƒd†5Bqâd },Ì==Ì÷ÕÛ…ëWáø †aŠä5ƒ¼.·™×‚²yõµ‘\;[üZY»NOÙ,ÀË/)¯;8h>¨ÖW'5ew²Çø$K¶%vÑï³jsÄR/#zy '£\Ù˜øê¼ðl4ý:j8ÜWÙwè§M3íIX¯e³/ÊϿЇ“z¤ßÝùR¬ Ve¸žCû[—ÛF÷'æcaÛö²\cOSz+¼:,€”'…*7b¯󟃘ÆZAxãÆ1èóH,+ Ì áôtÖ‡`ë¶zj,Ì[baÖé‹õ.#±ØCË—×À±ã5ô±°xtê%rmæe/ÆôÙô]欳 hÚ˜ZŽf^ñS?Í-”¾¸¼Š–^Áª’È}AJ,¬4camÚœEÏñ&½&5™Ó«±°Ây-(K»k âÞ\'½cIÀ ǺwÝjœºën™c-Ø ÇºwÝjœºën™c-ø_ÐÎm­£ky³âTš X¦:–(œ«ù;ÈÍeUmBwÏiônGÔâ9dÛ,-r%£NòXL’³,¡A-&ÁÔõkZDW¯æÅNn…Fãÿ΂ßq, ˆJJÊÆù é,VÜ÷$Ý¡¼ùñùcV£˜òå<èöwuj Ǻ߷}5¢RSs˜Õ˜‰a#×ä$ m@Ä{Z, $7²÷Ôêœ/Á©y:“±”·}õÎÚ]’v›™™Ë Çüßë§e„’€G^a6H©·ãG’(½<®ÆEww‰©ÈÇî<:ð/J@’"$3"++CÏI-” qÙ‹2)s´ù™]@ùZˆ—@|\ò{£¹ÿ"GÎSß) ˆq,IG1˜åc¬}@ò{›¤Òˆ4ðÈ¿@ZÙ¦q©§Æ¨>Eù§v1Ó’P•Rû™ö=Kç*JxÚµŒ¯£]×øü¯¥]¿àš×^Ôµ þÞÒw×W?kk¶$Ç‚²4æÑ˜ÞX®F™UJrM寭KÖ#‘€E‘¼º4í£u¿ÈçÝÚ I"ZFÀ¢½ÎŒÁ£¨¸BvÒ;®@ùˆÐhÀ‘ °ÌꫬH~®H€düq‚ÇqAðOW¦HÓDÆšiMÝY»¨ùSûhÀ*ê»ÿ”ç÷ï¼´WªMÿÛlUEí©Ô”BóÏgÏyÅ;! DZ‹ã?-^¿(i_2¦³õ;w‚aç5n¿ŒwY&;.K—r‚áö߀{êŒNÝS·ûö3ûÿcÖcËGs IEND®B`‚golly-2.7-src/gui-android/Golly/res/values-sw720dp-land/0000755000175000017500000000000012536111546020002 500000000000000golly-2.7-src/gui-android/Golly/res/values-sw720dp-land/dimens.xml0000644000175000017500000000041512536111364021721 00000000000000 128dp golly-2.7-src/gui-android/Golly/res/drawable-xhdpi/0000755000175000017500000000000012536111546017256 500000000000000golly-2.7-src/gui-android/Golly/res/drawable-xhdpi/ic_launcher.png0000755000175000017500000001524012536111364022163 00000000000000‰PNG  IHDR``â˜w8gIDATx^í]XTWþgèEPö[T¬AEÅ öšˆ-š1ÉfM²kM1qÓMÛ˜ØcD£FÅ*h¬AEKTD* ½Ìþ÷Í 00f¢&ó¾o¾ÿy÷½sλ÷žþd0”²GzuãÅaÀ#~ŒxŒ`Ž~…£Ð6œ6&‹ÿ“óc¢ú6 ¢f‚Œ/á§Xõ­!mÌŒ7¿y}vއG-ÈdFþׄÿ …qqYhØd•5Ç)P ¢tÈŠÜ›ñcsóšWZýúV5¹¶ñ\bcsѰé1þ™ÍO!?¥³@›,ø{ Ñ(ý¦¦ ¤¦šÂkØÚy£–ñD Ÿ29Bº¯˜›Öؽg0ê>Õ–H¼ƒFõwbèÐ ¿]‡BFÀŵ=¯!GB|4ºtމݓ$ü|¸Ž&áÅÅ $%žÅ {вe–„‡¸!úŠ/\]›¡  H‡ ÝMA %¤ê£¤D†µ:K´98:!=-¹0yÒIÔªU‚êh×6ºÞðáÛâÊÕIxÖË®ôzAAéèÛ{fϺмÒÖ6#кµP¨”‡Àýžÿ ={$cÊ ÃàÙÕõ\M%L̆Ûã0ïk%ü…écÑ·Ÿ¬…æÌ#¿@†í?_ÄgŸlD-ÛBÌš3#Fv*ÅSRKrð6¬ÛÆYc‹eïNÃè±M f‡8~îL0ñݸæLªÈ0ÿ­õt`®mgÎä ¶Ý6|¸<UÑ>çÅ«Z¥«W¤¤˜£c—¡d„š·°•¼y%d`ÔÅLN÷|½ò†ŠÍàá¡´#ÔøÓ­.`Ò„«˜>{:wt€££¹„‘'aa÷øQ>{îPtïîÄeIÉÁ<š/¡¡©xaJ(ÏÉÅGŸôF·n®àÜË,ÄÙÓéøðý`„wľýÑų6g£¬ MÆÏ[0h`ŠV&I÷Y"‡·O_¤$·.¥MŒýF6îÄ' `gÆOâ¬ÖA{èÉ@ØXW^Šõ*€sç¬Ñ¥ûÞ®-¬È¹¼DZ§ó¨\ÉäéX¼ð–½3´‰„Ëdex£Æw0uÒ,{Ï&&2i}–É(ä›_ @ãÆ ¥¸™g.p²0Ÿšsa‘|®ÀÕ%ë7táž —pN /â=¼4÷7\¯ƒ'›ÃÜœ¸¹BÀ*\Ï>Â+ó´?¥B™™¦hÙz’’]Ji+áÑ›+ÍC,Y|€´yë¤=êÂ/|ðîW°^šf†vÏø!!±¾ÒžS€ßâËÍýÖ­Ù!Ïù¡ Ð¾Þ«÷YÌ}1 'Oç)4¸+œ_†Ï Äå©>cz6ÌÀ¢%㔦dyœ‚þà}\¾âLõ'ãU7¥ú\–‡­[VcÔÈ3@,…½ûŽÆñ“ÊÆ$r(s‹dì ØÈåsŒNÚ#ÎÿˆÚöÂÛ yèUbè÷–wÄÒwž‡¢¤ÌU!—ßÇÛooÂÒEç1c¦6þ4‚¸r‡ÀWÿð5|GÆbè°q8qÊ 2Nyµîbf–ŒUß­‘ðþ¦âlXW.žåagƒÝ;W£¾G6úœŽ1mÊá xÔç>°wïZa؈9H¿çQÎàW }‡“8ì»Z•Tž]þ[‘Éó5h“É 0~ü.l\‚åvÐIû;KÎi®ÞŸ/Ãç_tÆÿ¾÷Áí¸ºxÊ9Óýâ­á\ ‘žn†wßï…M›½–jWŠ/]tŽKO1nݲæSìCM¨ ²ï[¢a£x¼6?/κ"áB Zðæs8r´—'9Ú<}‹îƒïˆXé±ZÐÂEC$¼„êj·nxÿ½@ôè–,1àÀAwnÄC¹¯4—–@üÑ^tzFØAUbâü÷#OmN°³ÏÄèQ¿âÝe'áüT—³ªi×6ºÞ ."ÔµS§êàÜ…ºèÐ> ÏöH•ÖsõQP §:è„«×j£ã3©•ðû÷M°?ЉIVè핌vmïiÜ{r²7S7ääš`ð DÚš*¤/â}ŒxîêÖ.–²ãæM+ ¢Lh?h냚¶°p'4n”E7‘z™öTíÇÖ»„žÿýj¸y BÓfŽˆ¾˜„ô”¼8ûWIW¾c‰Öm¼¸/Ø!:ꮄ¿:ÿ0 —j*cÑÙ³3ìk[à\X,,M·ÁÏ$ÿzÔ'~›Œ®ÝžæŒ#ôÔ4kâQ¾7$Úƒ<(øñ^ÄÍ9ôT8¼{m—×]iÓÝ´¹’SÇsüÆÈÉ)’ðÁ~‚§§n HÍ´<é $ÑÖ¬y]ÄÜHÇõ߃1}Ú^e’SíÊ xý_]‘’2;©÷ŽËAû¶?ãÍ0yê`¸ÖëCÃG©fŠeCà#žûÄcô¸1èã݉O­jà°[¨™%|â”É4䘛)gT1÷Šm[obÅ`o—Ù/MÅè1-T¸ŒÚK öDâ§ý}Ùú|}]U×VâÇ~ ¥-ñ3÷M‹»"ÃV~ÝgÏú•£ ˆŠÊ‡¢8ßwo¼ÙE'틆kXzññèÐé9ØØ8£iS.;BÏ.]¾O†ÜÁ—ŸÄ¸IÑ Amx¸«í%ÞªåeLžð;^šçÃÛQ’IˆŒÊàRö»„Ï{uÚµ« [ròˆ¸p6B8ÏÉÅç+»·Wá2¤Ý+ä,ÌÄ;KŽâ칺\zÚH¸¹™ÐÍÔx:6mØÏYtWçêST$G·ž>dp“RÚ„p#&IwS°uóA¼à×G'íÂöÑåRÙm¡W„ÑèÚ}§º uqä&ÔóÉÀ¢"ñït,ú÷I¼óÞ`²•z85M}4j¼Q£º#.sƒî+©­BO:^ïYØ%*ñ÷úRkbdHšÂNQÈ øô¿‚zÂØØ•¸¬/ ¥,~9÷EÚjãä©–’a*üG”¸Ÿ|ˆW_Ñmdd˜ åÓc”äRJ›° ¹ŸÉdùTyoýtÒþ Z¶PºCÊz€Ñ0ÚF;@hÛw4Æwß{ãÚµzôù$`úô#t#ÜàÔ/á”—ã‡Õm$; >Þõë+ñiS¯KKJF†¾XÙ;ºÑÛhC/f æÍ;‚!ïHxb¢%>Xñ,ÕØŽtq˜¢cÇËø×GàÙI©Çß¾mMP KŸ—×ynþ'д±RUºX}Ü¿…¶æÒQ,á ÿ}œnóëy`Ûö2ÚêÖMÇØ±GñòKÑô=IZVU´k»€^— ŠÈË7‡…y‘dðT<„i/pK‹B­¸p~˜ÂÒR#N]:LQ± ÷9=˜•76ñ#+h˜™Uv€ ¼°P©eéÂuI#+Ë”š;²óÜ`f’Lõ5uÊî¡ût=-ñËÆ=à!x­ó§O„ Ö…‹N05ID×.w4tá¤$sDD6„BfO]º2®FjŒÇÞˆŒ²Çº càÕ»;\\¬{ë>}îG1wÎ&Qåàðì?0ýú·§wмûMz3µM†bæÃŽo‰O¿˜\J[jJBÅø±[Ð¥K*½¶UÓ®ízzÝ„é?rôj]i˜”ÅÎÏ…sÝcÌÝ9þƒ|Fl wu^ïÚy7Þ{çÂÃòäOýý˯z2d:¸mÀï×òp71ûvïÅäçûé¤}ãú_5¢‚ê׫.]²Â3ž#è~°§%h)¥Š4¸۹ô¥bÅòÓ˜7¿#]–Œ¡ZH7¤Æ›5‹EXè)•åqž'å°hz@d¤:zN£n̬82Wéi§¢F¿©Y ƒ×‡ñïÿøRM£¦Þ´Ù-+Ûi´h÷ínϲіhßÞl¸"ir ‰yˆŒHeð^ ¬ÛV†…±]Mñd¢ ×?9ã¢VV´v$)ò{lWsŠ–°h[)—p¹ˆ¨ð†lWs)2€k²îÆyï/oÅË|¤^?ªxN~¾‚]EÛÊ«pqÎÀ†žR[J5.®-µ­œsááölWÓœíDÛJåC®ÄX²(ß~Û†m)Ÿb¼Â„Y{ʶ–9Ä‹¹”©ñdÆÔ´‰:áì1J[r$m}tÒ¾“Æ©ÓÓï$˜3wÆkd=UkG¥«AèùŽÌŒþv/ÆOœÊµWi%K¹A*ܳK$S;vhí¡žëÖ7ÀŒÙÓÈUÛÛrçOœx„½ã2ØÈƒÕ'5ÎX¼p;.]rÆÖí"eF\[Œª¼¾\VÈ®°ò«îT‘[kÁ ˆoÔŠ‹î"شŵ»Q:i¿± O9¸@Cô2[»j4w$u[J>ý$pæÌmXÉŽYÃ}Gá`0Ÿ8—jÄ?üpÞx-ºÊ%()Ù‚õ³Ø“¡%OUŸÏRPó$ÖüÀæ®YLŸƒÔ4Ñ–²lüÚun øÀjVêØbü„9Œ`1qLÊ[RJªAC ÿø:löoŠ7øI†biOLþ£iÓ0=ò“„ÿsÁì ´‰œ§`ìÝÀ´ûguÒþ¿¯k¥Mï›°è¾à-¦Ÿ÷§–àÀ%%…©!´‚PÉ•šsÏu87³œ µJñÕ«qjWŸœr¸þ1oB( ‘bOLûzÁDñʸۖì˜RGM=\àbÃN¼kNõN;^• „:x‹º|^žŒù–ùÔç5ËšÔ¸°75Ìãz®æïˆa {/І‹z°›·,ae­àK!ò¸iV¶¨isp(Våi&ÝVG{yÚônT÷qMðˆŸ£žTxxX_è\Cá)_èœ'Þ'üPï’¬sêx—xW—² —ÞÇßúô„Ä|fž~à×ÙJ/t^¼°q¢©©*(ò·f_͉/â«ßyïÆ¿ÐYz¥¹?¶üˆ¿ËWd×üŽþ>#ÝUø¹…/]¼M»ÚWš Öˆ·ˆª ‘Y+¾ÅßFü±‡F@(Âù% %ñ­a°hc¬ø?±öÆ‹o#óÿóÕg !+O0^|kXtU1×Èøš1¾âÙ•ëWO·~9üGF3>å„kz<çÿy&£o-#IEND®B`‚golly-2.7-src/gui-android/Golly/res/layout/0000755000175000017500000000000012536111546015700 500000000000000golly-2.7-src/gui-android/Golly/res/layout/help_layout.xml0000644000175000017500000000637312536111364020676 00000000000000