golly-2.8-src/0000755000175100017510000000000012751756121010310 500000000000000golly-2.8-src/gui-wx/0000755000175100017510000000000012751756121011530 500000000000000golly-2.8-src/gui-wx/Info.plist.in0000644000175100017510000000404012660172450014017 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 2016 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.8-src/gui-wx/wxpython.cpp0000644000175100017510000032071112751752464014066 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 // ----------------------------------------------------------------------------- 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); const char* filename; int remember = 0; if (!PyArg_ParseTuple(args, (char*)"s|i", &filename, &remember)) return NULL; const char* err = GSF_open(wxString(filename,wxConvLocal), remember); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_save(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); const char* filename; const char* format; int remember = 0; if (!PyArg_ParseTuple(args, (char*)"ss|i", &filename, &format, &remember)) return NULL; const char* err = GSF_save(wxString(filename,wxConvLocal), 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) ); 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) ); 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); const 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; const char* filename; const char* description = NULL; // ignored if (!PyArg_ParseTuple(args, (char*)"O!s|s", &PyList_Type, &inlist, &filename, &description)) 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); const char* dirname; const char* newdir; if (!PyArg_ParseTuple(args, (char*)"ss", &dirname, &newdir)) return NULL; const char* err = GSF_setdir(dirname, wxString(newdir,wxConvLocal)); if (err) PYTHON_ERROR(err); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getdir(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); const 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); const 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; const 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); int remove_if_empty = 0; if (!PyArg_ParseTuple(args, (char*)"|i", &remove_if_empty)) return NULL; if (viewptr->SelectionExists()) { currlayer->currsel.Shrink(false, remove_if_empty != 0); // 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); const 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; const 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 (!tempalgo->CreateBorderCells()) break; tempalgo->step(); if (!tempalgo->DeleteBorderCells()) 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 layer for storing the clipboard pattern Layer* templayer = CreateTemporaryLayer(); if (!templayer) { PYTHON_ERROR("getclip error: failed to create temporary layer."); } // 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(templayer, &top, &left, &bottom, &right) ) { if ( viewptr->OutsideLimits(top, left, bottom, right) ) { delete templayer; 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 templayer lifealgo* tempalgo = templayer->algo; 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 templayer; 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 templayer; } else { // assume error message has been displayed delete templayer; 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); const 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); const 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); const 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); const char* x; const 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_setview(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); int wd, ht; if (!PyArg_ParseTuple(args, (char*)"ii", &wd, &ht)) return NULL; if (wd < 0) wd = 0; if (ht < 0) ht = 0; int currwd, currht; bigview->GetClientSize(&currwd, &currht); if (currwd < 0) currwd = 0; if (currht < 0) currht = 0; int mainwd, mainht; mainptr->GetSize(&mainwd, &mainht); mainptr->SetSize(mainwd + (wd - currwd), mainht + (ht - currht)); RETURN_NONE; } // ----------------------------------------------------------------------------- static PyObject* py_getview(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); if (!PyArg_ParseTuple(args, (char*)"")) return NULL; int currwd, currht; bigview->GetClientSize(&currwd, &currht); if (currwd < 0) currwd = 0; if (currht < 0) currht = 0; // return viewport size as wd,ht tuple PyObject* tuple = PyTuple_New(2); PyTuple_SetItem(tuple, 0, Py_BuildValue((char*)"i", currwd)); PyTuple_SetItem(tuple, 1, Py_BuildValue((char*)"i", currht)); return tuple; } // ----------------------------------------------------------------------------- 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); const 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(wxString(name,wxConvLocal), 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(); UpdateIconColors(); 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; } } } UpdateIconColors(); 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); const 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); const 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); const 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); const 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); const 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); const 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); const 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 s[0] = GSF_getkey(); s[1] = '\0'; return Py_BuildValue((char*)"s", s); } // ----------------------------------------------------------------------------- static PyObject* py_dokey(PyObject* self, PyObject* args) { if (PythonScriptAborted()) return NULL; wxUnusedVar(self); const 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); const 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); const 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); const 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); const 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); const 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); const char* err = NULL; if (!PyArg_ParseTuple(args, (char*)"|s", &err)) return NULL; GSF_exit(wxString(err, wxConvLocal)); 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); const 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" }, { "setview", py_setview, METH_VARARGS, "set pixel dimensions of viewport" }, { "getview", py_getview, METH_VARARGS, "get pixel dimensions of viewport" }, { "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"); #ifdef __WXMAC__ // use decomposed UTF8 so interpreter can find path with non-ASCII chars scriptsdir = wxString(scriptsdir.fn_str(),wxConvLocal); #endif 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 interpreters 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 AbortPythonScript() { // raise an exception with a special message PyErr_SetString(PyExc_KeyboardInterrupt, abortmsg); } // ----------------------------------------------------------------------------- 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.8-src/gui-wx/wxselect.h0000644000175100017510000001513412751752464013471 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, bool remove_if_empty = false); // shrink the selection so it just encloses all the live cells // and optionally fit the new selection inside the current viewport; // if remove_if_empty is true then an empty selection is removed 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.8-src/gui-wx/wxundo.cpp0000644000175100017510000017614612660172450013513 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 "); // the following prefixes are used when creating temporary file names // (only use 3 characters because longer strings are truncated on Windows) const wxString genchange_prefix = wxT("gg_"); const wxString setgen_prefix = wxT("gs_"); const wxString dupe1_prefix = wxT("g1_"); const wxString dupe2_prefix = wxT("g2_"); const wxString dupe3_prefix = wxT("g3_"); const wxString dupe4_prefix = wxT("g4_"); const wxString dupe5_prefix = wxT("g5_"); const wxString dupe6_prefix = wxT("g6_"); // ----------------------------------------------------------------------------- // the next two classes are needed because Golly allows multiple starting points // (by setting the generation count back to 0), so we need to ensure that a Reset // goes back to the correct starting info class VariableInfo { public: VariableInfo() {} ~VariableInfo() {} // note that we have to remember pointer to layer and not its index // (the latter can change if user adds/deletes/moves a layer) Layer* layerptr; wxString savename; bigint savex; bigint savey; int savemag; int savebase; int saveexpo; }; class StartingInfo { public: StartingInfo(StartingInfo* dupe, Layer* oldlayer, Layer* newlayer); ~StartingInfo(); void Restore(); void RemoveClone(Layer* cloneptr); // this info is the same in each clone bool savedirty; algo_type savealgo; wxString saverule; // this info can be different in each clone VariableInfo layer[MAX_LAYERS]; int count; }; // ----------------------------------------------------------------------------- StartingInfo::StartingInfo(StartingInfo* dupe, Layer* oldlayer, Layer* newlayer) { if (dupe) { // called from DuplicateHistory so duplicate given starting info savedirty = dupe->savedirty; savealgo = dupe->savealgo; saverule = dupe->saverule; // new duplicate layer is not a clone count = 0; for (int n = 0; n < dupe->count; n++) { if (dupe->layer[n].layerptr == oldlayer) { layer[0].layerptr = newlayer; layer[0].savename = dupe->layer[n].savename; layer[0].savex = dupe->layer[n].savex; layer[0].savey = dupe->layer[n].savey; layer[0].savemag = dupe->layer[n].savemag; layer[0].savebase = dupe->layer[n].savebase; layer[0].saveexpo = dupe->layer[n].saveexpo; count = 1; break; } } } else { // save current starting info (set by most recent SaveStartingPattern) savedirty = currlayer->startdirty; savealgo = currlayer->startalgo; saverule = currlayer->startrule; // save variable info for currlayer and its clones (if any) count = 0; for (int i = 0; i < numlayers; i++) { Layer* lptr = GetLayer(i); if (lptr == currlayer || (lptr->cloneid > 0 && lptr->cloneid == currlayer->cloneid)) { layer[count].layerptr = lptr; layer[count].savename = lptr->startname; layer[count].savex = lptr->startx; layer[count].savey = lptr->starty; layer[count].savemag = lptr->startmag; layer[count].savebase = lptr->startbase; layer[count].saveexpo = lptr->startexpo; count++; } } if (count == 0) Warning(_("Bug detected in StartingInfo ctor!")); } } // ----------------------------------------------------------------------------- StartingInfo::~StartingInfo() { // no need to do anything } // ----------------------------------------------------------------------------- void StartingInfo::Restore() { // restore starting info (for use by next ResetPattern) currlayer->startdirty = savedirty; currlayer->startalgo = savealgo; currlayer->startrule = saverule; // restore variable info for currlayer and its clones (if any); // note that currlayer might have changed since the starting info // was saved, and there might be more or fewer clones for (int i = 0; i < numlayers; i++) { Layer* lptr = GetLayer(i); for (int n = 0; n < count; n++) { if (lptr == layer[n].layerptr) { lptr->startname = layer[n].savename; lptr->startx = layer[n].savex; lptr->starty = layer[n].savey; lptr->startmag = layer[n].savemag; lptr->startbase = layer[n].savebase; lptr->startexpo = layer[n].saveexpo; break; } } } } // ----------------------------------------------------------------------------- void StartingInfo::RemoveClone(Layer* cloneptr) { for (int n = 0; n < count; n++) { if (layer[n].layerptr == cloneptr) { layer[n].layerptr = NULL; return; } } } // ----------------------------------------------------------------------------- // 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 bool scriptgen; // gen change was done by script? 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 StartingInfo* startinfo; // saves starting info for ResetPattern // 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 oldcurrfile, newcurrfile; // old and new currfile paths // also uses oldgen, newgen // and startinfo // 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; startinfo = NULL; whichlayer = NULL; // simplifies UndoRedo::DeletingClone cellinfo = NULL; cellcount = 0; oldfile = wxEmptyString; newfile = wxEmptyString; oldtempstart = wxEmptyString; newtempstart = wxEmptyString; oldcurrfile = wxEmptyString; newcurrfile = wxEmptyString; } // ----------------------------------------------------------------------------- bool delete_all_temps = false; // ok to delete all temporary files? ChangeNode::~ChangeNode() { if (startinfo) delete startinfo; if (cellinfo) free(cellinfo); // it's always ok to delete oldfile and newfile if they exist if (!oldfile.IsEmpty() && wxFileExists(oldfile)) { wxRemoveFile(oldfile); } if (!newfile.IsEmpty() && wxFileExists(newfile)) { wxRemoveFile(newfile); } if (delete_all_temps) { // we're in ClearUndoRedo so it's safe to delete oldtempstart/newtempstart/oldcurrfile/newcurrfile // if they are in tempdir and not being used to store the current layer's starting pattern // (the latter condition allows user to Reset after disabling undo/redo) if (!oldtempstart.IsEmpty() && wxFileExists(oldtempstart) && oldtempstart.StartsWith(tempdir) && oldtempstart != currlayer->currfile) { wxRemoveFile(oldtempstart); //printf("removed oldtempstart: %s\n", (const char*)oldtempstart.mb_str(wxConvLocal)); fflush(stdout); } if (!newtempstart.IsEmpty() && wxFileExists(newtempstart) && newtempstart.StartsWith(tempdir) && newtempstart != currlayer->currfile) { wxRemoveFile(newtempstart); //printf("removed newtempstart: %s\n", (const char*)newtempstart.mb_str(wxConvLocal)); fflush(stdout); } if (!oldcurrfile.IsEmpty() && wxFileExists(oldcurrfile) && oldcurrfile.StartsWith(tempdir) && oldcurrfile != currlayer->currfile) { wxRemoveFile(oldcurrfile); //printf("removed oldcurrfile: %s\n", (const char*)oldcurrfile.mb_str(wxConvLocal)); fflush(stdout); } if (!newcurrfile.IsEmpty() && wxFileExists(newcurrfile) && newcurrfile.StartsWith(tempdir) && newcurrfile != currlayer->currfile) { wxRemoveFile(newcurrfile); //printf("removed newcurrfile: %s\n", (const char*)newcurrfile.mb_str(wxConvLocal)); fflush(stdout); } } } // ----------------------------------------------------------------------------- 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: currlayer->currfile = oldcurrfile; if (undo) { currlayer->currsel = oldsel; mainptr->RestorePattern(oldgen, oldfile, oldx, oldy, oldmag, oldbase, oldexpo); } else { if (startinfo) { // restore starting info for use by ResetPattern startinfo->Restore(); } 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->currfile = oldcurrfile; if (startinfo) { // restore starting info for use by ResetPattern startinfo->Restore(); } } else { mainptr->ChangeGenCount(newgen.tostring(), true); currlayer->startgen = newstartgen; currlayer->savestart = newsave; currlayer->tempstart = newtempstart; currlayer->currfile = newcurrfile; } // 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 (and 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 // 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; 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; } else { // save starting pattern in a unique temporary file prevfile = wxFileName::CreateTempFileName(tempdir + genchange_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 + genchange_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; // also remember the file containing the starting pattern // (in case it is changed by by RememberSetGen or RememberNameChange) change->oldcurrfile = currlayer->currfile; if (change->oldgen == currlayer->startgen) { // save starting info set by recent SaveStartingPattern call // (the info will be restored when redoing this genchange node) change->startinfo = new StartingInfo(NULL, NULL, NULL); } // 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 // until the scriptstart node, or until the list is empty while (!undolist.IsEmpty()) { node = undolist.GetFirst(); change = (ChangeNode*) node->GetData(); if (change->changeid == scriptstart) { undolist.Erase(node); redolist.Insert(change); break; } // undo this change so Reset and Undo restore to the same pattern UndoChange(); } } // 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 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 + setgen_prefix); // also need to update currfile (currlayer->savestart is true) if (!currlayer->savestart) Warning(_("Bug in RememberSetGen: savestart is false!")); currlayer->currfile = currlayer->tempstart; } // 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->oldcurrfile = oldcurrfile; change->newcurrfile = currlayer->currfile; if (oldtempstart != currlayer->tempstart) { // save starting info set by most recent SaveStartingPattern call // (the info will be restored when undoing this setgen node) change->startinfo = new StartingInfo(NULL, NULL, NULL); } 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 fix up any nodes that have pointers to that clone // (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->whichlayer == cloneptr) { change->whichlayer = NULL; } if (change->startinfo) { change->startinfo->RemoveClone(cloneptr); } node = node->GetNext(); } node = redolist.GetFirst(); while (node) { ChangeNode* change = (ChangeNode*) node->GetData(); if (change->whichlayer == cloneptr) { change->whichlayer = NULL; } if (change->startinfo) { change->startinfo->RemoveClone(cloneptr); } 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_UNDO); mainptr->Stop(); 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_REDO); mainptr->Stop(); 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; } // set flag so ChangeNode::~ChangeNode() can delete all temporary files delete_all_temps = true; // clear the undo/redo lists (and delete each node's data) WX_CLEAR_LIST(wxList, undolist); WX_CLEAR_LIST(wxList, redolist); delete_all_temps = 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, if necessary, 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 + dupe1_prefix); if ( !wxCopyFile(srcnode->oldfile, destnode->oldfile, true) ) allcopied = false; } if ( !srcnode->newfile.IsEmpty() && wxFileExists(srcnode->newfile) ) { destnode->newfile = wxFileName::CreateTempFileName(tempdir + dupe2_prefix); if ( !wxCopyFile(srcnode->newfile, destnode->newfile, true) ) allcopied = false; } if ( !srcnode->oldcurrfile.IsEmpty() && wxFileExists(srcnode->oldcurrfile) ) { if (srcnode->oldcurrfile == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->oldcurrfile = tempstart1; } else if (srcnode->oldcurrfile.StartsWith(tempdir)) { destnode->oldcurrfile = wxFileName::CreateTempFileName(tempdir + dupe3_prefix); if ( !wxCopyFile(srcnode->oldcurrfile, destnode->oldcurrfile, true) ) allcopied = false; } } if ( !srcnode->newcurrfile.IsEmpty() && wxFileExists(srcnode->newcurrfile) ) { if (srcnode->newcurrfile == srcnode->oldcurrfile) { // use destnode->oldcurrfile set above or earlier in DuplicateHistory destnode->newcurrfile = destnode->oldcurrfile; } else if (srcnode->newcurrfile == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->newcurrfile = tempstart1; } else if (srcnode->newcurrfile.StartsWith(tempdir)) { destnode->newcurrfile = wxFileName::CreateTempFileName(tempdir + dupe4_prefix); if ( !wxCopyFile(srcnode->newcurrfile, destnode->newcurrfile, 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 if (srcnode->oldtempstart.StartsWith(tempdir)) { destnode->oldtempstart = wxFileName::CreateTempFileName(tempdir + dupe5_prefix); if ( !wxCopyFile(srcnode->oldtempstart, destnode->oldtempstart, true) ) allcopied = false; } } if ( !srcnode->newtempstart.IsEmpty() && wxFileExists(srcnode->newtempstart) ) { if (srcnode->newtempstart == srcnode->oldtempstart) { // use destnode->oldtempstart set above or earlier in DuplicateHistory destnode->newtempstart = destnode->oldtempstart; } else if (srcnode->newtempstart == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->newtempstart = tempstart1; } else if (srcnode->newtempstart.StartsWith(tempdir)) { destnode->newtempstart = wxFileName::CreateTempFileName(tempdir + dupe6_prefix); if ( !wxCopyFile(srcnode->newtempstart, destnode->newtempstart, true) ) allcopied = false; } } 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); // should already be empty but play safe // 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; // copy existing temporary file to new name if ( !prevfile.IsEmpty() && wxFileExists(prevfile) ) { prevfile = wxFileName::CreateTempFileName(tempdir + genchange_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); } if (change->startinfo) { newchange->startinfo = new StartingInfo(change->startinfo, oldlayer, newlayer); } // if node is a name change then update whichlayer if (newchange->changeid == namechange) { if (change->whichlayer == oldlayer) { newchange->whichlayer = newlayer; } else { newchange->whichlayer = NULL; } } // 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; } 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); } if (change->startinfo) { newchange->startinfo = new StartingInfo(change->startinfo, oldlayer, newlayer); } // if node is a name change then update whichlayer if (newchange->changeid == namechange) { if (change->whichlayer == oldlayer) { newchange->whichlayer = newlayer; } else { newchange->whichlayer = NULL; } } // 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; } redolist.Append(newchange); node = node->GetNext(); } } golly-2.8-src/gui-wx/wxscript.h0000644000175100017510000001122112751752464013507 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 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 wxlua/wxperl/wxpython.cpp: extern bool autoupdate; // update display after changing current universe? extern bool allowcheck; // allow event checking? extern wxString scripterr; // 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 functions in wxlua/wxperl/wxpython.cpp. const char* GSF_open(const wxString& filename, int remember); const char* GSF_save(const wxString& filename, const char* format, int remember); const char* GSF_setdir(const char* dirname, const wxString& newdir); const char* GSF_getdir(const char* dirname); const char* GSF_setalgo(const char* algostring); const char* GSF_setrule(const char* rulestring); const char* GSF_setgen(const char* genstring); const char* GSF_setpos(const char* x, const char* y); const char* GSF_setcell(int x, int y, int newstate); const char* GSF_paste(int x, int y, const 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(const char* optname, int newval, int* oldval); bool GSF_getoption(const char* optname, int* optval); bool GSF_setcolor(const char* colname, wxColor& newcol, wxColor& oldcol); bool GSF_getcolor(const char* colname, wxColor& color); void GSF_setname(const wxString& 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); char GSF_getkey(); void GSF_dokey(const char* ascii); void GSF_update(); void GSF_exit(const wxString& errmsg); #endif golly-2.8-src/gui-wx/wxlua.h0000644000175100017510000000223112675241401012752 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 _WXLUA_H_ #define _WXLUA_H_ void RunLuaScript(const wxString& filepath); // Run the given .lua file. void AbortLuaScript(); // Abort the currently running Lua script. void FinishLuaScripting(); // Called when app is quitting. #endif golly-2.8-src/gui-wx/wxalgos.h0000644000175100017510000001232312525071110013271 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.8-src/gui-wx/wxpython.h0000644000175100017510000000225212525071110013505 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.8-src/gui-wx/wxutils.cpp0000644000175100017510000004763512675241401013705 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" // ----------------------------------------------------------------------------- // 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; } } // ----------------------------------------------------------------------------- int SaveChanges(const wxString& query, const wxString& msg) { #if defined(__WXMAC__) // 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 } #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) { // 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__) // 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; // Golly supports Lua and Python scripts // (with optional support for Perl if ENABLE_PERL is defined) return ( ext.IsSameAs(wxT("lua"),false) || ext.IsSameAs(wxT("py"),false) || ext.IsSameAs(wxT("pl"),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.8-src/gui-wx/wxstatus.cpp0000644000175100017510000005172312660172450014062 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); // no need to 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); } } // ----------------------------------------------------------------------------- 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); } } } // ----------------------------------------------------------------------------- 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) { #ifdef __WXGTK__ // avoid erasing background on GTK+ SetBackgroundStyle(wxBG_STYLE_CUSTOM); #endif // 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 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.8-src/gui-wx/wxgolly.h0000755000175100017510000000434312525071110013320 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.8-src/gui-wx/wxgolly.cpp0000755000175100017510000003136012751752464013675 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; }; int wx_poll::checkevents() { // avoid calling Yield too often long t = stopwatch->Time(); if (t > nextcheck) { nextcheck = t + 100; // call 10 times per sec if (mainptr->infront) { // make sure viewport window keeps keyboard focus viewptr->SetFocus(); } insideYield = true; wxGetApp().Yield(true); insideYield = false; } 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->pendingfiles.Add(fullPath); // next OnIdle will call OpenFile (if we call OpenFile here with a script // that opens a modal dialog then dialog can't be closed!) } #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 2016 The Golly Gang."); if (debuglevel > 0) { banner += wxString::Format(_(" *** debuglevel = %d ***"), debuglevel); } 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_LUA = wxT("golly-start.lua"); const wxString START_PYTHON = wxT("golly-start.py"); wxString startscript = gollydir + START_LUA; if (wxFileExists(startscript)) { mainptr->pendingfiles.Add(startscript); } else { // look in user-specific data directory startscript = datadir + START_LUA; 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 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.8-src/gui-wx/wxinfo.cpp0000644000175100017510000001704112660172450013465 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"))); #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.8-src/gui-wx/local-win-template.mk0000644000175100017510000000157112751752464015511 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 LUA_DEFS = -DLUA_COMPAT_5_2 # Uncomment the next line if building a 32-bit version of Golly: # LUA_DEFS = -DLUA_COMPAT_5_2 -DLUA_32BITS # Change the next line depending on where you installed Python: PYTHON_INCLUDE = -I"C:\Python27-64\include" # Uncomment the next 4 lines to allow Golly to run Perl scripts: # PERL_INCLUDE = \ # -DENABLE_PERL \ # -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.8-src/gui-wx/wxmain.cpp0000644000175100017510000031111412751752464013466 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 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 // ----------------------------------------------------------------------------- #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, FILES_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/files.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/files_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[FILES_TOOL] = XPM_BITMAP(files); 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[FILES_TOOL] = XPM_BITMAP(files_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[FILES_TOOL], disdowntool[FILES_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 FILES_TOOL: cmdid = ID_SHOW_FILES; 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 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 == FILES_TOOL && showfiles) { 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); // 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(FILES_TOOL, _("Show/hide files")); 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(FILES_TOOL, showfiles); 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(FILES_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) { 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 } } // ----------------------------------------------------------------------------- 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(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_FILES, active); mbar->Enable(ID_FILE_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(); 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 && !inscript && !(timeline && currlayer->algo->isrecording())); mbar->Enable(ID_SLOWER, active && !inscript && !(timeline && currlayer->algo->isrecording())); 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); mbar->Enable(ID_SMARTSCALE, active); 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_FILES, showfiles); 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_SMARTSCALE, smartscale); 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(bool update_now) { if (inscript || currlayer->undoredo->doingscriptchanges) return; if (!IsIconized()) { bigview->Refresh(false); if (update_now) bigview->Update(); if (showstatus) { statusptr->CheckMouseLocation(infront); statusptr->Refresh(false); if (update_now) statusptr->Update(); } } } // ----------------------------------------------------------------------------- // 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); #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 | #ifdef __WXMSW__ // need this to avoid layer/edit/timeline bar buttons flashing on Windows wxNO_FULL_REPAINT_ON_RESIZE #else // better for Mac and Linux wxFULL_REPAINT_ON_RESIZE #endif ) { #ifdef __WXGTK__ // avoid erasing background on GTK+ SetBackgroundStyle(wxBG_STYLE_CUSTOM); #endif } ~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 } // ----------------------------------------------------------------------------- static bool ok_to_resize = true; void RightWindow::OnSize(wxSizeEvent& event) { // we need this to update right pane when dragging sash, or when toggling left pane if (mainptr && ok_to_resize) { mainptr->ResizeBigView(); } 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; if (w < 0) w = 0; if (h < 0) h = 0; // following will call RightWindow::OnSize so avoid ResizeBigView being called twice ok_to_resize = false; splitwin->SetSize(x, y, w, h); ok_to_resize = true; ResizeBigView(); } // ----------------------------------------------------------------------------- void MainFrame::ResizeBigView() { int wd, ht; rightpane->GetClientSize(&wd, &ht); if (wd > 0 && ht > 0) { // resize layer/edit/timeline bars and main viewport window int y = 0; if (showlayer) { ResizeLayerBar(wd); y += LayerBarHeight(); ht -= LayerBarHeight(); } if (showedit) { ResizeEditBar(wd); y += EditBarHeight(); ht -= EditBarHeight(); } if (showtimeline) { ht -= TimelineBarHeight(); // timeline bar goes underneath viewport ResizeTimelineBar(y + ht, wd); } #ifdef __WXMAC__ if (!fullscreen) { // make room for hbar and vbar wd -= 15; ht -= 15; if (wd < 0) wd = 0; if (ht < 0) ht = 0; // resize hbar and vbar hbar->SetSize(0, y + ht, wd, 15); vbar->SetSize(wd, y, 15, ht); } #endif if (wd < 0) wd = 0; if (ht < 0) ht = 0; bigview->SetSize(0, y, wd, ht); } } // ----------------------------------------------------------------------------- void MainFrame::ResizeStatusBar(int wd, int ht) { wxUnusedVar(ht); // assume showstatus is true statusptr->statusht = showexact ? STATUS_EXHT : STATUS_HT; if (showtool) wd -= TOOLBARWD; if (wd < 0) wd = 0; statusptr->SetSize(showtool ? TOOLBARWD : 0, 0, wd, statusptr->statusht); } // ----------------------------------------------------------------------------- void MainFrame::ToggleStatusBar() { showstatus = !showstatus; int wd, ht; GetClientSize(&wd, &ht); if (wd < 0) wd = 0; if (ht < 0) ht = 0; if (showstatus) { ResizeStatusBar(wd, ht); } else { statusptr->statusht = 0; statusptr->SetSize(0, 0, 0, 0); } ResizeSplitWindow(wd, ht); UpdateEverything(); } // ----------------------------------------------------------------------------- void MainFrame::ToggleExactNumbers() { showexact = !showexact; int wd, ht; GetClientSize(&wd, &ht); if (wd < 0) wd = 0; if (ht < 0) ht = 0; 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 (wd < 0) wd = 0; if (ht < 0) ht = 0; 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 restorefiledir; // restore file 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 #ifdef __WXMAC__ hbar->Show(false); vbar->Show(false); #else bigview->SetScrollbar(wxHORIZONTAL, 0, 0, 0, true); bigview->SetScrollbar(wxVERTICAL, 0, 0, 0, true); #endif // 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 file directory if necessary restorefiledir = showfiles; if (restorefiledir) { dirwinwd = splitwin->GetSashPosition(); splitwin->Unsplit(filectrl); showfiles = 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 file directory if necessary if ( restorefiledir && !splitwin->IsSplit() ) { splitwin->SplitVertically(filectrl, RightPane(), dirwinwd); showfiles = true; } } if (!fullscreen) { // restore scroll bars BEFORE setting viewport size #ifdef __WXMAC__ hbar->Show(true); vbar->Show(true); #else bigview->UpdateScrollBars(); #endif } // adjust size of viewport (and file directory if visible) int wd, ht; GetClientSize(&wd, &ht); ResizeSplitWindow(wd, ht); UpdateEverything(); } // ----------------------------------------------------------------------------- void MainFrame::ToggleAllowUndo() { if (generating) { command_pending = true; cmdevent.SetId(ID_NO_UNDO); Stop(); 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 (ID_GENTIMER, MainFrame::OnGenTimer) EVT_CLOSE ( MainFrame::OnClose) #ifdef __WXMAC__ EVT_COMMAND_SCROLL (wxID_ANY, MainFrame::OnScroll) #endif END_EVENT_TABLE() // ----------------------------------------------------------------------------- void MainFrame::OnMenu(wxCommandEvent& event) { 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 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_FILES: ToggleShowFiles(); break; case ID_FILE_DIR: ChangeFileDir(); 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: StartOrStop(); 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_SMARTSCALE: viewptr->ToggleSmarterScaling(); 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_LUA: ShowHelp(_("Help/lua.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 } 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 file 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) { size_t count = pendingfiles.GetCount(); if (count == 2 && pendingfiles[0] == pendingfiles[1]) { // avoid opening same file twice (only seems to happen in wxMSW) count = 1; } inidle = true; for (size_t n = 0; n < count; n++) { OpenFile(pendingfiles[n]); } inidle = false; pendingfiles.Clear(); } if (call_close) { call_close = false; Close(false); // false allows OnClose handler to veto close } 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; if (showfiles) dirctrl = mainptr->filectrl; 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 (showfiles) dirctrl = filectrl; 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) { command_pending = true; if ( IsScriptFile(filepath) ) { AddRecentScript(filepath); cmdevent.SetId(ID_RUN_RECENT + 1); } else { AddRecentPattern(filepath); cmdevent.SetId(ID_OPEN_RECENT + 1); } Stop(); } 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 ToggleShowFiles(); UpdateMenuItems(); UpdateToolBar(); } // ----------------------------------------------------------------------------- #ifdef __WXMAC__ void MainFrame::OnScroll(wxScrollEvent& event) { WXTYPE type = event.GetEventType(); WXTYPE newtype = type; // build equivalent wxScrollWinEvent and post it to bigview so that // PatternView::OnScroll gets called and hbar/vbar are updated if (type == wxEVT_SCROLL_LINEUP) newtype = wxEVT_SCROLLWIN_LINEUP; if (type == wxEVT_SCROLL_LINEDOWN) newtype = wxEVT_SCROLLWIN_LINEDOWN; if (type == wxEVT_SCROLL_PAGEUP) newtype = wxEVT_SCROLLWIN_PAGEUP; if (type == wxEVT_SCROLL_PAGEDOWN) newtype = wxEVT_SCROLLWIN_PAGEDOWN; if (type == wxEVT_SCROLL_THUMBTRACK) newtype = wxEVT_SCROLLWIN_THUMBTRACK; if (type == wxEVT_SCROLL_THUMBRELEASE) newtype = wxEVT_SCROLLWIN_THUMBRELEASE; wxScrollWinEvent newevt(newtype, event.GetPosition(), event.GetOrientation()); wxPostEvent(bigview->GetEventHandler(), newevt); } #endif // __WXMAC__ // ----------------------------------------------------------------------------- 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(luafile)) wxRemoveFile(luafile); 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]); } 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--; } if (layer->currname.IsEmpty()) { // this should never happen, but play safe label += wxT("UNKNOWN"); } else { 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->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_FILES, _("Show Files") + GetAccelerator(DO_SHOWFILES)); fileMenu->Append(ID_FILE_DIR, _("Set File Folder...") + GetAccelerator(DO_FILEDIR)); #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_SMARTSCALE, _("Smarter Scaling") + GetAccelerator(DO_SMARTSCALE)); 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_LUA, _("Lua 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(); 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, 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_FILES, DO_SHOWFILES); SetAccelerator(mbar, ID_FILE_DIR, DO_FILEDIR); 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_SMARTSCALE, DO_SMARTSCALE); 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::CreateDirControl() { filectrl = 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 ); #ifdef __WXMSW__ // now remove wxDIRCTRL_DIR_ONLY so we see files filectrl->SetWindowStyle(wxNO_BORDER); #endif #if defined(__WXGTK__) // make sure background is white when using KDE's GTK theme #if wxCHECK_VERSION(2,9,0) filectrl->GetTreeCtrl()->SetBackgroundStyle(wxBG_STYLE_ERASE); #else filectrl->GetTreeCtrl()->SetBackgroundStyle(wxBG_STYLE_COLOUR); #endif filectrl->GetTreeCtrl()->SetBackgroundColour(*wxWHITE); // reduce indent a bit filectrl->GetTreeCtrl()->SetIndent(8); #elif defined(__WXMAC__) // reduce indent a bit more filectrl->GetTreeCtrl()->SetIndent(6); #else // reduce indent a lot on Windows filectrl->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); filectrl->GetTreeCtrl()->SetFont(font); #endif if ( wxFileName::DirExists(filedir) ) { // only show filedir and its contents SimplifyTree(filedir, filectrl->GetTreeCtrl(), filectrl->GetRootId()); } // install event handler to detect clicking on a file filectrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_LEFT_DOWN, wxMouseEventHandler(MainFrame::OnTreeClick)); filectrl->GetTreeCtrl()->Connect(wxID_ANY, wxEVT_RIGHT_DOWN, wxMouseEventHandler(MainFrame::OnTreeClick)); filectrl->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); 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 // 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"); luafile = datadir + wxT("golly_clip.lua"); perlfile = datadir + wxT("golly_clip.pl"); pythonfile = datadir + wxT("golly_clip.py"); // create timer for generating patterns (see OnGenTimer in wxcontrol.cpp) gentimer = new wxTimer(this, ID_GENTIMER); 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); // create a split window with file 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); // create filectrl in left pane CreateDirControl(); // create a window for right pane which contains layer/edit/timeline bars // and pattern viewport rightpane = new RightWindow(splitwin); // 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 #ifndef __WXMAC__ // avoid Mac bug if wxGLCanvas has built-in scroll bars wxVSCROLL | wxHSCROLL | #endif wxFULL_REPAINT_ON_RESIZE); // this is the main viewport window (tile windows have a tileindex >= 0) viewptr->tileindex = -1; bigview = viewptr; #ifdef __WXMAC__ // manually create scroll bars to avoid wxGLCanvas bug on Mac hbar = new wxScrollBar(rightpane, wxID_ANY, wxPoint(0,0), wxSize(-1, 15), wxSB_HORIZONTAL); vbar = new wxScrollBar(rightpane, wxID_ANY, wxPoint(0,0), wxSize(15, -1), wxSB_VERTICAL); hbar->SetMinSize(wxDefaultSize); vbar->SetMinSize(wxDefaultSize); #endif #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(filectrl, rightpane, dirwinwd); splitwin->SetSashPosition(dirwinwd); splitwin->SetMinimumPaneSize(MIN_DIRWD); splitwin->Unsplit(filectrl); splitwin->UpdateSize(); if (showfiles) splitwin->SplitVertically(filectrl, rightpane, dirwinwd); } // ----------------------------------------------------------------------------- MainFrame::~MainFrame() { #ifdef __WXMAC__ delete hbar; delete vbar; #endif delete gentimer; DestroyDrawingData(); } golly-2.8-src/gui-wx/wxutils.h0000644000175100017510000001003212675241401013327 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 Lua, Perl or Python script. // It simply checks if the file's extension is .lua or .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.8-src/gui-wx/wxlua.cpp0000755000175100017510000025155012751752464013335 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 a statically embedded Lua interpreter to execute .lua scripts. Here is the official Lua copyright notice: Copyright 1994-2015 Lua.org, PUC-Rio. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #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 "wx/dir.h" // for wxDir #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 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 "wxlua.h" #include "lua.hpp" // Lua header files for C++ // ----------------------------------------------------------------------------- // some useful macros #define CHECK_RGB(r,g,b,cmd) \ if (r < 0 || r > 255 || g < 0 || g > 255 || g < 0 || g > 255) { \ char msg[128]; \ sprintf(msg, "%s error: bad rgb value (%d,%d,%d)", cmd, r, g, b); \ GollyError(L, msg); \ } #ifdef __WXMAC__ // use decomposed UTF8 so fopen will work #define FILENAME wxString(filename,wxConvUTF8).fn_str() #else #define FILENAME filename #endif #ifdef __WXMSW__ // encoding conversion from Lua string to wxString is different on Windows #define LUA_ENC wxConvLocal #else #define LUA_ENC wxConvUTF8 #endif // ----------------------------------------------------------------------------- static bool aborted = false; // stop the current script? static void CheckEvents(lua_State* L) { // this routine is called at the start of every g_* function so we can // detect user events (eg. hitting the stop button or escape key) if (allowcheck) wxGetApp().Poller()->checkevents(); if (insideYield) return; // we're outside Yield so safe to do a longjmp from lua_error if (aborted) { // AbortLuaScript was called lua_pushstring(L, abortmsg); lua_error(L); } } // ----------------------------------------------------------------------------- static void GollyError(lua_State* L, const char* errmsg) { // handle an error detected in a g_* function; // note that luaL_error will prepend file path and line number info luaL_error(L, "\n%s", errmsg); } // ----------------------------------------------------------------------------- static int g_open(lua_State* L) { CheckEvents(L); const char* filename = luaL_checkstring(L, 1); int remember = 0; if (lua_gettop(L) > 1) remember = lua_toboolean(L, 2) ? 1 : 0; const char* err = GSF_open(wxString(filename, LUA_ENC), remember); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_save(lua_State* L) { CheckEvents(L); const char* filename = luaL_checkstring(L, 1); const char* format = luaL_checkstring(L, 2); int remember = 0; if (lua_gettop(L) > 2) remember = lua_toboolean(L, 3) ? 1 : 0; const char* err = GSF_save(wxString(filename, LUA_ENC), format, remember); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_opendialog(lua_State* L) { CheckEvents(L); const char* title = "Choose a file"; const char* filetypes = "All files (*)|*"; const char* initialdir = ""; const char* initialfname = ""; int mustexist = 1; if (lua_gettop(L) > 0) title = luaL_checkstring(L, 1); if (lua_gettop(L) > 1) filetypes = luaL_checkstring(L, 2); if (lua_gettop(L) > 2) initialdir = luaL_checkstring(L, 3); if (lua_gettop(L) > 3) initialfname = luaL_checkstring(L, 4); if (lua_gettop(L) > 4) mustexist = lua_toboolean(L, 5) ? 1 : 0; wxString wxs_title(title, LUA_ENC); wxString wxs_filetypes(filetypes, LUA_ENC); wxString wxs_initialdir(initialdir, LUA_ENC); wxString wxs_initialfname(initialfname, LUA_ENC); 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) ); if (opendlg.ShowModal() == wxID_OK) wxs_result = opendlg.GetPath(); } lua_pushstring(L, (const char*)wxs_result.mb_str(wxConvUTF8)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_savedialog(lua_State* L) { CheckEvents(L); const char* title = "Choose a save location and filename"; const char* filetypes = "All files (*)|*"; const char* initialdir = ""; const char* initialfname = ""; int suppressprompt = 0; if (lua_gettop(L) > 0) title = luaL_checkstring(L, 1); if (lua_gettop(L) > 1) filetypes = luaL_checkstring(L, 2); if (lua_gettop(L) > 2) initialdir = luaL_checkstring(L, 3); if (lua_gettop(L) > 3) initialfname = luaL_checkstring(L, 4); if (lua_gettop(L) > 4) suppressprompt = lua_toboolean(L, 5) ? 1 : 0; wxString wxs_title(title, LUA_ENC); wxString wxs_filetypes(filetypes, LUA_ENC); wxString wxs_initialdir(initialdir, LUA_ENC); wxString wxs_initialfname(initialfname, LUA_ENC); 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)); wxString wxs_savefname = wxEmptyString; if (savedlg.ShowModal() == wxID_OK) wxs_savefname = savedlg.GetPath(); lua_pushstring(L, (const char*)wxs_savefname.mb_str(wxConvUTF8)); return 1; // result is a string } // ----------------------------------------------------------------------------- static const char* ExtractCellArray(lua_State* L, lifealgo* universe, bool shift = false) { // extract cell array from given universe lua_newtable(L); 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 arraylen = 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 lua_pushinteger(L, cx - ileft); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, cy - itop ); lua_rawseti(L, -2, ++arraylen); } else { lua_pushinteger(L, cx); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, cy); lua_rawseti(L, -2, ++arraylen); } if (multistate) { lua_pushinteger(L, v); lua_rawseti(L, -2, ++arraylen); } } else { cx = iright; // done this row } } } if (multistate && arraylen > 0 && (arraylen & 1) == 0) { // add padding zero so the cell 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) lua_pushinteger(L, 0); lua_rawseti(L, -2, ++arraylen); } } return NULL; } // ----------------------------------------------------------------------------- static int g_load(lua_State* L) { CheckEvents(L); const char* filename = luaL_checkstring(L, 1); // create temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, false); // 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, false); err = readpattern(FILENAME, *tempalgo); if (!err) break; } } } if (err) { delete tempalgo; GollyError(L, err); } // convert pattern into a cell array, shifting cell coords so that the // bounding box's top left cell is at 0,0 err = ExtractCellArray(L, tempalgo, true); delete tempalgo; if (err) GollyError(L, err); return 1; // result is a cell array } // ----------------------------------------------------------------------------- static int g_store(lua_State* L) { CheckEvents(L); luaL_checktype(L, 1, LUA_TTABLE); // cell array int len = luaL_len(L, 1); const char* filename = luaL_checkstring(L, 2); // create temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, false); const char* err = tempalgo->setrule(currlayer->algo->getrule()); if (err) tempalgo->setrule(tempalgo->DefaultRule()); // copy cell array into temporary universe bool multistate = (len & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = len / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; lua_rawgeti(L, 1, item+1); int x = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, item+2); int y = lua_tointeger(L,-1); lua_pop(L,1); // check if x,y is outside bounded grid err = GSF_checkpos(tempalgo, x, y); if (err) { delete tempalgo; GollyError(L, err); } if (multistate) { lua_rawgeti(L, 1, item+3); int state = lua_tointeger(L,-1); lua_pop(L,1); if (tempalgo->setcell(x, y, state) < 0) { tempalgo->endofpattern(); delete tempalgo; GollyError(L, "store error: state value is out of range."); } } else { tempalgo->setcell(x, y, 1); } } 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) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_setdir(lua_State* L) { CheckEvents(L); const char* dirname = luaL_checkstring(L, 1); const char* newdir = luaL_checkstring(L, 2); const char* err = GSF_setdir(dirname, wxString(newdir, LUA_ENC)); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getdir(lua_State* L) { CheckEvents(L); const char* dirname = luaL_checkstring(L, 1); const char* dirstring = GSF_getdir(dirname); if (dirstring == NULL) GollyError(L, "getdir error: unknown directory name."); lua_pushstring(L, dirstring); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_getfiles(lua_State* L) { CheckEvents(L); const char* dirname = luaL_checkstring(L, 1); wxString dirpath = wxString(dirname, LUA_ENC); if (!wxFileName::DirExists(dirpath)) { GollyError(L, "getfiles error: given directory does not exist."); } lua_newtable(L); int arraylen = 0; wxDir dir(dirpath); if (dir.IsOpened()) { wxString filename; // get all files bool more = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES | wxDIR_HIDDEN); while (more) { lua_pushstring(L, (const char*)filename.mb_str(wxConvUTF8)); lua_rawseti(L, -2, ++arraylen); more = dir.GetNext(&filename); } // now get all directories and append platform-specific path separator more = dir.GetFirst(&filename, wxEmptyString, wxDIR_DIRS | wxDIR_HIDDEN); while (more) { filename += wxFILE_SEP_PATH; lua_pushstring(L, (const char*)filename.mb_str(wxConvUTF8)); lua_rawseti(L, -2, ++arraylen); more = dir.GetNext(&filename); } } return 1; // result is a table of strings } // ----------------------------------------------------------------------------- static int g_new(lua_State* L) { CheckEvents(L); mainptr->NewPattern(wxString(luaL_checkstring(L, 1), LUA_ENC)); DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_cut(lua_State* L) { CheckEvents(L); if (viewptr->SelectionExists()) { viewptr->CutSelection(); DoAutoUpdate(); } else { GollyError(L, "cut error: no selection."); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_copy(lua_State* L) { CheckEvents(L); if (viewptr->SelectionExists()) { viewptr->CopySelection(); DoAutoUpdate(); } else { GollyError(L, "copy error: no selection."); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_clear(lua_State* L) { CheckEvents(L); int where = luaL_checkinteger(L, 1); if (viewptr->SelectionExists()) { if (where == 0) viewptr->ClearSelection(); else viewptr->ClearOutsideSelection(); DoAutoUpdate(); } else { GollyError(L, "clear error: no selection."); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_paste(lua_State* L) { CheckEvents(L); int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); const char* mode = luaL_checkstring(L, 3); const char* err = GSF_paste(x, y, mode); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_shrink(lua_State* L) { CheckEvents(L); bool remove_if_empty = false; if (lua_gettop(L) > 0) remove_if_empty = lua_toboolean(L, 1) ? true : false; if (viewptr->SelectionExists()) { currlayer->currsel.Shrink(false, remove_if_empty); // false == don't fit in viewport DoAutoUpdate(); } else { GollyError(L, "shrink error: no selection."); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_randfill(lua_State* L) { CheckEvents(L); int perc = luaL_checkinteger(L, 1); if (perc < 1 || perc > 100) { GollyError(L, "randfill error: percentage must be from 1 to 100."); } if (viewptr->SelectionExists()) { int oldperc = randomfill; randomfill = perc; viewptr->RandomFill(); randomfill = oldperc; DoAutoUpdate(); } else { GollyError(L, "randfill error: no selection."); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_flip(lua_State* L) { CheckEvents(L); int direction = luaL_checkinteger(L, 1); if (viewptr->SelectionExists()) { viewptr->FlipSelection(direction != 0); // 1 = top-bottom DoAutoUpdate(); } else { GollyError(L, "flip error: no selection."); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_rotate(lua_State* L) { CheckEvents(L); int direction = luaL_checkinteger(L, 1); if (viewptr->SelectionExists()) { viewptr->RotateSelection(direction == 0); // 0 = clockwise DoAutoUpdate(); } else { GollyError(L, "rotate error: no selection."); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_parse(lua_State* L) { CheckEvents(L); const char* s = luaL_checkstring(L, 1); // defaults for optional params int x0 = 0; int y0 = 0; int axx = 1; int axy = 0; int ayx = 0; int ayy = 1; if (lua_gettop(L) > 1) x0 = luaL_checkinteger(L, 2); if (lua_gettop(L) > 2) y0 = luaL_checkinteger(L, 3); if (lua_gettop(L) > 3) axx = luaL_checkinteger(L, 4); if (lua_gettop(L) > 4) axy = luaL_checkinteger(L, 5); if (lua_gettop(L) > 5) ayx = luaL_checkinteger(L, 6); if (lua_gettop(L) > 6) ayy = luaL_checkinteger(L, 7); lua_newtable(L); int arraylen = 0; int x = 0; int 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 '*': lua_pushinteger(L, x0 + x * axx + y * axy); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, y0 + x * ayx + y * ayy); lua_rawseti(L, -2, ++arraylen); x++; break; } c = *s++; } } else { // parsing RLE format; first check if multi-state data is present bool multistate = false; const 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++) { lua_pushinteger(L, x0 + x * axx + y * axy); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, y0 + x * ayx + y * ayy); lua_rawseti(L, -2, ++arraylen); if (multistate) { lua_pushinteger(L, 1); lua_rawseti(L, -2, ++arraylen); } } 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 { // be forgiving and treat 'p'..'y' like 'o' state = 1; s--; } } for (int k = 0; k < prefix; k++, x++) { lua_pushinteger(L, x0 + x * axx + y * axy); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, y0 + x * ayx + y * ayy); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, state); lua_rawseti(L, -2, ++arraylen); } } } prefix = 0; } c = *s++; } if (multistate && arraylen > 0 && (arraylen & 1) == 0) { // add padding zero lua_pushinteger(L, 0); lua_rawseti(L, -2, ++arraylen); } } return 1; // result is a cell array } // ----------------------------------------------------------------------------- static int g_transform(lua_State* L) { CheckEvents(L); luaL_checktype(L, 1, LUA_TTABLE); // cell array int x0 = luaL_checkinteger(L, 2); int y0 = luaL_checkinteger(L, 3); // defaults for optional params int axx = 1; int axy = 0; int ayx = 0; int ayy = 1; if (lua_gettop(L) > 3) axx = luaL_checkinteger(L, 4); if (lua_gettop(L) > 4) axy = luaL_checkinteger(L, 5); if (lua_gettop(L) > 5) ayx = luaL_checkinteger(L, 6); if (lua_gettop(L) > 6) ayy = luaL_checkinteger(L, 7); lua_newtable(L); int arraylen = 0; bool multistate = (luaL_len(L, 1) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = luaL_len(L, 1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; lua_rawgeti(L, 1, item+1); int x = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, item+2); int y = lua_tointeger(L,-1); lua_pop(L,1); lua_pushinteger(L, x0 + x * axx + y * axy); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, y0 + x * ayx + y * ayy); lua_rawseti(L, -2, ++arraylen); if (multistate) { lua_rawgeti(L, 1, item+3); int state = lua_tointeger(L,-1); lua_pop(L,1); lua_pushinteger(L, state); lua_rawseti(L, -2, ++arraylen); } } if (multistate && arraylen > 0 && (arraylen & 1) == 0) { // add padding zero lua_pushinteger(L, 0); lua_rawseti(L, -2, ++arraylen); } return 1; // result is a cell array } // ----------------------------------------------------------------------------- static int g_evolve(lua_State* L) { CheckEvents(L); luaL_checktype(L, 1, LUA_TTABLE); // cell array int ngens = luaL_checkinteger(L, 2); if (ngens < 0) { GollyError(L, "evolve error: number of generations is negative."); } // create a temporary universe of same type as current universe lifealgo* tempalgo = CreateNewUniverse(currlayer->algtype, false); const char* err = tempalgo->setrule(currlayer->algo->getrule()); if (err) tempalgo->setrule(tempalgo->DefaultRule()); // copy cell array into temporary universe bool multistate = (luaL_len(L, 1) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = luaL_len(L, 1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; lua_rawgeti(L, 1, item+1); int x = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, item+2); int y = lua_tointeger(L,-1); lua_pop(L,1); // check if x,y is outside bounded grid err = GSF_checkpos(tempalgo, x, y); if (err) { delete tempalgo; GollyError(L, err); } if (multistate) { lua_rawgeti(L, 1, item+3); int state = lua_tointeger(L,-1); lua_pop(L,1); if (tempalgo->setcell(x, y, state) < 0) { tempalgo->endofpattern(); delete tempalgo; GollyError(L, "evolve error: state value is out of range."); } } else { tempalgo->setcell(x, y, 1); } } 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 (!tempalgo->CreateBorderCells()) break; tempalgo->step(); if (!tempalgo->DeleteBorderCells()) break; ngens--; } } else { tempalgo->setIncrement(ngens); tempalgo->step(); } mainptr->generating = false; // convert new pattern into a cell array err = ExtractCellArray(L, tempalgo); delete tempalgo; if (err) GollyError(L, err); return 1; // result is a cell array } // ----------------------------------------------------------------------------- static const char* BAD_STATE = "putcells error: state value is out of range."; static int g_putcells(lua_State* L) { CheckEvents(L); luaL_checktype(L, 1, LUA_TTABLE); // cell array // defaults 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"; if (lua_gettop(L) > 1) x0 = luaL_checkinteger(L, 2); if (lua_gettop(L) > 2) y0 = luaL_checkinteger(L, 3); if (lua_gettop(L) > 3) axx = luaL_checkinteger(L, 4); if (lua_gettop(L) > 4) axy = luaL_checkinteger(L, 5); if (lua_gettop(L) > 5) ayx = luaL_checkinteger(L, 6); if (lua_gettop(L) > 6) ayy = luaL_checkinteger(L, 7); if (lua_gettop(L) > 7) mode = luaL_checkstring(L, 8); wxString modestr = wxString(mode, LUA_ENC); 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)) ) { GollyError(L, "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 = (luaL_len(L, 1) & 1) == 1; int ints_per_cell = multistate ? 3 : 2; int num_cells = luaL_len(L, 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; lua_rawgeti(L, 1, item+1); int x = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, item+2); int y = lua_tointeger(L,-1); lua_pop(L,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 arrays can contain dead cells so newstate might be 0 lua_rawgeti(L, 1, item+3); newstate = lua_tointeger(L,-1); lua_pop(L,1); } if (newstate != oldstate && oldstate > 0) { curralgo->setcell(newx, newy, 0); if (savecells) ChangeCell(newx, newy, oldstate, 0); pattchanged = true; } } } } 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; lua_rawgeti(L, 1, item+1); int x = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, item+2); int y = lua_tointeger(L,-1); lua_pop(L,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 arrays can contain dead cells so newstate might be 0 lua_rawgeti(L, 1, item+3); newstate = lua_tointeger(L,-1); lua_pop(L,1); 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; } } } 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; lua_rawgeti(L, 1, item+1); int x = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, item+2); int y = lua_tointeger(L,-1); lua_pop(L,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 arrays can contain dead cells so newstate might be 0 lua_rawgeti(L, 1, item+3); newstate = lua_tointeger(L,-1); lua_pop(L,1); 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) { err = BAD_STATE; break; } if (savecells) ChangeCell(newx, newy, oldstate, newstate); pattchanged = true; } } } if (pattchanged) { curralgo->endofpattern(); MarkLayerDirty(); DoAutoUpdate(); } if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getcells(lua_State* L) { CheckEvents(L); luaL_checktype(L, 1, LUA_TTABLE); // rect array with 0 or 4 ints lua_newtable(L); int arraylen = 0; int numints = luaL_len(L, 1); if (numints == 0) { // return empty cell array } else if (numints == 4) { lua_rawgeti(L, 1, 1); int ileft = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 2); int itop = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 3); int wd = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 4); int ht = luaL_checkinteger(L,-1); lua_pop(L,1); const char* err = GSF_checkrect(ileft, itop, wd, ht); if (err) GollyError(L, err); int iright = ileft + wd - 1; int ibottom = itop + ht - 1; int cx, cy; int v = 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) { lua_pushinteger(L, cx); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, cy); lua_rawseti(L, -2, ++arraylen); if (multistate) { lua_pushinteger(L, v); lua_rawseti(L, -2, ++arraylen); } } } else { cx = iright; // done this row } } } if (multistate && arraylen > 0 && (arraylen & 1) == 0) { // add padding zero lua_pushinteger(L, 0); lua_rawseti(L, -2, ++arraylen); } } else { GollyError(L, "getcells error: array must be {} or {x,y,wd,ht}."); } return 1; // result is a cell array } // ----------------------------------------------------------------------------- static int g_join(lua_State* L) { CheckEvents(L); luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 2, LUA_TTABLE); bool multi1 = (luaL_len(L, 1) & 1) == 1; bool multi2 = (luaL_len(L, 2) & 1) == 1; bool multiout = multi1 || multi2; int ints_per_cell, num_cells; int x, y, state; lua_newtable(L); int arraylen = 0; // append 1st array ints_per_cell = multi1 ? 3 : 2; num_cells = luaL_len(L, 1) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; lua_rawgeti(L, 1, item+1); x = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, item+2); y = lua_tointeger(L,-1); lua_pop(L,1); if (multi1) { lua_rawgeti(L, 1, item+3); state = lua_tointeger(L,-1); lua_pop(L,1); } else { state = 1; } lua_pushinteger(L, x); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, y); lua_rawseti(L, -2, ++arraylen); if (multiout) { lua_pushinteger(L, state); lua_rawseti(L, -2, ++arraylen); } } // append 2nd array ints_per_cell = multi2 ? 3 : 2; num_cells = luaL_len(L, 2) / ints_per_cell; for (int n = 0; n < num_cells; n++) { int item = ints_per_cell * n; lua_rawgeti(L, 2, item+1); x = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 2, item+2); y = lua_tointeger(L,-1); lua_pop(L,1); if (multi2) { lua_rawgeti(L, 2, item+3); state = lua_tointeger(L,-1); lua_pop(L,1); } else { state = 1; } lua_pushinteger(L, x); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, y); lua_rawseti(L, -2, ++arraylen); if (multiout) { lua_pushinteger(L, state); lua_rawseti(L, -2, ++arraylen); } } if (multiout && arraylen > 0 && (arraylen & 1) == 0) { // add padding zero lua_pushinteger(L, 0); lua_rawseti(L, -2, ++arraylen); } return 1; // result is a cell array } // ----------------------------------------------------------------------------- static int g_hash(lua_State* L) { CheckEvents(L); // arg must be a table with 4 ints luaL_checktype(L, 1, LUA_TTABLE); int numints = luaL_len(L, 1); if (numints != 4) { GollyError(L, "hash error: array must have 4 integers."); } lua_rawgeti(L, 1, 1); int x = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 2); int y = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 3); int wd = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 4); int ht = luaL_checkinteger(L,-1); lua_pop(L,1); const char* err = GSF_checkrect(x, y, wd, ht); if (err) GollyError(L, err); lua_pushinteger(L, GSF_hash(x, y, wd, ht)); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_getclip(lua_State* L) { CheckEvents(L); if (!mainptr->ClipboardHasText()) { GollyError(L, "getclip error: no pattern in clipboard."); } // create a temporary layer for storing the clipboard pattern Layer* templayer = CreateTemporaryLayer(); if (!templayer) { GollyError(L, "getclip error: failed to create temporary layer."); } // 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(templayer, &top, &left, &bottom, &right) ) { if ( viewptr->OutsideLimits(top, left, bottom, right) ) { delete templayer; GollyError(L, "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; // push pattern's width and height (not necessarily the minimal bounding box // because the pattern might have empty borders, or it might even be empty) lua_pushinteger(L, wd); lua_pushinteger(L, ht); // now push cell array lua_newtable(L); int arraylen = 0; // extract cells from templayer lifealgo* tempalgo = templayer->algo; bool multistate = tempalgo->NumCellStates() > 2; int cx, cy; 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 lua_pushinteger(L, cx - ileft); lua_rawseti(L, -2, ++arraylen); lua_pushinteger(L, cy - itop ); lua_rawseti(L, -2, ++arraylen); if (multistate) { lua_pushinteger(L, v); lua_rawseti(L, -2, ++arraylen); } } else { cx = iright; // done this row } } } // if no live cells then return {wd,ht} rather than {wd,ht,0} if (multistate && arraylen > 2 && (arraylen & 1) == 0) { // add padding zero lua_pushinteger(L, 0); lua_rawseti(L, -2, ++arraylen); } delete templayer; } else { delete templayer; GollyError(L, "getclip error: failed to get clipboard pattern."); } return 3; // result is wd, ht, cell array } // ----------------------------------------------------------------------------- static int g_select(lua_State* L) { CheckEvents(L); // arg must be a table with 0 or 4 ints luaL_checktype(L, 1, LUA_TTABLE); int numints = luaL_len(L, 1); if (numints == 0) { // remove any existing selection GSF_select(0, 0, 0, 0); } else if (numints == 4) { lua_rawgeti(L, 1, 1); int x = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 2); int y = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 3); int wd = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 4); int ht = luaL_checkinteger(L,-1); lua_pop(L,1); const char* err = GSF_checkrect(x, y, wd, ht); if (err) GollyError(L, err); GSF_select(x, y, wd, ht); } else { GollyError(L, "select error: array must be {} or {x,y,wd,ht}."); } DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getrect(lua_State* L) { CheckEvents(L); lua_newtable(L); if (!currlayer->algo->isEmpty()) { bigint top, left, bottom, right; currlayer->algo->findedges(&top, &left, &bottom, &right); if (viewptr->OutsideLimits(top, left, bottom, right)) { GollyError(L, "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; lua_pushinteger(L, x); lua_rawseti(L, -2, 1); lua_pushinteger(L, y); lua_rawseti(L, -2, 2); lua_pushinteger(L, wd); lua_rawseti(L, -2, 3); lua_pushinteger(L, ht); lua_rawseti(L, -2, 4); } return 1; // result is a table (empty or with 4 ints) } // ----------------------------------------------------------------------------- static int g_getselrect(lua_State* L) { CheckEvents(L); lua_newtable(L); if (viewptr->SelectionExists()) { if (currlayer->currsel.TooBig()) { GollyError(L, "getselrect error: selection is too big."); } int x, y, wd, ht; currlayer->currsel.GetRect(&x, &y, &wd, &ht); lua_pushinteger(L, x); lua_rawseti(L, -2, 1); lua_pushinteger(L, y); lua_rawseti(L, -2, 2); lua_pushinteger(L, wd); lua_rawseti(L, -2, 3); lua_pushinteger(L, ht); lua_rawseti(L, -2, 4); } return 1; // result is a table (empty or with 4 ints) } // ----------------------------------------------------------------------------- static int g_setcell(lua_State* L) { CheckEvents(L); int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); int state = luaL_checkinteger(L, 3); const char* err = GSF_setcell(x, y, state); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getcell(lua_State* L) { CheckEvents(L); int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); // check if x,y is outside bounded grid const char* err = GSF_checkpos(currlayer->algo, x, y); if (err) GollyError(L, err); lua_pushinteger(L, currlayer->algo->getcell(x, y)); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_setcursor(lua_State* L) { CheckEvents(L); const char* newcursor = luaL_checkstring(L, 1); 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 { GollyError(L, "setcursor error: unknown cursor string."); } // return old cursor (simplifies saving and restoring cursor) lua_pushstring(L, oldcursor); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_getcursor(lua_State* L) { CheckEvents(L); lua_pushstring(L, CursorToString(currlayer->curs)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_empty(lua_State* L) { CheckEvents(L); lua_pushboolean(L, currlayer->algo->isEmpty()); return 1; // result is a boolean } // ----------------------------------------------------------------------------- static int g_run(lua_State* L) { CheckEvents(L); int ngens = luaL_checkinteger(L, 1); 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 0; // no result } // ----------------------------------------------------------------------------- static int g_step(lua_State* L) { CheckEvents(L); if (!currlayer->algo->isEmpty()) { mainptr->NextGeneration(true); // step by current increment DoAutoUpdate(); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_setstep(lua_State* L) { CheckEvents(L); int exp = luaL_checkinteger(L, 1); mainptr->SetStepExponent(exp); DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getstep(lua_State* L) { CheckEvents(L); lua_pushinteger(L, currlayer->currexpo); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_setbase(lua_State* L) { CheckEvents(L); int base = luaL_checkinteger(L, 1); if (base < 2) base = 2; if (base > MAX_BASESTEP) base = MAX_BASESTEP; currlayer->currbase = base; mainptr->SetGenIncrement(); DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getbase(lua_State* L) { CheckEvents(L); lua_pushinteger(L, currlayer->currbase); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_advance(lua_State* L) { CheckEvents(L); int where = luaL_checkinteger(L, 1); int ngens = luaL_checkinteger(L, 2); if (ngens > 0) { if (viewptr->SelectionExists()) { while (ngens > 0) { ngens--; if (where == 0) currlayer->currsel.Advance(); else currlayer->currsel.AdvanceOutside(); } DoAutoUpdate(); } else { GollyError(L, "advance error: no selection."); } } return 0; // no result } // ----------------------------------------------------------------------------- static int g_reset(lua_State* L) { CheckEvents(L); if (currlayer->algo->getGeneration() != currlayer->startgen) { mainptr->ResetPattern(); DoAutoUpdate(); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_setgen(lua_State* L) { CheckEvents(L); const char* genstring = luaL_checkstring(L, 1); const char* err = GSF_setgen(genstring); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getgen(lua_State* L) { CheckEvents(L); char sepchar = '\0'; if (lua_gettop(L) > 0) { const char* s = luaL_checkstring(L, 1); sepchar = s[0]; } lua_pushstring(L, currlayer->algo->getGeneration().tostring(sepchar)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_getpop(lua_State* L) { CheckEvents(L); char sepchar = '\0'; if (lua_gettop(L) > 0) { const char* s = luaL_checkstring(L, 1); sepchar = s[0]; } lua_pushstring(L, currlayer->algo->getPopulation().tostring(sepchar)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_numstates(lua_State* L) { CheckEvents(L); lua_pushinteger(L, currlayer->algo->NumCellStates()); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_numalgos(lua_State* L) { CheckEvents(L); lua_pushinteger(L, NumAlgos()); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_setalgo(lua_State* L) { CheckEvents(L); const char* algostring = luaL_checkstring(L, 1); const char* err = GSF_setalgo(algostring); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getalgo(lua_State* L) { CheckEvents(L); int index = currlayer->algtype; if (lua_gettop(L) > 0) index = luaL_checkinteger(L, 1); if (index < 0 || index >= NumAlgos()) { char msg[64]; sprintf(msg, "getalgo error: bad index (%d)", index); GollyError(L, msg); } lua_pushstring(L, GetAlgoName(index)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_setrule(lua_State* L) { CheckEvents(L); const char* rulestring = luaL_checkstring(L, 1); const char* err = GSF_setrule(rulestring); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getrule(lua_State* L) { CheckEvents(L); lua_pushstring(L, currlayer->algo->getrule()); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_getwidth(lua_State* L) { CheckEvents(L); lua_pushinteger(L, currlayer->algo->gridwd); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_getheight(lua_State* L) { CheckEvents(L); lua_pushinteger(L, currlayer->algo->gridht); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_setpos(lua_State* L) { CheckEvents(L); const char* x = luaL_checkstring(L, 1); const char* y = luaL_checkstring(L, 2); const char* err = GSF_setpos(x, y); if (err) GollyError(L, err); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getpos(lua_State* L) { CheckEvents(L); char sepchar = '\0'; if (lua_gettop(L) > 0) { const char* s = luaL_checkstring(L, 1); sepchar = s[0]; } bigint bigx, bigy; viewptr->GetPos(bigx, bigy); // return position as x,y strings lua_pushstring(L, bigx.tostring(sepchar)); lua_pushstring(L, bigy.tostring(sepchar)); return 2; // result is 2 strings } // ----------------------------------------------------------------------------- static int g_setmag(lua_State* L) { CheckEvents(L); int mag = luaL_checkinteger(L, 1); viewptr->SetMag(mag); DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getmag(lua_State* L) { CheckEvents(L); lua_pushinteger(L, viewptr->GetMag()); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_fit(lua_State* L) { CheckEvents(L); viewptr->FitPattern(); DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_fitsel(lua_State* L) { CheckEvents(L); if (viewptr->SelectionExists()) { viewptr->FitSelection(); DoAutoUpdate(); } else { GollyError(L, "fitsel error: no selection."); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_visrect(lua_State* L) { CheckEvents(L); // arg must be a table with 4 ints luaL_checktype(L, 1, LUA_TTABLE); int numints = luaL_len(L, 1); if (numints != 4) { GollyError(L, "visrect error: array must have 4 integers."); } lua_rawgeti(L, 1, 1); int x = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 2); int y = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 3); int wd = luaL_checkinteger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 4); int ht = luaL_checkinteger(L,-1); lua_pop(L,1); const char* err = GSF_checkrect(x, y, wd, ht); if (err) GollyError(L, 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); lua_pushboolean(L, visible); return 1; // result is a boolean } // ----------------------------------------------------------------------------- static int g_setview(lua_State* L) { CheckEvents(L); int wd = luaL_checkinteger(L, 1); int ht = luaL_checkinteger(L, 2); if (wd < 0) wd = 0; if (ht < 0) ht = 0; int currwd, currht; bigview->GetClientSize(&currwd, &currht); if (currwd < 0) currwd = 0; if (currht < 0) currht = 0; int mainwd, mainht; mainptr->GetSize(&mainwd, &mainht); mainptr->SetSize(mainwd + (wd - currwd), mainht + (ht - currht)); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getview(lua_State* L) { CheckEvents(L); int currwd, currht; bigview->GetClientSize(&currwd, &currht); if (currwd < 0) currwd = 0; if (currht < 0) currht = 0; lua_pushinteger(L, currwd); lua_pushinteger(L, currht); return 2; // result is 2 integers (wd, ht) } // ----------------------------------------------------------------------------- static int g_update(lua_State* L) { CheckEvents(L); GSF_update(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_autoupdate(lua_State* L) { CheckEvents(L); autoupdate = lua_toboolean(L, 1) ? true : false; // avoids stupid MVC warning return 0; // no result } // ----------------------------------------------------------------------------- static int g_addlayer(lua_State* L) { CheckEvents(L); if (numlayers >= MAX_LAYERS) { GollyError(L, "addlayer error: no more layers can be added."); } else { AddLayer(); DoAutoUpdate(); } // return index of new layer lua_pushinteger(L, currindex); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_clone(lua_State* L) { CheckEvents(L); if (numlayers >= MAX_LAYERS) { GollyError(L, "clone error: no more layers can be added."); } else { CloneLayer(); DoAutoUpdate(); } // return index of new layer lua_pushinteger(L, currindex); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_duplicate(lua_State* L) { CheckEvents(L); if (numlayers >= MAX_LAYERS) { GollyError(L, "duplicate error: no more layers can be added."); } else { DuplicateLayer(); DoAutoUpdate(); } // return index of new layer lua_pushinteger(L, currindex); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_dellayer(lua_State* L) { CheckEvents(L); if (numlayers <= 1) { GollyError(L, "dellayer error: there is only one layer."); } else { DeleteLayer(); DoAutoUpdate(); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_movelayer(lua_State* L) { CheckEvents(L); int fromindex = luaL_checkinteger(L, 1); int toindex = luaL_checkinteger(L, 2); if (fromindex < 0 || fromindex >= numlayers) { char msg[64]; sprintf(msg, "movelayer error: bad fromindex (%d)", fromindex); GollyError(L, msg); } if (toindex < 0 || toindex >= numlayers) { char msg[64]; sprintf(msg, "movelayer error: bad toindex (%d)", toindex); GollyError(L, msg); } MoveLayer(fromindex, toindex); DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_setlayer(lua_State* L) { CheckEvents(L); int index = luaL_checkinteger(L, 1); if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "setlayer error: bad index (%d)", index); GollyError(L, msg); } SetLayer(index); DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getlayer(lua_State* L) { CheckEvents(L); lua_pushinteger(L, currindex); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_numlayers(lua_State* L) { CheckEvents(L); lua_pushinteger(L, numlayers); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_maxlayers(lua_State* L) { CheckEvents(L); lua_pushinteger(L, MAX_LAYERS); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_setname(lua_State* L) { CheckEvents(L); const char* name = luaL_checkstring(L, 1); int index = currindex; if (lua_gettop(L) > 1) index = luaL_checkinteger(L, 2); if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "setname error: bad index (%d)", index); GollyError(L, msg); } GSF_setname(wxString(name, LUA_ENC), index); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getname(lua_State* L) { CheckEvents(L); int index = currindex; if (lua_gettop(L) > 0) index = luaL_checkinteger(L, 1); if (index < 0 || index >= numlayers) { char msg[64]; sprintf(msg, "getname error: bad index (%d)", index); GollyError(L, msg); } lua_pushstring(L, (const char*)GetLayer(index)->currname.mb_str(wxConvUTF8)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_setcolors(lua_State* L) { CheckEvents(L); luaL_checktype(L, 1, LUA_TTABLE); int len = luaL_len(L, 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 lua_rawgeti(L, 1, 1); int r1 = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 2); int g1 = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 3); int b1 = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 4); int r2 = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 5); int g2 = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, 6); int b2 = lua_tointeger(L,-1); lua_pop(L,1); CHECK_RGB(r1, g1, b1, "setcolors"); CHECK_RGB(r2, g2, b2, "setcolors"); currlayer->fromrgb.Set(r1, g1, b1); currlayer->torgb.Set(r2, g2, b2); CreateColorGradient(); UpdateIconColors(); UpdateCloneColors(); } else if (len % 4 == 0) { int i = 0; while (i < len) { lua_rawgeti(L, 1, ++i); int s = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, ++i); int r = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, ++i); int g = lua_tointeger(L,-1); lua_pop(L,1); lua_rawgeti(L, 1, ++i); int b = lua_tointeger(L,-1); lua_pop(L,1); CHECK_RGB(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, "setcolors error: bad state (%d)", s); GollyError(L, msg); } else { currlayer->cellr[s] = r; currlayer->cellg[s] = g; currlayer->cellb[s] = b; } } } UpdateIconColors(); UpdateCloneColors(); } else { GollyError(L, "setcolors error: array length is not a multiple of 4."); } DoAutoUpdate(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getcolors(lua_State* L) { CheckEvents(L); int state = -1; if (lua_gettop(L) > 0) state = luaL_checkinteger(L, 1); lua_newtable(L); if (state == -1) { // return colors for ALL states, including state 0 int tindex = 0; for (state = 0; state < currlayer->algo->NumCellStates(); state++) { lua_pushinteger(L, state); lua_rawseti(L, -2, ++tindex); lua_pushinteger(L, currlayer->cellr[state]); lua_rawseti(L, -2, ++tindex); lua_pushinteger(L, currlayer->cellg[state]); lua_rawseti(L, -2, ++tindex); lua_pushinteger(L, currlayer->cellb[state]); lua_rawseti(L, -2, ++tindex); } } else if (state >= 0 && state < currlayer->algo->NumCellStates()) { lua_pushinteger(L, state); lua_rawseti(L, -2, 1); lua_pushinteger(L, currlayer->cellr[state]); lua_rawseti(L, -2, 2); lua_pushinteger(L, currlayer->cellg[state]); lua_rawseti(L, -2, 3); lua_pushinteger(L, currlayer->cellb[state]); lua_rawseti(L, -2, 4); } else { char msg[64]; sprintf(msg, "getcolors error: bad state (%d)", state); GollyError(L, msg); } return 1; // result is a table } // ----------------------------------------------------------------------------- static int g_setoption(lua_State* L) { CheckEvents(L); const char* optname = luaL_checkstring(L, 1); int newval = luaL_checkinteger(L, 2); int oldval; if (!GSF_setoption(optname, newval, &oldval)) { GollyError(L, "setoption error: unknown option."); } // return old value (simplifies saving and restoring settings) lua_pushinteger(L, oldval); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_getoption(lua_State* L) { CheckEvents(L); const char* optname = luaL_checkstring(L, 1); int optval; if (!GSF_getoption(optname, &optval)) { GollyError(L, "getoption error: unknown option."); } lua_pushinteger(L, optval); return 1; // result is an integer } // ----------------------------------------------------------------------------- static int g_setcolor(lua_State* L) { CheckEvents(L); const char* colname = luaL_checkstring(L, 1); int r = luaL_checkinteger(L, 2); int g = luaL_checkinteger(L, 3); int b = luaL_checkinteger(L, 4); CHECK_RGB(r, g, b, "setcolor"); wxColor newcol(r, g, b); wxColor oldcol; if (!GSF_setcolor(colname, newcol, oldcol)) { GollyError(L, "setcolor error: unknown color."); } // return old r,g,b values (simplifies saving and restoring colors) lua_pushinteger(L, oldcol.Red()); lua_pushinteger(L, oldcol.Green()); lua_pushinteger(L, oldcol.Blue()); return 3; // result is 3 ints } // ----------------------------------------------------------------------------- static int g_getcolor(lua_State* L) { CheckEvents(L); const char* colname = luaL_checkstring(L, 1); wxColor color; if (!GSF_getcolor(colname, color)) { GollyError(L, "getcolor error: unknown color."); } // return r,g,b values lua_pushinteger(L, color.Red()); lua_pushinteger(L, color.Green()); lua_pushinteger(L, color.Blue()); return 3; // result is 3 ints } // ----------------------------------------------------------------------------- static int g_setclipstr(lua_State* L) { CheckEvents(L); mainptr->CopyTextToClipboard(wxString(luaL_checkstring(L, 1), LUA_ENC)); return 0; // no result } // ----------------------------------------------------------------------------- static int g_getclipstr(lua_State* L) { CheckEvents(L); wxTextDataObject data; if (!mainptr->GetTextFromClipboard(&data)) { GollyError(L, "getclipstr error: no text in clipboard."); } wxString clipstr = data.GetText(); lua_pushstring(L, (const char*)clipstr.mb_str(wxConvUTF8)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_getstring(lua_State* L) { CheckEvents(L); const char* prompt = luaL_checkstring(L, 1); const char* initial = lua_gettop(L) > 1 ? luaL_checkstring(L, 2) : ""; const char* title = lua_gettop(L) > 2 ? luaL_checkstring(L, 3) : ""; wxString result; if (!GetString(wxString(title, LUA_ENC), wxString(prompt, LUA_ENC), wxString(initial, LUA_ENC), result)) { // user hit Cancel button so abort script lua_pushstring(L, abortmsg); lua_error(L); } lua_pushstring(L, (const char*)result.mb_str(wxConvUTF8)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_getxy(lua_State* L) { CheckEvents(L); statusptr->CheckMouseLocation(mainptr->infront); // sets mousepos if (viewptr->showcontrols) mousepos = wxEmptyString; lua_pushstring(L, (const char*)mousepos.mb_str(wxConvUTF8)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_getevent(lua_State* L) { CheckEvents(L); int get = 1; if (lua_gettop(L) > 0) get = lua_toboolean(L, 1) ? 1 : 0; wxString event; GSF_getevent(event, get); lua_pushstring(L, (const char*)event.mb_str(wxConvUTF8)); return 1; // result is a string } // ----------------------------------------------------------------------------- static int g_doevent(lua_State* L) { CheckEvents(L); const char* event = luaL_checkstring(L, 1); if (event[0]) { const char* err = GSF_doevent(wxString(event, LUA_ENC)); if (err) GollyError(L, err); } return 0; // no result } // ----------------------------------------------------------------------------- static int g_show(lua_State* L) { CheckEvents(L); inscript = false; statusptr->DisplayMessage(wxString(luaL_checkstring(L, 1), LUA_ENC)); inscript = true; // make sure status bar is visible if (!showstatus) mainptr->ToggleStatusBar(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_error(lua_State* L) { CheckEvents(L); inscript = false; statusptr->ErrorMessage(wxString(luaL_checkstring(L, 1), LUA_ENC)); inscript = true; // make sure status bar is visible if (!showstatus) mainptr->ToggleStatusBar(); return 0; // no result } // ----------------------------------------------------------------------------- static int g_warn(lua_State* L) { CheckEvents(L); Warning(wxString(luaL_checkstring(L, 1), LUA_ENC)); return 0; // no result } // ----------------------------------------------------------------------------- static int g_note(lua_State* L) { CheckEvents(L); Note(wxString(luaL_checkstring(L, 1), LUA_ENC)); return 0; // no result } // ----------------------------------------------------------------------------- static int g_help(lua_State* L) { CheckEvents(L); ShowHelp(wxString(luaL_checkstring(L, 1), LUA_ENC)); return 0; // no result } // ----------------------------------------------------------------------------- static int g_check(lua_State* L) { // CheckEvents(L); // don't call CheckEvents here otherwise we can't safely write code like // if g.getlayer() == target then // g.check(0) // ... do stuff to target layer ... // g.check(1) allowcheck = (luaL_checkinteger(L, 1) != 0); return 0; // no result } // ----------------------------------------------------------------------------- static int g_continue(lua_State* L) { // do NOT call CheckEvents here aborted = false; // continue executing any remaining code // if not empty, error will be displayed when script ends scripterr = wxString(luaL_checkstring(L, 1), LUA_ENC); return 0; // no result } // ----------------------------------------------------------------------------- static int g_exit(lua_State* L) { // script will terminate so no point calling CheckEvents here if (lua_gettop(L) == 0) { GSF_exit(wxEmptyString); } else { GSF_exit(wxString(luaL_checkstring(L, 1), LUA_ENC)); } lua_pushstring(L, abortmsg); lua_error(L); return 0; // never get here (lua_error does a longjmp) } // ----------------------------------------------------------------------------- static const struct luaL_Reg gollyfuncs [] = { // filing { "open", g_open }, // open given pattern/script/rule/html file { "save", g_save }, // save pattern in given file using given format { "opendialog", g_opendialog }, // return input path and filename chosen by user { "savedialog", g_savedialog }, // return output path and filename chosen by user { "load", g_load }, // read pattern file and return cell array { "store", g_store }, // write cell array to a file (in RLE format) { "setdir", g_setdir }, // set location of specified directory { "getdir", g_getdir }, // return location of specified directory { "getfiles", g_getfiles }, // return array of files in specified directory // editing { "new", g_new }, // create new universe and set window title { "cut", g_cut }, // cut selection to clipboard { "copy", g_copy }, // copy selection to clipboard { "clear", g_clear }, // clear inside/outside selection { "paste", g_paste }, // paste clipboard pattern at x,y using given mode { "shrink", g_shrink }, // shrink selection { "randfill", g_randfill }, // randomly fill selection to given percentage { "flip", g_flip }, // flip selection top-bottom or left-right { "rotate", g_rotate }, // rotate selection 90 deg clockwise or anticlockwise { "parse", g_parse }, // parse RLE or Life 1.05 string and return cell array { "transform", g_transform }, // apply an affine transformation to cell array { "evolve", g_evolve }, // generate pattern contained in given cell array { "putcells", g_putcells }, // paste given cell array into current universe { "getcells", g_getcells }, // return cell array in given rectangle { "join", g_join }, // return concatenation of given cell arrays { "hash", g_hash }, // return hash value for pattern in given rectangle { "getclip", g_getclip }, // return pattern in clipboard (as wd, ht, cell array) { "select", g_select }, // select {x, y, wd, ht} rectangle or remove if {} { "getrect", g_getrect }, // return pattern rectangle as {} or {x, y, wd, ht} { "getselrect", g_getselrect }, // return selection rectangle as {} or {x, y, wd, ht} { "setcell", g_setcell }, // set given cell to given state { "getcell", g_getcell }, // get state of given cell { "setcursor", g_setcursor }, // set cursor (returns old cursor) { "getcursor", g_getcursor }, // return current cursor // control { "empty", g_empty }, // return true if universe is empty { "run", g_run }, // run current pattern for given number of gens { "step", g_step }, // run current pattern for current step { "setstep", g_setstep }, // set step exponent { "getstep", g_getstep }, // return current step exponent { "setbase", g_setbase }, // set base step { "getbase", g_getbase }, // return current base step { "advance", g_advance }, // advance inside/outside selection by given gens { "reset", g_reset }, // restore starting pattern { "setgen", g_setgen }, // set current generation to given string { "getgen", g_getgen }, // return current generation as string { "getpop", g_getpop }, // return current population as string { "numstates", g_numstates }, // return number of cell states in current universe { "numalgos", g_numalgos }, // return number of algorithms { "setalgo", g_setalgo }, // set current algorithm using given string { "getalgo", g_getalgo }, // return name of given or current algorithm { "setrule", g_setrule }, // set current rule using given string { "getrule", g_getrule }, // return current rule { "getwidth", g_getwidth }, // return width of universe (0 if unbounded) { "getheight", g_getheight }, // return height of universe (0 if unbounded) // viewing { "setpos", g_setpos }, // move given cell to middle of viewport { "getpos", g_getpos }, // return x,y position of cell in middle of viewport { "setmag", g_setmag }, // set magnification (0=1:1, 1=1:2, -1=2:1, etc) { "getmag", g_getmag }, // return current magnification { "fit", g_fit }, // fit entire pattern in viewport { "fitsel", g_fitsel }, // fit selection in viewport { "visrect", g_visrect }, // return true if given rect is completely visible { "setview", g_setview }, // set pixel dimensions of viewport { "getview", g_getview }, // get pixel dimensions of viewport { "update", g_update }, // update display (viewport and status bar) { "autoupdate", g_autoupdate }, // update display after each change to universe? // layers { "addlayer", g_addlayer }, // add a new layer { "clone", g_clone }, // add a cloned layer (shares universe) { "duplicate", g_duplicate }, // add a duplicate layer (copies universe) { "dellayer", g_dellayer }, // delete current layer { "movelayer", g_movelayer }, // move given layer to new index { "setlayer", g_setlayer }, // switch to given layer { "getlayer", g_getlayer }, // return index of current layer { "numlayers", g_numlayers }, // return current number of layers { "maxlayers", g_maxlayers }, // return maximum number of layers { "setname", g_setname }, // set name of given layer { "getname", g_getname }, // get name of given layer { "setcolors", g_setcolors }, // set color(s) used in current layer { "getcolors", g_getcolors }, // get color(s) used in current layer // miscellaneous { "setoption", g_setoption }, // set given option to new value (and return old value) { "getoption", g_getoption }, // return current value of given option { "setcolor", g_setcolor }, // set given color to new r,g,b (returns old r,g,b) { "getcolor", g_getcolor }, // return r,g,b values of given color { "setclipstr", g_setclipstr }, // set the clipboard contents to a given string value { "getclipstr", g_getclipstr }, // retrieve the contents of the clipboard as a string { "getstring", g_getstring }, // display dialog box and get string from user { "getxy", g_getxy }, // return current grid location of mouse { "getevent", g_getevent }, // return keyboard/mouse event or empty string if none { "doevent", g_doevent }, // pass given keyboard/mouse event to Golly to handle { "show", g_show }, // show given string in status bar { "error", g_error }, // beep and show given string in status bar { "warn", g_warn }, // show given string in warning dialog { "note", g_note }, // show given string in note dialog { "help", g_help }, // show given HTML file in help window { "check", g_check }, // allow event checking? { "continue", g_continue }, // continue executing code after a pcall error { "exit", g_exit }, // exit script with optional error message {NULL, NULL} }; // ----------------------------------------------------------------------------- static int create_golly_table(lua_State* L) { // create a table with our g_* functions and register them luaL_newlib(L, gollyfuncs); return 1; } // ----------------------------------------------------------------------------- // we want to allow a Lua script to call another Lua script via g_open // so we use lua_level to detect if a Lua state has already been created static int lua_level = 0; static lua_State* L = NULL; void RunLuaScript(const wxString& filepath) { if (lua_level == 0) { aborted = false; L = luaL_newstate(); luaL_openlibs(L); // we want our g_* functions to be called from Lua as g.* lua_pushcfunction(L, create_golly_table); lua_setglobal(L, "golly"); // It would be nice if we could do this now: // // luaL_dostring(L, "local g = golly()"); // // But it doesn't work because g goes out of scope, so users // will have to start their scripts with that line. // Note that we could do this: // // luaL_dostring(L, "g = golly()"); // // But it's ~10% slower to access functions because g is global. // append gollydir/Scripts/Lua/?.lua and gollydir/Scripts/Lua/?/init.lua // to package.path so scripts can do things like this: // local gp = require "gplus" // local gpt = require "gplus.text" ('.' will be changed to path separator) wxString luadir = gollydir; luadir += wxT("Scripts"); luadir += wxFILE_SEP_PATH; luadir += wxT("Lua"); luadir += wxFILE_SEP_PATH; wxString pstring = wxT("package.path = package.path..';"); pstring += luadir; pstring += wxT("?.lua;"); pstring += luadir; pstring += wxT("?"); pstring += wxFILE_SEP_PATH; pstring += wxT("init.lua'"); // convert any backslashes to "\\" to avoid "\" being treated as escape char // (definitely necessary on Windows because wxFILE_SEP_PATH is a backslash) pstring.Replace(wxT("\\"), wxT("\\\\")); luaL_dostring(L, (const char*)pstring.mb_str(wxConvUTF8)); } lua_level++; // don't use wxConvUTF8 in next line because caller has already converted // filepath to decomposed UTF8 if on a Mac if (luaL_dofile(L, (const char*)filepath.mb_str(wxConvLocal))) { scripterr += wxString(lua_tostring(L,-1), LUA_ENC); scripterr += wxT("\n"); // scripterr is checked at the end of RunScript in wxscript.cpp lua_pop(L,1); } lua_level--; if (lua_level == 0) { lua_close(L); } } // ----------------------------------------------------------------------------- void AbortLuaScript() { // calling lua_error here causes nasty problems (presumably due to doing // a longjmp from inside Yield) so we set the aborted flag and check it // in CheckEvents only after Yield has finished aborted = true; } // ----------------------------------------------------------------------------- void FinishLuaScripting() { // no need to do anything } golly-2.8-src/gui-wx/wxselect.cpp0000644000175100017510000022302212751752464014021 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) currlayer->algo->CreateBorderCells(); currlayer->algo->step(); if (boundedgrid) currlayer->algo->DeleteBorderCells(); 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) tempalgo->CreateBorderCells(); tempalgo->step(); if (boundedgrid) tempalgo->DeleteBorderCells(); 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) currlayer->algo->CreateBorderCells(); currlayer->algo->step(); if (boundedgrid) currlayer->algo->DeleteBorderCells(); 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) currlayer->algo->CreateBorderCells(); currlayer->algo->step(); if (boundedgrid) currlayer->algo->DeleteBorderCells(); 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, bool remove_if_empty) { if (!exists) return; if (mainptr->generating) { mainptr->command_pending = true; mainptr->cmdevent.SetId(fit ? ID_SHRINKFIT : ID_SHRINK); mainptr->Stop(); return; } // check if there is no pattern if (currlayer->algo->isEmpty()) { if (remove_if_empty) { viewptr->RemoveSelection(); } else { 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(); else mainptr->UpdatePatternAndStatus(); return; } // check if selection is completely outside pattern edges if (Outside(top, left, bottom, right)) { if (remove_if_empty) { viewptr->RemoveSelection(); } else { 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()) { if (remove_if_empty) { viewptr->RemoveSelection(); delete tempalgo; return; } else { 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_CLEAR); mainptr->Stop(); 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_OUTSIDE); mainptr->Stop(); 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_RANDOM); mainptr->Stop(); 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(topbottom ? ID_FLIPTB : ID_FLIPLR); mainptr->Stop(); 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(clockwise ? ID_ROTATEC : ID_ROTATEA); mainptr->Stop(); 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.8-src/gui-wx/wxmain.h0000755000175100017510000002675412751752464013153 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(bool update_now = false); 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 ToggleShowFiles(); void ChangeFileDir(); void SetFileDir(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 StartGenTimer(); void StartGenerating(); void StopGenerating(); void StartOrStop(); void Stop(); void FinishUp(); void GoFaster(); void GoSlower(); 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); // view functions void ToggleStatusBar(); void ToggleExactNumbers(); void ToggleToolBar(); void ToggleFullScreen(); void ShowPatternInfo(); void ResizeSplitWindow(int wd, int ht); void ResizeStatusBar(int wd, int ht); void ResizeBigView(); 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(); wxTimer* gentimer; // timer for generating patterns bool generating; // currently generating a 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 luafile; // name of temporary Lua script 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? #ifdef __WXMAC__ // these scroll bars are needed to avoid bug in wxGLCanvas on Mac wxScrollBar* hbar; wxScrollBar* vbar; #endif 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 OnGenTimer(wxTimerEvent& event); void OnClose(wxCloseEvent& event); #ifdef __WXMAC__ void OnScroll(wxScrollEvent& event); #endif // file functions bool LoadImage(const wxString& path); 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 CreateDirControl(); void SimplifyTree(wxString& dir, wxTreeCtrl* treectrl, wxTreeItemId root); void DoPendingAction(bool restart); // splittable window contains file directory in left pane // and layer/edit/timeline bars plus viewport window in right pane wxSplitterWindow* splitwin; wxGenericDirCtrl* filectrl; int hypdown; // for hyperspeed int minexpo; // currexpo at maximum delay (must be <= 0) long begintime, endtime; // for timing info double begingen, endgen; // ditto }; // ids for menu commands, etc 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, // 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_FILES, ID_FILE_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_SMARTSCALE, 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_LUA, 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, // for loading a lexicon pattern ID_HELP_BUTT, // for help button in tool bar ID_GENTIMER // for gentimer }; #endif golly-2.8-src/gui-wx/wxfile.cpp0000644000175100017510000020067112751752464013466 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 "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 #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::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??? SetTitle(wtitle); } // ----------------------------------------------------------------------------- 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) { command_pending = true; cmdevent.SetId(wxID_NEW); Stop(); 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 SetTitle(_("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) { 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); } Stop(); 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) { command_pending = true; cmdevent.SetId(wxID_OPEN); Stop(); 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); if ( opendlg.ShowModal() == wxID_OK ) { wxFileName fullpath( opendlg.GetPath() ); opensavedir = fullpath.GetPath(); OpenFile( opendlg.GetPath() ); } } // ----------------------------------------------------------------------------- void MainFrame::OpenScript() { if (generating) { command_pending = true; cmdevent.SetId(ID_RUN_SCRIPT); Stop(); return; } wxString filetypes = _("Lua or Python (*.lua;*.py)|*.lua;*.py"); filetypes += _("|Lua (*.lua)|*.lua"); filetypes += _("|Python (*.py)|*.py"); #ifdef ENABLE_PERL filetypes += _("|Perl (*.pl)|*.pl"); #endif wxFileDialog opendlg(this, _("Choose a script"), rundir, wxEmptyString, filetypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST); 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) { command_pending = true; cmdevent.SetId(ID_OPEN_CLIP); Stop(); 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 Lua, Perl or Python code: // if "--" or "local" or "require" is at start of line then we assume Lua, // if "use" or "my" is at start of line then we assume Perl, // if "import" or "from" is 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 '-': if (linelen == 1 && p[-1] == '-') return luafile; // Lua comment at start of line linelen++; 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 == 5 && strncmp(p-5,"local",5) == 0) return luafile; if (linelen == 7 && strncmp(p-7,"require",7) == 0) return luafile; 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) { command_pending = true; cmdevent.SetId(ID_RUN_CLIP); Stop(); 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()) { outfile.Write( data.GetText() ); 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) { command_pending = true; cmdevent.SetId(id); Stop(); 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) { command_pending = true; cmdevent.SetId(id); Stop(); 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); return err; } // ----------------------------------------------------------------------------- bool MainFrame::SavePattern() { if (generating) { command_pending = true; cmdevent.SetId(wxID_SAVE); Stop(); return false; } if (warn_on_save && currlayer->dirty && currlayer->algo->getGeneration() > currlayer->startgen && !TimelineExists()) { 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 ); 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::ToggleShowFiles() { 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 showfiles = !showfiles; if (splitwin->IsSplit()) { // hide left pane splitwin->Unsplit(filectrl); } else { splitwin->SplitVertically(filectrl, RightPane(), dirwinwd); } viewptr->SetFocus(); #ifndef __WXMAC__ // restore scroll bars bigview->UpdateScrollBars(); #endif } // ----------------------------------------------------------------------------- void MainFrame::ChangeFileDir() { wxDirDialog dirdlg(this, _("Choose a new file folder"), filedir, wxDD_NEW_DIR_BUTTON); if (dirdlg.ShowModal() == wxID_OK) SetFileDir(dirdlg.GetPath()); } // ----------------------------------------------------------------------------- void MainFrame::SetFileDir(const wxString& newdir) { if (filedir != newdir) { filedir = newdir; if (showfiles) { // show new file directory SimplifyTree(filedir, filectrl->GetTreeCtrl(), filectrl->GetRootId()); } } } // ----------------------------------------------------------------------------- void MainFrame::ShowPrefsDialog(const wxString& page) { if (viewptr->waitingforclick) return; if (generating) { command_pending = true; cmdevent.SetId(wxID_PREFERENCES); Stop(); 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 // 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.8-src/gui-wx/wxtimeline.cpp0000644000175100017510000010605112660172450014340 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 ID_AUTOTIMER // for autotimer }; // 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(); void StartAutoTimer(); void StopAutoTimer(); // detect press and release of a bitmap button void OnButtonDown(wxMouseEvent& event); void OnButtonUp(wxMouseEvent& event); void OnKillFocus(wxFocusEvent& event); wxTimer* autotimer; // timer for auto play 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 OnAutoTimer(wxTimerEvent& 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) EVT_TIMER (ID_AUTOTIMER, TimelineBar::OnAutoTimer) 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), #ifdef __WXMSW__ // need this to avoid buttons flashing on Windows wxNO_FULL_REPAINT_ON_RESIZE #else // better for Mac and Linux wxFULL_REPAINT_ON_RESIZE #endif ) { #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; #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 // create timer for auto play autotimer = new wxTimer(this, ID_AUTOTIMER); } // ----------------------------------------------------------------------------- TimelineBar::~TimelineBar() { delete timelinefont; delete timelinebitmap; delete slider; delete framebar; delete autotimer; } // ----------------------------------------------------------------------------- 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; StartAutoTimer(); } else if (type == wxEVT_SCROLL_LINEDOWN) { currlayer->tlspeed++; if (currlayer->tlspeed > MAXSPEED) currlayer->tlspeed = MAXSPEED; StartAutoTimer(); } else if (type == wxEVT_SCROLL_PAGEUP) { currlayer->tlspeed -= PAGESIZE; if (currlayer->tlspeed < MINSPEED) currlayer->tlspeed = MINSPEED; StartAutoTimer(); } else if (type == wxEVT_SCROLL_PAGEDOWN) { currlayer->tlspeed += PAGESIZE; if (currlayer->tlspeed > MAXSPEED) currlayer->tlspeed = MAXSPEED; StartAutoTimer(); } else if (type == wxEVT_SCROLL_THUMBTRACK) { currlayer->tlspeed = event.GetPosition(); if (currlayer->tlspeed < MINSPEED) currlayer->tlspeed = MINSPEED; if (currlayer->tlspeed > MAXSPEED) currlayer->tlspeed = MAXSPEED; StartAutoTimer(); } else if (type == wxEVT_SCROLL_THUMBRELEASE) { UpdateSlider(); StartAutoTimer(); } #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(); // stop autoplay if scroll bar is used if (currlayer->autoplay != 0) { currlayer->autoplay = 0; StopAutoTimer(); 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 TimelineBar::OnAutoTimer(wxTimerEvent& WXUNUSED(event)) { if (currlayer->autoplay == 0) return; if (currlayer->algo->isrecording()) return; // assume currlayer->algo->getframecount() > 0 int frameinc = 1; if (currlayer->tlspeed > 0) { // skip 2^tlspeed frames frameinc = 1 << currlayer->tlspeed; } 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 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 UpdateButtons(); } } DisplayCurrentFrame(); UpdateScrollBar(); } // ----------------------------------------------------------------------------- void TimelineBar::StartAutoTimer() { if (currlayer->autoplay == 0) return; int interval = SIXTY_HERTZ; // do ~60 calls of OnAutoTimer per sec // increase interval if user wants a delay between each frame if (currlayer->tlspeed < 0) { interval = 100 * (-currlayer->tlspeed); // if tlspeed is -1 then interval is 100; ie. call OnAutoTimer 10 times per sec } StopAutoTimer(); autotimer->Start(interval, wxTIMER_CONTINUOUS); } // ----------------------------------------------------------------------------- void TimelineBar::StopAutoTimer() { if (autotimer->IsRunning()) autotimer->Stop(); } // ----------------------------------------------------------------------------- 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 && showtimeline) { 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; if (r.width < 0) r.width = 0; 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; mainptr->ResizeBigView(); tbarptr->Show(showtimeline); // needed on Windows mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void StartStopRecording() { if (!inscript && currlayer->algo->hyperCapable()) { if (currlayer->algo->isrecording()) { mainptr->Stop(); // StopGenerating() has called currlayer->algo->stoprecording() } else { tbarptr->StopAutoTimer(); 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; } mainptr->StartGenerating(); } else { // this should never happen Warning(_("Bug: could not start recording!")); } } } } // ----------------------------------------------------------------------------- void DeleteTimeline() { if (!inscript && TimelineExists() && !currlayer->algo->isrecording()) { tbarptr->StopAutoTimer(); 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; tbarptr->StopAutoTimer(); // 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() { return currlayer->algo->getframecount() > 0; } // ----------------------------------------------------------------------------- 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; } if (currlayer->autoplay == 0) { tbarptr->StopAutoTimer(); } else { tbarptr->StartAutoTimer(); } mainptr->UpdateUserInterface(); } // ----------------------------------------------------------------------------- void PlayTimelineFaster() { if (currlayer->algo->isrecording()) return; if (currlayer->tlspeed < MAXSPEED) { currlayer->tlspeed++; if (showtimeline) tbarptr->UpdateSlider(); tbarptr->StartAutoTimer(); } } // ----------------------------------------------------------------------------- void PlayTimelineSlower() { if (currlayer->algo->isrecording()) return; if (currlayer->tlspeed > MINSPEED) { currlayer->tlspeed--; if (showtimeline) tbarptr->UpdateSlider(); tbarptr->StartAutoTimer(); } } // ----------------------------------------------------------------------------- void ResetTimelineSpeed() { if (currlayer->algo->isrecording()) return; currlayer->tlspeed = 0; if (showtimeline) tbarptr->UpdateSlider(); tbarptr->StartAutoTimer(); } // ----------------------------------------------------------------------------- bool TimelineIsPlaying() { return currlayer->autoplay != 0; } golly-2.8-src/gui-wx/wxedit.cpp0000644000175100017510000010122112660172450013451 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), #ifdef __WXMSW__ // need this to avoid buttons flashing on Windows wxNO_FULL_REPAINT_ON_RESIZE #else // better for Mac and Linux wxFULL_REPAINT_ON_RESIZE #endif ) { #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; #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 && showedit) { 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; mainptr->ResizeBigView(); 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) { mainptr->ResizeBigView(); 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.8-src/gui-wx/wxlayer.cpp0000644000175100017510000036247212660172450013661 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 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), #ifdef __WXMSW__ // need this to avoid buttons flashing on Windows wxNO_FULL_REPAINT_ON_RESIZE #else // better for Mac and Linux wxFULL_REPAINT_ON_RESIZE #endif ) { #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 && currbuttwd >= 0) { 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 } } // ----------------------------------------------------------------------------- void LayerBar::OnButtonDown(wxMouseEvent& event) { // a layer bar button has been pressed 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 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); } } } // ----------------------------------------------------------------------------- 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)); #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)); #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 && showlayer) { 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; if (showlayer) { ShiftEditBar(layerbarht); // move edit bar down } else { // hide layer bar ShiftEditBar(-layerbarht); // move edit bar up } mainptr->ResizeBigView(); 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++ ) { if (layer[i]->tilerect.width < 0) layer[i]->tilerect.width = 0; if (layer[i]->tilerect.height < 0) layer[i]->tilerect.height = 0; 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->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; } } } } // ----------------------------------------------------------------------------- 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); } // ----------------------------------------------------------------------------- static unsigned char* CreateIconAtlas(wxBitmap** srcicons, int iconsize) { 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; } // allocate enough memory for texture atlas to store RGBA pixels for a row of icons // (note that we use calloc so all alpha bytes are initially 0) int rowbytes = currlayer->numicons * iconsize * 4; unsigned char* atlasptr = (unsigned char*) calloc(rowbytes * iconsize, 1); if (atlasptr) { for (int state = 1; state <= currlayer->numicons; state++) { if (srcicons && srcicons[state]) { int wd = srcicons[state]->GetWidth(); // should be iconsize - 1 int ht = srcicons[state]->GetHeight(); // ditto wxAlphaPixelData icondata(*srcicons[state]); if (icondata) { wxAlphaPixelData::Iterator iconpxl(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; } // start at top left byte of icon int tpos = (state-1) * iconsize * 4; for (int row = 0; row < ht; row++) { wxAlphaPixelData::Iterator iconrow = iconpxl; int rowstart = tpos; for (int col = 0; col < wd; col++) { unsigned char r = iconpxl.Red(); unsigned char g = iconpxl.Green(); unsigned char b = iconpxl.Blue(); if (r || g || b) { // non-black pixel if (multicolor) { // use non-black pixel in multi-colored icon if (swapcolors) { atlasptr[tpos] = 255 - r; atlasptr[tpos+1] = 255 - g; atlasptr[tpos+2] = 255 - b; } else { atlasptr[tpos] = r; atlasptr[tpos+1] = g; atlasptr[tpos+2] = b; } } else { // grayscale icon (r = g = b) if (r == 255) { // replace white pixel with live cell color atlasptr[tpos] = liver; atlasptr[tpos+1] = liveg; atlasptr[tpos+2] = liveb; } else { // replace gray pixel with appropriate shade between // live and dead cell colors float frac = (float)r / 255.0; atlasptr[tpos] = (int)(deadr + frac * (liver - deadr) + 0.5); atlasptr[tpos+1] = (int)(deadg + frac * (liveg - deadg) + 0.5); atlasptr[tpos+2] = (int)(deadb + frac * (liveb - deadb) + 0.5); } } atlasptr[tpos+3] = 255; // alpha channel is opaque } // move to next pixel tpos += 4; iconpxl++; } // move to next row tpos = rowstart + rowbytes; iconpxl = iconrow; iconpxl.OffsetY(icondata, 1); } } } } } return atlasptr; } // ----------------------------------------------------------------------------- Layer* CreateTemporaryLayer() { Layer* templayer = new Layer(); if (templayer == NULL) Warning(_("Failed to create temporary layer!")); return templayer; } // ----------------------------------------------------------------------------- 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_ADD_LAYER); mainptr->Stop(); 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; currlayer->multicoloricons = oldlayer->multicoloricons; currlayer->numicons = oldlayer->numicons; for (int n = 0; n <= currlayer->numicons; 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 atlas currlayer->atlas7x7 = oldlayer->atlas7x7; currlayer->atlas15x15 = oldlayer->atlas15x15; currlayer->atlas31x31 = oldlayer->atlas31x31; } else { // duplicate icons from old layer currlayer->icons7x7 = CopyIcons(oldlayer->icons7x7, currlayer->numicons); currlayer->icons15x15 = CopyIcons(oldlayer->icons15x15, currlayer->numicons); currlayer->icons31x31 = CopyIcons(oldlayer->icons31x31, currlayer->numicons); // create icon texture atlases currlayer->atlas7x7 = CreateIconAtlas(oldlayer->icons7x7, 8); currlayer->atlas15x15 = CreateIconAtlas(oldlayer->icons15x15, 16); currlayer->atlas31x31 = CreateIconAtlas(oldlayer->icons31x31, 32); } } 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_CLONE); mainptr->Stop(); return; } cloning = true; AddLayer(); cloning = false; } // ----------------------------------------------------------------------------- void DuplicateLayer() { if (numlayers >= MAX_LAYERS) return; if (mainptr->generating) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_DUPLICATE); mainptr->Stop(); return; } duplicating = true; AddLayer(); duplicating = false; } // ----------------------------------------------------------------------------- void DeleteLayer() { if (numlayers <= 1) return; if (mainptr->generating) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_DEL_LAYER); mainptr->Stop(); 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_LAYER0 + index); mainptr->Stop(); 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(); } // ----------------------------------------------------------------------------- void MoveLayerDialog() { if (inscript || numlayers <= 1) return; if (mainptr->generating) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_MOVE_LAYER); mainptr->Stop(); 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_NAME_LAYER); mainptr->Stop(); 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; } } // ----------------------------------------------------------------------------- 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; } // also delete icon texture atlases if (layer->atlas7x7) { free(layer->atlas7x7); layer->atlas7x7 = NULL; } if (layer->atlas15x15) { free(layer->atlas15x15); layer->atlas15x15 = NULL; } if (layer->atlas31x31) { free(layer->atlas31x31); layer->atlas31x31 = 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(); } } } } // create icon texture atlases (used for rendering) currlayer->numicons = maxstate; currlayer->atlas7x7 = CreateIconAtlas(currlayer->icons7x7, 8); currlayer->atlas15x15 = CreateIconAtlas(currlayer->icons15x15, 16); currlayer->atlas31x31 = CreateIconAtlas(currlayer->icons31x31, 32); 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 UpdateCloneColors() { if (currlayer->cloneid > 0) { 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; cloneptr->multicoloricons = currlayer->multicoloricons; cloneptr->numicons = currlayer->numicons; for (int n = 0; n <= currlayer->numicons; 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 atlas cloneptr->atlas7x7 = currlayer->atlas7x7; cloneptr->atlas15x15 = currlayer->atlas15x15; cloneptr->atlas31x31 = currlayer->atlas31x31; } } } } // ----------------------------------------------------------------------------- void UpdateLayerColors() { UpdateCurrentColors(); // above has created icon texture data so don't call UpdateIconColors here // if current layer has clones then update their colors UpdateCloneColors(); } // ----------------------------------------------------------------------------- void UpdateIconColors() { // delete current icon texture atlases if (currlayer->atlas7x7) { free(currlayer->atlas7x7); } if (currlayer->atlas15x15) { free(currlayer->atlas15x15); } if (currlayer->atlas31x31) { free(currlayer->atlas31x31); } // re-create icon texture atlases currlayer->atlas7x7 = CreateIconAtlas(currlayer->icons7x7, 8); currlayer->atlas15x15 = CreateIconAtlas(currlayer->icons15x15, 16); currlayer->atlas31x31 = CreateIconAtlas(currlayer->icons31x31, 32); } // ----------------------------------------------------------------------------- void InvertIconColors(unsigned char* atlasptr, int iconsize, int numicons) { if (atlasptr) { int numbytes = numicons * iconsize * iconsize * 4; int i = 0; while (i < numbytes) { if (atlasptr[i+3] == 0) { // ignore transparent pixel } else { // invert pixel color atlasptr[i] = 255 - atlasptr[i]; atlasptr[i+1] = 255 - atlasptr[i+1]; atlasptr[i+2] = 255 - atlasptr[i+2]; } i += 4; } } } // ----------------------------------------------------------------------------- void InvertCellColors() { bool clone_inverted[MAX_LAYERS] = {false}; // swapcolors has changed so 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) int maxstate = algoinfo[layerptr->algtype]->maxstates - 1; for (int n = 0; n <= maxstate; n++) { layerptr->cellr[n] = 255 - layerptr->cellr[n]; layerptr->cellg[n] = 255 - layerptr->cellg[n]; layerptr->cellb[n] = 255 - layerptr->cellb[n]; } // clones share icon texture data so we must be careful to only invert them once if (layerptr->cloneid == 0 || !clone_inverted[layerptr->cloneid]) { // invert colors in icon texture atlases // (do NOT use maxstate here -- might be > layerptr->numicons) InvertIconColors(layerptr->atlas7x7, 8, layerptr->numicons); InvertIconColors(layerptr->atlas15x15, 16, layerptr->numicons); InvertIconColors(layerptr->atlas31x31, 32, layerptr->numicons); if (layerptr->cloneid > 0) clone_inverted[layerptr->cloneid] = true; } } } // ----------------------------------------------------------------------------- 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 currfile.Clear(); // no pattern file has been loaded startgen = 0; // initial starting generation currname = _("untitled"); // initial window title 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 atlas7x7 = NULL; // no texture atlas for 7x7 icons atlas15x15 = NULL; // no texture atlas for 15x15 icons atlas31x31 = NULL; // no texture atlas for 31x31 icons currframe = 0; // first frame in timeline autoplay = 0; // not playing tlspeed = 0; // default speed for autoplay // 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; // 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 currfile = currlayer->currfile; savestart = currlayer->savestart; startalgo = currlayer->startalgo; startdirty = currlayer->startdirty; startrule = currlayer->startrule; startx = currlayer->startx; starty = currlayer->starty; startbase = currlayer->startbase; startexpo = currlayer->startexpo; startmag = currlayer->startmag; startgen = currlayer->startgen; startsel = currlayer->startsel; if (cloning) { // if clone is created after pattern has been generated // then we don't want a reset to change its name startname = currlayer->currname; } else { startname = currlayer->startname; } } 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->currfile == currlayer->tempstart) { 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 (wxFileExists(tempstart)) wxRemoveFile(tempstart); // delete 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() { // update icon texture data before calling UpdateCloneColors UpdateIconColors(); // 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]; } 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]; } 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]; // we also save/restore showicons option bool saveshowicons; }; // ----------------------------------------------------------------------------- void SetLayerColors() { if (inscript || viewptr->waitingforclick) return; if (mainptr->generating) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_SET_COLORS); mainptr->Stop(); return; } bool wastoggled = swapcolors; if (swapcolors) viewptr->ToggleCellColors(); // swapcolors is now false // 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(); // swapcolors is now true mainptr->UpdateEverything(); } golly-2.8-src/gui-wx/wxinfo.h0000644000175100017510000000227012525071110013117 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.8-src/gui-wx/makefile-win0000755000175100017510000004672212751752464013767 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 DEBUG_INFO=0 DEBUG_FLAG=0 UNICODE=1 USE_OPENGL=1 # Build Golly: # cd \golly\gui-wx # nmake -f makefile-win BUILD=release RUNTIME_LIBS=static DEBUG_INFO=0 DEBUG_FLAG=0 UNICODE=1 USE_OPENGL=1 # # 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 DEBUG_INFO=0 DEBUG_FLAG=0 UNICODE=1 USE_OPENGL=1 TARGET_CPU=X64 # Build Golly: # cd \golly\gui-wx # nmake -f makefile-win BUILD=release RUNTIME_LIBS=static DEBUG_INFO=0 DEBUG_FLAG=0 UNICODE=1 USE_OPENGL=1 TARGET_CPU=X64 # # If you only build one wxWidgets configuration (e.g. a 32-bit release) then you can edit # \wxWidgets\build\msw\config.vc and set all 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\gui-wx # nmake -f makefile-win # All system-dependent changes belong in local-win.mk !include local-win.mk ### Golly-related variables: ### APP_VERSION = 2.8 # these directory paths are relative to the location of this makefile: EXEDIR = .. DOCSDIR = ..\docs BASEDIR = ..\gollybase CMDDIR = ..\cmdline LUADIR = ..\lua # for building binary and source distributions: RELEASENAME = $(EXEDIR)\golly-$(APP_VERSION) GUIFILES = makefile-gtk makefile-mac makefile-win local-win-template.mk \ golly.rc Info.plist.in wx*.h wx*.cpp GUIDIRS = configure bitmaps icons LUAFILES = $(LUADIR)\*.h $(LUADIR)\*.c $(LUADIR)\*.hpp $(LUADIR)\Makefile $(LUADIR)\ReadMe.html BINFILES = $(EXEDIR)\Golly.exe $(EXEDIR)\bgolly.exe $(DOCSDIR)\ReadMe.html $(DOCSDIR)\License.html !if "$(TARGET_CPU)" == "X64" LIBDIRNAME = $(WX_DIR)\lib\vc_x64_$(LIBTYPE_SUFFIX)$(CFG) WX_CPU_DEF = WX_CPU_AMD64 # ensures include/wx/msw/amd64.manifest is included in golly.res BINNAME = $(RELEASENAME)-win-64bit !else LIBDIRNAME = $(WX_DIR)\lib\vc_$(LIBTYPE_SUFFIX)$(CFG) WX_CPU_DEF = WX_CPU_X86 BINNAME = $(RELEASENAME)-win-32bit !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 BASEO = $(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 wxprefs.h \ wxlua.h wxperl.h wxpython.h wxrender.h wxrule.h wxscript.h wxselect.h wxstatus.h \ wxtimeline.h wxundo.h wxutils.h wxview.h WXO = $(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)/wxlua.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 LUAO = $(LUADIR)\lapi.obj \ $(LUADIR)\lauxlib.obj \ $(LUADIR)\lbaselib.obj \ $(LUADIR)\lbitlib.obj \ $(LUADIR)\lcode.obj \ $(LUADIR)\lcorolib.obj \ $(LUADIR)\lctype.obj \ $(LUADIR)\ldblib.obj \ $(LUADIR)\ldebug.obj \ $(LUADIR)\ldo.obj \ $(LUADIR)\ldump.obj \ $(LUADIR)\lfunc.obj \ $(LUADIR)\lgc.obj \ $(LUADIR)\linit.obj \ $(LUADIR)\liolib.obj \ $(LUADIR)\llex.obj \ $(LUADIR)\lmathlib.obj \ $(LUADIR)\lmem.obj \ $(LUADIR)\loadlib.obj \ $(LUADIR)\lobject.obj \ $(LUADIR)\lopcodes.obj \ $(LUADIR)\loslib.obj \ $(LUADIR)\lparser.obj \ $(LUADIR)\lstate.obj \ $(LUADIR)\lstring.obj \ $(LUADIR)\lstrlib.obj \ $(LUADIR)\ltable.obj \ $(LUADIR)\ltablib.obj \ $(LUADIR)\ltm.obj \ $(LUADIR)\lundump.obj \ $(LUADIR)\lutf8lib.obj \ $(LUADIR)\lvm.obj \ $(LUADIR)\lzio.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 $(BASEO): $(BASEH) $(WXO): $(BASEH) $(WXH) icons\*.ico bitmaps\*.xpm $(LUAO): cd "$(LUADIR)" cl /MT /O2 /c /nologo $(LUA_DEFS) *.c cd "$(MAKEDIR)" $(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 -if exist $(LUADIR)\*.obj del $(LUADIR)\*.obj $(EXEDIR)\Golly.exe: $(BASEO) $(WXO) $(LUAO) golly.res link /LARGEADDRESSAWARE /NOLOGO /OUT:$(EXEDIR)\Golly.exe $(LDFLAGS) $(__DEBUGINFO_1) /pdb:"golly.pdb" \ /MANIFEST:NO /LIBPATH:$(LIBDIRNAME) /SUBSYSTEM:WINDOWS $(BASEO) $(WXO) $(LUAO) 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 \ wx$(PORTNAME)$(WXUNIVNAME)$(WX_RELEASE)$(WXUNICODEFLAG)$(WXDEBUGFLAG)$(WX_LIB_FLAVOUR)_gl.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 opengl32.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: $(BASEO) $(OBJDIR)/bgolly.obj link /LARGEADDRESSAWARE /NOLOGO /OUT:$(EXEDIR)\bgolly.exe $(LDFLAGS) /LIBPATH:$(LIBDIRNAME) \ $(OBJDIR)/bgolly.obj $(BASEO) wxzlib$(WXDEBUGFLAG).lib $(EXEDIR)\RuleTableToTree.exe: $(BASEO) $(OBJDIR)/RuleTableToTree.obj link /LARGEADDRESSAWARE /NOLOGO /OUT:$(EXEDIR)\RuleTableToTree.exe $(LDFLAGS) /LIBPATH:$(LIBDIRNAME) \ $(OBJDIR)/RuleTableToTree.obj $(BASEO) 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)/wxlua.obj: wxlua.cpp $(CXX) /c /nologo /Fo$@ $(CXXFLAGS) $(LUA_DEFS) /I$(LUADIR) wxlua.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\lua 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 ($(LUAFILES)) do xcopy %F $(RELEASENAME)-src\lua 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 $(BINNAME) mkdir $(BINNAME) mkdir $(BINNAME)\Help mkdir $(BINNAME)\Patterns mkdir $(BINNAME)\Rules mkdir $(BINNAME)\Scripts xcopy /S /I $(EXEDIR)\Help $(BINNAME)\Help xcopy /S /I $(EXEDIR)\Patterns $(BINNAME)\Patterns xcopy /S /I $(EXEDIR)\Rules $(BINNAME)\Rules xcopy /S /I $(EXEDIR)\Scripts $(BINNAME)\Scripts for %%F IN ($(BINFILES)) do xcopy %F $(BINNAME) echo Now zip $(BINNAME) into $(BINNAME).zip golly-2.8-src/gui-wx/wxrender.h0000755000175100017510000000637312660172450013467 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 DestroyDrawingData(); // Call this when the main window is destroyed. void DrawView(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. // This routine does not use OpenGL -- it's for drawing icons outside the // viewport (eg. in the edit bar). class Layer; void InitPaste(Layer* pastelayer, wxRect& bbox); // Initialize some globals used to draw the pattern stored in pastelayer. // 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 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.8-src/gui-wx/wxundo.h0000644000175100017510000001437412660172450013152 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 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.8-src/gui-wx/makefile-gtk0000644000175100017510000002524612751752464013752 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 --with-opengl # (depending on your g++ version you might also need --disable-precomp-headers) # make # sudo make install # sudo ldconfig APP_VERSION = 2.8 # these directory paths are relative to the location of this makefile: EXEDIR = .. DOCSDIR = ../docs BASEDIR = ../gollybase CMDDIR = ../cmdline LUADIR = ../lua OTHERGUIS = ../gui-android ../gui-common ../gui-ios ../gui-web # 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) $(OTHERGUIS) GUIFILES = makefile-gtk makefile-mac makefile-win local-win-template.mk \ golly.rc Info.plist.in wx*.h wx*.cpp configure bitmaps icons LUAFILES = $(LUADIR)/*.h $(LUADIR)/*.c $(LUADIR)/*.hpp $(LUADIR)/Makefile $(LUADIR)/ReadMe.html LUALIB = $(LUADIR)/liblua.a 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) # uncomment the next line to allow Golly to run Perl scripts: # ENABLE_PERL = 1 ifdef ENABLE_PERL CXXFLAGS += -DENABLE_PERL 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)" endif # 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 # libs for OpenGL EXTRALIBS_OPENGL = -lwx_gtk2u_gl-3.0 -lGL -lGLU # 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 wxprefs.h \ wxlua.h wxperl.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)/wxlua.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 -(cd $(LUADIR) && $(MAKE) clean) golly: $(OBJDIR) $(BASEOBJ) $(WXOBJ) $(LUALIB) $(CXXC) $(CXXFLAGS) -o $(EXEDIR)/golly $(BASEOBJ) $(WXOBJ) $(LUALIB) \ $(LDFLAGS) $(ZLIB_LDFLAGS) $(EXTRALIBS_OPENGL) $(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) $(LUALIB): (cd $(LUADIR) && $(MAKE) all) $(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)/wxlua.o: wxlua.cpp $(CXXC) $(CXXFLAGS) $(WX_CXXFLAGS) -I$(LUADIR) -c -o $@ wxlua.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 mkdir $(RELEASENAME)-src/lua cp -rp $(SRCFILES) $(SHAREDFILES) $(RELEASENAME)-src cp -rp $(GUIFILES) $(RELEASENAME)-src/gui-wx cp -rp $(LUAFILES) $(RELEASENAME)-src/lua find $(RELEASENAME)-src -name '.[^.]*' -delete find $(RELEASENAME)-src -name '*.o' -delete find $(RELEASENAME)-src -name 'makefile' -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 $(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.8-src/gui-wx/wxcontrol.cpp0000644000175100017510000024212712751752464014231 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 "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 name, 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 (use currlayer->currfile as the starting pattern) if (currlayer->currfile.IsEmpty()) Warning(_("Bug in SaveStartingPattern: currfile is empty!")); return true; } currlayer->currfile = currlayer->tempstart; // ResetPattern will load tempstart // 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, 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; } } return true; } // ----------------------------------------------------------------------------- void MainFrame::ResetPattern(bool resetundo) { if (currlayer->algo->getGeneration() == currlayer->startgen) return; if (generating) { command_pending = true; cmdevent.SetId(ID_RESET); Stop(); 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->currfile.IsEmpty()) { // if this happens then savestart or currfile 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 LoadPattern(currlayer->currfile, 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); Warning(_("Failed to reset pattern from this file:\n") + currlayer->currfile); } // 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) { // best to clear the pattern and set the expected gen count CreateUniverse(); currlayer->algo->setGeneration(gen); Warning(_("Could not restore pattern from this file:\n") + filename); } // 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) { command_pending = true; cmdevent.SetId(ID_SETGEN); Stop(); 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::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::StartGenTimer() { int interval = SIXTY_HERTZ; // do ~60 calls of OnGenTimer per sec // increase interval if user wants a delay if (currlayer->currexpo < 0) { interval = statusptr->GetCurrentDelay(); if (interval < SIXTY_HERTZ) interval += SIXTY_HERTZ; } if (gentimer->IsRunning()) gentimer->Stop(); gentimer->Start(interval, wxTIMER_CONTINUOUS); } // ----------------------------------------------------------------------------- void MainFrame::GoFaster() { if (TimelineExists()) { PlayTimelineFaster(); } else { currlayer->currexpo++; SetGenIncrement(); // only need to refresh status bar UpdateStatus(); if (generating && currlayer->currexpo <= 0) { // decrease gentimer interval StartGenTimer(); } } } // ----------------------------------------------------------------------------- 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) { // increase gentimer interval StartGenTimer(); } } else { Beep(); } } } // ----------------------------------------------------------------------------- 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(); if (generating && currlayer->currexpo <= 0) { // update gentimer interval StartGenTimer(); } } // ----------------------------------------------------------------------------- void MainFrame::SetStepExponent(int newexpo) { currlayer->currexpo = newexpo; if (currlayer->currexpo < minexpo) currlayer->currexpo = minexpo; SetGenIncrement(); if (generating && currlayer->currexpo <= 0) { // update gentimer interval StartGenTimer(); } } // ----------------------------------------------------------------------------- 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); } else { // update main viewport window, possibly including all tile windows // (tile windows are children of bigview) if (numlayers > 1 && (stacklayers || tilelayers)) { bigview->Refresh(false); } else { viewptr->Refresh(false); } } if (showstatus) { statusptr->CheckMouseLocation(infront); statusptr->Refresh(false); } } // ----------------------------------------------------------------------------- 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 (!curralgo->CreateBorderCells()) { SetGenIncrement(); // restore correct increment return false; } curralgo->step(); if (!curralgo->DeleteBorderCells()) { SetGenIncrement(); // restore correct increment return false; } if (curralgo->isrecording()) curralgo->extendtimeline(); 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 (curralgo->isrecording()) curralgo->extendtimeline(); } 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::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 StartGenerating 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 StartGenerating 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::StartGenerating() { if (viewptr->drawingcells || viewptr->waitingforclick) { 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; } // no need to test inscript or currlayer->stayclean if (allowundo && !currlayer->algo->isrecording()) currlayer->undoredo->RememberGenStart(); // for DisplayTimingInfo begintime = stopwatch->Time(); begingen = currlayer->algo->getGeneration().todouble(); // for hyperspeed hypdown = 64; generating = true; wxGetApp().PollerReset(); UpdateUserInterface(); // only show hashing info while generating lifealgo::setVerbose(currlayer->showhashinfo); StartGenTimer(); } // ----------------------------------------------------------------------------- void MainFrame::FinishUp() { // 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(); } // note that we must call RememberGenFinish BEFORE processing any pending command if (allowundo && !currlayer->algo->isrecording()) 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 } // ----------------------------------------------------------------------------- void MainFrame::StopGenerating() { if (gentimer->IsRunning()) gentimer->Stop(); generating = false; wxGetApp().PollerInterrupt(); lifealgo::setVerbose(0); // for DisplayTimingInfo endtime = stopwatch->Time(); endgen = currlayer->algo->getGeneration().todouble(); if (insideYield) { // we're currently in the event poller somewhere inside step(), so we must let // step() complete and only call FinishUp after StepPattern has finished } else { FinishUp(); } } // ----------------------------------------------------------------------------- void MainFrame::OnGenTimer(wxTimerEvent& WXUNUSED(event)) { // called when gentimer fires a timer event // play safe and avoid re-entrancy if timer fires while insideYield if (insideYield) return; if (!StepPattern()) { if (generating) { // call StopGenerating() to stop gentimer Stop(); } else { // StopGenerating() was called while insideYield FinishUp(); } return; } if (currlayer->algo->isrecording()) { if (showtimeline) UpdateTimelineBar(); if (currlayer->algo->getframecount() == MAX_FRAME_COUNT) { if (generating) { // call StopGenerating() to stop gentimer Stop(); } else { // StopGenerating() was called while insideYield FinishUp(); } wxString msg; msg.Printf(_("No more frames can be recorded (maximum = %d)."), MAX_FRAME_COUNT); Warning(msg); return; } } else if (currlayer->hyperspeed && currlayer->algo->hyperCapable()) { hypdown--; if (hypdown == 0) { hypdown = 64; GoFaster(); } } if (!generating) { // StopGenerating() was called while insideYield FinishUp(); } } // ----------------------------------------------------------------------------- void MainFrame::Stop() { if (inscript) { PassKeyToScript(WXK_ESCAPE); } else if (generating) { StopGenerating(); } } // ----------------------------------------------------------------------------- void MainFrame::StartOrStop() { if (inscript || generating) { Stop(); } else if (TimelineExists()) { if (currlayer->algo->isrecording()) { // should never happen if generating is false Warning(_("Bug: recording but not generating!")); } else { PlayTimeline(1); // play forwards or stop if already playing } } else { StartGenerating(); } } // ----------------------------------------------------------------------------- // 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) { 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 (!curralgo->CreateBorderCells()) break; curralgo->step(); if (!curralgo->DeleteBorderCells()) 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) curralgo->CreateBorderCells(); curralgo->step(); if (boundedgrid) curralgo->DeleteBorderCells(); 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) { command_pending = true; cmdevent.SetId(ID_SETRULE); Stop(); 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 (currlayer->algtype != oldalgo) { // ChangeAlgorithm was called so we're almost done; // we just have to call UpdateEverything 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 modified .rule file) wxString newrule = wxString(currlayer->algo->getrule(), wxConvLocal); int newmaxstate = currlayer->algo->NumCellStates() - 1; if (oldrule != newrule || oldmaxstate != newmaxstate) { // if pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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 colors or icons changed) 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) { command_pending = true; cmdevent.SetId(ID_ALGO0 + newalgotype); Stop(); 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 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 (rulechanged) { // show new rule in window title (but don't change file name) SetWindowTitle(wxEmptyString); 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) { command_pending = true; cmdevent.SetId(ID_CONVERT); Stop(); 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.8-src/gui-wx/wxprefs.cpp0000644000175100017510000056736512751752464013706 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 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 smartscale = false; // smarter scaling when zoomed out? bool swapcolors = false; // swap colors used for cell states? 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 = 50; // 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 choosedir; // directory used by Choose File button wxString filedir; // directory used by Show Files 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 showfiles = true; // show file 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 // 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; #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_SHOWFILES: return "Show Files"; case DO_FILEDIR: return "Set File 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_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_SMARTSCALE: return "Smarter Scaling"; 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_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 UpdateStatusBrushes() { for (int i = 0; i < NumAlgos(); i++) { algoinfo[i]->statusbrush->SetColour(algoinfo[i]->statusrgb); } } // ----------------------------------------------------------------------------- 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 // set default status brushes (in case prefs file doesn't exist) UpdateStatusBrushes(); } // ----------------------------------------------------------------------------- void FreeDefaultColors() { delete borderrgb; delete selectrgb; delete pastergb; } // ----------------------------------------------------------------------------- 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 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/S")); namedrules.Add(wxT("Persian Rug|B234/S")); 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 // this might be better for high-res screens???!!! // MAX_MAG = 6; // maximum cell size = 64x64 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; rundir = gollydir + SCRIPT_DIR; opensavedir = gollydir; choosedir = gollydir; filedir = gollydir; // 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, "smart_scale") == 0) { smartscale = 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, "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); } else if (strcmp(keyword, "run_dir") == 0) { GetRelPath(value, rundir, SCRIPT_DIR); } else if (strcmp(keyword, "choose_dir") == 0) { GetRelPath(value, choosedir); } else if (strcmp(keyword, "file_dir") == 0) { GetRelPath(value, filedir); } else if (strcmp(keyword, "pattern_dir") == 0) { GetRelPath(value, filedir); // deprecated } 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_files") == 0 || strcmp(keyword, "show_patterns") == 0) { // deprecated showfiles = value[0] == '1'; } else if (strcmp(keyword, "show_scripts") == 0) { // deprecated } 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 status brushes may have changed UpdateStatusBrushes(); // 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(); } // ----------------------------------------------------------------------------- static bool inonchar = false; void KeyComboCtrl::OnChar(wxKeyEvent& event) { // avoid infinite recursion due to ChangeValue call below if (inonchar) { event.Skip(); return; } inonchar = true; 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(); inonchar = false; } // ----------------------------------------------------------------------------- #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"); #ifdef ENABLE_PERL filetypes += _("|Script (*.lua;*.pl;*.py)|*.lua;*.pl;*.py"); #else filetypes += _("|Script (*.lua;*.py)|*.lua;*.py"); #endif filetypes += _("|Rule (*.rule)|*.rule"); filetypes += _("|HTML (*.html;*.htm)|*.html;*.htm"); wxFileDialog opendlg(this, _("Choose a pattern/script/rule/HTML file"), choosedir, wxEmptyString, filetypes, wxFD_OPEN | wxFD_FILE_MUST_EXIST); 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; } UpdateStatusBrushes(); 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.8-src/gui-wx/wxalgos.cpp0000644000175100017510000010330712660172450013640 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() { // QuickLife must be 1st and HashLife must be 2nd qlifealgo::doInitializeAlgoInfo(AlgoData::tick()); hlifealgo::doInitializeAlgoInfo(AlgoData::tick()); // these algos can be in any order (but nicer if alphabetic) generationsalgo::doInitializeAlgoInfo(AlgoData::tick()); jvnalgo::doInitializeAlgoInfo(AlgoData::tick()); // RuleLoader must be last so we can display detailed error messages // (see LoadRule in wxhelp.cpp) 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.8-src/gui-wx/configure/0000755000175100017510000000000012751756121013511 500000000000000golly-2.8-src/gui-wx/configure/m4/0000755000175100017510000000000012751756120014030 500000000000000golly-2.8-src/gui-wx/configure/m4/shlib.m40000644000175100017510000000147312525071110015304 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.8-src/gui-wx/configure/m4/wxwin.m40000644000175100017510000011730712525071110015363 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.8-src/gui-wx/configure/m4/wximage.m40000644000175100017510000000133212525071110015636 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.8-src/gui-wx/configure/config.guess0000755000175100017510000012743212660172502015754 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.8-src/gui-wx/configure/aclocal.m40000644000175100017510000011016312751752551015276 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.8-src/gui-wx/configure/config.sub0000755000175100017510000010532712660172502015416 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.8-src/gui-wx/configure/configure.ac0000644000175100017510000001015312751752464015725 00000000000000AC_PREREQ(2.61) AC_INIT([golly], [2.8]) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([-Wall 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_ENABLE([perl], [AS_HELP_STRING([--enable_perl], [support Perl scripts (deprecated)])], , [enable_perl=no]) 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])], [std,gl], [$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 (if enabled) AS_IF([test "x$enable_perl" = xyes], [ AC_PATH_PROGS([PERL], [perl5 perl]) AS_IF([test "x$PERL" = x], [AC_MSG_ERROR([missing Perl])]) AC_SUBST([PERL_CPPFLAGS], [-DENABLE_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.8-src/gui-wx/configure/install-sh0000755000175100017510000003325612660172502015440 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.8-src/gui-wx/configure/missing0000755000175100017510000002415212660172502015026 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.8-src/gui-wx/configure/configure0000755000175100017510000072606112751752552015360 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for golly 2.8. # # # 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.8' PACKAGE_STRING='golly 2.8' 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 PERL_CPPFLAGS 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 enable_perl 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.8 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.8:";; 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] --enable_perl support Perl scripts (deprecated) --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.8 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.8, 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.8' # 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 --enable-perl was given. if test "${enable_perl+set}" = set; then : enableval=$enable_perl; else enable_perl=no 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 std,gl` { $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 std,gl 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 std,gl` 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 std,gl` WX_CXXFLAGS=`$WX_CONFIG_WITH_ARGS --cxxflags std,gl` WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags std,gl` 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 (if enabled) if test "x$enable_perl" = xyes; then : 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_CPPFLAGS=-DENABLE_PERL 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 fi # 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.8, 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.8 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.8-src/gui-wx/configure/autogen.sh0000755000175100017510000000124112751752464015436 00000000000000#!/bin/bash -e rm -f sources.am echo nodist_liblua_a_SOURCES = ../../lua/*.{h,hpp,c} >>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 = \ ../../lua \ ../../gui-wx/{makefile-{gtk,mac,win},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.8-src/gui-wx/configure/Makefile.in0000644000175100017510000064226212751752552015516 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) liblua_a_AR = $(AR) $(ARFLAGS) liblua_a_LIBADD = nodist_liblua_a_OBJECTS = liblua_a-lapi.$(OBJEXT) \ liblua_a-lauxlib.$(OBJEXT) liblua_a-lbaselib.$(OBJEXT) \ liblua_a-lbitlib.$(OBJEXT) liblua_a-lcode.$(OBJEXT) \ liblua_a-lcorolib.$(OBJEXT) liblua_a-lctype.$(OBJEXT) \ liblua_a-ldblib.$(OBJEXT) liblua_a-ldebug.$(OBJEXT) \ liblua_a-ldo.$(OBJEXT) liblua_a-ldump.$(OBJEXT) \ liblua_a-lfunc.$(OBJEXT) liblua_a-lgc.$(OBJEXT) \ liblua_a-linit.$(OBJEXT) liblua_a-liolib.$(OBJEXT) \ liblua_a-llex.$(OBJEXT) liblua_a-lmathlib.$(OBJEXT) \ liblua_a-lmem.$(OBJEXT) liblua_a-loadlib.$(OBJEXT) \ liblua_a-lobject.$(OBJEXT) liblua_a-lopcodes.$(OBJEXT) \ liblua_a-loslib.$(OBJEXT) liblua_a-lparser.$(OBJEXT) \ liblua_a-lstate.$(OBJEXT) liblua_a-lstring.$(OBJEXT) \ liblua_a-lstrlib.$(OBJEXT) liblua_a-ltable.$(OBJEXT) \ liblua_a-ltablib.$(OBJEXT) liblua_a-ltm.$(OBJEXT) \ liblua_a-lundump.$(OBJEXT) liblua_a-lutf8lib.$(OBJEXT) \ liblua_a-lvm.$(OBJEXT) liblua_a-lzio.$(OBJEXT) liblua_a_OBJECTS = $(nodist_liblua_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-wxlua.$(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 liblua.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 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ SOURCES = $(libgolly_a_SOURCES) $(nodist_liblua_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_CPPFLAGS = @PERL_CPPFLAGS@ 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 @LINUX_TRUE@liblua_a_CPPFLAGS = -DLUA_USE_LINUX @MAC_TRUE@liblua_a_CPPFLAGS = -DLUA_USE_MACOSX noinst_LIBRARIES = libgolly.a liblua.a doc_DATA = ../../docs/License.html ../../docs/ReadMe.html nodist_liblua_a_SOURCES = ../../lua/lapi.h ../../lua/lauxlib.h \ ../../lua/lcode.h ../../lua/lctype.h ../../lua/ldebug.h \ ../../lua/ldo.h ../../lua/lfunc.h ../../lua/lgc.h \ ../../lua/llex.h ../../lua/llimits.h ../../lua/lmem.h \ ../../lua/lobject.h ../../lua/lopcodes.h ../../lua/lparser.h \ ../../lua/lprefix.h ../../lua/lstate.h ../../lua/lstring.h \ ../../lua/ltable.h ../../lua/ltm.h ../../lua/luaconf.h \ ../../lua/lua.h ../../lua/lualib.h ../../lua/lundump.h \ ../../lua/lvm.h ../../lua/lzio.h ../../lua/lua.hpp \ ../../lua/lapi.c ../../lua/lauxlib.c ../../lua/lbaselib.c \ ../../lua/lbitlib.c ../../lua/lcode.c ../../lua/lcorolib.c \ ../../lua/lctype.c ../../lua/ldblib.c ../../lua/ldebug.c \ ../../lua/ldo.c ../../lua/ldump.c ../../lua/lfunc.c \ ../../lua/lgc.c ../../lua/linit.c ../../lua/liolib.c \ ../../lua/llex.c ../../lua/lmathlib.c ../../lua/lmem.c \ ../../lua/loadlib.c ../../lua/lobject.c ../../lua/lopcodes.c \ ../../lua/loslib.c ../../lua/lparser.c ../../lua/lstate.c \ ../../lua/lstring.c ../../lua/lstrlib.c ../../lua/ltable.c \ ../../lua/ltablib.c ../../lua/ltm.c ../../lua/lundump.c \ ../../lua/lutf8lib.c ../../lua/lvm.c ../../lua/lzio.c 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/wxlua.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/wxlua.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/hensel.png \ ../../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/lua.html ../../Help/mouse.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.lua \ ../../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.lua \ ../../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/chase-the-glider.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/Non-Totalistic/horiship-guns.rle \ ../../Patterns/Non-Totalistic/JustFriends/oscillators.rle \ ../../Patterns/Non-Totalistic/JustFriends/p137loop.rle \ ../../Patterns/Non-Totalistic/JustFriends/p384drifter.rle \ ../../Patterns/Non-Totalistic/JustFriends/p8256c4dirtyrake.rle \ ../../Patterns/Non-Totalistic/JustFriends/spaceships.rle \ ../../Patterns/Non-Totalistic/p42-knightship.rle \ ../../Patterns/Non-Totalistic/Sierpinski-builder.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/Lua/bricklayer.lua ../../Scripts/Lua/density.lua \ ../../Scripts/Lua/draw-lines.lua \ ../../Scripts/Lua/envelope.lua \ ../../Scripts/Lua/flood-fill.lua ../../Scripts/Lua/giffer.lua \ ../../Scripts/Lua/goto.lua ../../Scripts/Lua/gplus/guns.lua \ ../../Scripts/Lua/gplus/init.lua \ ../../Scripts/Lua/gplus/objects.lua \ ../../Scripts/Lua/gplus/strict.lua \ ../../Scripts/Lua/gplus/text.lua \ ../../Scripts/Lua/gun-demo.lua \ ../../Scripts/Lua/heisenburp.lua ../../Scripts/Lua/invert.lua \ ../../Scripts/Lua/life-integer-gun30.lua \ ../../Scripts/Lua/make-torus.lua \ ../../Scripts/Lua/metafier.lua \ ../../Scripts/Lua/move-object.lua \ ../../Scripts/Lua/move-selection.lua \ ../../Scripts/Lua/oscar.lua \ ../../Scripts/Lua/p1100-MWSS-gun.lua \ ../../Scripts/Lua/pd-glider.lua ../../Scripts/Lua/pop-plot.lua \ ../../Scripts/Lua/shift.lua ../../Scripts/Lua/slide-show.lua \ ../../Scripts/Lua/tile.lua \ ../../Scripts/Lua/tile-with-clip.lua \ ../../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 = ../../lua ../../gui-wx/makefile-gtk \ ../../gui-wx/makefile-mac ../../gui-wx/makefile-win \ ../../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/app/build.gradle \ ../../gui-android/Golly/app/src/main/AndroidManifest.xml \ ../../gui-android/Golly/app/src/main/assets/readme.txt \ ../../gui-android/Golly/app/src/main/assets/triangle-down.png \ ../../gui-android/Golly/app/src/main/assets/triangle-right.png \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/BaseActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/BaseApp.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/EditActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/HelpActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/InfoActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/MainActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/OpenActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/PatternGLSurfaceView.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/RuleActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/SettingsActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/StateActivity.java \ ../../gui-android/Golly/app/src/main/java/net/sf/golly/StateGLSurfaceView.java \ ../../gui-android/Golly/app/src/main/jni/jnicalls.cpp \ ../../gui-android/Golly/app/src/main/jni/jnicalls.h \ ../../gui-android/Golly/app/src/main/res/drawable-hdpi/ic_launcher.png \ ../../gui-android/Golly/app/src/main/res/drawable-mdpi/ic_launcher.png \ ../../gui-android/Golly/app/src/main/res/drawable-xhdpi/ic_launcher.png \ ../../gui-android/Golly/app/src/main/res/drawable-xxhdpi/ic_launcher.png \ ../../gui-android/Golly/app/src/main/res/layout/edit_layout.xml \ ../../gui-android/Golly/app/src/main/res/layout/help_layout.xml \ ../../gui-android/Golly/app/src/main/res/layout/info_layout.xml \ ../../gui-android/Golly/app/src/main/res/layout/main_layout_wide.xml \ ../../gui-android/Golly/app/src/main/res/layout/main_layout.xml \ ../../gui-android/Golly/app/src/main/res/layout/open_layout.xml \ ../../gui-android/Golly/app/src/main/res/layout/rule_layout.xml \ ../../gui-android/Golly/app/src/main/res/layout/settings_layout.xml \ ../../gui-android/Golly/app/src/main/res/layout/state_layout.xml \ ../../gui-android/Golly/app/src/main/res/menu/control_menu.xml \ ../../gui-android/Golly/app/src/main/res/menu/edit_menu.xml \ ../../gui-android/Golly/app/src/main/res/menu/main.xml \ ../../gui-android/Golly/app/src/main/res/menu/mode_menu.xml \ ../../gui-android/Golly/app/src/main/res/menu/paste_menu.xml \ ../../gui-android/Golly/app/src/main/res/menu/pastemode_menu.xml \ ../../gui-android/Golly/app/src/main/res/menu/selection_menu.xml \ ../../gui-android/Golly/app/src/main/res/menu/view_menu.xml \ ../../gui-android/Golly/app/src/main/res/values/dimens.xml \ ../../gui-android/Golly/app/src/main/res/values/strings.xml \ ../../gui-android/Golly/app/src/main/res/values/styles.xml \ ../../gui-android/Golly/app/src/main/res/values-sw600dp/dimens.xml \ ../../gui-android/Golly/app/src/main/res/values-sw720dp-land/dimens.xml \ ../../gui-android/Golly/app/src/main/res/values-v11/styles.xml \ ../../gui-android/Golly/app/src/main/res/values-v14/styles.xml \ ../../gui-android/Golly/build.gradle \ ../../gui-android/Golly/.gitignore \ ../../gui-android/Golly/gradlew \ ../../gui-android/Golly/gradlew.bat \ ../../gui-android/Golly/gradle/wrapper/gradle-wrapper.jar \ ../../gui-android/Golly/gradle/wrapper/gradle-wrapper.properties \ ../../gui-android/Golly/settings.gradle \ ../../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) $(PYTHON_INCLUDE) \ $(PERL_CPPFLAGS) $(PERL_INCLUDE) \ $(liblua_a_CPPFLAGS) -I$(top_srcdir)/../../lua golly_CXXFLAGS = $(AM_CXXFLAGS) $(WX_CXXFLAGS_ONLY) golly_LDADD = $(WX_LIBS) libgolly.a liblua.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: .c .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 liblua.a: $(liblua_a_OBJECTS) $(liblua_a_DEPENDENCIES) $(EXTRA_liblua_a_DEPENDENCIES) -rm -f liblua.a $(liblua_a_AR) liblua.a $(liblua_a_OBJECTS) $(liblua_a_LIBADD) $(RANLIB) liblua.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-wxlua.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)/liblua_a-lapi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lauxlib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lbaselib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lbitlib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lcode.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lcorolib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lctype.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-ldblib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-ldebug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-ldo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-ldump.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lfunc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lgc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-linit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-liolib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-llex.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lmathlib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lmem.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-loadlib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lobject.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lopcodes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-loslib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lparser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lstate.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lstring.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lstrlib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-ltable.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-ltablib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-ltm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lundump.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lutf8lib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lvm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblua_a-lzio.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@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` liblua_a-lapi.o: ../../lua/lapi.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lapi.o -MD -MP -MF $(DEPDIR)/liblua_a-lapi.Tpo -c -o liblua_a-lapi.o `test -f '../../lua/lapi.c' || echo '$(srcdir)/'`../../lua/lapi.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lapi.Tpo $(DEPDIR)/liblua_a-lapi.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lapi.c' object='liblua_a-lapi.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lapi.o `test -f '../../lua/lapi.c' || echo '$(srcdir)/'`../../lua/lapi.c liblua_a-lapi.obj: ../../lua/lapi.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lapi.obj -MD -MP -MF $(DEPDIR)/liblua_a-lapi.Tpo -c -o liblua_a-lapi.obj `if test -f '../../lua/lapi.c'; then $(CYGPATH_W) '../../lua/lapi.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lapi.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lapi.Tpo $(DEPDIR)/liblua_a-lapi.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lapi.c' object='liblua_a-lapi.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lapi.obj `if test -f '../../lua/lapi.c'; then $(CYGPATH_W) '../../lua/lapi.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lapi.c'; fi` liblua_a-lauxlib.o: ../../lua/lauxlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lauxlib.o -MD -MP -MF $(DEPDIR)/liblua_a-lauxlib.Tpo -c -o liblua_a-lauxlib.o `test -f '../../lua/lauxlib.c' || echo '$(srcdir)/'`../../lua/lauxlib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lauxlib.Tpo $(DEPDIR)/liblua_a-lauxlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lauxlib.c' object='liblua_a-lauxlib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lauxlib.o `test -f '../../lua/lauxlib.c' || echo '$(srcdir)/'`../../lua/lauxlib.c liblua_a-lauxlib.obj: ../../lua/lauxlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lauxlib.obj -MD -MP -MF $(DEPDIR)/liblua_a-lauxlib.Tpo -c -o liblua_a-lauxlib.obj `if test -f '../../lua/lauxlib.c'; then $(CYGPATH_W) '../../lua/lauxlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lauxlib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lauxlib.Tpo $(DEPDIR)/liblua_a-lauxlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lauxlib.c' object='liblua_a-lauxlib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lauxlib.obj `if test -f '../../lua/lauxlib.c'; then $(CYGPATH_W) '../../lua/lauxlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lauxlib.c'; fi` liblua_a-lbaselib.o: ../../lua/lbaselib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lbaselib.o -MD -MP -MF $(DEPDIR)/liblua_a-lbaselib.Tpo -c -o liblua_a-lbaselib.o `test -f '../../lua/lbaselib.c' || echo '$(srcdir)/'`../../lua/lbaselib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lbaselib.Tpo $(DEPDIR)/liblua_a-lbaselib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lbaselib.c' object='liblua_a-lbaselib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lbaselib.o `test -f '../../lua/lbaselib.c' || echo '$(srcdir)/'`../../lua/lbaselib.c liblua_a-lbaselib.obj: ../../lua/lbaselib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lbaselib.obj -MD -MP -MF $(DEPDIR)/liblua_a-lbaselib.Tpo -c -o liblua_a-lbaselib.obj `if test -f '../../lua/lbaselib.c'; then $(CYGPATH_W) '../../lua/lbaselib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lbaselib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lbaselib.Tpo $(DEPDIR)/liblua_a-lbaselib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lbaselib.c' object='liblua_a-lbaselib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lbaselib.obj `if test -f '../../lua/lbaselib.c'; then $(CYGPATH_W) '../../lua/lbaselib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lbaselib.c'; fi` liblua_a-lbitlib.o: ../../lua/lbitlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lbitlib.o -MD -MP -MF $(DEPDIR)/liblua_a-lbitlib.Tpo -c -o liblua_a-lbitlib.o `test -f '../../lua/lbitlib.c' || echo '$(srcdir)/'`../../lua/lbitlib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lbitlib.Tpo $(DEPDIR)/liblua_a-lbitlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lbitlib.c' object='liblua_a-lbitlib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lbitlib.o `test -f '../../lua/lbitlib.c' || echo '$(srcdir)/'`../../lua/lbitlib.c liblua_a-lbitlib.obj: ../../lua/lbitlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lbitlib.obj -MD -MP -MF $(DEPDIR)/liblua_a-lbitlib.Tpo -c -o liblua_a-lbitlib.obj `if test -f '../../lua/lbitlib.c'; then $(CYGPATH_W) '../../lua/lbitlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lbitlib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lbitlib.Tpo $(DEPDIR)/liblua_a-lbitlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lbitlib.c' object='liblua_a-lbitlib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lbitlib.obj `if test -f '../../lua/lbitlib.c'; then $(CYGPATH_W) '../../lua/lbitlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lbitlib.c'; fi` liblua_a-lcode.o: ../../lua/lcode.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lcode.o -MD -MP -MF $(DEPDIR)/liblua_a-lcode.Tpo -c -o liblua_a-lcode.o `test -f '../../lua/lcode.c' || echo '$(srcdir)/'`../../lua/lcode.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lcode.Tpo $(DEPDIR)/liblua_a-lcode.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lcode.c' object='liblua_a-lcode.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lcode.o `test -f '../../lua/lcode.c' || echo '$(srcdir)/'`../../lua/lcode.c liblua_a-lcode.obj: ../../lua/lcode.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lcode.obj -MD -MP -MF $(DEPDIR)/liblua_a-lcode.Tpo -c -o liblua_a-lcode.obj `if test -f '../../lua/lcode.c'; then $(CYGPATH_W) '../../lua/lcode.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lcode.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lcode.Tpo $(DEPDIR)/liblua_a-lcode.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lcode.c' object='liblua_a-lcode.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lcode.obj `if test -f '../../lua/lcode.c'; then $(CYGPATH_W) '../../lua/lcode.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lcode.c'; fi` liblua_a-lcorolib.o: ../../lua/lcorolib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lcorolib.o -MD -MP -MF $(DEPDIR)/liblua_a-lcorolib.Tpo -c -o liblua_a-lcorolib.o `test -f '../../lua/lcorolib.c' || echo '$(srcdir)/'`../../lua/lcorolib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lcorolib.Tpo $(DEPDIR)/liblua_a-lcorolib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lcorolib.c' object='liblua_a-lcorolib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lcorolib.o `test -f '../../lua/lcorolib.c' || echo '$(srcdir)/'`../../lua/lcorolib.c liblua_a-lcorolib.obj: ../../lua/lcorolib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lcorolib.obj -MD -MP -MF $(DEPDIR)/liblua_a-lcorolib.Tpo -c -o liblua_a-lcorolib.obj `if test -f '../../lua/lcorolib.c'; then $(CYGPATH_W) '../../lua/lcorolib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lcorolib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lcorolib.Tpo $(DEPDIR)/liblua_a-lcorolib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lcorolib.c' object='liblua_a-lcorolib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lcorolib.obj `if test -f '../../lua/lcorolib.c'; then $(CYGPATH_W) '../../lua/lcorolib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lcorolib.c'; fi` liblua_a-lctype.o: ../../lua/lctype.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lctype.o -MD -MP -MF $(DEPDIR)/liblua_a-lctype.Tpo -c -o liblua_a-lctype.o `test -f '../../lua/lctype.c' || echo '$(srcdir)/'`../../lua/lctype.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lctype.Tpo $(DEPDIR)/liblua_a-lctype.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lctype.c' object='liblua_a-lctype.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lctype.o `test -f '../../lua/lctype.c' || echo '$(srcdir)/'`../../lua/lctype.c liblua_a-lctype.obj: ../../lua/lctype.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lctype.obj -MD -MP -MF $(DEPDIR)/liblua_a-lctype.Tpo -c -o liblua_a-lctype.obj `if test -f '../../lua/lctype.c'; then $(CYGPATH_W) '../../lua/lctype.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lctype.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lctype.Tpo $(DEPDIR)/liblua_a-lctype.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lctype.c' object='liblua_a-lctype.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lctype.obj `if test -f '../../lua/lctype.c'; then $(CYGPATH_W) '../../lua/lctype.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lctype.c'; fi` liblua_a-ldblib.o: ../../lua/ldblib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ldblib.o -MD -MP -MF $(DEPDIR)/liblua_a-ldblib.Tpo -c -o liblua_a-ldblib.o `test -f '../../lua/ldblib.c' || echo '$(srcdir)/'`../../lua/ldblib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ldblib.Tpo $(DEPDIR)/liblua_a-ldblib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ldblib.c' object='liblua_a-ldblib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ldblib.o `test -f '../../lua/ldblib.c' || echo '$(srcdir)/'`../../lua/ldblib.c liblua_a-ldblib.obj: ../../lua/ldblib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ldblib.obj -MD -MP -MF $(DEPDIR)/liblua_a-ldblib.Tpo -c -o liblua_a-ldblib.obj `if test -f '../../lua/ldblib.c'; then $(CYGPATH_W) '../../lua/ldblib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ldblib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ldblib.Tpo $(DEPDIR)/liblua_a-ldblib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ldblib.c' object='liblua_a-ldblib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ldblib.obj `if test -f '../../lua/ldblib.c'; then $(CYGPATH_W) '../../lua/ldblib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ldblib.c'; fi` liblua_a-ldebug.o: ../../lua/ldebug.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ldebug.o -MD -MP -MF $(DEPDIR)/liblua_a-ldebug.Tpo -c -o liblua_a-ldebug.o `test -f '../../lua/ldebug.c' || echo '$(srcdir)/'`../../lua/ldebug.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ldebug.Tpo $(DEPDIR)/liblua_a-ldebug.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ldebug.c' object='liblua_a-ldebug.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ldebug.o `test -f '../../lua/ldebug.c' || echo '$(srcdir)/'`../../lua/ldebug.c liblua_a-ldebug.obj: ../../lua/ldebug.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ldebug.obj -MD -MP -MF $(DEPDIR)/liblua_a-ldebug.Tpo -c -o liblua_a-ldebug.obj `if test -f '../../lua/ldebug.c'; then $(CYGPATH_W) '../../lua/ldebug.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ldebug.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ldebug.Tpo $(DEPDIR)/liblua_a-ldebug.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ldebug.c' object='liblua_a-ldebug.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ldebug.obj `if test -f '../../lua/ldebug.c'; then $(CYGPATH_W) '../../lua/ldebug.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ldebug.c'; fi` liblua_a-ldo.o: ../../lua/ldo.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ldo.o -MD -MP -MF $(DEPDIR)/liblua_a-ldo.Tpo -c -o liblua_a-ldo.o `test -f '../../lua/ldo.c' || echo '$(srcdir)/'`../../lua/ldo.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ldo.Tpo $(DEPDIR)/liblua_a-ldo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ldo.c' object='liblua_a-ldo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ldo.o `test -f '../../lua/ldo.c' || echo '$(srcdir)/'`../../lua/ldo.c liblua_a-ldo.obj: ../../lua/ldo.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ldo.obj -MD -MP -MF $(DEPDIR)/liblua_a-ldo.Tpo -c -o liblua_a-ldo.obj `if test -f '../../lua/ldo.c'; then $(CYGPATH_W) '../../lua/ldo.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ldo.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ldo.Tpo $(DEPDIR)/liblua_a-ldo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ldo.c' object='liblua_a-ldo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ldo.obj `if test -f '../../lua/ldo.c'; then $(CYGPATH_W) '../../lua/ldo.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ldo.c'; fi` liblua_a-ldump.o: ../../lua/ldump.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ldump.o -MD -MP -MF $(DEPDIR)/liblua_a-ldump.Tpo -c -o liblua_a-ldump.o `test -f '../../lua/ldump.c' || echo '$(srcdir)/'`../../lua/ldump.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ldump.Tpo $(DEPDIR)/liblua_a-ldump.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ldump.c' object='liblua_a-ldump.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ldump.o `test -f '../../lua/ldump.c' || echo '$(srcdir)/'`../../lua/ldump.c liblua_a-ldump.obj: ../../lua/ldump.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ldump.obj -MD -MP -MF $(DEPDIR)/liblua_a-ldump.Tpo -c -o liblua_a-ldump.obj `if test -f '../../lua/ldump.c'; then $(CYGPATH_W) '../../lua/ldump.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ldump.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ldump.Tpo $(DEPDIR)/liblua_a-ldump.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ldump.c' object='liblua_a-ldump.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ldump.obj `if test -f '../../lua/ldump.c'; then $(CYGPATH_W) '../../lua/ldump.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ldump.c'; fi` liblua_a-lfunc.o: ../../lua/lfunc.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lfunc.o -MD -MP -MF $(DEPDIR)/liblua_a-lfunc.Tpo -c -o liblua_a-lfunc.o `test -f '../../lua/lfunc.c' || echo '$(srcdir)/'`../../lua/lfunc.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lfunc.Tpo $(DEPDIR)/liblua_a-lfunc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lfunc.c' object='liblua_a-lfunc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lfunc.o `test -f '../../lua/lfunc.c' || echo '$(srcdir)/'`../../lua/lfunc.c liblua_a-lfunc.obj: ../../lua/lfunc.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lfunc.obj -MD -MP -MF $(DEPDIR)/liblua_a-lfunc.Tpo -c -o liblua_a-lfunc.obj `if test -f '../../lua/lfunc.c'; then $(CYGPATH_W) '../../lua/lfunc.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lfunc.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lfunc.Tpo $(DEPDIR)/liblua_a-lfunc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lfunc.c' object='liblua_a-lfunc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lfunc.obj `if test -f '../../lua/lfunc.c'; then $(CYGPATH_W) '../../lua/lfunc.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lfunc.c'; fi` liblua_a-lgc.o: ../../lua/lgc.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lgc.o -MD -MP -MF $(DEPDIR)/liblua_a-lgc.Tpo -c -o liblua_a-lgc.o `test -f '../../lua/lgc.c' || echo '$(srcdir)/'`../../lua/lgc.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lgc.Tpo $(DEPDIR)/liblua_a-lgc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lgc.c' object='liblua_a-lgc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lgc.o `test -f '../../lua/lgc.c' || echo '$(srcdir)/'`../../lua/lgc.c liblua_a-lgc.obj: ../../lua/lgc.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lgc.obj -MD -MP -MF $(DEPDIR)/liblua_a-lgc.Tpo -c -o liblua_a-lgc.obj `if test -f '../../lua/lgc.c'; then $(CYGPATH_W) '../../lua/lgc.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lgc.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lgc.Tpo $(DEPDIR)/liblua_a-lgc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lgc.c' object='liblua_a-lgc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lgc.obj `if test -f '../../lua/lgc.c'; then $(CYGPATH_W) '../../lua/lgc.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lgc.c'; fi` liblua_a-linit.o: ../../lua/linit.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-linit.o -MD -MP -MF $(DEPDIR)/liblua_a-linit.Tpo -c -o liblua_a-linit.o `test -f '../../lua/linit.c' || echo '$(srcdir)/'`../../lua/linit.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-linit.Tpo $(DEPDIR)/liblua_a-linit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/linit.c' object='liblua_a-linit.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-linit.o `test -f '../../lua/linit.c' || echo '$(srcdir)/'`../../lua/linit.c liblua_a-linit.obj: ../../lua/linit.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-linit.obj -MD -MP -MF $(DEPDIR)/liblua_a-linit.Tpo -c -o liblua_a-linit.obj `if test -f '../../lua/linit.c'; then $(CYGPATH_W) '../../lua/linit.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/linit.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-linit.Tpo $(DEPDIR)/liblua_a-linit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/linit.c' object='liblua_a-linit.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-linit.obj `if test -f '../../lua/linit.c'; then $(CYGPATH_W) '../../lua/linit.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/linit.c'; fi` liblua_a-liolib.o: ../../lua/liolib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-liolib.o -MD -MP -MF $(DEPDIR)/liblua_a-liolib.Tpo -c -o liblua_a-liolib.o `test -f '../../lua/liolib.c' || echo '$(srcdir)/'`../../lua/liolib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-liolib.Tpo $(DEPDIR)/liblua_a-liolib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/liolib.c' object='liblua_a-liolib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-liolib.o `test -f '../../lua/liolib.c' || echo '$(srcdir)/'`../../lua/liolib.c liblua_a-liolib.obj: ../../lua/liolib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-liolib.obj -MD -MP -MF $(DEPDIR)/liblua_a-liolib.Tpo -c -o liblua_a-liolib.obj `if test -f '../../lua/liolib.c'; then $(CYGPATH_W) '../../lua/liolib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/liolib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-liolib.Tpo $(DEPDIR)/liblua_a-liolib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/liolib.c' object='liblua_a-liolib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-liolib.obj `if test -f '../../lua/liolib.c'; then $(CYGPATH_W) '../../lua/liolib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/liolib.c'; fi` liblua_a-llex.o: ../../lua/llex.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-llex.o -MD -MP -MF $(DEPDIR)/liblua_a-llex.Tpo -c -o liblua_a-llex.o `test -f '../../lua/llex.c' || echo '$(srcdir)/'`../../lua/llex.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-llex.Tpo $(DEPDIR)/liblua_a-llex.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/llex.c' object='liblua_a-llex.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-llex.o `test -f '../../lua/llex.c' || echo '$(srcdir)/'`../../lua/llex.c liblua_a-llex.obj: ../../lua/llex.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-llex.obj -MD -MP -MF $(DEPDIR)/liblua_a-llex.Tpo -c -o liblua_a-llex.obj `if test -f '../../lua/llex.c'; then $(CYGPATH_W) '../../lua/llex.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/llex.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-llex.Tpo $(DEPDIR)/liblua_a-llex.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/llex.c' object='liblua_a-llex.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-llex.obj `if test -f '../../lua/llex.c'; then $(CYGPATH_W) '../../lua/llex.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/llex.c'; fi` liblua_a-lmathlib.o: ../../lua/lmathlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lmathlib.o -MD -MP -MF $(DEPDIR)/liblua_a-lmathlib.Tpo -c -o liblua_a-lmathlib.o `test -f '../../lua/lmathlib.c' || echo '$(srcdir)/'`../../lua/lmathlib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lmathlib.Tpo $(DEPDIR)/liblua_a-lmathlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lmathlib.c' object='liblua_a-lmathlib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lmathlib.o `test -f '../../lua/lmathlib.c' || echo '$(srcdir)/'`../../lua/lmathlib.c liblua_a-lmathlib.obj: ../../lua/lmathlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lmathlib.obj -MD -MP -MF $(DEPDIR)/liblua_a-lmathlib.Tpo -c -o liblua_a-lmathlib.obj `if test -f '../../lua/lmathlib.c'; then $(CYGPATH_W) '../../lua/lmathlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lmathlib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lmathlib.Tpo $(DEPDIR)/liblua_a-lmathlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lmathlib.c' object='liblua_a-lmathlib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lmathlib.obj `if test -f '../../lua/lmathlib.c'; then $(CYGPATH_W) '../../lua/lmathlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lmathlib.c'; fi` liblua_a-lmem.o: ../../lua/lmem.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lmem.o -MD -MP -MF $(DEPDIR)/liblua_a-lmem.Tpo -c -o liblua_a-lmem.o `test -f '../../lua/lmem.c' || echo '$(srcdir)/'`../../lua/lmem.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lmem.Tpo $(DEPDIR)/liblua_a-lmem.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lmem.c' object='liblua_a-lmem.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lmem.o `test -f '../../lua/lmem.c' || echo '$(srcdir)/'`../../lua/lmem.c liblua_a-lmem.obj: ../../lua/lmem.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lmem.obj -MD -MP -MF $(DEPDIR)/liblua_a-lmem.Tpo -c -o liblua_a-lmem.obj `if test -f '../../lua/lmem.c'; then $(CYGPATH_W) '../../lua/lmem.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lmem.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lmem.Tpo $(DEPDIR)/liblua_a-lmem.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lmem.c' object='liblua_a-lmem.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lmem.obj `if test -f '../../lua/lmem.c'; then $(CYGPATH_W) '../../lua/lmem.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lmem.c'; fi` liblua_a-loadlib.o: ../../lua/loadlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-loadlib.o -MD -MP -MF $(DEPDIR)/liblua_a-loadlib.Tpo -c -o liblua_a-loadlib.o `test -f '../../lua/loadlib.c' || echo '$(srcdir)/'`../../lua/loadlib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-loadlib.Tpo $(DEPDIR)/liblua_a-loadlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/loadlib.c' object='liblua_a-loadlib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-loadlib.o `test -f '../../lua/loadlib.c' || echo '$(srcdir)/'`../../lua/loadlib.c liblua_a-loadlib.obj: ../../lua/loadlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-loadlib.obj -MD -MP -MF $(DEPDIR)/liblua_a-loadlib.Tpo -c -o liblua_a-loadlib.obj `if test -f '../../lua/loadlib.c'; then $(CYGPATH_W) '../../lua/loadlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/loadlib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-loadlib.Tpo $(DEPDIR)/liblua_a-loadlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/loadlib.c' object='liblua_a-loadlib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-loadlib.obj `if test -f '../../lua/loadlib.c'; then $(CYGPATH_W) '../../lua/loadlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/loadlib.c'; fi` liblua_a-lobject.o: ../../lua/lobject.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lobject.o -MD -MP -MF $(DEPDIR)/liblua_a-lobject.Tpo -c -o liblua_a-lobject.o `test -f '../../lua/lobject.c' || echo '$(srcdir)/'`../../lua/lobject.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lobject.Tpo $(DEPDIR)/liblua_a-lobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lobject.c' object='liblua_a-lobject.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lobject.o `test -f '../../lua/lobject.c' || echo '$(srcdir)/'`../../lua/lobject.c liblua_a-lobject.obj: ../../lua/lobject.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lobject.obj -MD -MP -MF $(DEPDIR)/liblua_a-lobject.Tpo -c -o liblua_a-lobject.obj `if test -f '../../lua/lobject.c'; then $(CYGPATH_W) '../../lua/lobject.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lobject.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lobject.Tpo $(DEPDIR)/liblua_a-lobject.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lobject.c' object='liblua_a-lobject.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lobject.obj `if test -f '../../lua/lobject.c'; then $(CYGPATH_W) '../../lua/lobject.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lobject.c'; fi` liblua_a-lopcodes.o: ../../lua/lopcodes.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lopcodes.o -MD -MP -MF $(DEPDIR)/liblua_a-lopcodes.Tpo -c -o liblua_a-lopcodes.o `test -f '../../lua/lopcodes.c' || echo '$(srcdir)/'`../../lua/lopcodes.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lopcodes.Tpo $(DEPDIR)/liblua_a-lopcodes.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lopcodes.c' object='liblua_a-lopcodes.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lopcodes.o `test -f '../../lua/lopcodes.c' || echo '$(srcdir)/'`../../lua/lopcodes.c liblua_a-lopcodes.obj: ../../lua/lopcodes.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lopcodes.obj -MD -MP -MF $(DEPDIR)/liblua_a-lopcodes.Tpo -c -o liblua_a-lopcodes.obj `if test -f '../../lua/lopcodes.c'; then $(CYGPATH_W) '../../lua/lopcodes.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lopcodes.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lopcodes.Tpo $(DEPDIR)/liblua_a-lopcodes.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lopcodes.c' object='liblua_a-lopcodes.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lopcodes.obj `if test -f '../../lua/lopcodes.c'; then $(CYGPATH_W) '../../lua/lopcodes.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lopcodes.c'; fi` liblua_a-loslib.o: ../../lua/loslib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-loslib.o -MD -MP -MF $(DEPDIR)/liblua_a-loslib.Tpo -c -o liblua_a-loslib.o `test -f '../../lua/loslib.c' || echo '$(srcdir)/'`../../lua/loslib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-loslib.Tpo $(DEPDIR)/liblua_a-loslib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/loslib.c' object='liblua_a-loslib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-loslib.o `test -f '../../lua/loslib.c' || echo '$(srcdir)/'`../../lua/loslib.c liblua_a-loslib.obj: ../../lua/loslib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-loslib.obj -MD -MP -MF $(DEPDIR)/liblua_a-loslib.Tpo -c -o liblua_a-loslib.obj `if test -f '../../lua/loslib.c'; then $(CYGPATH_W) '../../lua/loslib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/loslib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-loslib.Tpo $(DEPDIR)/liblua_a-loslib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/loslib.c' object='liblua_a-loslib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-loslib.obj `if test -f '../../lua/loslib.c'; then $(CYGPATH_W) '../../lua/loslib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/loslib.c'; fi` liblua_a-lparser.o: ../../lua/lparser.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lparser.o -MD -MP -MF $(DEPDIR)/liblua_a-lparser.Tpo -c -o liblua_a-lparser.o `test -f '../../lua/lparser.c' || echo '$(srcdir)/'`../../lua/lparser.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lparser.Tpo $(DEPDIR)/liblua_a-lparser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lparser.c' object='liblua_a-lparser.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lparser.o `test -f '../../lua/lparser.c' || echo '$(srcdir)/'`../../lua/lparser.c liblua_a-lparser.obj: ../../lua/lparser.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lparser.obj -MD -MP -MF $(DEPDIR)/liblua_a-lparser.Tpo -c -o liblua_a-lparser.obj `if test -f '../../lua/lparser.c'; then $(CYGPATH_W) '../../lua/lparser.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lparser.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lparser.Tpo $(DEPDIR)/liblua_a-lparser.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lparser.c' object='liblua_a-lparser.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lparser.obj `if test -f '../../lua/lparser.c'; then $(CYGPATH_W) '../../lua/lparser.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lparser.c'; fi` liblua_a-lstate.o: ../../lua/lstate.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lstate.o -MD -MP -MF $(DEPDIR)/liblua_a-lstate.Tpo -c -o liblua_a-lstate.o `test -f '../../lua/lstate.c' || echo '$(srcdir)/'`../../lua/lstate.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lstate.Tpo $(DEPDIR)/liblua_a-lstate.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lstate.c' object='liblua_a-lstate.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lstate.o `test -f '../../lua/lstate.c' || echo '$(srcdir)/'`../../lua/lstate.c liblua_a-lstate.obj: ../../lua/lstate.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lstate.obj -MD -MP -MF $(DEPDIR)/liblua_a-lstate.Tpo -c -o liblua_a-lstate.obj `if test -f '../../lua/lstate.c'; then $(CYGPATH_W) '../../lua/lstate.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lstate.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lstate.Tpo $(DEPDIR)/liblua_a-lstate.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lstate.c' object='liblua_a-lstate.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lstate.obj `if test -f '../../lua/lstate.c'; then $(CYGPATH_W) '../../lua/lstate.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lstate.c'; fi` liblua_a-lstring.o: ../../lua/lstring.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lstring.o -MD -MP -MF $(DEPDIR)/liblua_a-lstring.Tpo -c -o liblua_a-lstring.o `test -f '../../lua/lstring.c' || echo '$(srcdir)/'`../../lua/lstring.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lstring.Tpo $(DEPDIR)/liblua_a-lstring.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lstring.c' object='liblua_a-lstring.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lstring.o `test -f '../../lua/lstring.c' || echo '$(srcdir)/'`../../lua/lstring.c liblua_a-lstring.obj: ../../lua/lstring.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lstring.obj -MD -MP -MF $(DEPDIR)/liblua_a-lstring.Tpo -c -o liblua_a-lstring.obj `if test -f '../../lua/lstring.c'; then $(CYGPATH_W) '../../lua/lstring.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lstring.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lstring.Tpo $(DEPDIR)/liblua_a-lstring.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lstring.c' object='liblua_a-lstring.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lstring.obj `if test -f '../../lua/lstring.c'; then $(CYGPATH_W) '../../lua/lstring.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lstring.c'; fi` liblua_a-lstrlib.o: ../../lua/lstrlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lstrlib.o -MD -MP -MF $(DEPDIR)/liblua_a-lstrlib.Tpo -c -o liblua_a-lstrlib.o `test -f '../../lua/lstrlib.c' || echo '$(srcdir)/'`../../lua/lstrlib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lstrlib.Tpo $(DEPDIR)/liblua_a-lstrlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lstrlib.c' object='liblua_a-lstrlib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lstrlib.o `test -f '../../lua/lstrlib.c' || echo '$(srcdir)/'`../../lua/lstrlib.c liblua_a-lstrlib.obj: ../../lua/lstrlib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lstrlib.obj -MD -MP -MF $(DEPDIR)/liblua_a-lstrlib.Tpo -c -o liblua_a-lstrlib.obj `if test -f '../../lua/lstrlib.c'; then $(CYGPATH_W) '../../lua/lstrlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lstrlib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lstrlib.Tpo $(DEPDIR)/liblua_a-lstrlib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lstrlib.c' object='liblua_a-lstrlib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lstrlib.obj `if test -f '../../lua/lstrlib.c'; then $(CYGPATH_W) '../../lua/lstrlib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lstrlib.c'; fi` liblua_a-ltable.o: ../../lua/ltable.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ltable.o -MD -MP -MF $(DEPDIR)/liblua_a-ltable.Tpo -c -o liblua_a-ltable.o `test -f '../../lua/ltable.c' || echo '$(srcdir)/'`../../lua/ltable.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ltable.Tpo $(DEPDIR)/liblua_a-ltable.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ltable.c' object='liblua_a-ltable.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ltable.o `test -f '../../lua/ltable.c' || echo '$(srcdir)/'`../../lua/ltable.c liblua_a-ltable.obj: ../../lua/ltable.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ltable.obj -MD -MP -MF $(DEPDIR)/liblua_a-ltable.Tpo -c -o liblua_a-ltable.obj `if test -f '../../lua/ltable.c'; then $(CYGPATH_W) '../../lua/ltable.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ltable.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ltable.Tpo $(DEPDIR)/liblua_a-ltable.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ltable.c' object='liblua_a-ltable.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ltable.obj `if test -f '../../lua/ltable.c'; then $(CYGPATH_W) '../../lua/ltable.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ltable.c'; fi` liblua_a-ltablib.o: ../../lua/ltablib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ltablib.o -MD -MP -MF $(DEPDIR)/liblua_a-ltablib.Tpo -c -o liblua_a-ltablib.o `test -f '../../lua/ltablib.c' || echo '$(srcdir)/'`../../lua/ltablib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ltablib.Tpo $(DEPDIR)/liblua_a-ltablib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ltablib.c' object='liblua_a-ltablib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ltablib.o `test -f '../../lua/ltablib.c' || echo '$(srcdir)/'`../../lua/ltablib.c liblua_a-ltablib.obj: ../../lua/ltablib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ltablib.obj -MD -MP -MF $(DEPDIR)/liblua_a-ltablib.Tpo -c -o liblua_a-ltablib.obj `if test -f '../../lua/ltablib.c'; then $(CYGPATH_W) '../../lua/ltablib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ltablib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ltablib.Tpo $(DEPDIR)/liblua_a-ltablib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ltablib.c' object='liblua_a-ltablib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ltablib.obj `if test -f '../../lua/ltablib.c'; then $(CYGPATH_W) '../../lua/ltablib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ltablib.c'; fi` liblua_a-ltm.o: ../../lua/ltm.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ltm.o -MD -MP -MF $(DEPDIR)/liblua_a-ltm.Tpo -c -o liblua_a-ltm.o `test -f '../../lua/ltm.c' || echo '$(srcdir)/'`../../lua/ltm.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ltm.Tpo $(DEPDIR)/liblua_a-ltm.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ltm.c' object='liblua_a-ltm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ltm.o `test -f '../../lua/ltm.c' || echo '$(srcdir)/'`../../lua/ltm.c liblua_a-ltm.obj: ../../lua/ltm.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-ltm.obj -MD -MP -MF $(DEPDIR)/liblua_a-ltm.Tpo -c -o liblua_a-ltm.obj `if test -f '../../lua/ltm.c'; then $(CYGPATH_W) '../../lua/ltm.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ltm.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-ltm.Tpo $(DEPDIR)/liblua_a-ltm.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/ltm.c' object='liblua_a-ltm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-ltm.obj `if test -f '../../lua/ltm.c'; then $(CYGPATH_W) '../../lua/ltm.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/ltm.c'; fi` liblua_a-lundump.o: ../../lua/lundump.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lundump.o -MD -MP -MF $(DEPDIR)/liblua_a-lundump.Tpo -c -o liblua_a-lundump.o `test -f '../../lua/lundump.c' || echo '$(srcdir)/'`../../lua/lundump.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lundump.Tpo $(DEPDIR)/liblua_a-lundump.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lundump.c' object='liblua_a-lundump.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lundump.o `test -f '../../lua/lundump.c' || echo '$(srcdir)/'`../../lua/lundump.c liblua_a-lundump.obj: ../../lua/lundump.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lundump.obj -MD -MP -MF $(DEPDIR)/liblua_a-lundump.Tpo -c -o liblua_a-lundump.obj `if test -f '../../lua/lundump.c'; then $(CYGPATH_W) '../../lua/lundump.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lundump.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lundump.Tpo $(DEPDIR)/liblua_a-lundump.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lundump.c' object='liblua_a-lundump.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lundump.obj `if test -f '../../lua/lundump.c'; then $(CYGPATH_W) '../../lua/lundump.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lundump.c'; fi` liblua_a-lutf8lib.o: ../../lua/lutf8lib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lutf8lib.o -MD -MP -MF $(DEPDIR)/liblua_a-lutf8lib.Tpo -c -o liblua_a-lutf8lib.o `test -f '../../lua/lutf8lib.c' || echo '$(srcdir)/'`../../lua/lutf8lib.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lutf8lib.Tpo $(DEPDIR)/liblua_a-lutf8lib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lutf8lib.c' object='liblua_a-lutf8lib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lutf8lib.o `test -f '../../lua/lutf8lib.c' || echo '$(srcdir)/'`../../lua/lutf8lib.c liblua_a-lutf8lib.obj: ../../lua/lutf8lib.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lutf8lib.obj -MD -MP -MF $(DEPDIR)/liblua_a-lutf8lib.Tpo -c -o liblua_a-lutf8lib.obj `if test -f '../../lua/lutf8lib.c'; then $(CYGPATH_W) '../../lua/lutf8lib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lutf8lib.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lutf8lib.Tpo $(DEPDIR)/liblua_a-lutf8lib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lutf8lib.c' object='liblua_a-lutf8lib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lutf8lib.obj `if test -f '../../lua/lutf8lib.c'; then $(CYGPATH_W) '../../lua/lutf8lib.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lutf8lib.c'; fi` liblua_a-lvm.o: ../../lua/lvm.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lvm.o -MD -MP -MF $(DEPDIR)/liblua_a-lvm.Tpo -c -o liblua_a-lvm.o `test -f '../../lua/lvm.c' || echo '$(srcdir)/'`../../lua/lvm.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lvm.Tpo $(DEPDIR)/liblua_a-lvm.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lvm.c' object='liblua_a-lvm.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lvm.o `test -f '../../lua/lvm.c' || echo '$(srcdir)/'`../../lua/lvm.c liblua_a-lvm.obj: ../../lua/lvm.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lvm.obj -MD -MP -MF $(DEPDIR)/liblua_a-lvm.Tpo -c -o liblua_a-lvm.obj `if test -f '../../lua/lvm.c'; then $(CYGPATH_W) '../../lua/lvm.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lvm.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lvm.Tpo $(DEPDIR)/liblua_a-lvm.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lvm.c' object='liblua_a-lvm.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lvm.obj `if test -f '../../lua/lvm.c'; then $(CYGPATH_W) '../../lua/lvm.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lvm.c'; fi` liblua_a-lzio.o: ../../lua/lzio.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lzio.o -MD -MP -MF $(DEPDIR)/liblua_a-lzio.Tpo -c -o liblua_a-lzio.o `test -f '../../lua/lzio.c' || echo '$(srcdir)/'`../../lua/lzio.c @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lzio.Tpo $(DEPDIR)/liblua_a-lzio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lzio.c' object='liblua_a-lzio.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lzio.o `test -f '../../lua/lzio.c' || echo '$(srcdir)/'`../../lua/lzio.c liblua_a-lzio.obj: ../../lua/lzio.c @am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblua_a-lzio.obj -MD -MP -MF $(DEPDIR)/liblua_a-lzio.Tpo -c -o liblua_a-lzio.obj `if test -f '../../lua/lzio.c'; then $(CYGPATH_W) '../../lua/lzio.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lzio.c'; fi` @am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/liblua_a-lzio.Tpo $(DEPDIR)/liblua_a-lzio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../../lua/lzio.c' object='liblua_a-lzio.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblua_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblua_a-lzio.obj `if test -f '../../lua/lzio.c'; then $(CYGPATH_W) '../../lua/lzio.c'; else $(CYGPATH_W) '$(srcdir)/../../lua/lzio.c'; fi` .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-wxlua.o: ../../gui-wx/wxlua.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxlua.o -MD -MP -MF $(DEPDIR)/golly-wxlua.Tpo -c -o golly-wxlua.o `test -f '../../gui-wx/wxlua.cpp' || echo '$(srcdir)/'`../../gui-wx/wxlua.cpp @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxlua.Tpo $(DEPDIR)/golly-wxlua.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxlua.cpp' object='golly-wxlua.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-wxlua.o `test -f '../../gui-wx/wxlua.cpp' || echo '$(srcdir)/'`../../gui-wx/wxlua.cpp golly-wxlua.obj: ../../gui-wx/wxlua.cpp @am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(golly_CPPFLAGS) $(CPPFLAGS) $(golly_CXXFLAGS) $(CXXFLAGS) -MT golly-wxlua.obj -MD -MP -MF $(DEPDIR)/golly-wxlua.Tpo -c -o golly-wxlua.obj `if test -f '../../gui-wx/wxlua.cpp'; then $(CYGPATH_W) '../../gui-wx/wxlua.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxlua.cpp'; fi` @am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/golly-wxlua.Tpo $(DEPDIR)/golly-wxlua.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../../gui-wx/wxlua.cpp' object='golly-wxlua.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-wxlua.obj `if test -f '../../gui-wx/wxlua.cpp'; then $(CYGPATH_W) '../../gui-wx/wxlua.cpp'; else $(CYGPATH_W) '$(srcdir)/../../gui-wx/wxlua.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 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.8-src/gui-wx/configure/ar-lib0000755000175100017510000001330312660172502014517 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 tardir=$(bindistdir) && $(am__tar) \ | GZIP=$(GZIP_ENV) gzip -c >$(bindistdir).tar.gz rm -r $(bindistdir) golly-2.8-src/gui-wx/configure/sources.am0000644000175100017510000007752112751752551015452 00000000000000nodist_liblua_a_SOURCES = ../../lua/lapi.h ../../lua/lauxlib.h ../../lua/lcode.h ../../lua/lctype.h ../../lua/ldebug.h ../../lua/ldo.h ../../lua/lfunc.h ../../lua/lgc.h ../../lua/llex.h ../../lua/llimits.h ../../lua/lmem.h ../../lua/lobject.h ../../lua/lopcodes.h ../../lua/lparser.h ../../lua/lprefix.h ../../lua/lstate.h ../../lua/lstring.h ../../lua/ltable.h ../../lua/ltm.h ../../lua/luaconf.h ../../lua/lua.h ../../lua/lualib.h ../../lua/lundump.h ../../lua/lvm.h ../../lua/lzio.h ../../lua/lua.hpp ../../lua/lapi.c ../../lua/lauxlib.c ../../lua/lbaselib.c ../../lua/lbitlib.c ../../lua/lcode.c ../../lua/lcorolib.c ../../lua/lctype.c ../../lua/ldblib.c ../../lua/ldebug.c ../../lua/ldo.c ../../lua/ldump.c ../../lua/lfunc.c ../../lua/lgc.c ../../lua/linit.c ../../lua/liolib.c ../../lua/llex.c ../../lua/lmathlib.c ../../lua/lmem.c ../../lua/loadlib.c ../../lua/lobject.c ../../lua/lopcodes.c ../../lua/loslib.c ../../lua/lparser.c ../../lua/lstate.c ../../lua/lstring.c ../../lua/lstrlib.c ../../lua/ltable.c ../../lua/ltablib.c ../../lua/ltm.c ../../lua/lundump.c ../../lua/lutf8lib.c ../../lua/lvm.c ../../lua/lzio.c 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/wxlua.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/wxlua.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/hensel.png ../../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/lua.html ../../Help/mouse.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.lua ../../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.lua ../../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/chase-the-glider.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/Non-Totalistic/horiship-guns.rle ../../Patterns/Non-Totalistic/JustFriends/oscillators.rle ../../Patterns/Non-Totalistic/JustFriends/p137loop.rle ../../Patterns/Non-Totalistic/JustFriends/p384drifter.rle ../../Patterns/Non-Totalistic/JustFriends/p8256c4dirtyrake.rle ../../Patterns/Non-Totalistic/JustFriends/spaceships.rle ../../Patterns/Non-Totalistic/p42-knightship.rle ../../Patterns/Non-Totalistic/Sierpinski-builder.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/Lua/bricklayer.lua ../../Scripts/Lua/density.lua ../../Scripts/Lua/draw-lines.lua ../../Scripts/Lua/envelope.lua ../../Scripts/Lua/flood-fill.lua ../../Scripts/Lua/giffer.lua ../../Scripts/Lua/goto.lua ../../Scripts/Lua/gplus/guns.lua ../../Scripts/Lua/gplus/init.lua ../../Scripts/Lua/gplus/objects.lua ../../Scripts/Lua/gplus/strict.lua ../../Scripts/Lua/gplus/text.lua ../../Scripts/Lua/gun-demo.lua ../../Scripts/Lua/heisenburp.lua ../../Scripts/Lua/invert.lua ../../Scripts/Lua/life-integer-gun30.lua ../../Scripts/Lua/make-torus.lua ../../Scripts/Lua/metafier.lua ../../Scripts/Lua/move-object.lua ../../Scripts/Lua/move-selection.lua ../../Scripts/Lua/oscar.lua ../../Scripts/Lua/p1100-MWSS-gun.lua ../../Scripts/Lua/pd-glider.lua ../../Scripts/Lua/pop-plot.lua ../../Scripts/Lua/shift.lua ../../Scripts/Lua/slide-show.lua ../../Scripts/Lua/tile.lua ../../Scripts/Lua/tile-with-clip.lua ../../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 = ../../lua ../../gui-wx/makefile-gtk ../../gui-wx/makefile-mac ../../gui-wx/makefile-win ../../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/app/build.gradle ../../gui-android/Golly/app/src/main/AndroidManifest.xml ../../gui-android/Golly/app/src/main/assets/readme.txt ../../gui-android/Golly/app/src/main/assets/triangle-down.png ../../gui-android/Golly/app/src/main/assets/triangle-right.png ../../gui-android/Golly/app/src/main/java/net/sf/golly/BaseActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/BaseApp.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/EditActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/HelpActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/InfoActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/MainActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/OpenActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/PatternGLSurfaceView.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/RuleActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/SettingsActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/StateActivity.java ../../gui-android/Golly/app/src/main/java/net/sf/golly/StateGLSurfaceView.java ../../gui-android/Golly/app/src/main/jni/jnicalls.cpp ../../gui-android/Golly/app/src/main/jni/jnicalls.h ../../gui-android/Golly/app/src/main/res/drawable-hdpi/ic_launcher.png ../../gui-android/Golly/app/src/main/res/drawable-mdpi/ic_launcher.png ../../gui-android/Golly/app/src/main/res/drawable-xhdpi/ic_launcher.png ../../gui-android/Golly/app/src/main/res/drawable-xxhdpi/ic_launcher.png ../../gui-android/Golly/app/src/main/res/layout/edit_layout.xml ../../gui-android/Golly/app/src/main/res/layout/help_layout.xml ../../gui-android/Golly/app/src/main/res/layout/info_layout.xml ../../gui-android/Golly/app/src/main/res/layout/main_layout_wide.xml ../../gui-android/Golly/app/src/main/res/layout/main_layout.xml ../../gui-android/Golly/app/src/main/res/layout/open_layout.xml ../../gui-android/Golly/app/src/main/res/layout/rule_layout.xml ../../gui-android/Golly/app/src/main/res/layout/settings_layout.xml ../../gui-android/Golly/app/src/main/res/layout/state_layout.xml ../../gui-android/Golly/app/src/main/res/menu/control_menu.xml ../../gui-android/Golly/app/src/main/res/menu/edit_menu.xml ../../gui-android/Golly/app/src/main/res/menu/main.xml ../../gui-android/Golly/app/src/main/res/menu/mode_menu.xml ../../gui-android/Golly/app/src/main/res/menu/paste_menu.xml ../../gui-android/Golly/app/src/main/res/menu/pastemode_menu.xml ../../gui-android/Golly/app/src/main/res/menu/selection_menu.xml ../../gui-android/Golly/app/src/main/res/menu/view_menu.xml ../../gui-android/Golly/app/src/main/res/values/dimens.xml ../../gui-android/Golly/app/src/main/res/values/strings.xml ../../gui-android/Golly/app/src/main/res/values/styles.xml ../../gui-android/Golly/app/src/main/res/values-sw600dp/dimens.xml ../../gui-android/Golly/app/src/main/res/values-sw720dp-land/dimens.xml ../../gui-android/Golly/app/src/main/res/values-v11/styles.xml ../../gui-android/Golly/app/src/main/res/values-v14/styles.xml ../../gui-android/Golly/build.gradle ../../gui-android/Golly/.gitignore ../../gui-android/Golly/gradlew ../../gui-android/Golly/gradlew.bat ../../gui-android/Golly/gradle/wrapper/gradle-wrapper.jar ../../gui-android/Golly/gradle/wrapper/gradle-wrapper.properties ../../gui-android/Golly/settings.gradle ../../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.8-src/gui-wx/configure/depcomp0000755000175100017510000005064312660172502015010 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.8-src/gui-wx/wxview.h0000755000175100017510000002047512660172450013161 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 "wx/glcanvas.h" // for wxGLCanvas, wxGLContext #include "bigint.h" // for bigint #include "lifealgo.h" // for lifealgo #include "wxselect.h" // for Selection #include "wxlayer.h" // for Layer // OpenGL is used for viewing and editing patterns: class PatternView : public wxGLCanvas { 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(Layer* templayer, 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 ToggleSmarterScaling(); 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 RememberOneCellChange(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 wxGLContext* glcontext; // OpenGL context for this canvas bool initgl; // need to initialize GL state? 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) 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.8-src/gui-wx/wxview.cpp0000644000175100017510000033507412751752464013527 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 "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 #include "wxmain.h" // for mainptr->... #include "wxstatus.h" // for statusptr->... #include "wxrender.h" // for InitPaste, DrawView #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" // ----------------------------------------------------------------------------- static bool stopdrawing = false; // terminate a draw done while generating? static Layer* pastelayer = NULL; // temporary layer with pattern to be pasted static wxRect pastebox; // bounding box for paste pattern static wxString oldrule; // rule before readclipboard is called static wxString newrule; // rule after readclipboard is called // 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) // this determines the rate at which OnDragTimer will be called after the mouse // is dragged outside the viewport but then kept still (note that OnMouseMotion // calls OnDragTimer when the mouse is moved, inside or outside the viewport) const int TEN_HERTZ = 100; // ----------------------------------------------------------------------------- // event table and handlers: BEGIN_EVENT_TABLE(PatternView, wxGLCanvas) 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 RefreshView() { // refresh main viewport window, including all tile windows if they exist // (tile windows are children of bigview) bigview->Refresh(false); } // ----------------------------------------------------------------------------- bool PatternView::OutsideLimits(bigint& t, bigint& l, bigint& b, bigint& r) { return ( t < bigint::min_coord || l < bigint::min_coord || b > bigint::max_coord || r > bigint::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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_CUT); mainptr->Stop(); return; } currlayer->currsel.CopyToClipboard(true); } // ----------------------------------------------------------------------------- void PatternView::CopySelection() { if (!SelectionExists()) return; if (mainptr->generating) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_COPY); mainptr->Stop(); 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); // pastelayer contains 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) pastebox = wxRect(ileft, itop, wd.toint(), ht.toint()); InitPaste(pastelayer, 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 ( HasCapture() ) ReleaseMouse(); mainptr->EnableAllMenus(true); mainptr->UpdateMenuAccelerators(); // restore accelerators // restore cursor currlayer->curs = savecurs; CheckCursor(mainptr->infront); if ( pasterect.width > 0 ) { // erase old pasterect Refresh(false); } 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 if (err) { // allow rule change to cause algo change mainptr->ChangeAlgorithm(pastelayer->algtype, newrule); } else { // show new rule in title bar mainptr->SetWindowTitle(wxEmptyString); // if pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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); } // use 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* pastealgo = pastelayer->algo; 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(Layer* templayer, 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), *templayer->algo, 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 templayer->algo; templayer->algo = CreateNewUniverse(i); err = readclipboard(mainptr->clipfile.mb_str(wxConvLocal), *templayer->algo, t, l, b, r); if (!err) { templayer->algtype = i; 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(templayer->algo->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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(toselection ? ID_PASTE_SEL : ID_PASTE); mainptr->Stop(); return; } // if clipboard text starts with "@RULE rulename" then install rulename.rule // and switch to that rule if (mainptr->ClipboardContainsRule()) return; // create a temporary layer for storing the clipboard pattern pastelayer = CreateTemporaryLayer(); if (pastelayer) { // read clipboard pattern into pastelayer bigint top, left, bottom, right; if ( GetClipboardPattern(pastelayer, &top, &left, &bottom, &right) ) { // temporarily set currlayer to pastelayer so we can update the paste pattern's colors and icons Layer* savelayer = currlayer; currlayer = pastelayer; UpdateLayerColors(); currlayer = savelayer; doing_paste = true; PasteTemporaryToCurrent(toselection, top, left, bottom, right); doing_paste = false; } delete pastelayer; pastelayer = NULL; } } // ----------------------------------------------------------------------------- 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 pastelayer lifealgo* savealgo = currlayer->algo; int savetype = currlayer->algtype; currlayer->algo = pastelayer->algo; currlayer->algtype = pastelayer->algtype; // 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 pastelayer->algo = currlayer->algo; currlayer->algo = savealgo; currlayer->algtype = savetype; inscript = false; if (result) { InitPaste(pastelayer, pastebox); RefreshView(); } return result; } // ----------------------------------------------------------------------------- bool PatternView::RotatePastePattern(bool clockwise) { bool result; Selection pastesel(pastebox.GetTop(), pastebox.GetLeft(), pastebox.GetBottom(), pastebox.GetRight()); // rotate the pattern in pastelayer lifealgo* savealgo = currlayer->algo; int savetype = currlayer->algtype; currlayer->algo = pastelayer->algo; currlayer->algtype = pastelayer->algtype; // 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 pastelayer->algo = 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); InitPaste(pastelayer, pastebox); RefreshView(); } 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; mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ToggleCellIcons() { showicons = !showicons; mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ToggleCellColors() { swapcolors = !swapcolors; InvertCellColors(); if (pastelayer) { // invert colors used to draw paste pattern for (int n = 0; n <= pastelayer->numicons; n++) { pastelayer->cellr[n] = 255 - pastelayer->cellr[n]; pastelayer->cellg[n] = 255 - pastelayer->cellg[n]; pastelayer->cellb[n] = 255 - pastelayer->cellb[n]; } InvertIconColors(pastelayer->atlas7x7, 8, pastelayer->numicons); InvertIconColors(pastelayer->atlas15x15, 16, pastelayer->numicons); InvertIconColors(pastelayer->atlas31x31, 32, pastelayer->numicons); } mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- void PatternView::ToggleSmarterScaling() { smartscale = !smartscale; 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 __WXMAC__ #define RefreshControls() RefreshRect(controlsrect,false) #else // safer to redraw entire viewport on Windows and Linux // otherwise we see partial drawing in some cases #define RefreshControls() Refresh(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; #ifdef __WXMAC__ mainptr->hbar->SetScrollbar(hthumb, 1, range, 1, true); #else bigview->SetScrollbar(wxHORIZONTAL, hthumb, 1, range, true); #endif } else { // keep thumb box in middle of scroll bar if grid width is infinite hthumb = (thumbrange - 1) * viewwd / 2; #ifdef __WXMAC__ mainptr->hbar->SetScrollbar(hthumb, viewwd, thumbrange * viewwd, viewwd, true); #else bigview->SetScrollbar(wxHORIZONTAL, hthumb, viewwd, thumbrange * viewwd, true); #endif } 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; #ifdef __WXMAC__ mainptr->vbar->SetScrollbar(vthumb, 1, range, 1, true); #else bigview->SetScrollbar(wxVERTICAL, vthumb, 1, range, true); #endif } else { // keep thumb box in middle of scroll bar if grid height is infinite vthumb = (thumbrange - 1) * viewht / 2; #ifdef __WXMAC__ mainptr->vbar->SetScrollbar(vthumb, viewht, thumbrange * viewht, viewht, true); #else bigview->SetScrollbar(wxVERTICAL, vthumb, viewht, thumbrange * viewht, true); #endif } } // ----------------------------------------------------------------------------- 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_FILEDIR: if (!busy) mainptr->ChangeFileDir(); break; case DO_SHOWFILES: mainptr->ToggleShowFiles(); 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) mainptr->StartOrStop(); 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_SMARTSCALE: ToggleSmarterScaling(); break; case DO_SHOWGRID: ToggleGridLines(); 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::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 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; } 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(); if (showstatus) statusptr->Refresh(false); RefreshView(); } CaptureMouse(); // get mouse up event even if outside view dragtimer->Start(TEN_HERTZ); 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 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(); if (showstatus) statusptr->Refresh(false); RefreshView(); } } // ----------------------------------------------------------------------------- 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(TEN_HERTZ); } // ----------------------------------------------------------------------------- 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(TEN_HERTZ); } // ----------------------------------------------------------------------------- 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 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)) { // OnPaint handlers must always create a wxPaintDC wxPaintDC dc(this); 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); } SetCurrent(*glcontext); if (initgl) { // do these gl calls once (and only after the window has been created) initgl = false; glDisable(GL_DEPTH_TEST); // we only do 2D drawing glDisable(GL_DITHER); // makes no diff??? // glDisable(GL_MULTISAMPLE); // unknown on Windows glDisable(GL_STENCIL_TEST); glDisable(GL_FOG); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // initialize GL matrix to match our preferred coordinate system glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, wd, ht, 0, -1, 1); // origin is top left and y increases down glViewport(0, 0, wd, ht); glMatrixMode(GL_MODELVIEW); } DrawView(tileindex); SwapBuffers(); } // ----------------------------------------------------------------------------- void PatternView::OnSize(wxSizeEvent& event) { if (!IsShownOnScreen()) return; // must not call SetCurrent (on Linux at least) int wd, ht; GetClientSize(&wd, &ht); // resize this viewport SetViewSize(wd, ht); SetCurrent(*glcontext); // update GL matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, wd, ht, 0, -1, 1); // origin is top left and y increases down glViewport(0, 0, wd, ht); glMatrixMode(GL_MODELVIEW); 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 == 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->draw_pending = true; mainptr->mouseevent.m_x = x; mainptr->mouseevent.m_y = y; mainptr->Stop(); 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(SIXTY_HERTZ); // call OnDragTimer ~60 times per sec 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); } } if (drawingcells || selectingcells || movingview || clickedcontrol > NO_CONTROL) { if (event.Dragging()) { wxTimerEvent unused; OnDragTimer(unused); } else { // no mouse buttons are being pressed so ensure ReleaseMouse gets called // (in case OnMouseUp doesn't get called when it should) 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(); } else { vthumb = newpos; currlayer->view->move(0, amount); // don't call UpdateEverything here because it calls UpdateScrollBars RefreshView(); } } } 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! } // ----------------------------------------------------------------------------- /* using this doesn't seem to change anything static int attributes[5] = { WX_GL_DOUBLEBUFFER, WX_GL_RGBA, WX_GL_DEPTH_SIZE, 0, // Golly only does 2D drawing 0 }; */ // create the viewport canvas PatternView::PatternView(wxWindow* parent, wxCoord x, wxCoord y, int wd, int ht, long style) : wxGLCanvas(parent, wxID_ANY, NULL /* attributes */, wxPoint(x,y), wxSize(wd,ht), style) { // create a new rendering context instance for this canvas glcontext = new wxGLContext(this); if (glcontext == NULL) Fatal(_("Failed to create OpenGL context!")); dragtimer = new wxTimer(this, wxID_ANY); if (dragtimer == NULL) Fatal(_("Failed to create drag timer!")); // avoid erasing background on Linux -- doesn't work // SetBackgroundStyle(wxBG_STYLE_CUSTOM); // avoid resizing problems on Mac/Linux -- doesn't work // SetBackgroundStyle(wxBG_STYLE_PAINT); initgl = true; // need to initialize GL state 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 } // ----------------------------------------------------------------------------- PatternView::~PatternView() { delete glcontext; delete dragtimer; } golly-2.8-src/gui-wx/wxrule.h0000644000175100017510000000240212525071110013130 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.8-src/gui-wx/wxedit.h0000644000175100017510000000310112525071110013103 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.8-src/gui-wx/icons/0000755000175100017510000000000012525071110012626 500000000000000golly-2.8-src/gui-wx/icons/appicon48.ico0000644000175100017510000000413612525071110015053 0000000000000000((0`Àÿÿÿ¿¿¿¿¿¿¿¿¿ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»Ì̼ÌË»»¼ÌËÌ̼ÌËÌ̼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»Ì̼ÌË»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»Ì̼ÌËÌ̼ÌËÌ̼ÌË»»¼ÌËÌÌ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»golly-2.8-src/gui-wx/icons/file-mc.icns0000644000175100017510000011434212525071110014745 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.8-src/gui-wx/icons/appicon.ico0000755000175100017510000000525612525071110014706 00000000000000(6 è^00hF( Àÿÿÿ{{{{{{{{{½½½{{{ÿÿÿÿÿÿÿÿÿîîîîîîîîé™î™™™™žé™î™™™™žé™î™™™™žé™îîîîîîé™îîîîîîé™îîîé™îîîé™îîîé™îîîîîîîîîîîîî陙™™î™žé™™™™î™žé™™™™î™žîîîîîîîî¬ç8ì`|œÐÿþ°( @€ÿÿÿ{{{{{{{{{½½½{{{ÿÿÿÿÿÿÿÿÿîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîéž™îî™éž™éž™éžîîéž™îî™éž™éž™éžîîîîîîîîîîîîîîîîîîéž™îî™éž™éž™éžîîéž™îî™éž™éž™éžîîîîîîîîîîîîîîîîîîéž™îîîîîîîîîîîîîéž™îîîîîîîîîîîîîîîîîîîîîîîîîîîîîéž™îîîîîîîî™éžîîéž™îîîîîîîî™éžîîîîîîîîîîîîîîîîîîéž™îîîîîîîî™éžîîéž™îîîîîîîî™éžîîîîîîîîîîîîîîîîîîéž™îîîîîîîî™éžîîéž™îîîîîîîî™éžîîîîîîîîîîîîîîîîîîîîîîîîîîîîî™éžîîîîîîîîîîîîî™éžîîîîîîîîîîîîîîîîîî鞙鞙鞙îî™éžîî鞙鞙鞙îî™éžîîîîîîîîîîîîîîîîîî鞙鞙鞙îî™éžîî鞙鞙鞙îî™éžîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî(0`ÿÿÿ{{{{{{{{{½½½{{{ÿÿÿÿÿÿÿÿÿîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™îîîîîîîîîîîîîîîîîîîîîîîîî陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™î陞îî陞™™é™ž™™é™ž™™îîîîîîîîîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîî陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™î陞îîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîî陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîî陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™î陞™™é™ž™™é™žîî陞™™îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîtîîîîîîîîîîî™îî™îî™îî™îîîîîîîî™îî™îî™îî™îîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîgolly-2.8-src/gui-wx/icons/app.icns0000644000175100017510000012673712525071110014224 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.8-src/gui-wx/icons/file-rle.icns0000644000175100017510000011400012525071110015117 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.8-src/gui-wx/icons/appicon16.ico0000644000175100017510000000053612525071110015046 00000000000000(( Àÿÿÿ¿¿¿¿¿¿¿¿¿ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿ»»»»»»»»¼Ì»ÌÌÌÌ˼̻ÌÌÌÌ˼̻ÌÌÌÌ˼̻»»»»»¼Ì»»»»»»¼Ì»»»»Ì˼̻»»»Ì˼̻»»»Ì˼̻»»»ÌË»»»»»»ÌË»»»»»»Ì˼ÌÌÌÌ»Ì˼ÌÌÌÌ»Ì˼ÌÌÌÌ»ÌË»»»»»»»»golly-2.8-src/gui-wx/icons/appicon32.ico0000644000175100017510000000177612525071110015053 00000000000000 h( @ÿÿÿ¿¿¿¿¿¿¿¿¿ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»¼ËÌ»»Ì¼Ë̼Ë̼˻»¼ËÌ»»Ì¼Ë̼Ë̼˻»»»»»»»»»»»»»»»»»¼ËÌ»»Ì¼Ë̼Ë̼˻»¼ËÌ»»Ì¼Ë̼Ë̼˻»»»»»»»»»»»»»»»»»¼ËÌ»»»»»»»»»»»»»¼ËÌ»»»»»»»»»»»»»»»»»»»»»»»»»»»»»¼ËÌ»»»»»»»»Ì¼Ë»»¼ËÌ»»»»»»»»Ì¼Ë»»»»»»»»»»»»»»»»»»¼ËÌ»»»»»»»»Ì¼Ë»»¼ËÌ»»»»»»»»Ì¼Ë»»»»»»»»»»»»»»»»»»¼ËÌ»»»»»»»»Ì¼Ë»»¼ËÌ»»»»»»»»Ì¼Ë»»»»»»»»»»»»»»»»»»»»»»»»»»»»»Ì¼Ë»»»»»»»»»»»»»Ì¼Ë»»»»»»»»»»»»»»»»»»¼Ë̼Ë̼ËÌ»»Ì¼Ë»»¼Ë̼Ë̼ËÌ»»Ì¼Ë»»»»»»»»»»»»»»»»»»¼Ë̼Ë̼ËÌ»»Ì¼Ë»»¼Ë̼Ë̼ËÌ»»Ì¼Ë»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»golly-2.8-src/gui-wx/icons/appicon.xpm0000644000175100017510000000253012525071110014725 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.8-src/gui-wx/wxperl.cpp0000644000175100017510000030665412751752464013521 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 "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" // ============================================================================= #ifdef ENABLE_PERL /* Golly uses an embedded Perl interpreter to execute scripts. See "perldoc perlembed" for details. 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). */ #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 // ----------------------------------------------------------------------------- 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; const char* filename = SvPV(ST(0), n_a); int remember = 0; if (items > 1) remember = SvIV(ST(1)); const char* err = GSF_open(wxString(filename,wxConvLocal), 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; const char* filename = SvPV(ST(0), n_a); const char* format = SvPV(ST(1), n_a); int remember = 0; if (items > 2) remember = SvIV(ST(2)); const char* err = GSF_save(wxString(filename,wxConvLocal), 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) ); 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) ); 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; const 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; const 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; const char* dirname = SvPV(ST(0), n_a); const char* newdir = SvPV(ST(1), n_a); const char* err = GSF_setdir(dirname, wxString(newdir,wxConvLocal)); 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; const 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; const 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; const 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; const 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; const 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 (!tempalgo->CreateBorderCells()) break; tempalgo->step(); if (!tempalgo->DeleteBorderCells()) 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 layer for storing the clipboard pattern Layer* templayer = CreateTemporaryLayer(); if (!templayer) { PERL_ERROR("g_getclip error: failed to create temporary layer."); } // 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(templayer, &top, &left, &bottom, &right) ) { if ( viewptr->OutsideLimits(top, left, bottom, right) ) { delete templayer; 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 templayer lifealgo* tempalgo = templayer->algo; 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 templayer; 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 templayer; } else { // assume error message has been displayed delete templayer; 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; const 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; const 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; const 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; const char* x = SvPV(ST(0), n_a); const 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; const 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(wxString(name,wxConvLocal), 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(); UpdateIconColors(); 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; } } } UpdateIconColors(); 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; const 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; const 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; const 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; const 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; const 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; const 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 s[0] = GSF_getkey(); s[1] = '\0'; 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; const 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; const 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; const 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; const 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; const 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; const 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; const char* err = (items == 1) ? SvPV(ST(0),n_a) : NULL; GSF_exit(wxString(err, wxConvLocal)); 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; const 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 #endif // ENABLE_PERL // ============================================================================= void RunPerlScript(const wxString &filepath) { #ifdef ENABLE_PERL // 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; } #else Warning(_("Sorry, but Perl scripting is no longer supported.")); #endif // ENABLE_PERL } // ----------------------------------------------------------------------------- void AbortPerlScript() { #ifdef ENABLE_PERL scripterr = wxString(abortmsg,wxConvLocal); // can't call Perl_croak here (done via RETURN_IF_ABORTED) #endif // ENABLE_PERL } // ----------------------------------------------------------------------------- void FinishPerlScripting() { #ifdef ENABLE_PERL #ifdef PERL510_OR_LATER if (inited) { PERL_SYS_TERM(); } #endif #ifdef USE_PERL_DYNAMIC // probably don't really need to do this FreePerlLib(); #endif #endif // ENABLE_PERL } golly-2.8-src/gui-wx/makefile-mac0000644000175100017510000003056512751752464013725 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.2 # 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.2 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.8 # these directory paths are relative to the location of this makefile: EXEDIR = .. DOCSDIR = ../docs BASEDIR = ../gollybase CMDDIR = ../cmdline LUADIR = ../lua OTHERGUIS = ../gui-android ../gui-common ../gui-ios ../gui-web # 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) $(OTHERGUIS) GUIFILES = makefile-gtk makefile-mac makefile-win local-win-template.mk \ golly.rc Info.plist.in wx*.h wx*.cpp configure bitmaps icons LUAFILES = $(LUADIR)/*.h $(LUADIR)/*.c $(LUADIR)/*.hpp $(LUADIR)/Makefile $(LUADIR)/ReadMe.html # uncomment the next line to allow Golly to run Perl scripts: # ENABLE_PERL = 1 ifdef ENABLE_PERL 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)) endif # 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: LUALIB = $(LUADIR)/liblua.a LIBDIRNAME = $(WXLIB_DIR)/lib TOOLKIT = OSX_COCOA TOOLKIT_LOWERCASE = osx_cocoa TOOLKIT_VERSION = # determine Mac OS X version (eg. 6 for Snow Leopard, 11 for El Capitan) OS_VERSION = $(shell sw_vers -productVersion | cut -f 2 -d '.') osx_ge = $(shell if [ $(OS_VERSION) -ge $(1) ] ; then echo "$(2)"; else echo "$(3)"; fi ;) CXXC = g++ CXXC += $(call osx_ge, 9, "-mmacosx-version-min=10.9", "-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 CXXFLAGS += $(call osx_ge, 11, "-Wno-potentially-evaluated-expression", "") ifdef ENABLE_PERL CXXFLAGS += -DENABLE_PERL endif 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 AudioToolbox -framework OpenGL -framework AGL 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 wxprefs.h \ wxlua.h wxperl.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)/wxlua.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) __WXLIB_GL_p = -lwx_$(PORTNAME)$(WXUNIVNAME)$(WXUNICODEFLAG)$(WXDEBUGFLAG)_gl-$(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 -(cd $(LUADIR) && $(MAKE) clean) 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) $(LUALIB) $(CXXC) -o $@ $(BASEOBJ) $(WXOBJ) $(LUALIB) $(LDFLAGS) -L$(LIBDIRNAME) \ $(__WXLIB_HTML_p) $(__WXLIB_ADV_p) $(__WXLIB_CORE_p) \ $(__WXLIB_BASE_p) $(__WXLIB_NET_p) $(__WXLIB_GL_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 $(LUALIB): (cd $(LUADIR) && $(MAKE) all) $(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)/wxlua.o: wxlua.cpp $(CXXC) $(CXXFLAGS) -I$(LUADIR) -c -o $@ wxlua.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 mkdir $(RELEASENAME)-src/lua cp -rp $(SRCFILES) $(SHAREDFILES) $(RELEASENAME)-src cp -rp $(GUIFILES) $(RELEASENAME)-src/gui-wx cp -rp $(LUAFILES) $(RELEASENAME)-src/lua find $(RELEASENAME)-src -name '.[^.]*' -delete find $(RELEASENAME)-src -name '*.o' -delete find $(RELEASENAME)-src -name 'makefile' -delete find $(RELEASENAME)-src/Scripts/Python -name '*.pyc' -delete #### BUGGY!!! tar -cf - ./$(RELEASENAME)-src | gzip > $(RELEASENAME)-src.tar.gz echo Now create zip archive of $(RELEASENAME)-src 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.8-src/gui-wx/wxstatus.h0000755000175100017510000000723612525071110013521 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.8-src/gui-wx/wxtimeline.h0000644000175100017510000000430412660172450014003 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? 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.8-src/gui-wx/wxhelp.cpp0000644000175100017510000013406412751752464013501 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 "ruleloaderalgo.h" // for noTABLEorTREE #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 scroll bar 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, bool fromfile) { wxString oldrule = wxString(currlayer->algo->getrule(),wxConvLocal); int oldmaxstate = currlayer->algo->NumCellStates() - 1; const char* err; // 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.")); return; } else if (inscript) { Warning(_("Cannot change rule while a script is running.")); return; } if (fromfile) { // load given rule from a .rule file // InitAlgorithms ensures the RuleLoader algo is the last algo int rule_loader_algo = NumAlgos() - 1; if (currlayer->algtype == rule_loader_algo) { // RuleLoader is current algo so no need to switch err = currlayer->algo->setrule( rulestring.mb_str(wxConvLocal) ); } else { // switch to RuleLoader algo lifealgo* tempalgo = CreateNewUniverse(rule_loader_algo); err = tempalgo->setrule( rulestring.mb_str(wxConvLocal) ); delete tempalgo; if (!err) { // change the current algorithm and switch to the new rule mainptr->ChangeAlgorithm(rule_loader_algo, rulestring); if (rule_loader_algo != currlayer->algtype) { RestoreRule(oldrule); Warning(_("Algorithm could not be changed (pattern is too big to convert).")); } else { mainptr->SetWindowTitle(wxEmptyString); mainptr->UpdateEverything(); } return; } } if (err) { // RuleLoader algo found some sort of error if (strcmp(err, noTABLEorTREE) == 0) { // .rule file has no TABLE or TREE section but it might be used // to override a built-in rule, so try each algo wxString temprule = rulestring; temprule.Replace(wxT("_"), wxT("/")); // eg. convert B3_S23 to B3/S23 for (int i = 0; i < NumAlgos(); i++) { lifealgo* tempalgo = CreateNewUniverse(i); err = tempalgo->setrule( temprule.mb_str(wxConvLocal) ); delete tempalgo; if (!err) { // change the current algorithm and switch to the new rule mainptr->ChangeAlgorithm(i, temprule); if (i != currlayer->algtype) { RestoreRule(oldrule); Warning(_("Algorithm could not be changed (pattern is too big to convert).")); } else { mainptr->SetWindowTitle(wxEmptyString); mainptr->UpdateEverything(); } return; } } } RestoreRule(oldrule); wxString msg = _("The rule file is not valid:\n") + rulestring; msg += _("\n\nThe error message:\n") + wxString(err,wxConvLocal); Warning(msg); return; } } else { // fromfile is false, so switch to rule given in a "rule:" link 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).")); } else { mainptr->SetWindowTitle(wxEmptyString); mainptr->UpdateEverything(); } return; } } } RestoreRule(oldrule); Warning(_("Given rule is not valid in any algorithm:\n") + rulestring); return; } } 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 mainptr->SetWindowTitle(wxEmptyString); // if pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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 if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { mainptr->ReduceCellStates(newmaxstate); } if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberRuleChange(oldrule); } } // update colors and/or icons for the new rule UpdateLayerColors(); // pattern might have changed or colors/icons might have changed mainptr->UpdateEverything(); } // ----------------------------------------------------------------------------- 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 file 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 file 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) { mainptr->command_pending = true; mainptr->cmdevent.SetId(ID_LOAD_LEXICON); mainptr->Stop(); 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.rule 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.")); } 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:")) ) { // switch to given rule (false = not necessarily in a .rule file) LoadRule( url.AfterFirst(':'), false ); } 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 the file 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.8-src/gui-wx/golly.rc�����������������������������������������������������������������������0000755�0001751�0001751�00000000463�12751752464�013140� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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" // force appropriate .manifest file to be included in .res file #define wxUSE_RC_MANIFEST 1 #include "wx/msw/wx.rc" �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/gui-wx/wxrule.cpp���������������������������������������������������������������������0000644�0001751�0001751�00000110400�12751752464�013504� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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 file 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 the file 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 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.8-src/gui-wx/wxhelp.h�����������������������������������������������������������������������0000644�0001751�0001751�00000003557�12751752464�013150� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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, bool fromfile = true); // Load given rule from a .rule file if fromfile is true, // otherwise switch to given rule specified in a "rule:" link. wxFrame* GetHelpFrame(); // Return a pointer to the help window. #endif �������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/gui-wx/wxscript.cpp�������������������������������������������������������������������0000644�0001751�0001751�00000167165�12751752464�014065� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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 "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 "wxlua.h" // for RunLuaScript, AbortLuaScript #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 luascript = false; // a Lua script is running? 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(true); // call Update() 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(const wxString& filename, int remember) { // convert non-absolute filename to absolute path relative to scriptloc wxFileName fullname(filename); if (!fullname.IsAbsolute()) fullname = scriptloc + filename; // return error message here if file doesn't exist wxString fullpath = fullname.GetFullPath(); if (!wxFileName::FileExists(fullpath)) { return "open error: 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(const wxString& filename, const char* format, int remember) { // convert non-absolute filename to absolute path relative to scriptloc wxFileName fullname(filename); if (!fullname.IsAbsolute()) fullname = scriptloc + filename; // 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(const char* dirname, const wxString& newdir) { wxString dirpath = newdir; 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, "files") == 0 || strcmp(dirname, "patterns") == 0) { // deprecated // change filedir and update panel if currently shown mainptr->SetFileDir(dirpath); } else if (strcmp(dirname, "download") == 0) { downloaddir = dirpath; } else { return "Unknown directory name."; } return NULL; // success } // ----------------------------------------------------------------------------- const char* GSF_getdir(const 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, "files") == 0) dirpath = filedir; else if (strcmp(dirname, "patterns") == 0) dirpath = filedir; // deprecated else if (strcmp(dirname, "scripts") == 0) dirpath = filedir; // ditto 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(const char* algostring) { // find index for given algo name char* algoname = ReplaceDeprecatedAlgo((char*) 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(const 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 pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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(const char* genstring) { const char* err = mainptr->ChangeGenCount(genstring); if (!err) DoAutoUpdate(); return err; } // ----------------------------------------------------------------------------- const char* GSF_setpos(const char* x, const 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(const wxString& name, int index) { if (name.length() == 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(name); 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 = name; 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, const 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(const 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(); 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(); 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(); DoAutoUpdate(); } } else if (strcmp(optname, "showexact") == 0) { *oldval = showexact ? 1 : 0; if (*oldval != newval) { mainptr->ToggleExactNumbers(); 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(); DoAutoUpdate(); } } else if (strcmp(optname, "showfiles") == 0 || strcmp(optname, "showpatterns") == 0) { // deprecated *oldval = showfiles ? 1 : 0; if (*oldval != newval) { mainptr->ToggleShowFiles(); DoAutoUpdate(); } } else if (strcmp(optname, "showscripts") == 0) { *oldval = 0; if (*oldval != newval) { // deprecated so do nothing DoAutoUpdate(); } } else if (strcmp(optname, "showstatusbar") == 0) { *oldval = showstatus ? 1 : 0; if (*oldval != newval) { mainptr->ToggleStatusBar(); DoAutoUpdate(); } } else if (strcmp(optname, "showtoolbar") == 0) { *oldval = showtool ? 1 : 0; if (*oldval != newval) { mainptr->ToggleToolBar(); DoAutoUpdate(); } } else if (strcmp(optname, "smartscale") == 0) { *oldval = smartscale ? 1 : 0; if (*oldval != newval) { viewptr->ToggleSmarterScaling(); 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(); DoAutoUpdate(); } } else if (strcmp(optname, "tilelayers") == 0) { *oldval = tilelayers ? 1 : 0; if (*oldval != newval) { ToggleTileLayers(); 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(const 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, "showfiles") == 0) *optval = showfiles ? 1 : 0; else if (strcmp(optname, "showpatterns") == 0) *optval = showfiles ? 1 : 0; // deprecated else if (strcmp(optname, "showscripts") == 0) *optval = 0; // ditto else if (strcmp(optname, "showstatusbar") == 0) *optval = showstatus ? 1 : 0; else if (strcmp(optname, "showtoolbar") == 0) *optval = showtool ? 1 : 0; else if (strcmp(optname, "smartscale") == 0) *optval = smartscale ? 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(const 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(); UpdateIconColors(); 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(); UpdateIconColors(); UpdateCloneColors(); DoAutoUpdate(); } } else if (strcmp(colname, "border") == 0) { oldcol = *borderrgb; if (oldcol != newcol) { *borderrgb = newcol; DoAutoUpdate(); } } else if (strcmp(colname, "paste") == 0) { oldcol = *pastergb; if (oldcol != newcol) { *pastergb = newcol; DoAutoUpdate(); } } else if (strcmp(colname, "select") == 0) { oldcol = *selectrgb; if (oldcol != newcol) { *selectrgb = newcol; DoAutoUpdate(); } } else if (strcmp(colname, "hashing") == 0) { // deprecated oldcol = algoinfo[HLIFE_ALGO]->statusrgb; if (oldcol != newcol) { algoinfo[HLIFE_ALGO]->statusrgb = newcol; UpdateStatusBrushes(); DoAutoUpdate(); } } else if (strcmp(colname, "nothashing") == 0) { // deprecated oldcol = algoinfo[QLIFE_ALGO]->statusrgb; if (oldcol != newcol) { algoinfo[QLIFE_ALGO]->statusrgb = newcol; UpdateStatusBrushes(); DoAutoUpdate(); } } else { // look for algo name char* algoname = ReplaceDeprecatedAlgo((char*) 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; UpdateStatusBrushes(); DoAutoUpdate(); } return true; } } // unknown color name return false; } return true; } // ----------------------------------------------------------------------------- bool GSF_getcolor(const 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((char*) 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) char GSF_getkey() { passkeys = true; // future keyboard events will call PassKeyToScript if (scriptchars.length() == 0) { // return empty string return '\0'; } else { // return first char in scriptchars and then remove it char ch = scriptchars.GetChar(0); scriptchars = scriptchars.AfterFirst(ch); return ch; } } // ----------------------------------------------------------------------------- // the following is deprecated (use GSF_doevent) void GSF_dokey(const 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; // pass in true so that Update() is called mainptr->UpdatePatternAndStatus(true); if (showtitle) { mainptr->SetWindowTitle(wxEmptyString); showtitle = false; } if (updateedit) { UpdateEditBar(); updateedit = false; } inscript = true; } // ----------------------------------------------------------------------------- void GSF_exit(const wxString& errmsg) { if (!errmsg.IsEmpty()) { // display given error message inscript = false; statusptr->ErrorMessage(errmsg); 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 AbortLuaScript/AbortPerlScript/AbortPythonScript // so don't display scripterr } else { wxString errtype; if (ext.IsSameAs(wxT("lua"), false)) { errtype = _("Lua error:"); } else 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_luascript = luascript; 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("lua"), false)) { luascript = true; RunLuaScript(fpath); } else 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 luascript = false; 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 Lua/Perl/Python error message CheckScriptError(ext); if (!scripterr.IsEmpty()) { if (in_luascript) { // abort the calling Lua script AbortLuaScript(); } else if (in_pyscript) { // abort the calling Python script AbortPythonScript(); } else if (in_plscript) { // abort the calling Perl script AbortPerlScript(); } } luascript = in_luascript; 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); luascript = false; plscript = false; pyscript = false; // update Undo/Redo items based on current layer's history if (allowundo) currlayer->undoredo->UpdateUndoRedoItems(); // display any 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 (luascript) AbortLuaScript(); 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 (luascript) AbortLuaScript(); if (plscript) AbortPerlScript(); if (pyscript) AbortPythonScript(); wxSetWorkingDirectory(gollydir); inscript = false; } FinishLuaScripting(); FinishPerlScripting(); FinishPythonScripting(); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/gui-wx/wxprefs.h����������������������������������������������������������������������0000644�0001751�0001751�00000043216�12751752464�013333� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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 smartscale; // smarter scaling when zoomed out? extern bool swapcolors; // swap colors used for cell states? 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 choosedir; // directory used by Choose File button extern wxString filedir; // directory used by Show Files 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 file directory window extern bool showfiles; // show file 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/rule/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_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_FILEDIR, // set file folder... DO_SETGEN, // set generation... DO_SETCOLORS, // set layer colors... 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_SHOWSTATES, // show all states DO_SHOWICONS, // show cell icons DO_SHOWEDIT, // show edit bar DO_SHOWEXACT, // show exact numbers DO_SHOWFILES, // show files DO_SHOWGRID, // show grid lines DO_HASHINFO, // show hash info DO_HELP, // show help DO_SHOWLAYER, // show layer bar 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_SMARTSCALE, // smarter scaling 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 void UpdateStatusBrushes(); // update colors in status brushes 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 = 10; // minimum dirwinwd // Golly uses wxTimers to control the speed of generating patterns, drawing cells, // playing timelines, etc. The value defined below will cause the timers to fire // at approximately 60 times per sec (to match the refresh rate of most screens). #ifdef __WXMSW__ // It seems that wxTimers on Windows only have a resolution of about 15.6ms // so we need to set SIXTY_HERTZ to a value below 16, based on Tim Hutton's // test results (using a 64-bit build of Golly on Windows 10): // interval=5 : 63.9gps = 15.6ms actual interval // interval=10 : 63.9gps = 15.6ms actual interval // interval=15 : 63.9gps = 15.6ms actual interval // interval=16 : 40.0gps = 25.0ms actual interval // interval=17 : 31.9gps = 31.3ms actual interval (= 2 times 15.6ms) // interval=20 : 31.9gps = 31.3ms actual interval // interval=25 : 31.9gps = 31.3ms actual interval const int SIXTY_HERTZ = 15; #else // Mac and Linux const int SIXTY_HERTZ = 16; // 1000/60 #endif // 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.8-src/gui-wx/bitmaps/�����������������������������������������������������������������������0000755�0001751�0001751�00000000000�12660172450�013163� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/gui-wx/bitmaps/cross_curs.xpm���������������������������������������������������������0000644�0001751�0001751�00000001027�12525071110�016005� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/open.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001666�12525071110�014572� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/pick_down.xpm����������������������������������������������������������0000644�0001751�0001751�00000001034�12525071110�015573� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/select_down.xpm��������������������������������������������������������0000644�0001751�0001751�00000001014�12525071110�016122� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/forwards.xpm�����������������������������������������������������������0000644�0001751�0001751�00000001022�12525071110�015442� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/delete.xpm�������������������������������������������������������������0000644�0001751�0001751�00000000776�12525071110�015074� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/files.xpm��������������������������������������������������������������0000644�0001751�0001751�00000001252�12660172450�014733� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *files_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.8-src/gui-wx/bitmaps/autofit_down.xpm�������������������������������������������������������0000644�0001751�0001751�00000001011�12525071110�016313� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/stopplay.xpm�����������������������������������������������������������0000644�0001751�0001751�00000000774�12525071110�015503� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/zoomout_curs.xpm�������������������������������������������������������0000644�0001751�0001751�00000001032�12525071110�016364� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/move.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001200�12525071110�014557� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/zoomout_down.xpm�������������������������������������������������������0000644�0001751�0001751�00000001015�12525071110�016360� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/zoomin_down.xpm��������������������������������������������������������0000644�0001751�0001751�00000001014�12525071110�016156� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/zoomin.xpm�������������������������������������������������������������0000644�0001751�0001751�00000001024�12525071110�015130� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/autofit.xpm������������������������������������������������������������0000644�0001751�0001751�00000001004�12525071110�015266� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/zoomin_curs.xpm��������������������������������������������������������0000644�0001751�0001751�00000001031�12525071110�016162� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/info.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001120�12525071110�014545� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/new.xpm����������������������������������������������������������������0000644�0001751�0001751�00000001302�12525071110�014405� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/add.xpm����������������������������������������������������������������0000644�0001751�0001751�00000000773�12525071110�014357� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/move_down.xpm����������������������������������������������������������0000644�0001751�0001751�00000001114�12525071110�015612� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/allstates.xpm����������������������������������������������������������0000644�0001751�0001751�00000001077�12525071110�015621� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/controls.xpm�����������������������������������������������������������0000644�0001751�0001751�00000025174�12525071110�015474� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/zoomout.xpm������������������������������������������������������������0000644�0001751�0001751�00000001025�12525071110�015332� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/reset.xpm��������������������������������������������������������������0000644�0001751�0001751�00000000772�12525071110�014750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/stack_down.xpm���������������������������������������������������������0000644�0001751�0001751�00000001013�12525071110�015747� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/tile_down.xpm����������������������������������������������������������0000644�0001751�0001751�00000001012�12525071110�015576� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/clone.xpm��������������������������������������������������������������0000644�0001751�0001751�00000000775�12525071110�014731� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/help.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001072�12525071110�014550� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/play.xpm���������������������������������������������������������������0000644�0001751�0001751�00000003122�12525071110�014563� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/draw.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001076�12525071110�014561� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/stop.xpm���������������������������������������������������������������0000644�0001751�0001751�00000006632�12525071110�014614� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/allstates_down.xpm�����������������������������������������������������0000644�0001751�0001751�00000001067�12525071110�016647� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/pick_curs.xpm����������������������������������������������������������0000644�0001751�0001751�00000001051�12525071110�015577� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/save.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001255�12525071110�014561� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/backwards.xpm����������������������������������������������������������0000644�0001751�0001751�00000001023�12525071110�015555� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/draw_down.xpm����������������������������������������������������������0000644�0001751�0001751�00000001066�12525071110�015607� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/redo.xpm���������������������������������������������������������������0000644�0001751�0001751�00000000770�12525071110�014555� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/select.xpm�������������������������������������������������������������0000644�0001751�0001751�00000001024�12525071110�015074� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/pick.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001044�12525071110�014545� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/deltime.xpm������������������������������������������������������������0000644�0001751�0001751�00000000773�12525071110�015252� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/undo.xpm���������������������������������������������������������������0000644�0001751�0001751�00000000770�12525071110�014571� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/hand_curs.xpm����������������������������������������������������������0000644�0001751�0001751�00000001027�12525071110�015566� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/duplicate.xpm����������������������������������������������������������0000644�0001751�0001751�00000000776�12525071110�015604� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/hyper_down.xpm���������������������������������������������������������0000644�0001751�0001751�00000001035�12525071110�015775� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/tile.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001022�12525071110�014550� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/algo.xpm���������������������������������������������������������������0000644�0001751�0001751�00000001120�12525071110�014534� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/record.xpm�������������������������������������������������������������0000644�0001751�0001751�00000001046�12525071110�015077� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/hyper.xpm��������������������������������������������������������������0000644�0001751�0001751�00000001017�12525071110�014746� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/bitmaps/files_down.xpm���������������������������������������������������������0000644�0001751�0001751�00000001305�12660172450�015761� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* XPM */ static const char *files_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.8-src/gui-wx/bitmaps/stack.xpm��������������������������������������������������������������0000644�0001751�0001751�00000001023�12525071110�014721� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/wxperl.h�����������������������������������������������������������������������0000644�0001751�0001751�00000002236�12525071110�013130� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/gui-wx/wxlayer.h����������������������������������������������������������������������0000644�0001751�0001751�00000025745�12660172450�013325� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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 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 // 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 // texture atlases for rendering icons unsigned char* atlas7x7; // atlas for 7x7 icons unsigned char* atlas15x15; // atlas for 15x15 icons unsigned char* atlas31x31; // atlas for 31x31 icons int numicons; // number of icons (= number of live states) 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 }; 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 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. 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* CreateTemporaryLayer(); // Create a temporary layer with the same algo type as currlayer. // 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. // Color handling routines: void CreateColorGradient(); // Create a color gradient for the current layer using // currlayer->fromrgb and currlayer->torgb. void UpdateIconColors(); // Update the icon texture atlases for the current layer. // Must be called BEFORE calling UpdateCloneColors. 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 icons. void InvertIconColors(unsigned char* atlasptr, int iconsize, int numicons); // Invert the icon colors in the given texture atlas. void SetLayerColors(); // Open a dialog to change the current layer's colors. #endif ���������������������������golly-2.8-src/gui-wx/wxrender.cpp�������������������������������������������������������������������0000644�0001751�0001751�00000160426�12751752464�014031� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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. All drawing in the viewport is done in this module using OpenGL 1. 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(). DrawView() does the following tasks: - Fills the entire viewport with the state 0 color. - 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). 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, DrawPasteImage() creates a suitable viewport and draws the paste pattern (stored in pastelayer). - Calls DrawControls() if the translucent controls need to be drawn. ----------------------------------------------------------------------------- */ #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 #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" // ----------------------------------------------------------------------------- // local data used in golly_render routines int currwd, currht; // current width and height of viewport, in pixels int scalefactor; // current scale factor (1, 2, 4, 8 or 16) unsigned char dead_alpha = 255; // alpha value for dead pixels unsigned char live_alpha = 255; // alpha value for live pixels GLuint rgbatexture = 0; // texture name for drawing RGBA bitmaps GLuint icontexture = 0; // texture name for drawing icons GLuint celltexture = 0; // texture name for drawing magnified cells unsigned char* iconatlas = NULL; // pointer to texture atlas for current set of icons unsigned char* cellatlas = NULL; // pointer to texture atlas for current set of magnified cells // cellatlas needs to be rebuilt if any of these parameters change int prevnum = 0; // previous number of live states int prevsize = 0; // previous cell size unsigned char prevalpha; // previous alpha component unsigned char prevr[256]; // previous red component of each state unsigned char prevg[256]; // previous green component of each state unsigned char prevb[256]; // previous blue component of each state // fixed texture coordinates used by glTexCoordPointer static const GLshort texture_coordinates[] = { 0,0, 1,0, 0,1, 1,1 }; // for drawing paste pattern Layer* pastelayer; // layer containing the paste pattern wxRect pastebbox; // bounding box in cell coords (not necessarily minimal) unsigned char* modedata[4] = {NULL}; // RGBA data for drawing current paste mode (And, Copy, Or, Xor) const int modewd = 32; // width of each modedata const int modeht = 16; // height of each modedata // for drawing translucent controls unsigned char* ctrlsbitmap = NULL; // RGBA data for controls bitmap unsigned char* darkbutt = NULL; // RGBA data for darkening one button 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; #ifdef __WXMSW__ // this constant isn't defined in the OpenGL headers on Windows (XP at least) #define GL_CLAMP_TO_EDGE 0x812F #endif // ----------------------------------------------------------------------------- static void SetColor(int r, int g, int b, int a) { glColor4ub(r, g, b, a); } // ----------------------------------------------------------------------------- static void FillRect(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 }; glVertexPointer(2, GL_FLOAT, 0, rect); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } // ----------------------------------------------------------------------------- static void EnableTextures() { if (!glIsEnabled(GL_TEXTURE_2D)) { // restore texture color and enable textures SetColor(255, 255, 255, 255); glEnable(GL_TEXTURE_2D); } } // ----------------------------------------------------------------------------- static void DisableTextures() { if (glIsEnabled(GL_TEXTURE_2D)) { glDisable(GL_TEXTURE_2D); }; } // ----------------------------------------------------------------------------- void CreateTranslucentControls() { wxImage image(controls_xpm); controlswd = image.GetWidth(); controlsht = image.GetHeight(); // create ctrlsbitmap and initialize its RGBA data based on pixels in image ctrlsbitmap = (unsigned char*) malloc(controlswd * controlsht * 4); if (ctrlsbitmap) { int p = 0; for ( int y = 0; y < controlsht; y++ ) { for ( int x = 0; x < controlswd; x++ ) { unsigned char r = image.GetRed(x,y); unsigned char g = image.GetGreen(x,y); unsigned char b = image.GetBlue(x,y); if (r == 0 && g == 0 && b == 0) { // make black pixel 100% transparent ctrlsbitmap[p++] = 0; ctrlsbitmap[p++] = 0; ctrlsbitmap[p++] = 0; ctrlsbitmap[p++] = 0; } else { // make all non-black pixels translucent ctrlsbitmap[p++] = r; ctrlsbitmap[p++] = g; ctrlsbitmap[p++] = b; ctrlsbitmap[p++] = 192; // 75% opaque } } } } // allocate bitmap for darkening a clicked button darkbutt = (unsigned char*) malloc(buttsize * buttsize * 4); // create bitmaps for drawing each paste mode paste_mode savemode = pmode; for (int i = 0; i < 4; i++) { pmode = (paste_mode) i; wxString pmodestr = wxString(GetPasteMode(),wxConvLocal); // uses pmode wxBitmap modemap(modewd, modeht, 32); wxMemoryDC dc; dc.SelectObject(modemap); wxRect r(0, 0, modewd, modeht); wxBrush brush(*wxWHITE); FillRect(dc, r, brush); dc.SetFont(*statusptr->GetStatusFont()); dc.SetBackgroundMode(wxSOLID); dc.SetTextBackground(*wxWHITE); dc.SetTextForeground(*wxBLACK); dc.SetPen(*wxBLACK); int textwd, textht; dc.GetTextExtent(pmodestr, &textwd, &textht); textwd += 4; dc.DrawText(pmodestr, 2, modeht - statusptr->GetTextAscent() - 4); dc.SelectObject(wxNullBitmap); // now convert modemap data into RGBA data suitable for passing into DrawRGBAData modedata[i] = (unsigned char*) malloc(modewd * modeht * 4); if (modedata[i]) { int j = 0; unsigned char* m = modedata[i]; wxAlphaPixelData data(modemap); if (data) { wxAlphaPixelData::Iterator p(data); for (int y = 0; y < modeht; y++) { wxAlphaPixelData::Iterator rowstart = p; for (int x = 0; x < modewd; x++) { if (x > textwd) { m[j++] = 0; m[j++] = 0; m[j++] = 0; m[j++] = 0; } else { m[j++] = p.Red(); m[j++] = p.Green(); m[j++] = p.Blue(); m[j++] = 255; } p++; } p = rowstart; p.OffsetY(data, 1); } } } } pmode = savemode; } // ----------------------------------------------------------------------------- void DestroyDrawingData() { if (cellatlas) free(cellatlas); if (ctrlsbitmap) free(ctrlsbitmap); if (darkbutt) free(darkbutt); for (int i = 0; i < 4; i++) { if (modedata[i]) free(modedata[i]); } } // ----------------------------------------------------------------------------- void DrawRGBAData(unsigned char* rgbadata, int x, int y, int w, int h) { // only need to create texture name once if (rgbatexture == 0) glGenTextures(1, &rgbatexture); EnableTextures(); glBindTexture(GL_TEXTURE_2D, rgbatexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // avoids edge effects when scaling glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // ditto glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexCoordPointer(2, GL_SHORT, 0, texture_coordinates); // update the texture with the new RGBA data glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbadata); 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); } // ----------------------------------------------------------------------------- static void LoadIconAtlas(int iconsize, int numicons) { // load the texture atlas containing all icons for later use in DrawIcons // create icon texture name once if (icontexture == 0) glGenTextures(1, &icontexture); EnableTextures(); glBindTexture(GL_TEXTURE_2D, icontexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); int atlaswd = iconsize * numicons; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, atlaswd, iconsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, iconatlas); #if 0 // test above code by displaying the entire atlas GLfloat wd = atlaswd; GLfloat ht = iconsize; glTexCoordPointer(2, GL_SHORT, 0, texture_coordinates); int x = 0; int y = 0; GLfloat vertices[] = { x, y, x + wd, y, x, y + ht, x + wd, y + ht, }; glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #endif } // ----------------------------------------------------------------------------- void DrawIcons(unsigned char* statedata, int x, int y, int w, int h, int pmscale, int stride, int numicons) { // called from golly_render::pixblit to draw icons for each live cell; // assume pmscale > 2 (should be 8, 16 or 32 -- if higher then the 31x31 icons // will be scaled up) // one icon = 2 triangles = 4 vertices = 8 coordinates for GL_TRIANGLE_STRIP: // // 0,1 *---* 2,3 // | / | // 4,5 *---* 6,7 // GLfloat vertices[8]; GLfloat texcoords[8]; EnableTextures(); glBindTexture(GL_TEXTURE_2D, icontexture); for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { unsigned char state = statedata[row*stride + col]; if (state > 0) { int xpos = x + col * pmscale; int ypos = y + row * pmscale; vertices[0] = xpos; vertices[1] = ypos; vertices[2] = xpos + pmscale; vertices[3] = ypos; vertices[4] = xpos; vertices[5] = ypos + pmscale; vertices[6] = xpos + pmscale; vertices[7] = ypos + pmscale; texcoords[0] = (state-1) * 1.0/numicons; texcoords[1] = 0.0; texcoords[2] = state * 1.0/numicons; texcoords[3] = 0.0; texcoords[4] = texcoords[0]; texcoords[5] = 1.0; texcoords[6] = texcoords[2]; texcoords[7] = 1.0; glTexCoordPointer(2, GL_FLOAT, 0, texcoords); glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } } // ----------------------------------------------------------------------------- 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) outside the viewport, // so we don't use OpenGL calls in here 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); } // ----------------------------------------------------------------------------- static bool ChangeCellAtlas(int cellsize, int numcells, unsigned char alpha) { if (numcells != prevnum) return true; if (cellsize != prevsize) return true; if (alpha != prevalpha) return true; for (int state = 1; state <= numcells; state++) { if (currlayer->cellr[state] != prevr[state]) return true; if (currlayer->cellg[state] != prevg[state]) return true; if (currlayer->cellb[state] != prevb[state]) return true; } return false; // no need to change cellatlas } // ----------------------------------------------------------------------------- static void LoadCellAtlas(int cellsize, int numcells, unsigned char alpha) { // cellatlas might need to be (re)created if (ChangeCellAtlas(cellsize, numcells, alpha)) { prevnum = numcells; prevsize = cellsize; prevalpha = alpha; for (int state = 1; state <= numcells; state++) { prevr[state] = currlayer->cellr[state]; prevg[state] = currlayer->cellg[state]; prevb[state] = currlayer->cellb[state]; } if (cellatlas) free(cellatlas); // allocate enough memory for texture atlas to store RGBA pixels for a row of cells // (note that we use calloc so all alpha bytes are initially 0) int rowbytes = numcells * cellsize * 4; cellatlas = (unsigned char*) calloc(rowbytes * cellsize, 1); if (cellatlas) { // set pixels in top row int tpos = 0; for (int state = 1; state <= numcells; state++) { unsigned char r = currlayer->cellr[state]; unsigned char g = currlayer->cellg[state]; unsigned char b = currlayer->cellb[state]; // if the cell size is > 2 then there is a 1 pixel gap at right and bottom edge of each cell int cellwd = cellsize > 2 ? cellsize-1 : 2; for (int i = 0; i < cellwd; i++) { cellatlas[tpos++] = r; cellatlas[tpos++] = g; cellatlas[tpos++] = b; cellatlas[tpos++] = alpha; } if (cellsize > 2) tpos += 4; // skip transparent pixel at right edge of cell } // copy top row to remaining rows int remrows = cellsize > 2 ? cellsize - 2 : 1; for (int i = 1; i <= remrows; i++) { memcpy(&cellatlas[i * rowbytes], cellatlas, rowbytes); } } } // create cell texture name once if (celltexture == 0) glGenTextures(1, &celltexture); EnableTextures(); glBindTexture(GL_TEXTURE_2D, celltexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // load the texture atlas containing all magnified cells for later use in DrawMagnifiedCells int atlaswd = cellsize * numcells; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, atlaswd, cellsize, 0, GL_RGBA, GL_UNSIGNED_BYTE, cellatlas); #if 0 // test above code by displaying the entire atlas GLfloat wd = atlaswd; GLfloat ht = cellsize; glTexCoordPointer(2, GL_SHORT, 0, texture_coordinates); int x = 0; int y = 0; GLfloat vertices[] = { x, y, x + wd, y, x, y + ht, x + wd, y + ht, }; glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #endif } // ----------------------------------------------------------------------------- void DrawMagnifiedCells(unsigned char* statedata, int x, int y, int w, int h, int pmscale, int stride, int numcells) { // called from golly_render::pixblit to draw cells magnified by pmscale (2, 4, ... 2^MAX_MAG) // one cell = 2 triangles = 4 vertices = 8 coordinates for GL_TRIANGLE_STRIP: // // 0,1 *---* 2,3 // | / | // 4,5 *---* 6,7 // GLfloat vertices[8]; GLfloat texcoords[8]; EnableTextures(); glBindTexture(GL_TEXTURE_2D, celltexture); for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { unsigned char state = statedata[row*stride + col]; if (state > 0) { int xpos = x + col * pmscale; int ypos = y + row * pmscale; vertices[0] = xpos; vertices[1] = ypos; vertices[2] = xpos + pmscale; vertices[3] = ypos; vertices[4] = xpos; vertices[5] = ypos + pmscale; vertices[6] = xpos + pmscale; vertices[7] = ypos + pmscale; texcoords[0] = (state-1) * 1.0/numcells; texcoords[1] = 0.0; texcoords[2] = state * 1.0/numcells; texcoords[3] = 0.0; texcoords[4] = texcoords[0]; texcoords[5] = 1.0; texcoords[6] = texcoords[2]; texcoords[7] = 1.0; glTexCoordPointer(2, GL_FLOAT, 0, texcoords); glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } } } } // ----------------------------------------------------------------------------- class golly_render : public liferender { public: golly_render() {} virtual ~golly_render() {} virtual void pixblit(int x, int y, int w, int h, unsigned char* pm, int pmscale); virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b, unsigned char* deada, unsigned char* livea); }; golly_render renderer; // create instance // ----------------------------------------------------------------------------- void golly_render::pixblit(int x, int y, int w, int h, unsigned char* pmdata, int pmscale) { 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; } if (pmscale == 1) { // draw RGBA pixel data at scale 1:1 DrawRGBAData(pmdata, x, y, w, h); } else if (showicons && pmscale > 4 && iconatlas) { // draw icons at scales 1:8 and above DrawIcons(pmdata, x, y, w/pmscale, h/pmscale, pmscale, stride, currlayer->numicons); } else { // draw magnified cells, assuming pmdata contains (w/pmscale)*(h/pmscale) bytes // where each byte contains a cell state DrawMagnifiedCells(pmdata, x, y, w/pmscale, h/pmscale, pmscale, stride, currlayer->numicons); } } // ----------------------------------------------------------------------------- void golly_render::getcolors(unsigned char** r, unsigned char** g, unsigned char** b, unsigned char* deada, unsigned char* livea) { *r = currlayer->cellr; *g = currlayer->cellg; *b = currlayer->cellb; *deada = dead_alpha; *livea = live_alpha; } // ----------------------------------------------------------------------------- void DrawSelection(wxRect& rect, bool active) { // draw semi-transparent rectangle DisableTextures(); if (active) { SetColor(selectrgb->Red(), selectrgb->Green(), selectrgb->Blue(), 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 InitPaste(Layer* player, wxRect& bbox) { // set globals used in DrawPasteImage pastelayer = player; pastebbox = bbox; } // ----------------------------------------------------------------------------- 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 DrawPasteImage() { int pastemag = currlayer->view->getmag(); // note that viewptr->pasterect.width > 0 int prectwd = viewptr->pasterect.width; int prectht = viewptr->pasterect.height; // 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; 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* 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* 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, pastemag); cellbox.height = PixelsToCells(pasteht, pastemag); 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; } } } wxRect r = viewptr->pasterect; if (r.width > pastewd || r.height > pasteht) { // 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 - pastewd; break; case BottomRight: // shift image to bottom right corner of pasterect r.x += r.width - pastewd; r.y += r.height - pasteht; break; case BottomLeft: // shift image to bottom left corner of pasterect r.y += r.height - pasteht; break; case Middle: // shift image to middle of pasterect; note that above code // has ensured (r.width - pastewd) and (r.height - pasteht) // are an even number of *cells* if pastemag > 0 r.x += (r.width - pastewd) / 2; r.y += (r.height - pasteht) / 2; break; } } // set up viewport for drawing paste pattern pastelayer->view->resize(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; } pastelayer->view->setpositionmag(midx, midy, pastemag); // temporarily turn off grid lines bool saveshow = showgridlines; showgridlines = false; // dead pixels will be 100% transparent and live pixels 100% opaque dead_alpha = 0; live_alpha = 255; currwd = pastelayer->view->getwidth(); currht = pastelayer->view->getheight(); glTranslatef(r.x, r.y, 0); // temporarily set currlayer to pastelayer so golly_render routines // will use the paste pattern's color and icons Layer* savelayer = currlayer; currlayer = pastelayer; if (showicons && pastemag > 2) { // only show icons at scales 1:8 and above if (pastemag == 3) { iconatlas = currlayer->atlas7x7; LoadIconAtlas(8, currlayer->numicons); } else if (pastemag == 4) { iconatlas = currlayer->atlas15x15; LoadIconAtlas(16, currlayer->numicons); } else { iconatlas = currlayer->atlas31x31; LoadIconAtlas(32, currlayer->numicons); } } else if (pastemag > 0) { LoadCellAtlas(1 << pastemag, currlayer->numicons, 255); } if (scalefactor > 1) { // change scale to 1:1 and increase its size by scalefactor pastelayer->view->setmag(0); currwd = currwd * scalefactor; currht = currht * scalefactor; pastelayer->view->resize(currwd, currht); glPushMatrix(); glScalef(1.0/scalefactor, 1.0/scalefactor, 1.0); pastelayer->algo->draw(*pastelayer->view, renderer); // restore viewport settings currwd = currwd / scalefactor; currht = currht / scalefactor; // restore OpenGL scale glPopMatrix(); } else { // no scaling pastelayer->algo->draw(*pastelayer->view, renderer); } currlayer = savelayer; showgridlines = saveshow; glTranslatef(-r.x, -r.y, 0); // overlay translucent rect to show paste area DisableTextures(); SetColor(pastergb->Red(), pastergb->Green(), pastergb->Blue(), 64); r = viewptr->pasterect; FillRect(r.x, r.y, r.width, r.height); // show current paste mode if (r.y > 0 && modedata[(int)pmode]) { DrawRGBAData(modedata[(int)pmode], r.x, r.y - modeht - 1, modewd, modeht); } } // ----------------------------------------------------------------------------- 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(wxRect& rect) { if (ctrlsbitmap) { DrawRGBAData(ctrlsbitmap, rect.x, rect.y, controlswd, controlsht); if (currcontrol > NO_CONTROL && darkbutt) { // 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; } // draw one darkened button int p = 0; for ( int row = 0; row < buttsize; row++ ) { for ( int col = 0; col < buttsize; col++ ) { unsigned char alpha = ctrlsbitmap[((row + y) * controlswd + col + x) * 4 + 3]; if (alpha == 0) { // pixel is transparent darkbutt[p++] = 0; darkbutt[p++] = 0; darkbutt[p++] = 0; darkbutt[p++] = 0; } else { // pixel is part of button so use a very dark gray darkbutt[p++] = 20; darkbutt[p++] = 20; darkbutt[p++] = 20; darkbutt[p++] = 128; // 50% opaque } } } DrawRGBAData(darkbutt, rect.x + x, rect.y + y, buttsize, buttsize); } } } // ----------------------------------------------------------------------------- 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<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; } 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 add/subtract 0.5 from coordinates 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) { GLfloat points[] = { -0.5, v-0.5, wd+0.5, v-0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); 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) { GLfloat points[] = { h-0.5, -0.5, h-0.5, ht+0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); 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) { GLfloat points[] = { -0.5, v-0.5, wd+0.5, v-0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(GL_LINES, 0, 2); } } i = leftbold; h = 0; while (true) { h += cellsize; if (h > wd) break; i++; if (i % boldspacing == 0) { GLfloat points[] = { h-0.5, -0.5, h-0.5, ht+0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); glDrawArrays(GL_LINES, 0, 2); } } } } // ----------------------------------------------------------------------------- void DrawGridBorder(int wd, int ht) { // 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 = 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->Red(), borderrgb->Green(), borderrgb->Blue(), 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 ReplaceAlpha(int iconsize, int numicons, unsigned char oldalpha, unsigned char newalpha) { if (iconatlas) { int numbytes = numicons * iconsize * iconsize * 4; int i = 3; while (i < numbytes) { if (iconatlas[i] == oldalpha) iconatlas[i] = newalpha; i += 4; } } } // ----------------------------------------------------------------------------- void DrawOneLayer() { // dead pixels will be 100% transparent, and live pixels will use opacity setting dead_alpha = 0; live_alpha = int(2.55 * opacity); int iconsize = 0; int currmag = currlayer->view->getmag(); if (showicons && currmag > 2) { // only show icons at scales 1:8 and above if (currmag == 3) { iconatlas = currlayer->atlas7x7; iconsize = 8; } else if (currmag == 4) { iconatlas = currlayer->atlas15x15; iconsize = 16; } else { iconatlas = currlayer->atlas31x31; iconsize = 32; } // DANGER: we're making assumptions about what CreateIconAtlas does in wxlayer.cpp if (live_alpha < 255) { // this is ugly, but we need to replace the alpha 255 values in iconatlas // with live_alpha so that LoadIconAtlas will load translucent icons ReplaceAlpha(iconsize, currlayer->numicons, 255, live_alpha); } // load iconatlas for use by DrawIcons LoadIconAtlas(iconsize, currlayer->numicons); } else if (currmag > 0) { LoadCellAtlas(1 << currmag, currlayer->numicons, live_alpha); } if (scalefactor > 1) { // temporarily change viewport scale to 1:1 and increase its size by scalefactor currlayer->view->setmag(0); currwd = currwd * scalefactor; currht = currht * scalefactor; currlayer->view->resize(currwd, currht); glPushMatrix(); glScalef(1.0/scalefactor, 1.0/scalefactor, 1.0); currlayer->algo->draw(*currlayer->view, renderer); // restore viewport settings currwd = currwd / scalefactor; currht = currht / scalefactor; currlayer->view->resize(currwd, currht); currlayer->view->setmag(currmag); // restore OpenGL scale glPopMatrix(); } else { currlayer->algo->draw(*currlayer->view, renderer); } if (showicons && currmag > 2 && live_alpha < 255) { // restore alpha values in iconatlas ReplaceAlpha(iconsize, currlayer->numicons, live_alpha, 255); } } // ----------------------------------------------------------------------------- void DrawStackedLayers() { // temporarily turn off grid lines bool saveshow = showgridlines; showgridlines = false; // overlay 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; if ( !currlayer->algo->isEmpty() ) { DrawOneLayer(); } // draw this layer's selection if necessary wxRect r; if ( currlayer->currsel.Visible(&r) ) { DrawSelection(r, i == currindex); } // restore viewport and currlayer currlayer->view = saveview; currlayer = savelayer; } showgridlines = saveshow; } // ----------------------------------------------------------------------------- void DrawTileFrame(wxRect& trect, int wd) { trect.Inflate(wd); wxRect r = trect; r.height = wd; FillRect(r.x, r.y, r.width, r.height); // top edge r.y += trect.height - wd; FillRect(r.x, r.y, r.width, r.height); // bottom edge r = trect; r.width = wd; FillRect(r.x, r.y, r.width, r.height); // left edge r.x += trect.width - wd; FillRect(r.x, r.y, r.width, r.height); // right edge } // ----------------------------------------------------------------------------- void DrawTileBorders() { 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 DisableTextures(); SetColor(144, 144, 144, 255); wxRect trect; for ( int i = 0; i < numlayers; i++ ) { if (i != currindex) { trect = GetLayer(i)->tilerect; DrawTileFrame(trect, tileborder); } } // draw green border around current tile trect = GetLayer(currindex)->tilerect; SetColor(0, 255, 0, 255); DrawTileFrame(trect, tileborder); } // ----------------------------------------------------------------------------- static bool firstview = true; void DrawView(int tileindex) { wxRect r; Layer* savelayer = NULL; viewport* saveview0 = NULL; int colorindex; int currmag = currlayer->view->getmag(); if (firstview) { firstview = false; // draw a tiny pixmap before calling DrawGridLines to avoid crash in NVIDIA driver // (this probably only happens on Windows but safer to do it on all platforms) unsigned char data[] = "RGBARGBARGBARGBA"; DrawRGBAData(data, 0, 0, 2, 2); // data has 4 pixels } // 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, currmag); else if ( currlayer->view->x > currlayer->algo->gridright ) currlayer->view->setpositionmag(currlayer->algo->gridright, currlayer->view->y, currmag); } if ( currlayer->algo->gridht > 0) { if ( currlayer->view->y < currlayer->algo->gridtop ) currlayer->view->setpositionmag(currlayer->view->x, currlayer->algo->gridtop, currmag); else if ( currlayer->view->y > currlayer->algo->gridbottom ) currlayer->view->setpositionmag(currlayer->view->x, currlayer->algo->gridbottom, currmag); } if ( viewptr->nopattupdate ) { // don't draw incomplete pattern, just fill background glClearColor(currlayer->cellr[0]/255.0, currlayer->cellg[0]/255.0, currlayer->cellb[0]/255.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); // might as well draw grid lines and border currwd = currlayer->view->getwidth(); currht = currlayer->view->getheight(); if ( viewptr->GridVisible() ) { DrawGridLines(currwd, currht); } if ( currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0 ) { DrawGridBorder(currwd, currht); } return; } if ( numlayers > 1 && tilelayers ) { if ( tileindex < 0 ) { DrawTileBorders(); // there's no need to fill bigview's background 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, currmag); } savelayer = currlayer; currlayer = GetLayer(tileindex); currmag = currlayer->view->getmag(); // possibly changed if not syncviews 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; } // fill the background with the current state 0 color // (note that currlayer might have changed) glClearColor(currlayer->cellr[0]/255.0, currlayer->cellg[0]/255.0, currlayer->cellb[0]/255.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); if (showicons && currmag > 2) { // only show icons at scales 1:8 and above if (currmag == 3) { iconatlas = currlayer->atlas7x7; LoadIconAtlas(8, currlayer->numicons); } else if (currmag == 4) { iconatlas = currlayer->atlas15x15; LoadIconAtlas(16, currlayer->numicons); } else { iconatlas = currlayer->atlas31x31; LoadIconAtlas(32, currlayer->numicons); } } else if (currmag > 0) { LoadCellAtlas(1 << currmag, currlayer->numicons, 255); } currwd = currlayer->view->getwidth(); currht = currlayer->view->getheight(); // all pixels are initially opaque dead_alpha = 255; live_alpha = 255; // draw pattern using a sequence of pixblit calls if (smartscale && currmag <= -1 && currmag >= -4) { // current scale is from 2^1:1 to 2^4:1 scalefactor = 1 << (-currmag); // temporarily change viewport scale to 1:1 and increase its size by scalefactor currlayer->view->setmag(0); currwd = currwd * scalefactor; currht = currht * scalefactor; currlayer->view->resize(currwd, currht); glPushMatrix(); glScalef(1.0/scalefactor, 1.0/scalefactor, 1.0); currlayer->algo->draw(*currlayer->view, renderer); // restore viewport settings currwd = currwd / scalefactor; currht = currht / scalefactor; currlayer->view->resize(currwd, currht); currlayer->view->setmag(currmag); // restore OpenGL scale glPopMatrix(); } else { // no scaling scalefactor = 1; currlayer->algo->draw(*currlayer->view, renderer); } if ( viewptr->GridVisible() ) { 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(); } if ( viewptr->waitingforclick && viewptr->pasterect.width > 0 ) { DrawPasteImage(); } if (viewptr->showcontrols) { DrawControls(viewptr->controlsrect); } if ( numlayers > 1 && tilelayers ) { // restore globals changed above currlayer = savelayer; viewptr = currlayer->tilewin; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/Rules/��������������������������������������������������������������������������������0000755�0001751�0001751�00000000000�12751756120�011401� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/Rules/Banks-II.rule�������������������������������������������������������������������0000644�0001751�0001751�00000000656�12525071110�013542� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TriTurmite_120010.rule����������������������������������������������������������0000644�0001751�0001751�00000074717�12525071110�015131� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Chou-Reggia-1.rule��������������������������������������������������������������0000644�0001751�0001751�00000014252�12525071110�014432� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Banks-III.rule������������������������������������������������������������������0000644�0001751�0001751�00000001533�12525071110�013646� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Banks-I.rule��������������������������������������������������������������������0000644�0001751�0001751�00000000446�12525071110�013426� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Byl-Loop.rule�������������������������������������������������������������������0000644�0001751�0001751�00000010432�12525071110�013633� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Turmite_121181121020.rule�������������������������������������������������������0000644�0001751�0001751�00000065016�12525071110�015122� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Devore.rule���������������������������������������������������������������������0000644�0001751�0001751�00000014426�12525071110�013431� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TreeGenerators/�����������������������������������������������������������������0000755�0001751�0001751�00000000000�12751756120�014332� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/Rules/TreeGenerators/RuleTreeGen.pl���������������������������������������������������0000644�0001751�0001751�00000002027�12525071110�016755� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TreeGenerators/LifeOnTheSlope.cpp�����������������������������������������������0000644�0001751�0001751�00000003146�12525071110�017566� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TreeGenerators/LifeOnTheEdge.cpp������������������������������������������������0000644�0001751�0001751�00000003034�12525071110�017344� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TreeGenerators/RuleTreeGen.java�������������������������������������������������0000644�0001751�0001751�00000003140�12525071110�017260� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TreeGenerators/RuleTreeGen.cpp��������������������������������������������������0000644�0001751�0001751�00000002700�12525071110�017122� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TreeGenerators/RuleTreeGen.py���������������������������������������������������0000644�0001751�0001751�00000003024�12525071110�016770� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TableGenerators/����������������������������������������������������������������0000755�0001751�0001751�00000000000�12751756120�014462� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/Rules/TableGenerators/make-ruletable.cpp����������������������������������������������0000644�0001751�0001751�00000056474�12525071110�020004� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Turmite_1202822111121111812a0281282.rule����������������������������������������0000644�0001751�0001751�00000167545�12525071110�016606� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Worm-1040512.rule���������������������������������������������������������������0000644�0001751�0001751�00000011251�12525071110�013734� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Sand-Margolus-emulated.rule�����������������������������������������������������0000644�0001751�0001751�00000006226�12525071110�016456� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Worm-1525115.rule���������������������������������������������������������������0000644�0001751�0001751�00000011351�12525071110�013744� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/SDSR-Loop.rule������������������������������������������������������������������0000644�0001751�0001751�00000035311�12525071110�013663� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Turmite_181181121010.rule�������������������������������������������������������0000644�0001751�0001751�00000065016�12525071110�015127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Codd2.rule����������������������������������������������������������������������0000644�0001751�0001751�00000021545�12525071110�013140� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/LifeHistory.rule����������������������������������������������������������������0000644�0001751�0001751�00000026222�12525071110�014443� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/HPP.rule������������������������������������������������������������������������0000644�0001751�0001751�00000064661�12525071110�012642� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Langtons-Loops.rule�������������������������������������������������������������0000644�0001751�0001751�00000015746�12525071110�015072� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/HPPMargolus_emulated.rule�������������������������������������������������������0000644�0001751�0001751�00000004261�12525071110�016222� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/WireWorld.rule������������������������������������������������������������������0000644�0001751�0001751�00000006056�12525071110�014123� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Tempesti.rule�������������������������������������������������������������������0000644�0001751�0001751�00000053205�12525071110�013775� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/AbsoluteTurmite_0N21S10E00S01W11N2.rule�����������������������������������������0000644�0001751�0001751�00000026337�12525071110�017547� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Worm-shared.rule����������������������������������������������������������������0000644�0001751�0001751�00000056602�12525071110�014377� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Worm-1042020.rule���������������������������������������������������������������0000644�0001751�0001751�00000011220�12525071110�013724� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Codd.rule�����������������������������������������������������������������������0000644�0001751�0001751�00000020161�12525071110�013047� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Ed-rep.rule���������������������������������������������������������������������0000644�0001751�0001751�00000002024�12525071110�013310� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Worm-1252121.rule���������������������������������������������������������������0000644�0001751�0001751�00000011351�12525071110�013736� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/LifeOnTheEdge.rule��������������������������������������������������������������0000644�0001751�0001751�00000012577�12525071110�014614� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/DLA-Margolus-emulated.rule������������������������������������������������������0000644�0001751�0001751�00000011070�12525071110�016162� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Life.rule�����������������������������������������������������������������������0000644�0001751�0001751�00000000441�12525071110�013054� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/BriansBrain.rule����������������������������������������������������������������0000644�0001751�0001751�00000000505�12525071110�014370� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Evoloop-finite.rule�������������������������������������������������������������0000644�0001751�0001751�00000010365�12525071110�015102� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Chou-Reggia-2.rule��������������������������������������������������������������0000644�0001751�0001751�00000006305�12525071110�014433� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Worm-1042015.rule���������������������������������������������������������������0000644�0001751�0001751�00000011272�12525071110�013737� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/LifeOnTheSlope.rule�������������������������������������������������������������0000644�0001751�0001751�00000010104�12525071110�015012� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Worm-complement.rule������������������������������������������������������������0000644�0001751�0001751�00000002565�12525071110�015273� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TripATronMargolus_emulated.rule�������������������������������������������������0000644�0001751�0001751�00000003577�12525071110�017466� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/LangtonsAnt_LLRR.rule�����������������������������������������������������������0000644�0001751�0001751�00000071753�12525071110�015276� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/TMGasMargolus_emulated.rule�����������������������������������������������������0000644�0001751�0001751�00000024217�12525071110�016551� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Sand-square4cyclic_emulated.rule������������������������������������������������0000644�0001751�0001751�00000035032�12525071110�017517� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/StarWars.rule�������������������������������������������������������������������0000644�0001751�0001751�00000000767�12525071110�013756� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Perrier.rule��������������������������������������������������������������������0000644�0001751�0001751�00000024547�12525071110�013622� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Banks-IV.rule�������������������������������������������������������������������0000644�0001751�0001751�00000001226�12525071110�013551� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/BBM-Margolus-emulated.rule������������������������������������������������������0000644�0001751�0001751�00000006527�12525071110�016175� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/AbsoluteTurmite_1N10S11S30N21W01N11S20E1.rule�����������������������������������0000644�0001751�0001751�00000034676�12525071110�020324� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/CrittersMargolus_emulated.rule��������������������������������������������������0000644�0001751�0001751�00000006707�12525071110�017401� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Langtons-Ant.rule���������������������������������������������������������������0000644�0001751�0001751�00000033360�12525071110�014510� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Caterpillars.rule���������������������������������������������������������������0000644�0001751�0001751�00000001024�12525071110�014620� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Evoloop.rule��������������������������������������������������������������������0000644�0001751�0001751�00000037607�12525071110�013636� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/AbsoluteTurmite_0S11W11E21S21W00N0.rule�����������������������������������������0000644�0001751�0001751�00000026371�12525071110�017557� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/Rules/Turmite_180121020081.rule�������������������������������������������������������0000644�0001751�0001751�00000064756�12525071110�015140� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������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.8-src/lua/����������������������������������������������������������������������������������0000755�0001751�0001751�00000000000�12675265511�011074� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lmathlib.c������������������������������������������������������������������������0000644�0001751�0001751�00000023225�12675241401�012750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lmathlib.c,v 1.117 2015/10/02 15:39:23 roberto Exp $ ** Standard mathematical library ** See Copyright Notice in lua.h */ #define lmathlib_c #define LUA_LIB #include "lprefix.h" #include <stdlib.h> #include <math.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" #undef PI #define PI (l_mathop(3.141592653589793238462643383279502884)) #if !defined(l_rand) /* { */ #if defined(LUA_USE_POSIX) #define l_rand() random() #define l_srand(x) srandom(x) #define L_RANDMAX 2147483647 /* (2^31 - 1), following POSIX */ #else #define l_rand() rand() #define l_srand(x) srand(x) #define L_RANDMAX RAND_MAX #endif #endif /* } */ static int math_abs (lua_State *L) { if (lua_isinteger(L, 1)) { lua_Integer n = lua_tointeger(L, 1); if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); lua_pushinteger(L, n); } else lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); return 1; } static int math_sin (lua_State *L) { lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); return 1; } static int math_cos (lua_State *L) { lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); return 1; } static int math_tan (lua_State *L) { lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); return 1; } static int math_asin (lua_State *L) { lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); return 1; } static int math_acos (lua_State *L) { lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); return 1; } static int math_atan (lua_State *L) { lua_Number y = luaL_checknumber(L, 1); lua_Number x = luaL_optnumber(L, 2, 1); lua_pushnumber(L, l_mathop(atan2)(y, x)); return 1; } static int math_toint (lua_State *L) { int valid; lua_Integer n = lua_tointegerx(L, 1, &valid); if (valid) lua_pushinteger(L, n); else { luaL_checkany(L, 1); lua_pushnil(L); /* value is not convertible to integer */ } return 1; } static void pushnumint (lua_State *L, lua_Number d) { lua_Integer n; if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ lua_pushinteger(L, n); /* result is integer */ else lua_pushnumber(L, d); /* result is float */ } static int math_floor (lua_State *L) { if (lua_isinteger(L, 1)) lua_settop(L, 1); /* integer is its own floor */ else { lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); pushnumint(L, d); } return 1; } static int math_ceil (lua_State *L) { if (lua_isinteger(L, 1)) lua_settop(L, 1); /* integer is its own ceil */ else { lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); pushnumint(L, d); } return 1; } static int math_fmod (lua_State *L) { if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { lua_Integer d = lua_tointeger(L, 2); if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ luaL_argcheck(L, d != 0, 2, "zero"); lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ } else lua_pushinteger(L, lua_tointeger(L, 1) % d); } else lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), luaL_checknumber(L, 2))); return 1; } /* ** next function does not use 'modf', avoiding problems with 'double*' ** (which is not compatible with 'float*') when lua_Number is not ** 'double'. */ static int math_modf (lua_State *L) { if (lua_isinteger(L ,1)) { lua_settop(L, 1); /* number is its own integer part */ lua_pushnumber(L, 0); /* no fractional part */ } else { lua_Number n = luaL_checknumber(L, 1); /* integer part (rounds toward zero) */ lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); pushnumint(L, ip); /* fractional part (test needed for inf/-inf) */ lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); } return 2; } static int math_sqrt (lua_State *L) { lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); return 1; } static int math_ult (lua_State *L) { lua_Integer a = luaL_checkinteger(L, 1); lua_Integer b = luaL_checkinteger(L, 2); lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); return 1; } static int math_log (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); lua_Number res; if (lua_isnoneornil(L, 2)) res = l_mathop(log)(x); else { lua_Number base = luaL_checknumber(L, 2); #if !defined(LUA_USE_C89) if (base == 2.0) res = l_mathop(log2)(x); else #endif if (base == 10.0) res = l_mathop(log10)(x); else res = l_mathop(log)(x)/l_mathop(log)(base); } lua_pushnumber(L, res); return 1; } static int math_exp (lua_State *L) { lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); return 1; } static int math_deg (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); return 1; } static int math_rad (lua_State *L) { lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); return 1; } static int math_min (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int imin = 1; /* index of current minimum value */ int i; luaL_argcheck(L, n >= 1, 1, "value expected"); for (i = 2; i <= n; i++) { if (lua_compare(L, i, imin, LUA_OPLT)) imin = i; } lua_pushvalue(L, imin); return 1; } static int math_max (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int imax = 1; /* index of current maximum value */ int i; luaL_argcheck(L, n >= 1, 1, "value expected"); for (i = 2; i <= n; i++) { if (lua_compare(L, imax, i, LUA_OPLT)) imax = i; } lua_pushvalue(L, imax); return 1; } /* ** This function uses 'double' (instead of 'lua_Number') to ensure that ** all bits from 'l_rand' can be represented, and that 'RANDMAX + 1.0' ** will keep full precision (ensuring that 'r' is always less than 1.0.) */ static int math_random (lua_State *L) { lua_Integer low, up; double r = (double)l_rand() * (1.0 / ((double)L_RANDMAX + 1.0)); switch (lua_gettop(L)) { /* check number of arguments */ case 0: { /* no arguments */ lua_pushnumber(L, (lua_Number)r); /* Number between 0 and 1 */ return 1; } case 1: { /* only upper limit */ low = 1; up = luaL_checkinteger(L, 1); break; } case 2: { /* lower and upper limits */ low = luaL_checkinteger(L, 1); up = luaL_checkinteger(L, 2); break; } default: return luaL_error(L, "wrong number of arguments"); } /* random integer in the interval [low, up] */ luaL_argcheck(L, low <= up, 1, "interval is empty"); luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1, "interval too large"); r *= (double)(up - low) + 1.0; lua_pushinteger(L, (lua_Integer)r + low); return 1; } static int math_randomseed (lua_State *L) { l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1)); (void)l_rand(); /* discard first value to avoid undesirable correlations */ return 0; } static int math_type (lua_State *L) { if (lua_type(L, 1) == LUA_TNUMBER) { if (lua_isinteger(L, 1)) lua_pushliteral(L, "integer"); else lua_pushliteral(L, "float"); } else { luaL_checkany(L, 1); lua_pushnil(L); } return 1; } /* ** {================================================================== ** Deprecated functions (for compatibility only) ** =================================================================== */ #if defined(LUA_COMPAT_MATHLIB) static int math_cosh (lua_State *L) { lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); return 1; } static int math_sinh (lua_State *L) { lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); return 1; } static int math_tanh (lua_State *L) { lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); return 1; } static int math_pow (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); lua_Number y = luaL_checknumber(L, 2); lua_pushnumber(L, l_mathop(pow)(x, y)); return 1; } static int math_frexp (lua_State *L) { int e; lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); lua_pushinteger(L, e); return 2; } static int math_ldexp (lua_State *L) { lua_Number x = luaL_checknumber(L, 1); int ep = (int)luaL_checkinteger(L, 2); lua_pushnumber(L, l_mathop(ldexp)(x, ep)); return 1; } static int math_log10 (lua_State *L) { lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); return 1; } #endif /* }================================================================== */ static const luaL_Reg mathlib[] = { {"abs", math_abs}, {"acos", math_acos}, {"asin", math_asin}, {"atan", math_atan}, {"ceil", math_ceil}, {"cos", math_cos}, {"deg", math_deg}, {"exp", math_exp}, {"tointeger", math_toint}, {"floor", math_floor}, {"fmod", math_fmod}, {"ult", math_ult}, {"log", math_log}, {"max", math_max}, {"min", math_min}, {"modf", math_modf}, {"rad", math_rad}, {"random", math_random}, {"randomseed", math_randomseed}, {"sin", math_sin}, {"sqrt", math_sqrt}, {"tan", math_tan}, {"type", math_type}, #if defined(LUA_COMPAT_MATHLIB) {"atan2", math_atan}, {"cosh", math_cosh}, {"sinh", math_sinh}, {"tanh", math_tanh}, {"pow", math_pow}, {"frexp", math_frexp}, {"ldexp", math_ldexp}, {"log10", math_log10}, #endif /* placeholders */ {"pi", NULL}, {"huge", NULL}, {"maxinteger", NULL}, {"mininteger", NULL}, {NULL, NULL} }; /* ** Open math library */ LUAMOD_API int luaopen_math (lua_State *L) { luaL_newlib(L, mathlib); lua_pushnumber(L, PI); lua_setfield(L, -2, "pi"); lua_pushnumber(L, (lua_Number)HUGE_VAL); lua_setfield(L, -2, "huge"); lua_pushinteger(L, LUA_MAXINTEGER); lua_setfield(L, -2, "maxinteger"); lua_pushinteger(L, LUA_MININTEGER); lua_setfield(L, -2, "mininteger"); return 1; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lapi.h����������������������������������������������������������������������������0000644�0001751�0001751�00000001035�12675241401�012101� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $ ** Auxiliary functions from Lua API ** See Copyright Notice in lua.h */ #ifndef lapi_h #define lapi_h #include "llimits.h" #include "lstate.h" #define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ "stack overflow");} #define adjustresults(L,nres) \ { if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } #define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ "not enough elements in the stack") #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/linit.c���������������������������������������������������������������������������0000644�0001751�0001751�00000003272�12675241401�012273� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $ ** Initialization of libraries for lua.c and other clients ** See Copyright Notice in lua.h */ #define linit_c #define LUA_LIB /* ** If you embed Lua in your program and need to open the standard ** libraries, call luaL_openlibs in your program. If you need a ** different set of libraries, copy this file to your project and edit ** it to suit your needs. ** ** You can also *preload* libraries, so that a later 'require' can ** open the library, which is already linked to the application. ** For that, do the following code: ** ** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); ** lua_pushcfunction(L, luaopen_modname); ** lua_setfield(L, -2, modname); ** lua_pop(L, 1); // remove _PRELOAD table */ #include "lprefix.h" #include <stddef.h> #include "lua.h" #include "lualib.h" #include "lauxlib.h" /* ** these libs are loaded by lua.c and are readily available to any Lua ** program */ static const luaL_Reg loadedlibs[] = { {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, #if defined(LUA_COMPAT_BITLIB) {LUA_BITLIBNAME, luaopen_bit32}, #endif {NULL, NULL} }; LUALIB_API void luaL_openlibs (lua_State *L) { const luaL_Reg *lib; /* "require" functions from 'loadedlibs' and set results to global table */ for (lib = loadedlibs; lib->func; lib++) { luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); /* remove lib */ } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lua.hpp���������������������������������������������������������������������������0000644�0001751�0001751�00000000277�12675241401�012304� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// lua.hpp // Lua header files for C++ // <<extern "C">> not supplied automatically because Lua also compiles as C++ extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lcorolib.c������������������������������������������������������������������������0000644�0001751�0001751�00000007250�12675241401�012761� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $ ** Coroutine Library ** See Copyright Notice in lua.h */ #define lcorolib_c #define LUA_LIB #include "lprefix.h" #include <stdlib.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" static lua_State *getco (lua_State *L) { lua_State *co = lua_tothread(L, 1); luaL_argcheck(L, co, 1, "thread expected"); return co; } static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) { lua_pushliteral(L, "too many arguments to resume"); return -1; /* error flag */ } if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } lua_xmove(L, co, narg); status = lua_resume(co, L, narg); if (status == LUA_OK || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres + 1)) { lua_pop(co, nres); /* remove results anyway */ lua_pushliteral(L, "too many results to resume"); return -1; /* error flag */ } lua_xmove(co, L, nres); /* move yielded values */ return nres; } else { lua_xmove(co, L, 1); /* move error message */ return -1; /* error flag */ } } static int luaB_coresume (lua_State *L) { lua_State *co = getco(L); int r; r = auxresume(L, co, lua_gettop(L) - 1); if (r < 0) { lua_pushboolean(L, 0); lua_insert(L, -2); return 2; /* return false + error message */ } else { lua_pushboolean(L, 1); lua_insert(L, -(r + 1)); return r + 1; /* return true + 'resume' returns */ } } static int luaB_auxwrap (lua_State *L) { lua_State *co = lua_tothread(L, lua_upvalueindex(1)); int r = auxresume(L, co, lua_gettop(L)); if (r < 0) { if (lua_isstring(L, -1)) { /* error object is a string? */ luaL_where(L, 1); /* add extra info */ lua_insert(L, -2); lua_concat(L, 2); } return lua_error(L); /* propagate error */ } return r; } static int luaB_cocreate (lua_State *L) { lua_State *NL; luaL_checktype(L, 1, LUA_TFUNCTION); NL = lua_newthread(L); lua_pushvalue(L, 1); /* move function to top */ lua_xmove(L, NL, 1); /* move function from L to NL */ return 1; } static int luaB_cowrap (lua_State *L) { luaB_cocreate(L); lua_pushcclosure(L, luaB_auxwrap, 1); return 1; } static int luaB_yield (lua_State *L) { return lua_yield(L, lua_gettop(L)); } static int luaB_costatus (lua_State *L) { lua_State *co = getco(L); if (L == co) lua_pushliteral(L, "running"); else { switch (lua_status(co)) { case LUA_YIELD: lua_pushliteral(L, "suspended"); break; case LUA_OK: { lua_Debug ar; if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ lua_pushliteral(L, "normal"); /* it is running */ else if (lua_gettop(co) == 0) lua_pushliteral(L, "dead"); else lua_pushliteral(L, "suspended"); /* initial state */ break; } default: /* some error occurred */ lua_pushliteral(L, "dead"); break; } } return 1; } static int luaB_yieldable (lua_State *L) { lua_pushboolean(L, lua_isyieldable(L)); return 1; } static int luaB_corunning (lua_State *L) { int ismain = lua_pushthread(L); lua_pushboolean(L, ismain); return 2; } static const luaL_Reg co_funcs[] = { {"create", luaB_cocreate}, {"resume", luaB_coresume}, {"running", luaB_corunning}, {"status", luaB_costatus}, {"wrap", luaB_cowrap}, {"yield", luaB_yield}, {"isyieldable", luaB_yieldable}, {NULL, NULL} }; LUAMOD_API int luaopen_coroutine (lua_State *L) { luaL_newlib(L, co_funcs); return 1; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lopcodes.c������������������������������������������������������������������������0000644�0001751�0001751�00000006726�12675241401�012773� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lopcodes.c,v 1.55 2015/01/05 13:48:33 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ #define lopcodes_c #define LUA_CORE #include "lprefix.h" #include <stddef.h> #include "lopcodes.h" /* ORDER OP */ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "MOVE", "LOADK", "LOADKX", "LOADBOOL", "LOADNIL", "GETUPVAL", "GETTABUP", "GETTABLE", "SETTABUP", "SETUPVAL", "SETTABLE", "NEWTABLE", "SELF", "ADD", "SUB", "MUL", "MOD", "POW", "DIV", "IDIV", "BAND", "BOR", "BXOR", "SHL", "SHR", "UNM", "BNOT", "NOT", "LEN", "CONCAT", "JMP", "EQ", "LT", "LE", "TEST", "TESTSET", "CALL", "TAILCALL", "RETURN", "FORLOOP", "FORPREP", "TFORCALL", "TFORLOOP", "SETLIST", "CLOSURE", "VARARG", "EXTRAARG", NULL }; #define opmode(t,a,b,c,m) (((t)<<7) | ((a)<<6) | ((b)<<4) | ((c)<<2) | (m)) LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { /* T A B C mode opcode */ opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_MOVE */ ,opmode(0, 1, OpArgK, OpArgN, iABx) /* OP_LOADK */ ,opmode(0, 1, OpArgN, OpArgN, iABx) /* OP_LOADKX */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_LOADBOOL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_LOADNIL */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_GETUPVAL */ ,opmode(0, 1, OpArgU, OpArgK, iABC) /* OP_GETTABUP */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_GETTABLE */ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABUP */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_SETUPVAL */ ,opmode(0, 0, OpArgK, OpArgK, iABC) /* OP_SETTABLE */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_NEWTABLE */ ,opmode(0, 1, OpArgR, OpArgK, iABC) /* OP_SELF */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_ADD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SUB */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MUL */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_MOD */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_POW */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_DIV */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_IDIV */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BAND */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BOR */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_BXOR */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHL */ ,opmode(0, 1, OpArgK, OpArgK, iABC) /* OP_SHR */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_UNM */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_BNOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_NOT */ ,opmode(0, 1, OpArgR, OpArgN, iABC) /* OP_LEN */ ,opmode(0, 1, OpArgR, OpArgR, iABC) /* OP_CONCAT */ ,opmode(0, 0, OpArgR, OpArgN, iAsBx) /* OP_JMP */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_EQ */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LT */ ,opmode(1, 0, OpArgK, OpArgK, iABC) /* OP_LE */ ,opmode(1, 0, OpArgN, OpArgU, iABC) /* OP_TEST */ ,opmode(1, 1, OpArgR, OpArgU, iABC) /* OP_TESTSET */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_CALL */ ,opmode(0, 1, OpArgU, OpArgU, iABC) /* OP_TAILCALL */ ,opmode(0, 0, OpArgU, OpArgN, iABC) /* OP_RETURN */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORLOOP */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_FORPREP */ ,opmode(0, 0, OpArgN, OpArgU, iABC) /* OP_TFORCALL */ ,opmode(0, 1, OpArgR, OpArgN, iAsBx) /* OP_TFORLOOP */ ,opmode(0, 0, OpArgU, OpArgU, iABC) /* OP_SETLIST */ ,opmode(0, 1, OpArgU, OpArgN, iABx) /* OP_CLOSURE */ ,opmode(0, 1, OpArgU, OpArgN, iABC) /* OP_VARARG */ ,opmode(0, 0, OpArgU, OpArgU, iAx) /* OP_EXTRAARG */ }; ������������������������������������������golly-2.8-src/lua/llex.h����������������������������������������������������������������������������0000644�0001751�0001751�00000004414�12675241401�012124� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #ifndef llex_h #define llex_h #include "lobject.h" #include "lzio.h" #define FIRST_RESERVED 257 #if !defined(LUA_ENV) #define LUA_ENV "_ENV" #endif /* * WARNING: if you change the order of this enumeration, * grep "ORDER RESERVED" */ enum RESERVED { /* terminal symbols denoted by reserved words */ TK_AND = FIRST_RESERVED, TK_BREAK, TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION, TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT, TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE, /* other terminal symbols */ TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_SHL, TK_SHR, TK_DBCOLON, TK_EOS, TK_FLT, TK_INT, TK_NAME, TK_STRING }; /* number of reserved words */ #define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1)) typedef union { lua_Number r; lua_Integer i; TString *ts; } SemInfo; /* semantics information */ typedef struct Token { int token; SemInfo seminfo; } Token; /* state of the lexer plus state of the parser when shared by all functions */ typedef struct LexState { int current; /* current character (charint) */ int linenumber; /* input line counter */ int lastline; /* line of last token 'consumed' */ Token t; /* current token */ Token lookahead; /* look ahead token */ struct FuncState *fs; /* current function (parser) */ struct lua_State *L; ZIO *z; /* input stream */ Mbuffer *buff; /* buffer for tokens */ Table *h; /* to avoid collection/reuse strings */ struct Dyndata *dyd; /* dynamic structures used by the parser */ TString *source; /* current source name */ TString *envn; /* environment variable name */ char decpoint; /* locale decimal point */ } LexState; LUAI_FUNC void luaX_init (lua_State *L); LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, int firstchar); LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l); LUAI_FUNC void luaX_next (LexState *ls); LUAI_FUNC int luaX_lookahead (LexState *ls); LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s); LUAI_FUNC const char *luaX_token2str (LexState *ls, int token); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lauxlib.h�������������������������������������������������������������������������0000644�0001751�0001751�00000020360�12675241401�012616� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ #ifndef lauxlib_h #define lauxlib_h #include <stddef.h> #include <stdio.h> #include "lua.h" /* extra error code for 'luaL_load' */ #define LUA_ERRFILE (LUA_ERRERR+1) typedef struct luaL_Reg { const char *name; lua_CFunction func; } luaL_Reg; #define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number)) LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz); #define luaL_checkversion(L) \ luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES) LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len); LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg); LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg, size_t *l); LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg, const char *def, size_t *l); LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg); LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def); LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg); LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg, lua_Integer def); LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t); LUALIB_API void (luaL_checkany) (lua_State *L, int arg); LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname); LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname); LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); LUALIB_API void (luaL_where) (lua_State *L, int lvl); LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def, const char *const lst[]); LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname); LUALIB_API int (luaL_execresult) (lua_State *L, int stat); /* predefined references */ #define LUA_NOREF (-2) #define LUA_REFNIL (-1) LUALIB_API int (luaL_ref) (lua_State *L, int t); LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, const char *mode); #define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL) LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode); LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); LUALIB_API lua_State *(luaL_newstate) (void); LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup); LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname); LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1, const char *msg, int level); LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, lua_CFunction openf, int glb); /* ** =============================================================== ** some useful macros ** =============================================================== */ #define luaL_newlibtable(L,l) \ lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1) #define luaL_newlib(L,l) \ (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) #define luaL_argcheck(L, cond,arg,extramsg) \ ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) #define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) #define luaL_dofile(L, fn) \ (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_dostring(L, s) \ (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) #define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) #define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ typedef struct luaL_Buffer { char *b; /* buffer address */ size_t size; /* buffer size */ size_t n; /* number of characters in buffer */ lua_State *L; char initb[LUAL_BUFFERSIZE]; /* initial buffer */ } luaL_Buffer; #define luaL_addchar(B,c) \ ((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \ ((B)->b[(B)->n++] = (c))) #define luaL_addsize(B,s) ((B)->n += (s)) LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz); LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz); LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz); #define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE) /* }====================================================== */ /* ** {====================================================== ** File handles for IO library ** ======================================================= */ /* ** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and ** initial structure 'luaL_Stream' (it may contain other fields ** after that initial structure). */ #define LUA_FILEHANDLE "FILE*" typedef struct luaL_Stream { FILE *f; /* stream (NULL for incompletely created streams) */ lua_CFunction closef; /* to close stream (NULL for closed streams) */ } luaL_Stream; /* }====================================================== */ /* compatibility with old module system */ #if defined(LUA_COMPAT_MODULE) LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname, int sizehint); LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, const luaL_Reg *l, int nup); #define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0)) #endif /* ** {================================================================== ** "Abstraction Layer" for basic report of messages and errors ** =================================================================== */ /* print a string */ #if !defined(lua_writestring) #define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout) #endif /* print a newline and flush the output */ #if !defined(lua_writeline) #define lua_writeline() (lua_writestring("\n", 1), fflush(stdout)) #endif /* print an error message */ #if !defined(lua_writestringerror) #define lua_writestringerror(s,p) \ (fprintf(stderr, (s), (p)), fflush(stderr)) #endif /* }================================================================== */ /* ** {============================================================ ** Compatibility with deprecated conversions ** ============================================================= */ #if defined(LUA_COMPAT_APIINTCASTS) #define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a)) #define luaL_optunsigned(L,a,d) \ ((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d))) #define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) #define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) #define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) #define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) #endif /* }============================================================ */ #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/luaconf.h�������������������������������������������������������������������������0000644�0001751�0001751�00000051101�12675241401�012602� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: luaconf.h,v 1.254 2015/10/21 18:17:40 roberto Exp $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ #ifndef luaconf_h #define luaconf_h #include <limits.h> #include <stddef.h> /* ** =================================================================== ** Search for "@@" to find all configurable definitions. ** =================================================================== */ /* ** {==================================================================== ** System Configuration: macros to adapt (if needed) Lua to some ** particular platform, for instance compiling it with 32-bit numbers or ** restricting it to C89. ** ===================================================================== */ /* @@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You ** can also define LUA_32BITS in the make file, but changing here you ** ensure that all software connected to Lua will be compiled with the ** same configuration. */ /* #define LUA_32BITS */ /* @@ LUA_USE_C89 controls the use of non-ISO-C89 features. ** Define it if you want Lua to avoid the use of a few C99 features ** or Windows-specific features on Windows. */ /* #define LUA_USE_C89 */ /* ** By default, Lua on Windows use (some) specific Windows features */ #if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) #define LUA_USE_WINDOWS /* enable goodies for regular Windows */ #endif #if defined(LUA_USE_WINDOWS) #define LUA_DL_DLL /* enable support for DLL */ #define LUA_USE_C89 /* broadly, Windows is C89 */ #endif #if defined(LUA_USE_LINUX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ #define LUA_USE_READLINE /* needs some extra libraries */ #endif #if defined(LUA_USE_MACOSX) #define LUA_USE_POSIX #define LUA_USE_DLOPEN /* MacOS does not need -ldl */ #define LUA_USE_READLINE /* needs an extra library: -lreadline */ #endif /* @@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for ** C89 ('long' and 'double'); Windows always has '__int64', so it does ** not need to use this case. */ #if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) #define LUA_C89_NUMBERS #endif /* @@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'. */ /* avoid undefined shifts */ #if ((INT_MAX >> 15) >> 15) >= 1 #define LUAI_BITSINT 32 #else /* 'int' always must have at least 16 bits */ #define LUAI_BITSINT 16 #endif /* @@ LUA_INT_TYPE defines the type for Lua integers. @@ LUA_FLOAT_TYPE defines the type for Lua floats. ** Lua should work fine with any mix of these options (if supported ** by your C compiler). The usual configurations are 64-bit integers ** and 'double' (the default), 32-bit integers and 'float' (for ** restricted platforms), and 'long'/'double' (for C compilers not ** compliant with C99, which may not have support for 'long long'). */ /* predefined options for LUA_INT_TYPE */ #define LUA_INT_INT 1 #define LUA_INT_LONG 2 #define LUA_INT_LONGLONG 3 /* predefined options for LUA_FLOAT_TYPE */ #define LUA_FLOAT_FLOAT 1 #define LUA_FLOAT_DOUBLE 2 #define LUA_FLOAT_LONGDOUBLE 3 #if defined(LUA_32BITS) /* { */ /* ** 32-bit integers and 'float' */ #if LUAI_BITSINT >= 32 /* use 'int' if big enough */ #define LUA_INT_TYPE LUA_INT_INT #else /* otherwise use 'long' */ #define LUA_INT_TYPE LUA_INT_LONG #endif #define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT #elif defined(LUA_C89_NUMBERS) /* }{ */ /* ** largest types available for C89 ('long' and 'double') */ #define LUA_INT_TYPE LUA_INT_LONG #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE #endif /* } */ /* ** default configuration for 64-bit Lua ('long long' and 'double') */ #if !defined(LUA_INT_TYPE) #define LUA_INT_TYPE LUA_INT_LONGLONG #endif #if !defined(LUA_FLOAT_TYPE) #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE #endif /* }================================================================== */ /* ** {================================================================== ** Configuration for Paths. ** =================================================================== */ /* @@ LUA_PATH_DEFAULT is the default path that Lua uses to look for ** Lua libraries. @@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for ** C libraries. ** CHANGE them if your machine has a non-conventional directory ** hierarchy or if you want to install your libraries in ** non-conventional directories. */ #define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #if defined(_WIN32) /* { */ /* ** In Windows, any exclamation mark ('!') in the path is replaced by the ** path of the directory of the executable file of the current process. */ #define LUA_LDIR "!\\lua\\" #define LUA_CDIR "!\\" #define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" #define LUA_PATH_DEFAULT \ LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ ".\\?.lua;" ".\\?\\init.lua" #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.dll;" \ LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ LUA_CDIR"loadall.dll;" ".\\?.dll" #else /* }{ */ #define LUA_ROOT "/usr/local/" #define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" #define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" #define LUA_PATH_DEFAULT \ LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ "./?.lua;" "./?/init.lua" #define LUA_CPATH_DEFAULT \ LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" #endif /* } */ /* @@ LUA_DIRSEP is the directory separator (for submodules). ** CHANGE it if your machine does not use "/" as the directory separator ** and is not Windows. (On Windows Lua automatically uses "\".) */ #if defined(_WIN32) #define LUA_DIRSEP "\\" #else #define LUA_DIRSEP "/" #endif /* }================================================================== */ /* ** {================================================================== ** Marks for exported symbols in the C code ** =================================================================== */ /* @@ LUA_API is a mark for all core API functions. @@ LUALIB_API is a mark for all auxiliary library functions. @@ LUAMOD_API is a mark for all standard library opening functions. ** CHANGE them if you need to define those functions in some special way. ** For instance, if you want to create one Windows DLL with the core and ** the libraries, you may want to use the following definition (define ** LUA_BUILD_AS_DLL to get it). */ #if defined(LUA_BUILD_AS_DLL) /* { */ #if defined(LUA_CORE) || defined(LUA_LIB) /* { */ #define LUA_API __declspec(dllexport) #else /* }{ */ #define LUA_API __declspec(dllimport) #endif /* } */ #else /* }{ */ #define LUA_API extern #endif /* } */ /* more often than not the libs go together with the core */ #define LUALIB_API LUA_API #define LUAMOD_API LUALIB_API /* @@ LUAI_FUNC is a mark for all extern functions that are not to be ** exported to outside modules. @@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables ** that are not to be exported to outside modules (LUAI_DDEF for ** definitions and LUAI_DDEC for declarations). ** CHANGE them if you need to mark them in some special way. Elf/gcc ** (versions 3.2 and later) mark them as "hidden" to optimize access ** when Lua is compiled as a shared library. Not all elf targets support ** this attribute. Unfortunately, gcc does not offer a way to check ** whether the target offers that support, and those without support ** give a warning about it. To avoid these warnings, change to the ** default definition. */ #if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ defined(__ELF__) /* { */ #define LUAI_FUNC __attribute__((visibility("hidden"))) extern #else /* }{ */ #define LUAI_FUNC extern #endif /* } */ #define LUAI_DDEC LUAI_FUNC #define LUAI_DDEF /* empty */ /* }================================================================== */ /* ** {================================================================== ** Compatibility with previous versions ** =================================================================== */ /* @@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2. @@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1. ** You can define it to get all options, or change specific options ** to fit your specific needs. */ #if defined(LUA_COMPAT_5_2) /* { */ /* @@ LUA_COMPAT_MATHLIB controls the presence of several deprecated ** functions in the mathematical library. */ #define LUA_COMPAT_MATHLIB /* @@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'. */ #define LUA_COMPAT_BITLIB /* @@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod. */ #define LUA_COMPAT_IPAIRS /* @@ LUA_COMPAT_APIINTCASTS controls the presence of macros for ** manipulating other integer types (lua_pushunsigned, lua_tounsigned, ** luaL_checkint, luaL_checklong, etc.) */ #define LUA_COMPAT_APIINTCASTS #endif /* } */ #if defined(LUA_COMPAT_5_1) /* { */ /* Incompatibilities from 5.2 -> 5.3 */ #define LUA_COMPAT_MATHLIB #define LUA_COMPAT_APIINTCASTS /* @@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'. ** You can replace it with 'table.unpack'. */ #define LUA_COMPAT_UNPACK /* @@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'. ** You can replace it with 'package.searchers'. */ #define LUA_COMPAT_LOADERS /* @@ macro 'lua_cpcall' emulates deprecated function lua_cpcall. ** You can call your C function directly (with light C functions). */ #define lua_cpcall(L,f,u) \ (lua_pushcfunction(L, (f)), \ lua_pushlightuserdata(L,(u)), \ lua_pcall(L,1,0,0)) /* @@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library. ** You can rewrite 'log10(x)' as 'log(x, 10)'. */ #define LUA_COMPAT_LOG10 /* @@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base ** library. You can rewrite 'loadstring(s)' as 'load(s)'. */ #define LUA_COMPAT_LOADSTRING /* @@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library. */ #define LUA_COMPAT_MAXN /* @@ The following macros supply trivial compatibility for some ** changes in the API. The macros themselves document how to ** change your code to avoid using them. */ #define lua_strlen(L,i) lua_rawlen(L, (i)) #define lua_objlen(L,i) lua_rawlen(L, (i)) #define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) #define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) /* @@ LUA_COMPAT_MODULE controls compatibility with previous ** module functions 'module' (Lua) and 'luaL_register' (C). */ #define LUA_COMPAT_MODULE #endif /* } */ /* @@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a @@ a float mark ('.0'). ** This macro is not on by default even in compatibility mode, ** because this is not really an incompatibility. */ /* #define LUA_COMPAT_FLOATSTRING */ /* }================================================================== */ /* ** {================================================================== ** Configuration for Numbers. ** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* ** satisfy your needs. ** =================================================================== */ /* @@ LUA_NUMBER is the floating-point type used by Lua. @@ LUAI_UACNUMBER is the result of an 'usual argument conversion' @@ over a floating number. @@ l_mathlim(x) corrects limit name 'x' to the proper float type ** by prefixing it with one of FLT/DBL/LDBL. @@ LUA_NUMBER_FRMLEN is the length modifier for writing floats. @@ LUA_NUMBER_FMT is the format for writing floats. @@ lua_number2str converts a float to a string. @@ l_mathop allows the addition of an 'l' or 'f' to all math operations. @@ l_floor takes the floor of a float. @@ lua_str2number converts a decimal numeric string to a number. */ /* The following definitions are good for most cases here */ #define l_floor(x) (l_mathop(floor)(x)) #define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n)) /* @@ lua_numbertointeger converts a float number to an integer, or ** returns 0 if float is not within the range of a lua_Integer. ** (The range comparisons are tricky because of rounding. The tests ** here assume a two-complement representation, where MININTEGER always ** has an exact representation as a float; MAXINTEGER may not have one, ** and therefore its conversion to float may have an ill-defined value.) */ #define lua_numbertointeger(n,p) \ ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \ (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \ (*(p) = (LUA_INTEGER)(n), 1)) /* now the variable definitions */ #if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */ #define LUA_NUMBER float #define l_mathlim(n) (FLT_##n) #define LUAI_UACNUMBER double #define LUA_NUMBER_FRMLEN "" #define LUA_NUMBER_FMT "%.7g" #define l_mathop(op) op##f #define lua_str2number(s,p) strtof((s), (p)) #elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ #define LUA_NUMBER long double #define l_mathlim(n) (LDBL_##n) #define LUAI_UACNUMBER long double #define LUA_NUMBER_FRMLEN "L" #define LUA_NUMBER_FMT "%.19Lg" #define l_mathop(op) op##l #define lua_str2number(s,p) strtold((s), (p)) #elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ #define LUA_NUMBER double #define l_mathlim(n) (DBL_##n) #define LUAI_UACNUMBER double #define LUA_NUMBER_FRMLEN "" #define LUA_NUMBER_FMT "%.14g" #define l_mathop(op) op #define lua_str2number(s,p) strtod((s), (p)) #else /* }{ */ #error "numeric float type not defined" #endif /* } */ /* @@ LUA_INTEGER is the integer type used by Lua. ** @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. ** @@ LUAI_UACINT is the result of an 'usual argument conversion' @@ over a lUA_INTEGER. @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. @@ LUA_INTEGER_FMT is the format for writing integers. @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. @@ lua_integer2str converts an integer to a string. */ /* The following definitions are good for most cases here */ #define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" #define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n)) #define LUAI_UACINT LUA_INTEGER /* ** use LUAI_UACINT here to avoid problems with promotions (which ** can turn a comparison between unsigneds into a signed comparison) */ #define LUA_UNSIGNED unsigned LUAI_UACINT /* now the variable definitions */ #if LUA_INT_TYPE == LUA_INT_INT /* { int */ #define LUA_INTEGER int #define LUA_INTEGER_FRMLEN "" #define LUA_MAXINTEGER INT_MAX #define LUA_MININTEGER INT_MIN #elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ #define LUA_INTEGER long #define LUA_INTEGER_FRMLEN "l" #define LUA_MAXINTEGER LONG_MAX #define LUA_MININTEGER LONG_MIN #elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */ /* use presence of macro LLONG_MAX as proxy for C99 compliance */ #if defined(LLONG_MAX) /* { */ /* use ISO C99 stuff */ #define LUA_INTEGER long long #define LUA_INTEGER_FRMLEN "ll" #define LUA_MAXINTEGER LLONG_MAX #define LUA_MININTEGER LLONG_MIN #elif defined(LUA_USE_WINDOWS) /* }{ */ /* in Windows, can use specific Windows types */ #define LUA_INTEGER __int64 #define LUA_INTEGER_FRMLEN "I64" #define LUA_MAXINTEGER _I64_MAX #define LUA_MININTEGER _I64_MIN #else /* }{ */ #error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" #endif /* } */ #else /* }{ */ #error "numeric integer type not defined" #endif /* } */ /* }================================================================== */ /* ** {================================================================== ** Dependencies with C99 and other C details ** =================================================================== */ /* @@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89. ** (All uses in Lua have only one format item.) */ #if !defined(LUA_USE_C89) #define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i) #else #define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i)) #endif /* @@ lua_strx2number converts an hexadecimal numeric string to a number. ** In C99, 'strtod' does that conversion. Otherwise, you can ** leave 'lua_strx2number' undefined and Lua will provide its own ** implementation. */ #if !defined(LUA_USE_C89) #define lua_strx2number(s,p) lua_str2number(s,p) #endif /* @@ lua_number2strx converts a float to an hexadecimal numeric string. ** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. ** Otherwise, you can leave 'lua_number2strx' undefined and Lua will ** provide its own implementation. */ #if !defined(LUA_USE_C89) #define lua_number2strx(L,b,sz,f,n) l_sprintf(b,sz,f,n) #endif /* ** 'strtof' and 'opf' variants for math functions are not valid in ** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the ** availability of these variants. ('math.h' is already included in ** all files that use these macros.) */ #if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) #undef l_mathop /* variants not available */ #undef lua_str2number #define l_mathop(op) (lua_Number)op /* no variant */ #define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) #endif /* @@ LUA_KCONTEXT is the type of the context ('ctx') for continuation ** functions. It must be a numerical type; Lua will use 'intptr_t' if ** available, otherwise it will use 'ptrdiff_t' (the nearest thing to ** 'intptr_t' in C89) */ #define LUA_KCONTEXT ptrdiff_t #if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ __STDC_VERSION__ >= 199901L #include <stdint.h> #if defined(INTPTR_MAX) /* even in C99 this type is optional */ #undef LUA_KCONTEXT #define LUA_KCONTEXT intptr_t #endif #endif /* @@ lua_getlocaledecpoint gets the locale "radix character" (decimal point). ** Change that if you do not want to use C locales. (Code using this ** macro must include header 'locale.h'.) */ #if !defined(lua_getlocaledecpoint) #define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) #endif /* }================================================================== */ /* ** {================================================================== ** Language Variations ** ===================================================================== */ /* @@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some ** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from ** numbers to strings. Define LUA_NOCVTS2N to turn off automatic ** coercion from strings to numbers. */ /* #define LUA_NOCVTN2S */ /* #define LUA_NOCVTS2N */ /* @@ LUA_USE_APICHECK turns on several consistency checks on the C API. ** Define it as a help when debugging C code. */ #if defined(LUA_USE_APICHECK) #include <assert.h> #define luai_apicheck(l,e) assert(e) #endif /* }================================================================== */ /* ** {================================================================== ** Macros that affect the API and must be stable (that is, must be the ** same when you compile Lua and when you compile code that links to ** Lua). You probably do not want/need to change them. ** ===================================================================== */ /* @@ LUAI_MAXSTACK limits the size of the Lua stack. ** CHANGE it if you need a different limit. This limit is arbitrary; ** its only purpose is to stop Lua from consuming unlimited stack ** space (and to reserve some numbers for pseudo-indices). */ #if LUAI_BITSINT >= 32 #define LUAI_MAXSTACK 1000000 #else #define LUAI_MAXSTACK 15000 #endif /* @@ LUA_EXTRASPACE defines the size of a raw memory area associated with ** a Lua state with very fast access. ** CHANGE it if you need a different size. */ #define LUA_EXTRASPACE (sizeof(void *)) /* @@ LUA_IDSIZE gives the maximum size for the description of the source @@ of a function in debug information. ** CHANGE it if you want a different size. */ #define LUA_IDSIZE 60 /* @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. ** CHANGE it if it uses too much C-stack space. (For long double, ** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a ** smaller buffer would force a memory allocation for each call to ** 'string.format'.) */ #if defined(LUA_FLOAT_LONGDOUBLE) #define LUAL_BUFFERSIZE 8192 #else #define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer))) #endif /* }================================================================== */ /* @@ LUA_QL describes how error messages quote program elements. ** Lua does not use these macros anymore; they are here for ** compatibility only. */ #define LUA_QL(x) "'" x "'" #define LUA_QS LUA_QL("%s") /* =================================================================== */ /* ** Local configuration. You can use this space to add your redefinitions ** without modifying the main part of the file. */ #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lbaselib.c������������������������������������������������������������������������0000644�0001751�0001751�00000032760�12675241401�012735� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lbaselib.c,v 1.312 2015/10/29 15:21:04 roberto Exp $ ** Basic library ** See Copyright Notice in lua.h */ #define lbaselib_c #define LUA_LIB #include "lprefix.h" #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" static int luaB_print (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; lua_getglobal(L, "tostring"); for (i=1; i<=n; i++) { const char *s; size_t l; lua_pushvalue(L, -1); /* function to be called */ lua_pushvalue(L, i); /* value to print */ lua_call(L, 1, 1); s = lua_tolstring(L, -1, &l); /* get result */ if (s == NULL) return luaL_error(L, "'tostring' must return a string to 'print'"); if (i>1) lua_writestring("\t", 1); lua_writestring(s, l); lua_pop(L, 1); /* pop result */ } lua_writeline(); return 0; } #define SPACECHARS " \f\n\r\t\v" static const char *b_str2int (const char *s, int base, lua_Integer *pn) { lua_Unsigned n = 0; int neg = 0; s += strspn(s, SPACECHARS); /* skip initial spaces */ if (*s == '-') { s++; neg = 1; } /* handle signal */ else if (*s == '+') s++; if (!isalnum((unsigned char)*s)) /* no digit? */ return NULL; do { int digit = (isdigit((unsigned char)*s)) ? *s - '0' : (toupper((unsigned char)*s) - 'A') + 10; if (digit >= base) return NULL; /* invalid numeral */ n = n * base + digit; s++; } while (isalnum((unsigned char)*s)); s += strspn(s, SPACECHARS); /* skip trailing spaces */ *pn = (lua_Integer)((neg) ? (0u - n) : n); return s; } static int luaB_tonumber (lua_State *L) { if (lua_isnoneornil(L, 2)) { /* standard conversion? */ luaL_checkany(L, 1); if (lua_type(L, 1) == LUA_TNUMBER) { /* already a number? */ lua_settop(L, 1); /* yes; return it */ return 1; } else { size_t l; const char *s = lua_tolstring(L, 1, &l); if (s != NULL && lua_stringtonumber(L, s) == l + 1) return 1; /* successful conversion to number */ /* else not a number */ } } else { size_t l; const char *s; lua_Integer n = 0; /* to avoid warnings */ lua_Integer base = luaL_checkinteger(L, 2); luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */ s = lua_tolstring(L, 1, &l); luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range"); if (b_str2int(s, (int)base, &n) == s + l) { lua_pushinteger(L, n); return 1; } /* else not a number */ } /* else not a number */ lua_pushnil(L); /* not a number */ return 1; } static int luaB_error (lua_State *L) { int level = (int)luaL_optinteger(L, 2, 1); lua_settop(L, 1); if (lua_isstring(L, 1) && level > 0) { /* add extra information? */ luaL_where(L, level); lua_pushvalue(L, 1); lua_concat(L, 2); } return lua_error(L); } static int luaB_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); return 1; /* no metatable */ } luaL_getmetafield(L, 1, "__metatable"); return 1; /* returns either __metatable field (if present) or metatable */ } static int luaB_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_checktype(L, 1, LUA_TTABLE); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) return luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; } static int luaB_rawequal (lua_State *L) { luaL_checkany(L, 1); luaL_checkany(L, 2); lua_pushboolean(L, lua_rawequal(L, 1, 2)); return 1; } static int luaB_rawlen (lua_State *L) { int t = lua_type(L, 1); luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1, "table or string expected"); lua_pushinteger(L, lua_rawlen(L, 1)); return 1; } static int luaB_rawget (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); lua_settop(L, 2); lua_rawget(L, 1); return 1; } static int luaB_rawset (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); luaL_checkany(L, 3); lua_settop(L, 3); lua_rawset(L, 1); return 1; } static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", "step", "setpause", "setstepmul", "isrunning", NULL}; static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, LUA_GCISRUNNING}; int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; int ex = (int)luaL_optinteger(L, 2, 0); int res = lua_gc(L, o, ex); switch (o) { case LUA_GCCOUNT: { int b = lua_gc(L, LUA_GCCOUNTB, 0); lua_pushnumber(L, (lua_Number)res + ((lua_Number)b/1024)); return 1; } case LUA_GCSTEP: case LUA_GCISRUNNING: { lua_pushboolean(L, res); return 1; } default: { lua_pushinteger(L, res); return 1; } } } static int luaB_type (lua_State *L) { int t = lua_type(L, 1); luaL_argcheck(L, t != LUA_TNONE, 1, "value expected"); lua_pushstring(L, lua_typename(L, t)); return 1; } static int pairsmeta (lua_State *L, const char *method, int iszero, lua_CFunction iter) { if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */ luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */ lua_pushcfunction(L, iter); /* will return generator, */ lua_pushvalue(L, 1); /* state, */ if (iszero) lua_pushinteger(L, 0); /* and initial value */ else lua_pushnil(L); } else { lua_pushvalue(L, 1); /* argument 'self' to metamethod */ lua_call(L, 1, 3); /* get 3 values from metamethod */ } return 3; } static int luaB_next (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 2); /* create a 2nd argument if there isn't one */ if (lua_next(L, 1)) return 2; else { lua_pushnil(L); return 1; } } static int luaB_pairs (lua_State *L) { return pairsmeta(L, "__pairs", 0, luaB_next); } /* ** Traversal function for 'ipairs' */ static int ipairsaux (lua_State *L) { lua_Integer i = luaL_checkinteger(L, 2) + 1; lua_pushinteger(L, i); return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; } /* ** This function will use either 'ipairsaux' or 'ipairsaux_raw' to ** traverse a table, depending on whether the table has metamethods ** that can affect the traversal. */ static int luaB_ipairs (lua_State *L) { #if defined(LUA_COMPAT_IPAIRS) return pairsmeta(L, "__ipairs", 1, ipairsaux); #else luaL_checkany(L, 1); lua_pushcfunction(L, ipairsaux); /* iteration function */ lua_pushvalue(L, 1); /* state */ lua_pushinteger(L, 0); /* initial value */ return 3; #endif } static int load_aux (lua_State *L, int status, int envidx) { if (status == LUA_OK) { if (envidx != 0) { /* 'env' parameter? */ lua_pushvalue(L, envidx); /* environment for loaded function */ if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ lua_pop(L, 1); /* remove 'env' if not used by previous call */ } return 1; } else { /* error (message is on top of the stack) */ lua_pushnil(L); lua_insert(L, -2); /* put before error message */ return 2; /* return nil plus error message */ } } static int luaB_loadfile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); const char *mode = luaL_optstring(L, 2, NULL); int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */ int status = luaL_loadfilex(L, fname, mode); return load_aux(L, status, env); } /* ** {====================================================== ** Generic Read function ** ======================================================= */ /* ** reserved slot, above all arguments, to hold a copy of the returned ** string to avoid it being collected while parsed. 'load' has four ** optional arguments (chunk, source name, mode, and environment). */ #define RESERVEDSLOT 5 /* ** Reader for generic 'load' function: 'lua_load' uses the ** stack for internal stuff, so the reader cannot change the ** stack top. Instead, it keeps its resulting string in a ** reserved slot inside the stack. */ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { (void)(ud); /* not used */ luaL_checkstack(L, 2, "too many nested functions"); lua_pushvalue(L, 1); /* get function */ lua_call(L, 0, 1); /* call it */ if (lua_isnil(L, -1)) { lua_pop(L, 1); /* pop result */ *size = 0; return NULL; } else if (!lua_isstring(L, -1)) luaL_error(L, "reader function must return a string"); lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ return lua_tolstring(L, RESERVEDSLOT, size); } static int luaB_load (lua_State *L) { int status; size_t l; const char *s = lua_tolstring(L, 1, &l); const char *mode = luaL_optstring(L, 3, "bt"); int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */ if (s != NULL) { /* loading a string? */ const char *chunkname = luaL_optstring(L, 2, s); status = luaL_loadbufferx(L, s, l, chunkname, mode); } else { /* loading from a reader function */ const char *chunkname = luaL_optstring(L, 2, "=(load)"); luaL_checktype(L, 1, LUA_TFUNCTION); lua_settop(L, RESERVEDSLOT); /* create reserved slot */ status = lua_load(L, generic_reader, NULL, chunkname, mode); } return load_aux(L, status, env); } /* }====================================================== */ static int dofilecont (lua_State *L, int d1, lua_KContext d2) { (void)d1; (void)d2; /* only to match 'lua_Kfunction' prototype */ return lua_gettop(L) - 1; } static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); lua_settop(L, 1); if (luaL_loadfile(L, fname) != LUA_OK) return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); return dofilecont(L, 0, 0); } static int luaB_assert (lua_State *L) { if (lua_toboolean(L, 1)) /* condition is true? */ return lua_gettop(L); /* return all arguments */ else { /* error */ luaL_checkany(L, 1); /* there must be a condition */ lua_remove(L, 1); /* remove it */ lua_pushliteral(L, "assertion failed!"); /* default message */ lua_settop(L, 1); /* leave only message (default if no other one) */ return luaB_error(L); /* call 'error' */ } } static int luaB_select (lua_State *L) { int n = lua_gettop(L); if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') { lua_pushinteger(L, n-1); return 1; } else { lua_Integer i = luaL_checkinteger(L, 1); if (i < 0) i = n + i; else if (i > n) i = n; luaL_argcheck(L, 1 <= i, 1, "index out of range"); return n - (int)i; } } /* ** Continuation function for 'pcall' and 'xpcall'. Both functions ** already pushed a 'true' before doing the call, so in case of success ** 'finishpcall' only has to return everything in the stack minus ** 'extra' values (where 'extra' is exactly the number of items to be ** ignored). */ static int finishpcall (lua_State *L, int status, lua_KContext extra) { if (status != LUA_OK && status != LUA_YIELD) { /* error? */ lua_pushboolean(L, 0); /* first result (false) */ lua_pushvalue(L, -2); /* error message */ return 2; /* return false, msg */ } else return lua_gettop(L) - (int)extra; /* return all results */ } static int luaB_pcall (lua_State *L) { int status; luaL_checkany(L, 1); lua_pushboolean(L, 1); /* first result if no errors */ lua_insert(L, 1); /* put it in place */ status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, finishpcall); return finishpcall(L, status, 0); } /* ** Do a protected call with error handling. After 'lua_rotate', the ** stack will have <f, err, true, f, [args...]>; so, the function passes ** 2 to 'finishpcall' to skip the 2 first values when returning results. */ static int luaB_xpcall (lua_State *L) { int status; int n = lua_gettop(L); luaL_checktype(L, 2, LUA_TFUNCTION); /* check error function */ lua_pushboolean(L, 1); /* first result */ lua_pushvalue(L, 1); /* function */ lua_rotate(L, 3, 2); /* move them below function's arguments */ status = lua_pcallk(L, n - 2, LUA_MULTRET, 2, 2, finishpcall); return finishpcall(L, status, 2); } static int luaB_tostring (lua_State *L) { luaL_checkany(L, 1); luaL_tolstring(L, 1, NULL); return 1; } static const luaL_Reg base_funcs[] = { {"assert", luaB_assert}, {"collectgarbage", luaB_collectgarbage}, {"dofile", luaB_dofile}, {"error", luaB_error}, {"getmetatable", luaB_getmetatable}, {"ipairs", luaB_ipairs}, {"loadfile", luaB_loadfile}, {"load", luaB_load}, #if defined(LUA_COMPAT_LOADSTRING) {"loadstring", luaB_load}, #endif {"next", luaB_next}, {"pairs", luaB_pairs}, {"pcall", luaB_pcall}, {"print", luaB_print}, {"rawequal", luaB_rawequal}, {"rawlen", luaB_rawlen}, {"rawget", luaB_rawget}, {"rawset", luaB_rawset}, {"select", luaB_select}, {"setmetatable", luaB_setmetatable}, {"tonumber", luaB_tonumber}, {"tostring", luaB_tostring}, {"type", luaB_type}, {"xpcall", luaB_xpcall}, /* placeholders */ {"_G", NULL}, {"_VERSION", NULL}, {NULL, NULL} }; LUAMOD_API int luaopen_base (lua_State *L) { /* open lib into global table */ lua_pushglobaltable(L); luaL_setfuncs(L, base_funcs, 0); /* set global _G */ lua_pushvalue(L, -1); lua_setfield(L, -2, "_G"); /* set global _VERSION */ lua_pushliteral(L, LUA_VERSION); lua_setfield(L, -2, "_VERSION"); return 1; } ����������������golly-2.8-src/lua/lstring.c�������������������������������������������������������������������������0000644�0001751�0001751�00000014662�12675241401�012643� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ #define lstring_c #define LUA_CORE #include "lprefix.h" #include <string.h> #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #define MEMERRMSG "not enough memory" /* ** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to ** compute its hash */ #if !defined(LUAI_HASHLIMIT) #define LUAI_HASHLIMIT 5 #endif /* ** equality for long strings */ int luaS_eqlngstr (TString *a, TString *b) { size_t len = a->u.lnglen; lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR); return (a == b) || /* same instance or... */ ((len == b->u.lnglen) && /* equal length and ... */ (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ } unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) { unsigned int h = seed ^ cast(unsigned int, l); size_t step = (l >> LUAI_HASHLIMIT) + 1; for (; l >= step; l -= step) h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1])); return h; } unsigned int luaS_hashlongstr (TString *ts) { lua_assert(ts->tt == LUA_TLNGSTR); if (ts->extra == 0) { /* no hash? */ ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash); ts->extra = 1; /* now it has its hash */ } return ts->hash; } /* ** resizes the string table */ void luaS_resize (lua_State *L, int newsize) { int i; stringtable *tb = &G(L)->strt; if (newsize > tb->size) { /* grow table if needed */ luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL; } for (i = 0; i < tb->size; i++) { /* rehash */ TString *p = tb->hash[i]; tb->hash[i] = NULL; while (p) { /* for each node in the list */ TString *hnext = p->u.hnext; /* save next */ unsigned int h = lmod(p->hash, newsize); /* new position */ p->u.hnext = tb->hash[h]; /* chain it */ tb->hash[h] = p; p = hnext; } } if (newsize < tb->size) { /* shrink table if needed */ /* vanishing slice should be empty */ lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); } tb->size = newsize; } /* ** Clear API string cache. (Entries cannot be empty, so fill them with ** a non-collectable string.) */ void luaS_clearcache (global_State *g) { int i, j; for (i = 0; i < STRCACHE_N; i++) for (j = 0; j < STRCACHE_M; j++) { if (iswhite(g->strcache[i][j])) /* will entry be collected? */ g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */ } } /* ** Initialize the string table and the string cache */ void luaS_init (lua_State *L) { global_State *g = G(L); int i, j; luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ /* pre-create memory-error message */ g->memerrmsg = luaS_newliteral(L, MEMERRMSG); luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */ for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */ for (j = 0; j < STRCACHE_M; j++) g->strcache[i][j] = g->memerrmsg; } /* ** creates a new string object */ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { TString *ts; GCObject *o; size_t totalsize; /* total size of TString object */ totalsize = sizelstring(l); o = luaC_newobj(L, tag, totalsize); ts = gco2ts(o); ts->hash = h; ts->extra = 0; getstr(ts)[l] = '\0'; /* ending 0 */ return ts; } TString *luaS_createlngstrobj (lua_State *L, size_t l) { TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed); ts->u.lnglen = l; return ts; } void luaS_remove (lua_State *L, TString *ts) { stringtable *tb = &G(L)->strt; TString **p = &tb->hash[lmod(ts->hash, tb->size)]; while (*p != ts) /* find previous element */ p = &(*p)->u.hnext; *p = (*p)->u.hnext; /* remove element from its list */ tb->nuse--; } /* ** checks whether short string exists and reuses it or creates a new one */ static TString *internshrstr (lua_State *L, const char *str, size_t l) { TString *ts; global_State *g = G(L); unsigned int h = luaS_hash(str, l, g->seed); TString **list = &g->strt.hash[lmod(h, g->strt.size)]; lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ for (ts = *list; ts != NULL; ts = ts->u.hnext) { if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { /* found! */ if (isdead(g, ts)) /* dead (but not collected yet)? */ changewhite(ts); /* resurrect it */ return ts; } } if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { luaS_resize(L, g->strt.size * 2); list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ } ts = createstrobj(L, l, LUA_TSHRSTR, h); memcpy(getstr(ts), str, l * sizeof(char)); ts->shrlen = cast_byte(l); ts->u.hnext = *list; *list = ts; g->strt.nuse++; return ts; } /* ** new string (with explicit length) */ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { if (l <= LUAI_MAXSHORTLEN) /* short string? */ return internshrstr(L, str, l); else { TString *ts; if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char)) luaM_toobig(L); ts = luaS_createlngstrobj(L, l); memcpy(getstr(ts), str, l * sizeof(char)); return ts; } } /* ** Create or reuse a zero-terminated string, first checking in the ** cache (using the string address as a key). The cache can contain ** only zero-terminated strings, so it is safe to use 'strcmp' to ** check hits. */ TString *luaS_new (lua_State *L, const char *str) { unsigned int i = point2uint(str) % STRCACHE_N; /* hash */ int j; TString **p = G(L)->strcache[i]; for (j = 0; j < STRCACHE_M; j++) { if (strcmp(str, getstr(p[j])) == 0) /* hit? */ return p[j]; /* that is it */ } /* normal route */ for (j = STRCACHE_M - 1; j > 0; j--) p[j] = p[j - 1]; /* move out last element */ /* new element is first in the list */ p[0] = luaS_newlstr(L, str, strlen(str)); return p[0]; } Udata *luaS_newudata (lua_State *L, size_t s) { Udata *u; GCObject *o; if (s > MAX_SIZE - sizeof(Udata)) luaM_toobig(L); o = luaC_newobj(L, LUA_TUSERDATA, sizeludata(s)); u = gco2u(o); u->len = s; u->metatable = NULL; setuservalue(L, u, luaO_nilobject); return u; } ������������������������������������������������������������������������������golly-2.8-src/lua/lvm.h�����������������������������������������������������������������������������0000644�0001751�0001751�00000007263�12675241401�011763� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lvm.h,v 2.39 2015/09/09 13:44:07 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ #ifndef lvm_h #define lvm_h #include "ldo.h" #include "lobject.h" #include "ltm.h" #if !defined(LUA_NOCVTN2S) #define cvt2str(o) ttisnumber(o) #else #define cvt2str(o) 0 /* no conversion from numbers to strings */ #endif #if !defined(LUA_NOCVTS2N) #define cvt2num(o) ttisstring(o) #else #define cvt2num(o) 0 /* no conversion from strings to numbers */ #endif /* ** You can define LUA_FLOORN2I if you want to convert floats to integers ** by flooring them (instead of raising an error if they are not ** integral values) */ #if !defined(LUA_FLOORN2I) #define LUA_FLOORN2I 0 #endif #define tonumber(o,n) \ (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n)) #define tointeger(o,i) \ (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) #define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2) /* ** fast track for 'gettable': 1 means 'aux' points to resulted value; ** 0 means 'aux' is metamethod (if 't' is a table) or NULL. 'f' is ** the raw get function to use. */ #define luaV_fastget(L,t,k,aux,f) \ (!ttistable(t) \ ? (aux = NULL, 0) /* not a table; 'aux' is NULL and result is 0 */ \ : (aux = f(hvalue(t), k), /* else, do raw access */ \ !ttisnil(aux) ? 1 /* result not nil? 'aux' has it */ \ : (aux = fasttm(L, hvalue(t)->metatable, TM_INDEX), /* get metamethod */\ aux != NULL ? 0 /* has metamethod? must call it */ \ : (aux = luaO_nilobject, 1)))) /* else, final result is nil */ /* ** standard implementation for 'gettable' */ #define luaV_gettable(L,t,k,v) { const TValue *aux; \ if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ else luaV_finishget(L,t,k,v,aux); } /* ** Fast track for set table. If 't' is a table and 't[k]' is not nil, ** call GC barrier, do a raw 't[k]=v', and return true; otherwise, ** return false with 'slot' equal to NULL (if 't' is not a table) or ** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro ** returns true, there is no need to 'invalidateTMcache', because the ** call is not creating a new entry. */ #define luaV_fastset(L,t,k,slot,f,v) \ (!ttistable(t) \ ? (slot = NULL, 0) \ : (slot = f(hvalue(t), k), \ ttisnil(slot) ? 0 \ : (luaC_barrierback(L, hvalue(t), v), \ setobj2t(L, cast(TValue *,slot), v), \ 1))) #define luaV_settable(L,t,k,v) { const TValue *slot; \ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ luaV_finishset(L,t,k,v,slot); } LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r); LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n); LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode); LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *tm); LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *oldval); LUAI_FUNC void luaV_finishOp (lua_State *L); LUAI_FUNC void luaV_execute (lua_State *L); LUAI_FUNC void luaV_concat (lua_State *L, int total); LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y); LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/ldebug.c��������������������������������������������������������������������������0000644�0001751�0001751�00000045447�12675241401�012430� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ldebug.c,v 2.117 2015/11/02 18:48:07 roberto Exp $ ** Debug Interface ** See Copyright Notice in lua.h */ #define ldebug_c #define LUA_CORE #include "lprefix.h" #include <stdarg.h> #include <stddef.h> #include <string.h> #include "lua.h" #include "lapi.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lvm.h" #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL) /* Active Lua function (given call info) */ #define ci_func(ci) (clLvalue((ci)->func)) static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name); static int currentpc (CallInfo *ci) { lua_assert(isLua(ci)); return pcRel(ci->u.l.savedpc, ci_func(ci)->p); } static int currentline (CallInfo *ci) { return getfuncline(ci_func(ci)->p, currentpc(ci)); } /* ** If function yielded, its 'func' can be in the 'extra' field. The ** next function restores 'func' to its correct value for debugging ** purposes. (It exchanges 'func' and 'extra'; so, when called again, ** after debugging, it also "re-restores" ** 'func' to its altered value. */ static void swapextra (lua_State *L) { if (L->status == LUA_YIELD) { CallInfo *ci = L->ci; /* get function that yielded */ StkId temp = ci->func; /* exchange its 'func' and 'extra' values */ ci->func = restorestack(L, ci->extra); ci->extra = savestack(L, temp); } } /* ** this function can be called asynchronous (e.g. during a signal) */ LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) { if (func == NULL || mask == 0) { /* turn off hooks? */ mask = 0; func = NULL; } if (isLua(L->ci)) L->oldpc = L->ci->u.l.savedpc; L->hook = func; L->basehookcount = count; resethookcount(L); L->hookmask = cast_byte(mask); } LUA_API lua_Hook lua_gethook (lua_State *L) { return L->hook; } LUA_API int lua_gethookmask (lua_State *L) { return L->hookmask; } LUA_API int lua_gethookcount (lua_State *L) { return L->basehookcount; } LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) { int status; CallInfo *ci; if (level < 0) return 0; /* invalid (negative) level */ lua_lock(L); for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous) level--; if (level == 0 && ci != &L->base_ci) { /* level found? */ status = 1; ar->i_ci = ci; } else status = 0; /* no such level */ lua_unlock(L); return status; } static const char *upvalname (Proto *p, int uv) { TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name); if (s == NULL) return "?"; else return getstr(s); } static const char *findvararg (CallInfo *ci, int n, StkId *pos) { int nparams = clLvalue(ci->func)->p->numparams; if (n >= cast_int(ci->u.l.base - ci->func) - nparams) return NULL; /* no such vararg */ else { *pos = ci->func + nparams + n; return "(*vararg)"; /* generic name for any vararg */ } } static const char *findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { const char *name = NULL; StkId base; if (isLua(ci)) { if (n < 0) /* access to vararg values? */ return findvararg(ci, -n, pos); else { base = ci->u.l.base; name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); } } else base = ci->func + 1; if (name == NULL) { /* no 'standard' name? */ StkId limit = (ci == L->ci) ? L->top : ci->next->func; if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ name = "(*temporary)"; /* generic name for any valid slot */ else return NULL; /* no name */ } *pos = base + (n - 1); return name; } LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) { const char *name; lua_lock(L); swapextra(L); if (ar == NULL) { /* information about non-active function? */ if (!isLfunction(L->top - 1)) /* not a Lua function? */ name = NULL; else /* consider live variables at function start (parameters) */ name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0); } else { /* active function; get information through 'ar' */ StkId pos = NULL; /* to avoid warnings */ name = findlocal(L, ar->i_ci, n, &pos); if (name) { setobj2s(L, L->top, pos); api_incr_top(L); } } swapextra(L); lua_unlock(L); return name; } LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { StkId pos = NULL; /* to avoid warnings */ const char *name; lua_lock(L); swapextra(L); name = findlocal(L, ar->i_ci, n, &pos); if (name) { setobjs2s(L, pos, L->top - 1); L->top--; /* pop value */ } swapextra(L); lua_unlock(L); return name; } static void funcinfo (lua_Debug *ar, Closure *cl) { if (noLuaClosure(cl)) { ar->source = "=[C]"; ar->linedefined = -1; ar->lastlinedefined = -1; ar->what = "C"; } else { Proto *p = cl->l.p; ar->source = p->source ? getstr(p->source) : "=?"; ar->linedefined = p->linedefined; ar->lastlinedefined = p->lastlinedefined; ar->what = (ar->linedefined == 0) ? "main" : "Lua"; } luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE); } static void collectvalidlines (lua_State *L, Closure *f) { if (noLuaClosure(f)) { setnilvalue(L->top); api_incr_top(L); } else { int i; TValue v; int *lineinfo = f->l.p->lineinfo; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue(L, L->top, t); /* push it on stack */ api_incr_top(L); setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */ for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */ luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */ } } static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, Closure *f, CallInfo *ci) { int status = 1; for (; *what; what++) { switch (*what) { case 'S': { funcinfo(ar, f); break; } case 'l': { ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1; break; } case 'u': { ar->nups = (f == NULL) ? 0 : f->c.nupvalues; if (noLuaClosure(f)) { ar->isvararg = 1; ar->nparams = 0; } else { ar->isvararg = f->l.p->is_vararg; ar->nparams = f->l.p->numparams; } break; } case 't': { ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0; break; } case 'n': { /* calling function is a known Lua function? */ if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous)) ar->namewhat = getfuncname(L, ci->previous, &ar->name); else ar->namewhat = NULL; if (ar->namewhat == NULL) { ar->namewhat = ""; /* not found */ ar->name = NULL; } break; } case 'L': case 'f': /* handled by lua_getinfo */ break; default: status = 0; /* invalid option */ } } return status; } LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { int status; Closure *cl; CallInfo *ci; StkId func; lua_lock(L); swapextra(L); if (*what == '>') { ci = NULL; func = L->top - 1; api_check(L, ttisfunction(func), "function expected"); what++; /* skip the '>' */ L->top--; /* pop function */ } else { ci = ar->i_ci; func = ci->func; lua_assert(ttisfunction(ci->func)); } cl = ttisclosure(func) ? clvalue(func) : NULL; status = auxgetinfo(L, what, ar, cl, ci); if (strchr(what, 'f')) { setobjs2s(L, L->top, func); api_incr_top(L); } swapextra(L); /* correct before option 'L', which can raise a mem. error */ if (strchr(what, 'L')) collectvalidlines(L, cl); lua_unlock(L); return status; } /* ** {====================================================== ** Symbolic Execution ** ======================================================= */ static const char *getobjname (Proto *p, int lastpc, int reg, const char **name); /* ** find a "name" for the RK value 'c' */ static void kname (Proto *p, int pc, int c, const char **name) { if (ISK(c)) { /* is 'c' a constant? */ TValue *kvalue = &p->k[INDEXK(c)]; if (ttisstring(kvalue)) { /* literal constant? */ *name = svalue(kvalue); /* it is its own name */ return; } /* else no reasonable name found */ } else { /* 'c' is a register */ const char *what = getobjname(p, pc, c, name); /* search for 'c' */ if (what && *what == 'c') { /* found a constant name? */ return; /* 'name' already filled */ } /* else no reasonable name found */ } *name = "?"; /* no reasonable name found */ } static int filterpc (int pc, int jmptarget) { if (pc < jmptarget) /* is code conditional (inside a jump)? */ return -1; /* cannot know who sets that register */ else return pc; /* current position sets that register */ } /* ** try to find last instruction before 'lastpc' that modified register 'reg' */ static int findsetreg (Proto *p, int lastpc, int reg) { int pc; int setreg = -1; /* keep last instruction that changed 'reg' */ int jmptarget = 0; /* any code before this address is conditional */ for (pc = 0; pc < lastpc; pc++) { Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); int a = GETARG_A(i); switch (op) { case OP_LOADNIL: { int b = GETARG_B(i); if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */ setreg = filterpc(pc, jmptarget); break; } case OP_TFORCALL: { if (reg >= a + 2) /* affect all regs above its base */ setreg = filterpc(pc, jmptarget); break; } case OP_CALL: case OP_TAILCALL: { if (reg >= a) /* affect all registers above base */ setreg = filterpc(pc, jmptarget); break; } case OP_JMP: { int b = GETARG_sBx(i); int dest = pc + 1 + b; /* jump is forward and do not skip 'lastpc'? */ if (pc < dest && dest <= lastpc) { if (dest > jmptarget) jmptarget = dest; /* update 'jmptarget' */ } break; } default: if (testAMode(op) && reg == a) /* any instruction that set A */ setreg = filterpc(pc, jmptarget); break; } } return setreg; } static const char *getobjname (Proto *p, int lastpc, int reg, const char **name) { int pc; *name = luaF_getlocalname(p, reg + 1, lastpc); if (*name) /* is a local? */ return "local"; /* else try symbolic execution */ pc = findsetreg(p, lastpc, reg); if (pc != -1) { /* could find instruction? */ Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); switch (op) { case OP_MOVE: { int b = GETARG_B(i); /* move from 'b' to 'a' */ if (b < GETARG_A(i)) return getobjname(p, pc, b, name); /* get name for 'b' */ break; } case OP_GETTABUP: case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ int t = GETARG_B(i); /* table index */ const char *vn = (op == OP_GETTABLE) /* name of indexed variable */ ? luaF_getlocalname(p, t + 1, pc) : upvalname(p, t); kname(p, pc, k, name); return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field"; } case OP_GETUPVAL: { *name = upvalname(p, GETARG_B(i)); return "upvalue"; } case OP_LOADK: case OP_LOADKX: { int b = (op == OP_LOADK) ? GETARG_Bx(i) : GETARG_Ax(p->code[pc + 1]); if (ttisstring(&p->k[b])) { *name = svalue(&p->k[b]); return "constant"; } break; } case OP_SELF: { int k = GETARG_C(i); /* key index */ kname(p, pc, k, name); return "method"; } default: break; /* go through to return NULL */ } } return NULL; /* could not find reasonable name */ } static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) { TMS tm = (TMS)0; /* to avoid warnings */ Proto *p = ci_func(ci)->p; /* calling function */ int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->code[pc]; /* calling instruction */ if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ *name = "?"; return "hook"; } switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: /* get function name */ return getobjname(p, pc, GETARG_A(i), name); case OP_TFORCALL: { /* for iterator */ *name = "for iterator"; return "for iterator"; } /* all other instructions can call only through metamethods */ case OP_SELF: case OP_GETTABUP: case OP_GETTABLE: tm = TM_INDEX; break; case OP_SETTABUP: case OP_SETTABLE: tm = TM_NEWINDEX; break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_MOD: case OP_POW: case OP_DIV: case OP_IDIV: case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: { int offset = cast_int(GET_OPCODE(i)) - cast_int(OP_ADD); /* ORDER OP */ tm = cast(TMS, offset + cast_int(TM_ADD)); /* ORDER TM */ break; } case OP_UNM: tm = TM_UNM; break; case OP_BNOT: tm = TM_BNOT; break; case OP_LEN: tm = TM_LEN; break; case OP_CONCAT: tm = TM_CONCAT; break; case OP_EQ: tm = TM_EQ; break; case OP_LT: tm = TM_LT; break; case OP_LE: tm = TM_LE; break; default: lua_assert(0); /* other instructions cannot call a function */ } *name = getstr(G(L)->tmname[tm]); return "metamethod"; } /* }====================================================== */ /* ** The subtraction of two potentially unrelated pointers is ** not ISO C, but it should not crash a program; the subsequent ** checks are ISO C and ensure a correct result. */ static int isinstack (CallInfo *ci, const TValue *o) { ptrdiff_t i = o - ci->u.l.base; return (0 <= i && i < (ci->top - ci->u.l.base) && ci->u.l.base + i == o); } /* ** Checks whether value 'o' came from an upvalue. (That can only happen ** with instructions OP_GETTABUP/OP_SETTABUP, which operate directly on ** upvalues.) */ static const char *getupvalname (CallInfo *ci, const TValue *o, const char **name) { LClosure *c = ci_func(ci); int i; for (i = 0; i < c->nupvalues; i++) { if (c->upvals[i]->v == o) { *name = upvalname(c->p, i); return "upvalue"; } } return NULL; } static const char *varinfo (lua_State *L, const TValue *o) { const char *name = NULL; /* to avoid warnings */ CallInfo *ci = L->ci; const char *kind = NULL; if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ if (!kind && isinstack(ci, o)) /* no? try a register */ kind = getobjname(ci_func(ci)->p, currentpc(ci), cast_int(o - ci->u.l.base), &name); } return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; } l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { const char *t = objtypename(o); luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); } l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2) { if (ttisstring(p1) || cvt2str(p1)) p1 = p2; luaG_typeerror(L, p1, "concatenate"); } l_noret luaG_opinterror (lua_State *L, const TValue *p1, const TValue *p2, const char *msg) { lua_Number temp; if (!tonumber(p1, &temp)) /* first operand is wrong? */ p2 = p1; /* now second is wrong */ luaG_typeerror(L, p2, msg); } /* ** Error when both values are convertible to numbers, but not to integers */ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { lua_Integer temp; if (!tointeger(p1, &temp)) p2 = p1; luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); } l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) { const char *t1 = objtypename(p1); const char *t2 = objtypename(p2); if (t1 == t2) luaG_runerror(L, "attempt to compare two %s values", t1); else luaG_runerror(L, "attempt to compare %s with %s", t1, t2); } /* add src:line information to 'msg' */ const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, int line) { char buff[LUA_IDSIZE]; if (src) luaO_chunkid(buff, getstr(src), LUA_IDSIZE); else { /* no source available; use "?" instead */ buff[0] = '?'; buff[1] = '\0'; } return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg); } l_noret luaG_errormsg (lua_State *L) { if (L->errfunc != 0) { /* is there an error handling function? */ StkId errfunc = restorestack(L, L->errfunc); setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ L->top++; /* assume EXTRA_STACK */ luaD_callnoyield(L, L->top - 2, 1); /* call it */ } luaD_throw(L, LUA_ERRRUN); } l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { CallInfo *ci = L->ci; const char *msg; va_list argp; va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); /* format message */ va_end(argp); if (isLua(ci)) /* if Lua function, add source:line information */ luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci)); luaG_errormsg(L); } void luaG_traceexec (lua_State *L) { CallInfo *ci = L->ci; lu_byte mask = L->hookmask; int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); if (counthook) resethookcount(L); /* reset count */ else if (!(mask & LUA_MASKLINE)) return; /* no line hook and count != 0; nothing to be done */ if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return; /* do not call hook again (VM yielded, so it did not move) */ } if (counthook) luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ if (mask & LUA_MASKLINE) { Proto *p = ci_func(ci)->p; int npc = pcRel(ci->u.l.savedpc, p); int newline = getfuncline(p, npc); if (npc == 0 || /* call linehook when enter a new function, */ ci->u.l.savedpc <= L->oldpc || /* when jump back (loop), or when */ newline != getfuncline(p, pcRel(L->oldpc, p))) /* enter a new line */ luaD_hook(L, LUA_HOOKLINE, newline); /* call line hook */ } L->oldpc = ci->u.l.savedpc; if (L->status == LUA_YIELD) { /* did hook yield? */ if (counthook) L->hookcount = 1; /* undo decrement to zero */ ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ ci->func = L->top - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/ltm.c�����������������������������������������������������������������������������0000644�0001751�0001751�00000007775�12675241401�011764� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ltm.c,v 2.36 2015/11/03 15:47:30 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ #define ltm_c #define LUA_CORE #include "lprefix.h" #include <string.h> #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lvm.h" static const char udatatypename[] = "userdata"; LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { "no value", "nil", "boolean", udatatypename, "number", "string", "table", "function", udatatypename, "thread", "proto" /* this last case is used for tests only */ }; void luaT_init (lua_State *L) { static const char *const luaT_eventname[] = { /* ORDER TM */ "__index", "__newindex", "__gc", "__mode", "__len", "__eq", "__add", "__sub", "__mul", "__mod", "__pow", "__div", "__idiv", "__band", "__bor", "__bxor", "__shl", "__shr", "__unm", "__bnot", "__lt", "__le", "__concat", "__call" }; int i; for (i=0; i<TM_N; i++) { G(L)->tmname[i] = luaS_new(L, luaT_eventname[i]); luaC_fix(L, obj2gco(G(L)->tmname[i])); /* never collect these names */ } } /* ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *tm = luaH_getshortstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast_byte(1u<<event); /* cache this fact */ return NULL; } else return tm; } const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) { Table *mt; switch (ttnov(o)) { case LUA_TTABLE: mt = hvalue(o)->metatable; break; case LUA_TUSERDATA: mt = uvalue(o)->metatable; break; default: mt = G(L)->mt[ttnov(o)]; } return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject); } void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, TValue *p3, int hasres) { ptrdiff_t result = savestack(L, p3); StkId func = L->top; setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ setobj2s(L, func + 1, p1); /* 1st argument */ setobj2s(L, func + 2, p2); /* 2nd argument */ L->top += 3; if (!hasres) /* no result? 'p3' is third argument */ setobj2s(L, L->top++, p3); /* 3rd argument */ /* metamethod may yield only when called from Lua code */ if (isLua(L->ci)) luaD_call(L, func, hasres); else luaD_callnoyield(L, func, hasres); if (hasres) { /* if has result, move it to its place */ p3 = restorestack(L, result); setobjs2s(L, p3, --L->top); } } int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; luaT_callTM(L, tm, p1, p2, res, 1); return 1; } void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { if (!luaT_callbinTM(L, p1, p2, res, event)) { switch (event) { case TM_CONCAT: luaG_concaterror(L, p1, p2); /* call never returns, but to avoid warnings: *//* FALLTHROUGH */ case TM_BAND: case TM_BOR: case TM_BXOR: case TM_SHL: case TM_SHR: case TM_BNOT: { lua_Number dummy; if (tonumber(p1, &dummy) && tonumber(p2, &dummy)) luaG_tointerror(L, p1, p2); else luaG_opinterror(L, p1, p2, "perform bitwise operation on"); } /* calls never return, but to avoid warnings: *//* FALLTHROUGH */ default: luaG_opinterror(L, p1, p2, "perform arithmetic on"); } } } int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { if (!luaT_callbinTM(L, p1, p2, L->top, event)) return -1; /* no metamethod */ else return !l_isfalse(L->top); } ���golly-2.8-src/lua/llex.c����������������������������������������������������������������������������0000644�0001751�0001751�00000041256�12675241401�012124� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: llex.c,v 2.95 2015/11/19 19:16:22 roberto Exp $ ** Lexical Analyzer ** See Copyright Notice in lua.h */ #define llex_c #define LUA_CORE #include "lprefix.h" #include <locale.h> #include <string.h> #include "lua.h" #include "lctype.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "llex.h" #include "lobject.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "lzio.h" #define next(ls) (ls->current = zgetc(ls->z)) #define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r') /* ORDER RESERVED */ static const char *const luaX_tokens [] = { "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "goto", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while", "//", "..", "...", "==", ">=", "<=", "~=", "<<", ">>", "::", "<eof>", "<number>", "<integer>", "<name>", "<string>" }; #define save_and_next(ls) (save(ls, ls->current), next(ls)) static l_noret lexerror (LexState *ls, const char *msg, int token); static void save (LexState *ls, int c) { Mbuffer *b = ls->buff; if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) { size_t newsize; if (luaZ_sizebuffer(b) >= MAX_SIZE/2) lexerror(ls, "lexical element too long", 0); newsize = luaZ_sizebuffer(b) * 2; luaZ_resizebuffer(ls->L, b, newsize); } b->buffer[luaZ_bufflen(b)++] = cast(char, c); } void luaX_init (lua_State *L) { int i; TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */ luaC_fix(L, obj2gco(e)); /* never collect this name */ for (i=0; i<NUM_RESERVED; i++) { TString *ts = luaS_new(L, luaX_tokens[i]); luaC_fix(L, obj2gco(ts)); /* reserved words are never collected */ ts->extra = cast_byte(i+1); /* reserved word */ } } const char *luaX_token2str (LexState *ls, int token) { if (token < FIRST_RESERVED) { /* single-byte symbols? */ lua_assert(token == cast_uchar(token)); return luaO_pushfstring(ls->L, "'%c'", token); } else { const char *s = luaX_tokens[token - FIRST_RESERVED]; if (token < TK_EOS) /* fixed format (symbols and reserved words)? */ return luaO_pushfstring(ls->L, "'%s'", s); else /* names, strings, and numerals */ return s; } } static const char *txtToken (LexState *ls, int token) { switch (token) { case TK_NAME: case TK_STRING: case TK_FLT: case TK_INT: save(ls, '\0'); return luaO_pushfstring(ls->L, "'%s'", luaZ_buffer(ls->buff)); default: return luaX_token2str(ls, token); } } static l_noret lexerror (LexState *ls, const char *msg, int token) { msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber); if (token) luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token)); luaD_throw(ls->L, LUA_ERRSYNTAX); } l_noret luaX_syntaxerror (LexState *ls, const char *msg) { lexerror(ls, msg, ls->t.token); } /* ** creates a new string and anchors it in scanner's table so that ** it will not be collected until the end of the compilation ** (by that time it should be anchored somewhere) */ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; TValue *o; /* entry for 'str' */ TString *ts = luaS_newlstr(L, str, l); /* create new string */ setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ o = luaH_set(L, ls->h, L->top - 1); if (ttisnil(o)) { /* not in use yet? */ /* boolean value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setbvalue(o, 1); /* t[string] = true */ luaC_checkGC(L); } else { /* string already present */ ts = tsvalue(keyfromval(o)); /* re-use value previously stored */ } L->top--; /* remove string from stack */ return ts; } /* ** increment line number and skips newline sequence (any of ** \n, \r, \n\r, or \r\n) */ static void inclinenumber (LexState *ls) { int old = ls->current; lua_assert(currIsNewline(ls)); next(ls); /* skip '\n' or '\r' */ if (currIsNewline(ls) && ls->current != old) next(ls); /* skip '\n\r' or '\r\n' */ if (++ls->linenumber >= MAX_INT) lexerror(ls, "chunk has too many lines", 0); } void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source, int firstchar) { ls->t.token = 0; ls->decpoint = '.'; ls->L = L; ls->current = firstchar; ls->lookahead.token = TK_EOS; /* no look-ahead token */ ls->z = z; ls->fs = NULL; ls->linenumber = 1; ls->lastline = 1; ls->source = source; ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */ luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */ } /* ** ======================================================= ** LEXICAL ANALYZER ** ======================================================= */ static int check_next1 (LexState *ls, int c) { if (ls->current == c) { next(ls); return 1; } else return 0; } /* ** Check whether current char is in set 'set' (with two chars) and ** saves it */ static int check_next2 (LexState *ls, const char *set) { lua_assert(set[2] == '\0'); if (ls->current == set[0] || ls->current == set[1]) { save_and_next(ls); return 1; } else return 0; } /* ** change all characters 'from' in buffer to 'to' */ static void buffreplace (LexState *ls, char from, char to) { if (from != to) { size_t n = luaZ_bufflen(ls->buff); char *p = luaZ_buffer(ls->buff); while (n--) if (p[n] == from) p[n] = to; } } /* ** in case of format error, try to change decimal point separator to ** the one defined in the current locale and check again */ static void trydecpoint (LexState *ls, TValue *o) { char old = ls->decpoint; ls->decpoint = lua_getlocaledecpoint(); buffreplace(ls, old, ls->decpoint); /* try new decimal separator */ if (luaO_str2num(luaZ_buffer(ls->buff), o) == 0) { /* format error with correct decimal point: no more options */ buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */ lexerror(ls, "malformed number", TK_FLT); } } /* LUA_NUMBER */ /* ** this function is quite liberal in what it accepts, as 'luaO_str2num' ** will reject ill-formed numerals. */ static int read_numeral (LexState *ls, SemInfo *seminfo) { TValue obj; const char *expo = "Ee"; int first = ls->current; lua_assert(lisdigit(ls->current)); save_and_next(ls); if (first == '0' && check_next2(ls, "xX")) /* hexadecimal? */ expo = "Pp"; for (;;) { if (check_next2(ls, expo)) /* exponent part? */ check_next2(ls, "-+"); /* optional exponent sign */ if (lisxdigit(ls->current)) save_and_next(ls); else if (ls->current == '.') save_and_next(ls); else break; } save(ls, '\0'); buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */ if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */ trydecpoint(ls, &obj); /* try to update decimal point separator */ if (ttisinteger(&obj)) { seminfo->i = ivalue(&obj); return TK_INT; } else { lua_assert(ttisfloat(&obj)); seminfo->r = fltvalue(&obj); return TK_FLT; } } /* ** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return ** its number of '='s; otherwise, return a negative number (-1 iff there ** are no '='s after initial bracket) */ static int skip_sep (LexState *ls) { int count = 0; int s = ls->current; lua_assert(s == '[' || s == ']'); save_and_next(ls); while (ls->current == '=') { save_and_next(ls); count++; } return (ls->current == s) ? count : (-count) - 1; } static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) { int line = ls->linenumber; /* initial line (for error message) */ save_and_next(ls); /* skip 2nd '[' */ if (currIsNewline(ls)) /* string starts with a newline? */ inclinenumber(ls); /* skip it */ for (;;) { switch (ls->current) { case EOZ: { /* error */ const char *what = (seminfo ? "string" : "comment"); const char *msg = luaO_pushfstring(ls->L, "unfinished long %s (starting at line %d)", what, line); lexerror(ls, msg, TK_EOS); break; /* to avoid warnings */ } case ']': { if (skip_sep(ls) == sep) { save_and_next(ls); /* skip 2nd ']' */ goto endloop; } break; } case '\n': case '\r': { save(ls, '\n'); inclinenumber(ls); if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */ break; } default: { if (seminfo) save_and_next(ls); else next(ls); } } } endloop: if (seminfo) seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep), luaZ_bufflen(ls->buff) - 2*(2 + sep)); } static void esccheck (LexState *ls, int c, const char *msg) { if (!c) { if (ls->current != EOZ) save_and_next(ls); /* add current to buffer for error message */ lexerror(ls, msg, TK_STRING); } } static int gethexa (LexState *ls) { save_and_next(ls); esccheck (ls, lisxdigit(ls->current), "hexadecimal digit expected"); return luaO_hexavalue(ls->current); } static int readhexaesc (LexState *ls) { int r = gethexa(ls); r = (r << 4) + gethexa(ls); luaZ_buffremove(ls->buff, 2); /* remove saved chars from buffer */ return r; } static unsigned long readutf8esc (LexState *ls) { unsigned long r; int i = 4; /* chars to be removed: '\', 'u', '{', and first digit */ save_and_next(ls); /* skip 'u' */ esccheck(ls, ls->current == '{', "missing '{'"); r = gethexa(ls); /* must have at least one digit */ while ((save_and_next(ls), lisxdigit(ls->current))) { i++; r = (r << 4) + luaO_hexavalue(ls->current); esccheck(ls, r <= 0x10FFFF, "UTF-8 value too large"); } esccheck(ls, ls->current == '}', "missing '}'"); next(ls); /* skip '}' */ luaZ_buffremove(ls->buff, i); /* remove saved chars from buffer */ return r; } static void utf8esc (LexState *ls) { char buff[UTF8BUFFSZ]; int n = luaO_utf8esc(buff, readutf8esc(ls)); for (; n > 0; n--) /* add 'buff' to string */ save(ls, buff[UTF8BUFFSZ - n]); } static int readdecesc (LexState *ls) { int i; int r = 0; /* result accumulator */ for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */ r = 10*r + ls->current - '0'; save_and_next(ls); } esccheck(ls, r <= UCHAR_MAX, "decimal escape too large"); luaZ_buffremove(ls->buff, i); /* remove read digits from buffer */ return r; } static void read_string (LexState *ls, int del, SemInfo *seminfo) { save_and_next(ls); /* keep delimiter (for error messages) */ while (ls->current != del) { switch (ls->current) { case EOZ: lexerror(ls, "unfinished string", TK_EOS); break; /* to avoid warnings */ case '\n': case '\r': lexerror(ls, "unfinished string", TK_STRING); break; /* to avoid warnings */ case '\\': { /* escape sequences */ int c; /* final character to be saved */ save_and_next(ls); /* keep '\\' for error messages */ switch (ls->current) { case 'a': c = '\a'; goto read_save; case 'b': c = '\b'; goto read_save; case 'f': c = '\f'; goto read_save; case 'n': c = '\n'; goto read_save; case 'r': c = '\r'; goto read_save; case 't': c = '\t'; goto read_save; case 'v': c = '\v'; goto read_save; case 'x': c = readhexaesc(ls); goto read_save; case 'u': utf8esc(ls); goto no_save; case '\n': case '\r': inclinenumber(ls); c = '\n'; goto only_save; case '\\': case '\"': case '\'': c = ls->current; goto read_save; case EOZ: goto no_save; /* will raise an error next loop */ case 'z': { /* zap following span of spaces */ luaZ_buffremove(ls->buff, 1); /* remove '\\' */ next(ls); /* skip the 'z' */ while (lisspace(ls->current)) { if (currIsNewline(ls)) inclinenumber(ls); else next(ls); } goto no_save; } default: { esccheck(ls, lisdigit(ls->current), "invalid escape sequence"); c = readdecesc(ls); /* digital escape '\ddd' */ goto only_save; } } read_save: next(ls); /* go through */ only_save: luaZ_buffremove(ls->buff, 1); /* remove '\\' */ save(ls, c); /* go through */ no_save: break; } default: save_and_next(ls); } } save_and_next(ls); /* skip delimiter */ seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1, luaZ_bufflen(ls->buff) - 2); } static int llex (LexState *ls, SemInfo *seminfo) { luaZ_resetbuffer(ls->buff); for (;;) { switch (ls->current) { case '\n': case '\r': { /* line breaks */ inclinenumber(ls); break; } case ' ': case '\f': case '\t': case '\v': { /* spaces */ next(ls); break; } case '-': { /* '-' or '--' (comment) */ next(ls); if (ls->current != '-') return '-'; /* else is a comment */ next(ls); if (ls->current == '[') { /* long comment? */ int sep = skip_sep(ls); luaZ_resetbuffer(ls->buff); /* 'skip_sep' may dirty the buffer */ if (sep >= 0) { read_long_string(ls, NULL, sep); /* skip long comment */ luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */ break; } } /* else short comment */ while (!currIsNewline(ls) && ls->current != EOZ) next(ls); /* skip until end of line (or end of file) */ break; } case '[': { /* long string or simply '[' */ int sep = skip_sep(ls); if (sep >= 0) { read_long_string(ls, seminfo, sep); return TK_STRING; } else if (sep != -1) /* '[=...' missing second bracket */ lexerror(ls, "invalid long string delimiter", TK_STRING); return '['; } case '=': { next(ls); if (check_next1(ls, '=')) return TK_EQ; else return '='; } case '<': { next(ls); if (check_next1(ls, '=')) return TK_LE; else if (check_next1(ls, '<')) return TK_SHL; else return '<'; } case '>': { next(ls); if (check_next1(ls, '=')) return TK_GE; else if (check_next1(ls, '>')) return TK_SHR; else return '>'; } case '/': { next(ls); if (check_next1(ls, '/')) return TK_IDIV; else return '/'; } case '~': { next(ls); if (check_next1(ls, '=')) return TK_NE; else return '~'; } case ':': { next(ls); if (check_next1(ls, ':')) return TK_DBCOLON; else return ':'; } case '"': case '\'': { /* short literal strings */ read_string(ls, ls->current, seminfo); return TK_STRING; } case '.': { /* '.', '..', '...', or number */ save_and_next(ls); if (check_next1(ls, '.')) { if (check_next1(ls, '.')) return TK_DOTS; /* '...' */ else return TK_CONCAT; /* '..' */ } else if (!lisdigit(ls->current)) return '.'; else return read_numeral(ls, seminfo); } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { return read_numeral(ls, seminfo); } case EOZ: { return TK_EOS; } default: { if (lislalpha(ls->current)) { /* identifier or reserved word? */ TString *ts; do { save_and_next(ls); } while (lislalnum(ls->current)); ts = luaX_newstring(ls, luaZ_buffer(ls->buff), luaZ_bufflen(ls->buff)); seminfo->ts = ts; if (isreserved(ts)) /* reserved word? */ return ts->extra - 1 + FIRST_RESERVED; else { return TK_NAME; } } else { /* single-char tokens (+ - / ...) */ int c = ls->current; next(ls); return c; } } } } } void luaX_next (LexState *ls) { ls->lastline = ls->linenumber; if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */ ls->t = ls->lookahead; /* use this one */ ls->lookahead.token = TK_EOS; /* and discharge it */ } else ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */ } int luaX_lookahead (LexState *ls) { lua_assert(ls->lookahead.token == TK_EOS); ls->lookahead.token = llex(ls, &ls->lookahead.seminfo); return ls->lookahead.token; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lgc.h�����������������������������������������������������������������������������0000644�0001751�0001751�00000011164�12675241401�011725� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lgc.h,v 2.90 2015/10/21 18:15:15 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ #ifndef lgc_h #define lgc_h #include "lobject.h" #include "lstate.h" /* ** Collectable objects may have one of three colors: white, which ** means the object is not marked; gray, which means the ** object is marked, but its references may be not marked; and ** black, which means that the object and all its references are marked. ** The main invariant of the garbage collector, while marking objects, ** is that a black object can never point to a white one. Moreover, ** any gray object must be in a "gray list" (gray, grayagain, weak, ** allweak, ephemeron) so that it can be visited again before finishing ** the collection cycle. These lists have no meaning when the invariant ** is not being enforced (e.g., sweep phase). */ /* how much to allocate before next GC step */ #if !defined(GCSTEPSIZE) /* ~100 small strings */ #define GCSTEPSIZE (cast_int(100 * sizeof(TString))) #endif /* ** Possible states of the Garbage Collector */ #define GCSpropagate 0 #define GCSatomic 1 #define GCSswpallgc 2 #define GCSswpfinobj 3 #define GCSswptobefnz 4 #define GCSswpend 5 #define GCScallfin 6 #define GCSpause 7 #define issweepphase(g) \ (GCSswpallgc <= (g)->gcstate && (g)->gcstate <= GCSswpend) /* ** macro to tell when main invariant (white objects cannot point to black ** ones) must be kept. During a collection, the sweep ** phase may break the invariant, as objects turned white may point to ** still-black objects. The invariant is restored when sweep ends and ** all objects are white again. */ #define keepinvariant(g) ((g)->gcstate <= GCSatomic) /* ** some useful bit tricks */ #define resetbits(x,m) ((x) &= cast(lu_byte, ~(m))) #define setbits(x,m) ((x) |= (m)) #define testbits(x,m) ((x) & (m)) #define bitmask(b) (1<<(b)) #define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2)) #define l_setbit(x,b) setbits(x, bitmask(b)) #define resetbit(x,b) resetbits(x, bitmask(b)) #define testbit(x,b) testbits(x, bitmask(b)) /* Layout for bit use in 'marked' field: */ #define WHITE0BIT 0 /* object is white (type 0) */ #define WHITE1BIT 1 /* object is white (type 1) */ #define BLACKBIT 2 /* object is black */ #define FINALIZEDBIT 3 /* object has been marked for finalization */ /* bit 7 is currently used by tests (luaL_checkmemory) */ #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) #define iswhite(x) testbits((x)->marked, WHITEBITS) #define isblack(x) testbit((x)->marked, BLACKBIT) #define isgray(x) /* neither white nor black */ \ (!testbits((x)->marked, WHITEBITS | bitmask(BLACKBIT))) #define tofinalize(x) testbit((x)->marked, FINALIZEDBIT) #define otherwhite(g) ((g)->currentwhite ^ WHITEBITS) #define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow))) #define isdead(g,v) isdeadm(otherwhite(g), (v)->marked) #define changewhite(x) ((x)->marked ^= WHITEBITS) #define gray2black(x) l_setbit((x)->marked, BLACKBIT) #define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS) /* ** Does one step of collection when debt becomes positive. 'pre'/'pos' ** allows some adjustments to be done only when needed. macro ** 'condchangemem' is used only for heavy tests (forcing a full ** GC cycle on every opportunity) */ #define luaC_condGC(L,pre,pos) \ { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \ condchangemem(L,pre,pos); } /* more often than not, 'pre'/'pos' are empty */ #define luaC_checkGC(L) luaC_condGC(L,,) #define luaC_barrier(L,p,v) ( \ (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0)) #define luaC_barrierback(L,p,v) ( \ (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \ luaC_barrierback_(L,p) : cast_void(0)) #define luaC_objbarrier(L,p,o) ( \ (isblack(p) && iswhite(o)) ? \ luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) #define luaC_upvalbarrier(L,uv) ( \ (iscollectable((uv)->v) && !upisopen(uv)) ? \ luaC_upvalbarrier_(L,uv) : cast_void(0)) LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrierback_ (lua_State *L, Table *o); LUAI_FUNC void luaC_upvalbarrier_ (lua_State *L, UpVal *uv); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); LUAI_FUNC void luaC_upvdeccount (lua_State *L, UpVal *uv); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lctype.h��������������������������������������������������������������������������0000644�0001751�0001751�00000003455�12675241401�012464� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lctype.h,v 1.12 2011/07/15 12:50:29 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ #ifndef lctype_h #define lctype_h #include "lua.h" /* ** WARNING: the functions defined here do not necessarily correspond ** to the similar functions in the standard C ctype.h. They are ** optimized for the specific needs of Lua */ #if !defined(LUA_USE_CTYPE) #if 'A' == 65 && '0' == 48 /* ASCII case: can use its own tables; faster and fixed */ #define LUA_USE_CTYPE 0 #else /* must use standard C ctype */ #define LUA_USE_CTYPE 1 #endif #endif #if !LUA_USE_CTYPE /* { */ #include <limits.h> #include "llimits.h" #define ALPHABIT 0 #define DIGITBIT 1 #define PRINTBIT 2 #define SPACEBIT 3 #define XDIGITBIT 4 #define MASK(B) (1 << (B)) /* ** add 1 to char to allow index -1 (EOZ) */ #define testprop(c,p) (luai_ctype_[(c)+1] & (p)) /* ** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_' */ #define lislalpha(c) testprop(c, MASK(ALPHABIT)) #define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT))) #define lisdigit(c) testprop(c, MASK(DIGITBIT)) #define lisspace(c) testprop(c, MASK(SPACEBIT)) #define lisprint(c) testprop(c, MASK(PRINTBIT)) #define lisxdigit(c) testprop(c, MASK(XDIGITBIT)) /* ** this 'ltolower' only works for alphabetic characters */ #define ltolower(c) ((c) | ('A' ^ 'a')) /* two more entries for 0 and -1 (EOZ) */ LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2]; #else /* }{ */ /* ** use standard C ctypes */ #include <ctype.h> #define lislalpha(c) (isalpha(c) || (c) == '_') #define lislalnum(c) (isalnum(c) || (c) == '_') #define lisdigit(c) (isdigit(c)) #define lisspace(c) (isspace(c)) #define lisprint(c) (isprint(c)) #define lisxdigit(c) (isxdigit(c)) #define ltolower(c) (tolower(c)) #endif /* } */ #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lstrlib.c�������������������������������������������������������������������������0000644�0001751�0001751�00000131447�12675241401�012635� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lstrlib.c,v 1.239 2015/11/25 16:28:17 roberto Exp $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ #define lstrlib_c #define LUA_LIB #include "lprefix.h" #include <ctype.h> #include <float.h> #include <limits.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** maximum number of captures that a pattern can do during ** pattern-matching. This limit is arbitrary. */ #if !defined(LUA_MAXCAPTURES) #define LUA_MAXCAPTURES 32 #endif /* macro to 'unsign' a character */ #define uchar(c) ((unsigned char)(c)) /* ** Some sizes are better limited to fit in 'int', but must also fit in ** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.) */ #define MAX_SIZET ((size_t)(~(size_t)0)) #define MAXSIZE \ (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX)) static int str_len (lua_State *L) { size_t l; luaL_checklstring(L, 1, &l); lua_pushinteger(L, (lua_Integer)l); return 1; } /* translate a relative string position: negative means back from end */ static lua_Integer posrelat (lua_Integer pos, size_t len) { if (pos >= 0) return pos; else if (0u - (size_t)pos > len) return 0; else return (lua_Integer)len + pos + 1; } static int str_sub (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); lua_Integer start = posrelat(luaL_checkinteger(L, 2), l); lua_Integer end = posrelat(luaL_optinteger(L, 3, -1), l); if (start < 1) start = 1; if (end > (lua_Integer)l) end = l; if (start <= end) lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1); else lua_pushliteral(L, ""); return 1; } static int str_reverse (lua_State *L) { size_t l, i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); char *p = luaL_buffinitsize(L, &b, l); for (i = 0; i < l; i++) p[i] = s[l - i - 1]; luaL_pushresultsize(&b, l); return 1; } static int str_lower (lua_State *L) { size_t l; size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); char *p = luaL_buffinitsize(L, &b, l); for (i=0; i<l; i++) p[i] = tolower(uchar(s[i])); luaL_pushresultsize(&b, l); return 1; } static int str_upper (lua_State *L) { size_t l; size_t i; luaL_Buffer b; const char *s = luaL_checklstring(L, 1, &l); char *p = luaL_buffinitsize(L, &b, l); for (i=0; i<l; i++) p[i] = toupper(uchar(s[i])); luaL_pushresultsize(&b, l); return 1; } static int str_rep (lua_State *L) { size_t l, lsep; const char *s = luaL_checklstring(L, 1, &l); lua_Integer n = luaL_checkinteger(L, 2); const char *sep = luaL_optlstring(L, 3, "", &lsep); if (n <= 0) lua_pushliteral(L, ""); else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ return luaL_error(L, "resulting string too large"); else { size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, totallen); while (n-- > 1) { /* first n-1 copies (followed by separator) */ memcpy(p, s, l * sizeof(char)); p += l; if (lsep > 0) { /* empty 'memcpy' is not that cheap */ memcpy(p, sep, lsep * sizeof(char)); p += lsep; } } memcpy(p, s, l * sizeof(char)); /* last copy (not followed by separator) */ luaL_pushresultsize(&b, totallen); } return 1; } static int str_byte (lua_State *L) { size_t l; const char *s = luaL_checklstring(L, 1, &l); lua_Integer posi = posrelat(luaL_optinteger(L, 2, 1), l); lua_Integer pose = posrelat(luaL_optinteger(L, 3, posi), l); int n, i; if (posi < 1) posi = 1; if (pose > (lua_Integer)l) pose = l; if (posi > pose) return 0; /* empty interval; return no values */ if (pose - posi >= INT_MAX) /* arithmetic overflow? */ return luaL_error(L, "string slice too long"); n = (int)(pose - posi) + 1; luaL_checkstack(L, n, "string slice too long"); for (i=0; i<n; i++) lua_pushinteger(L, uchar(s[posi+i-1])); return n; } static int str_char (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ int i; luaL_Buffer b; char *p = luaL_buffinitsize(L, &b, n); for (i=1; i<=n; i++) { lua_Integer c = luaL_checkinteger(L, i); luaL_argcheck(L, uchar(c) == c, i, "value out of range"); p[i - 1] = uchar(c); } luaL_pushresultsize(&b, n); return 1; } static int writer (lua_State *L, const void *b, size_t size, void *B) { (void)L; luaL_addlstring((luaL_Buffer *) B, (const char *)b, size); return 0; } static int str_dump (lua_State *L) { luaL_Buffer b; int strip = lua_toboolean(L, 2); luaL_checktype(L, 1, LUA_TFUNCTION); lua_settop(L, 1); luaL_buffinit(L,&b); if (lua_dump(L, writer, &b, strip) != 0) return luaL_error(L, "unable to dump given function"); luaL_pushresult(&b); return 1; } /* ** {====================================================== ** PATTERN MATCHING ** ======================================================= */ #define CAP_UNFINISHED (-1) #define CAP_POSITION (-2) typedef struct MatchState { const char *src_init; /* init of source string */ const char *src_end; /* end ('\0') of source string */ const char *p_end; /* end ('\0') of pattern */ lua_State *L; size_t nrep; /* limit to avoid non-linear complexity */ int matchdepth; /* control for recursive depth (to avoid C stack overflow) */ int level; /* total number of captures (finished or unfinished) */ struct { const char *init; ptrdiff_t len; } capture[LUA_MAXCAPTURES]; } MatchState; /* recursive function */ static const char *match (MatchState *ms, const char *s, const char *p); /* maximum recursion depth for 'match' */ #if !defined(MAXCCALLS) #define MAXCCALLS 200 #endif /* ** parameters to control the maximum number of operators handled in ** a match (to avoid non-linear complexity). The maximum will be: ** (subject length) * A_REPS + B_REPS */ #if !defined(A_REPS) #define A_REPS 4 #define B_REPS 100000 #endif #define L_ESC '%' #define SPECIALS "^$*+?.([%-" static int check_capture (MatchState *ms, int l) { l -= '1'; if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) return luaL_error(ms->L, "invalid capture index %%%d", l + 1); return l; } static int capture_to_close (MatchState *ms) { int level = ms->level; for (level--; level>=0; level--) if (ms->capture[level].len == CAP_UNFINISHED) return level; return luaL_error(ms->L, "invalid pattern capture"); } static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (ends with '%%')"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a ']' */ if (p == ms->p_end) luaL_error(ms->L, "malformed pattern (missing ']')"); if (*(p++) == L_ESC && p < ms->p_end) p++; /* skip escapes (e.g. '%]') */ } while (*p != ']'); return p+1; } default: { return p; } } } static int match_class (int c, int cl) { int res; switch (tolower(cl)) { case 'a' : res = isalpha(c); break; case 'c' : res = iscntrl(c); break; case 'd' : res = isdigit(c); break; case 'g' : res = isgraph(c); break; case 'l' : res = islower(c); break; case 'p' : res = ispunct(c); break; case 's' : res = isspace(c); break; case 'u' : res = isupper(c); break; case 'w' : res = isalnum(c); break; case 'x' : res = isxdigit(c); break; case 'z' : res = (c == 0); break; /* deprecated option */ default: return (cl == c); } return (islower(cl) ? res : !res); } static int matchbracketclass (int c, const char *p, const char *ec) { int sig = 1; if (*(p+1) == '^') { sig = 0; p++; /* skip the '^' */ } while (++p < ec) { if (*p == L_ESC) { p++; if (match_class(c, uchar(*p))) return sig; } else if ((*(p+1) == '-') && (p+2 < ec)) { p+=2; if (uchar(*(p-2)) <= c && c <= uchar(*p)) return sig; } else if (uchar(*p) == c) return sig; } return !sig; } static int singlematch (MatchState *ms, const char *s, const char *p, const char *ep) { if (s >= ms->src_end) return 0; else { int c = uchar(*s); switch (*p) { case '.': return 1; /* matches any char */ case L_ESC: return match_class(c, uchar(*(p+1))); case '[': return matchbracketclass(c, p, ep-1); default: return (uchar(*p) == c); } } } static const char *matchbalance (MatchState *ms, const char *s, const char *p) { if (p >= ms->p_end - 1) luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); if (*s != *p) return NULL; else { int b = *p; int e = *(p+1); int cont = 1; while (++s < ms->src_end) { if (*s == e) { if (--cont == 0) return s+1; } else if (*s == b) cont++; } } return NULL; /* string ends out of balance */ } static const char *max_expand (MatchState *ms, const char *s, const char *p, const char *ep) { ptrdiff_t i = 0; /* counts maximum expand for item */ while (singlematch(ms, s + i, p, ep)) i++; /* keeps trying to match with the maximum repetitions */ while (i>=0) { const char *res = match(ms, (s+i), ep+1); if (res) return res; i--; /* else didn't match; reduce 1 repetition to try again */ } return NULL; } static const char *min_expand (MatchState *ms, const char *s, const char *p, const char *ep) { for (;;) { const char *res = match(ms, s, ep+1); if (res != NULL) return res; else if (singlematch(ms, s, p, ep)) s++; /* try with one more repetition */ else return NULL; } } static const char *start_capture (MatchState *ms, const char *s, const char *p, int what) { const char *res; int level = ms->level; if (level >= LUA_MAXCAPTURES) luaL_error(ms->L, "too many captures"); ms->capture[level].init = s; ms->capture[level].len = what; ms->level = level+1; if ((res=match(ms, s, p)) == NULL) /* match failed? */ ms->level--; /* undo capture */ return res; } static const char *end_capture (MatchState *ms, const char *s, const char *p) { int l = capture_to_close(ms); const char *res; ms->capture[l].len = s - ms->capture[l].init; /* close capture */ if ((res = match(ms, s, p)) == NULL) /* match failed? */ ms->capture[l].len = CAP_UNFINISHED; /* undo capture */ return res; } static const char *match_capture (MatchState *ms, const char *s, int l) { size_t len; l = check_capture(ms, l); len = ms->capture[l].len; if ((size_t)(ms->src_end-s) >= len && memcmp(ms->capture[l].init, s, len) == 0) return s+len; else return NULL; } static const char *match (MatchState *ms, const char *s, const char *p) { if (ms->matchdepth-- == 0) luaL_error(ms->L, "pattern too complex"); init: /* using goto's to optimize tail recursion */ if (p != ms->p_end) { /* end of pattern? */ switch (*p) { case '(': { /* start capture */ if (*(p + 1) == ')') /* position capture? */ s = start_capture(ms, s, p + 2, CAP_POSITION); else s = start_capture(ms, s, p + 1, CAP_UNFINISHED); break; } case ')': { /* end capture */ s = end_capture(ms, s, p + 1); break; } case '$': { if ((p + 1) != ms->p_end) /* is the '$' the last char in pattern? */ goto dflt; /* no; go to default */ s = (s == ms->src_end) ? s : NULL; /* check end of string */ break; } case L_ESC: { /* escaped sequences not in the format class[*+?-]? */ switch (*(p + 1)) { case 'b': { /* balanced string? */ s = matchbalance(ms, s, p + 2); if (s != NULL) { p += 4; goto init; /* return match(ms, s, p + 4); */ } /* else fail (s == NULL) */ break; } case 'f': { /* frontier? */ const char *ep; char previous; p += 2; if (*p != '[') luaL_error(ms->L, "missing '[' after '%%f' in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s - 1); if (!matchbracketclass(uchar(previous), p, ep - 1) && matchbracketclass(uchar(*s), p, ep - 1)) { p = ep; goto init; /* return match(ms, s, ep); */ } s = NULL; /* match failed */ break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { /* capture results (%0-%9)? */ s = match_capture(ms, s, uchar(*(p + 1))); if (s != NULL) { p += 2; goto init; /* return match(ms, s, p + 2) */ } break; } default: goto dflt; } break; } default: dflt: { /* pattern class plus optional suffix */ const char *ep = classend(ms, p); /* points to optional suffix */ /* does not match at least once? */ if (!singlematch(ms, s, p, ep)) { if (*ep == '*' || *ep == '?' || *ep == '-') { /* accept empty? */ p = ep + 1; goto init; /* return match(ms, s, ep + 1); */ } else /* '+' or no suffix */ s = NULL; /* fail */ } else { /* matched once */ if (ms->nrep-- == 0) luaL_error(ms->L, "pattern too complex"); switch (*ep) { /* handle optional suffix */ case '?': { /* optional */ const char *res; if ((res = match(ms, s + 1, ep + 1)) != NULL) s = res; else { p = ep + 1; goto init; /* else return match(ms, s, ep + 1); */ } break; } case '+': /* 1 or more repetitions */ s++; /* 1 match already done */ /* FALLTHROUGH */ case '*': /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; case '-': /* 0 or more repetitions (minimum) */ s = min_expand(ms, s, p, ep); break; default: /* no suffix */ s++; p = ep; goto init; /* return match(ms, s + 1, ep); */ } } break; } } } ms->matchdepth++; return s; } static const char *lmemfind (const char *s1, size_t l1, const char *s2, size_t l2) { if (l2 == 0) return s1; /* empty strings are everywhere */ else if (l2 > l1) return NULL; /* avoids a negative 'l1' */ else { const char *init; /* to search for a '*s2' inside 's1' */ l2--; /* 1st char will be checked by 'memchr' */ l1 = l1-l2; /* 's2' cannot be found after that */ while (l1 > 0 && (init = (const char *)memchr(s1, *s2, l1)) != NULL) { init++; /* 1st char is already checked */ if (memcmp(init, s2+1, l2) == 0) return init-1; else { /* correct 'l1' and 's1' to try again */ l1 -= init-s1; s1 = init; } } return NULL; /* not found */ } } static void push_onecapture (MatchState *ms, int i, const char *s, const char *e) { if (i >= ms->level) { if (i == 0) /* ms->level == 0, too */ lua_pushlstring(ms->L, s, e - s); /* add whole match */ else luaL_error(ms->L, "invalid capture index %%%d", i + 1); } else { ptrdiff_t l = ms->capture[i].len; if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture"); if (l == CAP_POSITION) lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); else lua_pushlstring(ms->L, ms->capture[i].init, l); } } static int push_captures (MatchState *ms, const char *s, const char *e) { int i; int nlevels = (ms->level == 0 && s) ? 1 : ms->level; luaL_checkstack(ms->L, nlevels, "too many captures"); for (i = 0; i < nlevels; i++) push_onecapture(ms, i, s, e); return nlevels; /* number of strings pushed */ } /* check whether pattern has no special characters */ static int nospecials (const char *p, size_t l) { size_t upto = 0; do { if (strpbrk(p + upto, SPECIALS)) return 0; /* pattern has a special character */ upto += strlen(p + upto) + 1; /* may have more after \0 */ } while (upto <= l); return 1; /* no special chars found */ } static void prepstate (MatchState *ms, lua_State *L, const char *s, size_t ls, const char *p, size_t lp) { ms->L = L; ms->matchdepth = MAXCCALLS; ms->src_init = s; ms->src_end = s + ls; ms->p_end = p + lp; if (ls < (MAX_SIZET - B_REPS) / A_REPS) ms->nrep = A_REPS * ls + B_REPS; else /* overflow (very long subject) */ ms->nrep = MAX_SIZET; /* no limit */ } static void reprepstate (MatchState *ms) { ms->level = 0; lua_assert(ms->matchdepth == MAXCCALLS); } static int str_find_aux (lua_State *L, int find) { size_t ls, lp; const char *s = luaL_checklstring(L, 1, &ls); const char *p = luaL_checklstring(L, 2, &lp); lua_Integer init = posrelat(luaL_optinteger(L, 3, 1), ls); if (init < 1) init = 1; else if (init > (lua_Integer)ls + 1) { /* start after string's end? */ lua_pushnil(L); /* cannot find anything */ return 1; } /* explicit request or no special characters? */ if (find && (lua_toboolean(L, 4) || nospecials(p, lp))) { /* do a plain search */ const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp); if (s2) { lua_pushinteger(L, (s2 - s) + 1); lua_pushinteger(L, (s2 - s) + lp); return 2; } } else { MatchState ms; const char *s1 = s + init - 1; int anchor = (*p == '^'); if (anchor) { p++; lp--; /* skip anchor character */ } prepstate(&ms, L, s, ls, p, lp); do { const char *res; reprepstate(&ms); if ((res=match(&ms, s1, p)) != NULL) { if (find) { lua_pushinteger(L, (s1 - s) + 1); /* start */ lua_pushinteger(L, res - s); /* end */ return push_captures(&ms, NULL, 0) + 2; } else return push_captures(&ms, s1, res); } } while (s1++ < ms.src_end && !anchor); } lua_pushnil(L); /* not found */ return 1; } static int str_find (lua_State *L) { return str_find_aux(L, 1); } static int str_match (lua_State *L) { return str_find_aux(L, 0); } /* state for 'gmatch' */ typedef struct GMatchState { const char *src; /* current position */ const char *p; /* pattern */ MatchState ms; /* match state */ } GMatchState; static int gmatch_aux (lua_State *L) { GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3)); const char *src; for (src = gm->src; src <= gm->ms.src_end; src++) { const char *e; reprepstate(&gm->ms); if ((e = match(&gm->ms, src, gm->p)) != NULL) { if (e == src) /* empty match? */ gm->src =src + 1; /* go at least one position */ else gm->src = e; return push_captures(&gm->ms, src, e); } } return 0; /* not found */ } static int gmatch (lua_State *L) { size_t ls, lp; const char *s = luaL_checklstring(L, 1, &ls); const char *p = luaL_checklstring(L, 2, &lp); GMatchState *gm; lua_settop(L, 2); /* keep them on closure to avoid being collected */ gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState)); prepstate(&gm->ms, L, s, ls, p, lp); gm->src = s; gm->p = p; lua_pushcclosure(L, gmatch_aux, 3); return 1; } static void add_s (MatchState *ms, luaL_Buffer *b, const char *s, const char *e) { size_t l, i; lua_State *L = ms->L; const char *news = lua_tolstring(L, 3, &l); for (i = 0; i < l; i++) { if (news[i] != L_ESC) luaL_addchar(b, news[i]); else { i++; /* skip ESC */ if (!isdigit(uchar(news[i]))) { if (news[i] != L_ESC) luaL_error(L, "invalid use of '%c' in replacement string", L_ESC); luaL_addchar(b, news[i]); } else if (news[i] == '0') luaL_addlstring(b, s, e - s); else { push_onecapture(ms, news[i] - '1', s, e); luaL_tolstring(L, -1, NULL); /* if number, convert it to string */ lua_remove(L, -2); /* remove original value */ luaL_addvalue(b); /* add capture to accumulated result */ } } } } static void add_value (MatchState *ms, luaL_Buffer *b, const char *s, const char *e, int tr) { lua_State *L = ms->L; switch (tr) { case LUA_TFUNCTION: { int n; lua_pushvalue(L, 3); n = push_captures(ms, s, e); lua_call(L, n, 1); break; } case LUA_TTABLE: { push_onecapture(ms, 0, s, e); lua_gettable(L, 3); break; } default: { /* LUA_TNUMBER or LUA_TSTRING */ add_s(ms, b, s, e); return; } } if (!lua_toboolean(L, -1)) { /* nil or false? */ lua_pop(L, 1); lua_pushlstring(L, s, e - s); /* keep original text */ } else if (!lua_isstring(L, -1)) luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); luaL_addvalue(b); /* add result to accumulator */ } static int str_gsub (lua_State *L) { size_t srcl, lp; const char *src = luaL_checklstring(L, 1, &srcl); const char *p = luaL_checklstring(L, 2, &lp); int tr = lua_type(L, 3); lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); int anchor = (*p == '^'); lua_Integer n = 0; MatchState ms; luaL_Buffer b; luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING || tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3, "string/function/table expected"); luaL_buffinit(L, &b); if (anchor) { p++; lp--; /* skip anchor character */ } prepstate(&ms, L, src, srcl, p, lp); while (n < max_s) { const char *e; reprepstate(&ms); if ((e = match(&ms, src, p)) != NULL) { n++; add_value(&ms, &b, src, e, tr); } if (e && e>src) /* non empty match? */ src = e; /* skip it */ else if (src < ms.src_end) luaL_addchar(&b, *src++); else break; if (anchor) break; } luaL_addlstring(&b, src, ms.src_end-src); luaL_pushresult(&b); lua_pushinteger(L, n); /* number of substitutions */ return 2; } /* }====================================================== */ /* ** {====================================================== ** STRING FORMAT ** ======================================================= */ #if !defined(lua_number2strx) /* { */ /* ** Hexadecimal floating-point formatter */ #include <locale.h> #include <math.h> #define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char)) /* ** Number of bits that goes into the first digit. It can be any value ** between 1 and 4; the following definition tries to align the number ** to nibble boundaries by making what is left after that first digit a ** multiple of 4. */ #define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1) /* ** Add integer part of 'x' to buffer and return new 'x' */ static lua_Number adddigit (char *buff, int n, lua_Number x) { lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */ int d = (int)dd; buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */ return x - dd; /* return what is left */ } static int num2straux (char *buff, int sz, lua_Number x) { if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */ return l_sprintf(buff, sz, LUA_NUMBER_FMT, x); /* equal to '%g' */ else if (x == 0) { /* can be -0... */ /* create "0" or "-0" followed by exponent */ return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", x); } else { int e; lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */ int n = 0; /* character count */ if (m < 0) { /* is number negative? */ buff[n++] = '-'; /* add signal */ m = -m; /* make it positive */ } buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */ m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */ e -= L_NBFD; /* this digit goes before the radix point */ if (m > 0) { /* more digits? */ buff[n++] = lua_getlocaledecpoint(); /* add radix point */ do { /* add as many digits as needed */ m = adddigit(buff, n++, m * 16); } while (m > 0); } n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */ lua_assert(n < sz); return n; } } static int lua_number2strx (lua_State *L, char *buff, int sz, const char *fmt, lua_Number x) { int n = num2straux(buff, sz, x); if (fmt[SIZELENMOD] == 'A') { int i; for (i = 0; i < n; i++) buff[i] = toupper(uchar(buff[i])); } else if (fmt[SIZELENMOD] != 'a') luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); return n; } #endif /* } */ /* ** Maximum size of each formatted item. This maximum size is produced ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', ** and '\0') + number of decimal digits to represent maxfloat (which ** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra ** expenses", such as locale-dependent stuff) */ #define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) /* valid flags in a format specification */ #define FLAGS "-+ #0" /* ** maximum size of each format specification (such as "%-099.99d") */ #define MAX_FORMAT 32 static void addquoted (lua_State *L, luaL_Buffer *b, int arg) { size_t l; const char *s = luaL_checklstring(L, arg, &l); luaL_addchar(b, '"'); while (l--) { if (*s == '"' || *s == '\\' || *s == '\n') { luaL_addchar(b, '\\'); luaL_addchar(b, *s); } else if (*s == '\0' || iscntrl(uchar(*s))) { char buff[10]; if (!isdigit(uchar(*(s+1)))) l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s)); else l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s)); luaL_addstring(b, buff); } else luaL_addchar(b, *s); s++; } luaL_addchar(b, '"'); } static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { const char *p = strfrmt; while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */ if ((size_t)(p - strfrmt) >= sizeof(FLAGS)/sizeof(char)) luaL_error(L, "invalid format (repeated flags)"); if (isdigit(uchar(*p))) p++; /* skip width */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ if (*p == '.') { p++; if (isdigit(uchar(*p))) p++; /* skip precision */ if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ } if (isdigit(uchar(*p))) luaL_error(L, "invalid format (width or precision too long)"); *(form++) = '%'; memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); form += (p - strfrmt) + 1; *form = '\0'; return p; } /* ** add length modifier into formats */ static void addlenmod (char *form, const char *lenmod) { size_t l = strlen(form); size_t lm = strlen(lenmod); char spec = form[l - 1]; strcpy(form + l - 1, lenmod); form[l + lm - 1] = spec; form[l + lm] = '\0'; } static int str_format (lua_State *L) { int top = lua_gettop(L); int arg = 1; size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); const char *strfrmt_end = strfrmt+sfl; luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { if (*strfrmt != L_ESC) luaL_addchar(&b, *strfrmt++); else if (*++strfrmt == L_ESC) luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format ('%...') */ char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ int nb = 0; /* number of bytes in added item */ if (++arg > top) luaL_argerror(L, arg, "no value"); strfrmt = scanformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); break; } case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { lua_Integer n = luaL_checkinteger(L, arg); addlenmod(form, LUA_INTEGER_FRMLEN); nb = l_sprintf(buff, MAX_ITEM, form, n); break; } case 'a': case 'A': addlenmod(form, LUA_NUMBER_FRMLEN); nb = lua_number2strx(L, buff, MAX_ITEM, form, luaL_checknumber(L, arg)); break; case 'e': case 'E': case 'f': case 'g': case 'G': { addlenmod(form, LUA_NUMBER_FRMLEN); nb = l_sprintf(buff, MAX_ITEM, form, luaL_checknumber(L, arg)); break; } case 'q': { addquoted(L, &b, arg); break; } case 's': { size_t l; const char *s = luaL_tolstring(L, arg, &l); if (form[2] == '\0') /* no modifiers? */ luaL_addvalue(&b); /* keep entire string */ else { luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); if (!strchr(form, '.') && l >= 100) { /* no precision and string is too long to be formatted */ luaL_addvalue(&b); /* keep entire string */ } else { /* format the string into 'buff' */ nb = l_sprintf(buff, MAX_ITEM, form, s); lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ } } break; } default: { /* also treat cases 'pnLlh' */ return luaL_error(L, "invalid option '%%%c' to 'format'", *(strfrmt - 1)); } } lua_assert(nb < MAX_ITEM); luaL_addsize(&b, nb); } } luaL_pushresult(&b); return 1; } /* }====================================================== */ /* ** {====================================================== ** PACK/UNPACK ** ======================================================= */ /* value used for padding */ #if !defined(LUA_PACKPADBYTE) #define LUA_PACKPADBYTE 0x00 #endif /* maximum size for the binary representation of an integer */ #define MAXINTSIZE 16 /* number of bits in a character */ #define NB CHAR_BIT /* mask for one character (NB 1's) */ #define MC ((1 << NB) - 1) /* size of a lua_Integer */ #define SZINT ((int)sizeof(lua_Integer)) /* dummy union to get native endianness */ static const union { int dummy; char little; /* true iff machine is little endian */ } nativeendian = {1}; /* dummy structure to get native alignment requirements */ struct cD { char c; union { double d; void *p; lua_Integer i; lua_Number n; } u; }; #define MAXALIGN (offsetof(struct cD, u)) /* ** Union for serializing floats */ typedef union Ftypes { float f; double d; lua_Number n; char buff[5 * sizeof(lua_Number)]; /* enough for any float type */ } Ftypes; /* ** information to pack/unpack stuff */ typedef struct Header { lua_State *L; int islittle; int maxalign; } Header; /* ** options for pack/unpack */ typedef enum KOption { Kint, /* signed integers */ Kuint, /* unsigned integers */ Kfloat, /* floating-point numbers */ Kchar, /* fixed-length strings */ Kstring, /* strings with prefixed length */ Kzstr, /* zero-terminated strings */ Kpadding, /* padding */ Kpaddalign, /* padding for alignment */ Knop /* no-op (configuration or spaces) */ } KOption; /* ** Read an integer numeral from string 'fmt' or return 'df' if ** there is no numeral */ static int digit (int c) { return '0' <= c && c <= '9'; } static int getnum (const char **fmt, int df) { if (!digit(**fmt)) /* no number? */ return df; /* return default value */ else { int a = 0; do { a = a*10 + (*((*fmt)++) - '0'); } while (digit(**fmt) && a <= ((int)MAXSIZE - 9)/10); return a; } } /* ** Read an integer numeral and raises an error if it is larger ** than the maximum size for integers. */ static int getnumlimit (Header *h, const char **fmt, int df) { int sz = getnum(fmt, df); if (sz > MAXINTSIZE || sz <= 0) luaL_error(h->L, "integral size (%d) out of limits [1,%d]", sz, MAXINTSIZE); return sz; } /* ** Initialize Header */ static void initheader (lua_State *L, Header *h) { h->L = L; h->islittle = nativeendian.little; h->maxalign = 1; } /* ** Read and classify next option. 'size' is filled with option's size. */ static KOption getoption (Header *h, const char **fmt, int *size) { int opt = *((*fmt)++); *size = 0; /* default */ switch (opt) { case 'b': *size = sizeof(char); return Kint; case 'B': *size = sizeof(char); return Kuint; case 'h': *size = sizeof(short); return Kint; case 'H': *size = sizeof(short); return Kuint; case 'l': *size = sizeof(long); return Kint; case 'L': *size = sizeof(long); return Kuint; case 'j': *size = sizeof(lua_Integer); return Kint; case 'J': *size = sizeof(lua_Integer); return Kuint; case 'T': *size = sizeof(size_t); return Kuint; case 'f': *size = sizeof(float); return Kfloat; case 'd': *size = sizeof(double); return Kfloat; case 'n': *size = sizeof(lua_Number); return Kfloat; case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; case 'c': *size = getnum(fmt, -1); if (*size == -1) luaL_error(h->L, "missing size for format option 'c'"); return Kchar; case 'z': return Kzstr; case 'x': *size = 1; return Kpadding; case 'X': return Kpaddalign; case ' ': break; case '<': h->islittle = 1; break; case '>': h->islittle = 0; break; case '=': h->islittle = nativeendian.little; break; case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; default: luaL_error(h->L, "invalid format option '%c'", opt); } return Knop; } /* ** Read, classify, and fill other details about the next option. ** 'psize' is filled with option's size, 'notoalign' with its ** alignment requirements. ** Local variable 'size' gets the size to be aligned. (Kpadal option ** always gets its full alignment, other options are limited by ** the maximum alignment ('maxalign'). Kchar option needs no alignment ** despite its size. */ static KOption getdetails (Header *h, size_t totalsize, const char **fmt, int *psize, int *ntoalign) { KOption opt = getoption(h, fmt, psize); int align = *psize; /* usually, alignment follows size */ if (opt == Kpaddalign) { /* 'X' gets alignment from following option */ if (**fmt == '\0' || getoption(h, fmt, &align) == Kchar || align == 0) luaL_argerror(h->L, 1, "invalid next option for option 'X'"); } if (align <= 1 || opt == Kchar) /* need no alignment? */ *ntoalign = 0; else { if (align > h->maxalign) /* enforce maximum alignment */ align = h->maxalign; if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); } return opt; } /* ** Pack integer 'n' with 'size' bytes and 'islittle' endianness. ** The final 'if' handles the case when 'size' is larger than ** the size of a Lua integer, correcting the extra sign-extension ** bytes if necessary (by default they would be zeros). */ static void packint (luaL_Buffer *b, lua_Unsigned n, int islittle, int size, int neg) { char *buff = luaL_prepbuffsize(b, size); int i; buff[islittle ? 0 : size - 1] = (char)(n & MC); /* first byte */ for (i = 1; i < size; i++) { n >>= NB; buff[islittle ? i : size - 1 - i] = (char)(n & MC); } if (neg && size > SZINT) { /* negative number need sign extension? */ for (i = SZINT; i < size; i++) /* correct extra bytes */ buff[islittle ? i : size - 1 - i] = (char)MC; } luaL_addsize(b, size); /* add result to buffer */ } /* ** Copy 'size' bytes from 'src' to 'dest', correcting endianness if ** given 'islittle' is different from native endianness. */ static void copywithendian (volatile char *dest, volatile const char *src, int size, int islittle) { if (islittle == nativeendian.little) { while (size-- != 0) *(dest++) = *(src++); } else { dest += size - 1; while (size-- != 0) *(dest--) = *(src++); } } static int str_pack (lua_State *L) { luaL_Buffer b; Header h; const char *fmt = luaL_checkstring(L, 1); /* format string */ int arg = 1; /* current argument to pack */ size_t totalsize = 0; /* accumulate total size of result */ initheader(L, &h); lua_pushnil(L); /* mark to separate arguments from string buffer */ luaL_buffinit(L, &b); while (*fmt != '\0') { int size, ntoalign; KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); totalsize += ntoalign + size; while (ntoalign-- > 0) luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */ arg++; switch (opt) { case Kint: { /* signed integers */ lua_Integer n = luaL_checkinteger(L, arg); if (size < SZINT) { /* need overflow check? */ lua_Integer lim = (lua_Integer)1 << ((size * NB) - 1); luaL_argcheck(L, -lim <= n && n < lim, arg, "integer overflow"); } packint(&b, (lua_Unsigned)n, h.islittle, size, (n < 0)); break; } case Kuint: { /* unsigned integers */ lua_Integer n = luaL_checkinteger(L, arg); if (size < SZINT) /* need overflow check? */ luaL_argcheck(L, (lua_Unsigned)n < ((lua_Unsigned)1 << (size * NB)), arg, "unsigned overflow"); packint(&b, (lua_Unsigned)n, h.islittle, size, 0); break; } case Kfloat: { /* floating-point options */ volatile Ftypes u; char *buff = luaL_prepbuffsize(&b, size); lua_Number n = luaL_checknumber(L, arg); /* get argument */ if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ else if (size == sizeof(u.d)) u.d = (double)n; else u.n = n; /* move 'u' to final result, correcting endianness if needed */ copywithendian(buff, u.buff, size, h.islittle); luaL_addsize(&b, size); break; } case Kchar: { /* fixed-size string */ size_t len; const char *s = luaL_checklstring(L, arg, &len); if ((size_t)size <= len) /* string larger than (or equal to) needed? */ luaL_addlstring(&b, s, size); /* truncate string to asked size */ else { /* string smaller than needed */ luaL_addlstring(&b, s, len); /* add it all */ while (len++ < (size_t)size) /* pad extra space */ luaL_addchar(&b, LUA_PACKPADBYTE); } break; } case Kstring: { /* strings with length count */ size_t len; const char *s = luaL_checklstring(L, arg, &len); luaL_argcheck(L, size >= (int)sizeof(size_t) || len < ((size_t)1 << (size * NB)), arg, "string length does not fit in given size"); packint(&b, (lua_Unsigned)len, h.islittle, size, 0); /* pack length */ luaL_addlstring(&b, s, len); totalsize += len; break; } case Kzstr: { /* zero-terminated string */ size_t len; const char *s = luaL_checklstring(L, arg, &len); luaL_argcheck(L, strlen(s) == len, arg, "string contains zeros"); luaL_addlstring(&b, s, len); luaL_addchar(&b, '\0'); /* add zero at the end */ totalsize += len + 1; break; } case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */ case Kpaddalign: case Knop: arg--; /* undo increment */ break; } } luaL_pushresult(&b); return 1; } static int str_packsize (lua_State *L) { Header h; const char *fmt = luaL_checkstring(L, 1); /* format string */ size_t totalsize = 0; /* accumulate total size of result */ initheader(L, &h); while (*fmt != '\0') { int size, ntoalign; KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign); size += ntoalign; /* total space used by option */ luaL_argcheck(L, totalsize <= MAXSIZE - size, 1, "format result too large"); totalsize += size; switch (opt) { case Kstring: /* strings with length count */ case Kzstr: /* zero-terminated string */ luaL_argerror(L, 1, "variable-length format"); /* call never return, but to avoid warnings: *//* FALLTHROUGH */ default: break; } } lua_pushinteger(L, (lua_Integer)totalsize); return 1; } /* ** Unpack an integer with 'size' bytes and 'islittle' endianness. ** If size is smaller than the size of a Lua integer and integer ** is signed, must do sign extension (propagating the sign to the ** higher bits); if size is larger than the size of a Lua integer, ** it must check the unread bytes to see whether they do not cause an ** overflow. */ static lua_Integer unpackint (lua_State *L, const char *str, int islittle, int size, int issigned) { lua_Unsigned res = 0; int i; int limit = (size <= SZINT) ? size : SZINT; for (i = limit - 1; i >= 0; i--) { res <<= NB; res |= (lua_Unsigned)(unsigned char)str[islittle ? i : size - 1 - i]; } if (size < SZINT) { /* real size smaller than lua_Integer? */ if (issigned) { /* needs sign extension? */ lua_Unsigned mask = (lua_Unsigned)1 << (size*NB - 1); res = ((res ^ mask) - mask); /* do sign extension */ } } else if (size > SZINT) { /* must check unread bytes */ int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; for (i = limit; i < size; i++) { if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); } } return (lua_Integer)res; } static int str_unpack (lua_State *L) { Header h; const char *fmt = luaL_checkstring(L, 1); size_t ld; const char *data = luaL_checklstring(L, 2, &ld); size_t pos = (size_t)posrelat(luaL_optinteger(L, 3, 1), ld) - 1; int n = 0; /* number of results */ luaL_argcheck(L, pos <= ld, 3, "initial position out of string"); initheader(L, &h); while (*fmt != '\0') { int size, ntoalign; KOption opt = getdetails(&h, pos, &fmt, &size, &ntoalign); if ((size_t)ntoalign + size > ~pos || pos + ntoalign + size > ld) luaL_argerror(L, 2, "data string too short"); pos += ntoalign; /* skip alignment */ /* stack space for item + next position */ luaL_checkstack(L, 2, "too many results"); n++; switch (opt) { case Kint: case Kuint: { lua_Integer res = unpackint(L, data + pos, h.islittle, size, (opt == Kint)); lua_pushinteger(L, res); break; } case Kfloat: { volatile Ftypes u; lua_Number num; copywithendian(u.buff, data + pos, size, h.islittle); if (size == sizeof(u.f)) num = (lua_Number)u.f; else if (size == sizeof(u.d)) num = (lua_Number)u.d; else num = u.n; lua_pushnumber(L, num); break; } case Kchar: { lua_pushlstring(L, data + pos, size); break; } case Kstring: { size_t len = (size_t)unpackint(L, data + pos, h.islittle, size, 0); luaL_argcheck(L, pos + len + size <= ld, 2, "data string too short"); lua_pushlstring(L, data + pos + size, len); pos += len; /* skip string */ break; } case Kzstr: { size_t len = (int)strlen(data + pos); lua_pushlstring(L, data + pos, len); pos += len + 1; /* skip string plus final '\0' */ break; } case Kpaddalign: case Kpadding: case Knop: n--; /* undo increment */ break; } pos += size; } lua_pushinteger(L, pos + 1); /* next position */ return n + 1; } /* }====================================================== */ static const luaL_Reg strlib[] = { {"byte", str_byte}, {"char", str_char}, {"dump", str_dump}, {"find", str_find}, {"format", str_format}, {"gmatch", gmatch}, {"gsub", str_gsub}, {"len", str_len}, {"lower", str_lower}, {"match", str_match}, {"rep", str_rep}, {"reverse", str_reverse}, {"sub", str_sub}, {"upper", str_upper}, {"pack", str_pack}, {"packsize", str_packsize}, {"unpack", str_unpack}, {NULL, NULL} }; static void createmetatable (lua_State *L) { lua_createtable(L, 0, 1); /* table to be metatable for strings */ lua_pushliteral(L, ""); /* dummy string */ lua_pushvalue(L, -2); /* copy table */ lua_setmetatable(L, -2); /* set table as metatable for strings */ lua_pop(L, 1); /* pop dummy string */ lua_pushvalue(L, -2); /* get string library */ lua_setfield(L, -2, "__index"); /* metatable.__index = string */ lua_pop(L, 1); /* pop metatable */ } /* ** Open string library */ LUAMOD_API int luaopen_string (lua_State *L) { luaL_newlib(L, strlib); createmetatable(L); return 1; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/liolib.c��������������������������������������������������������������������������0000644�0001751�0001751�00000047057�12675241401�012437� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: liolib.c,v 2.148 2015/11/23 11:36:11 roberto Exp $ ** Standard I/O (and system) library ** See Copyright Notice in lua.h */ #define liolib_c #define LUA_LIB #include "lprefix.h" #include <ctype.h> #include <errno.h> #include <locale.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** Change this macro to accept other modes for 'fopen' besides ** the standard ones. */ #if !defined(l_checkmode) /* accepted extensions to 'mode' in 'fopen' */ #if !defined(L_MODEEXT) #define L_MODEEXT "b" #endif /* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */ #define l_checkmode(mode) \ (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \ (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ \ (strspn(mode, L_MODEEXT) == strlen(mode))) #endif /* ** {====================================================== ** l_popen spawns a new process connected to the current ** one through the file streams. ** ======================================================= */ #if !defined(l_popen) /* { */ #if defined(LUA_USE_POSIX) /* { */ #define l_popen(L,c,m) (fflush(NULL), popen(c,m)) #define l_pclose(L,file) (pclose(file)) #elif defined(LUA_USE_WINDOWS) /* }{ */ #define l_popen(L,c,m) (_popen(c,m)) #define l_pclose(L,file) (_pclose(file)) #else /* }{ */ /* ISO C definitions */ #define l_popen(L,c,m) \ ((void)((void)c, m), \ luaL_error(L, "'popen' not supported"), \ (FILE*)0) #define l_pclose(L,file) ((void)L, (void)file, -1) #endif /* } */ #endif /* } */ /* }====================================================== */ #if !defined(l_getc) /* { */ #if defined(LUA_USE_POSIX) #define l_getc(f) getc_unlocked(f) #define l_lockfile(f) flockfile(f) #define l_unlockfile(f) funlockfile(f) #else #define l_getc(f) getc(f) #define l_lockfile(f) ((void)0) #define l_unlockfile(f) ((void)0) #endif #endif /* } */ /* ** {====================================================== ** l_fseek: configuration for longer offsets ** ======================================================= */ #if !defined(l_fseek) /* { */ #if defined(LUA_USE_POSIX) /* { */ #include <sys/types.h> #define l_fseek(f,o,w) fseeko(f,o,w) #define l_ftell(f) ftello(f) #define l_seeknum off_t #elif defined(LUA_USE_WINDOWS) && !defined(_CRTIMP_TYPEINFO) \ && defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */ /* Windows (but not DDK) and Visual C++ 2005 or higher */ #define l_fseek(f,o,w) _fseeki64(f,o,w) #define l_ftell(f) _ftelli64(f) #define l_seeknum __int64 #else /* }{ */ /* ISO C definitions */ #define l_fseek(f,o,w) fseek(f,o,w) #define l_ftell(f) ftell(f) #define l_seeknum long #endif /* } */ #endif /* } */ /* }====================================================== */ #define IO_PREFIX "_IO_" #define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) #define IO_INPUT (IO_PREFIX "input") #define IO_OUTPUT (IO_PREFIX "output") typedef luaL_Stream LStream; #define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE)) #define isclosed(p) ((p)->closef == NULL) static int io_type (lua_State *L) { LStream *p; luaL_checkany(L, 1); p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE); if (p == NULL) lua_pushnil(L); /* not a file */ else if (isclosed(p)) lua_pushliteral(L, "closed file"); else lua_pushliteral(L, "file"); return 1; } static int f_tostring (lua_State *L) { LStream *p = tolstream(L); if (isclosed(p)) lua_pushliteral(L, "file (closed)"); else lua_pushfstring(L, "file (%p)", p->f); return 1; } static FILE *tofile (lua_State *L) { LStream *p = tolstream(L); if (isclosed(p)) luaL_error(L, "attempt to use a closed file"); lua_assert(p->f); return p->f; } /* ** When creating file handles, always creates a 'closed' file handle ** before opening the actual file; so, if there is a memory error, the ** handle is in a consistent state. */ static LStream *newprefile (lua_State *L) { LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream)); p->closef = NULL; /* mark file handle as 'closed' */ luaL_setmetatable(L, LUA_FILEHANDLE); return p; } /* ** Calls the 'close' function from a file handle. The 'volatile' avoids ** a bug in some versions of the Clang compiler (e.g., clang 3.0 for ** 32 bits). */ static int aux_close (lua_State *L) { LStream *p = tolstream(L); volatile lua_CFunction cf = p->closef; p->closef = NULL; /* mark stream as closed */ return (*cf)(L); /* close it */ } static int io_close (lua_State *L) { if (lua_isnone(L, 1)) /* no argument? */ lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */ tofile(L); /* make sure argument is an open stream */ return aux_close(L); } static int f_gc (lua_State *L) { LStream *p = tolstream(L); if (!isclosed(p) && p->f != NULL) aux_close(L); /* ignore closed and incompletely open files */ return 0; } /* ** function to close regular files */ static int io_fclose (lua_State *L) { LStream *p = tolstream(L); int res = fclose(p->f); return luaL_fileresult(L, (res == 0), NULL); } static LStream *newfile (lua_State *L) { LStream *p = newprefile(L); p->f = NULL; p->closef = &io_fclose; return p; } static void opencheck (lua_State *L, const char *fname, const char *mode) { LStream *p = newfile(L); p->f = fopen(fname, mode); if (p->f == NULL) luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); } static int io_open (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newfile(L); const char *md = mode; /* to traverse/check mode */ luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } /* ** function to close 'popen' files */ static int io_pclose (lua_State *L) { LStream *p = tolstream(L); return luaL_execresult(L, l_pclose(L, p->f)); } static int io_popen (lua_State *L) { const char *filename = luaL_checkstring(L, 1); const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newprefile(L); p->f = l_popen(L, filename, mode); p->closef = &io_pclose; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } static int io_tmpfile (lua_State *L) { LStream *p = newfile(L); p->f = tmpfile(); return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; } static FILE *getiofile (lua_State *L, const char *findex) { LStream *p; lua_getfield(L, LUA_REGISTRYINDEX, findex); p = (LStream *)lua_touserdata(L, -1); if (isclosed(p)) luaL_error(L, "standard %s file is closed", findex + IOPREF_LEN); return p->f; } static int g_iofile (lua_State *L, const char *f, const char *mode) { if (!lua_isnoneornil(L, 1)) { const char *filename = lua_tostring(L, 1); if (filename) opencheck(L, filename, mode); else { tofile(L); /* check that it's a valid file handle */ lua_pushvalue(L, 1); } lua_setfield(L, LUA_REGISTRYINDEX, f); } /* return current value */ lua_getfield(L, LUA_REGISTRYINDEX, f); return 1; } static int io_input (lua_State *L) { return g_iofile(L, IO_INPUT, "r"); } static int io_output (lua_State *L) { return g_iofile(L, IO_OUTPUT, "w"); } static int io_readline (lua_State *L); /* ** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit ** in the limit for upvalues of a closure) */ #define MAXARGLINE 250 static void aux_lines (lua_State *L, int toclose) { int n = lua_gettop(L) - 1; /* number of arguments to read */ luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments"); lua_pushinteger(L, n); /* number of arguments to read */ lua_pushboolean(L, toclose); /* close/not close file when finished */ lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */ lua_pushcclosure(L, io_readline, 3 + n); } static int f_lines (lua_State *L) { tofile(L); /* check that it's a valid file handle */ aux_lines(L, 0); return 1; } static int io_lines (lua_State *L) { int toclose; if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */ if (lua_isnil(L, 1)) { /* no file name? */ lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */ lua_replace(L, 1); /* put it at index 1 */ tofile(L); /* check that it's a valid file handle */ toclose = 0; /* do not close it after iteration */ } else { /* open a new file */ const char *filename = luaL_checkstring(L, 1); opencheck(L, filename, "r"); lua_replace(L, 1); /* put file at index 1 */ toclose = 1; /* close it after iteration */ } aux_lines(L, toclose); return 1; } /* ** {====================================================== ** READ ** ======================================================= */ /* maximum length of a numeral */ #define MAXRN 200 /* auxiliary structure used by 'read_number' */ typedef struct { FILE *f; /* file being read */ int c; /* current character (look ahead) */ int n; /* number of elements in buffer 'buff' */ char buff[MAXRN + 1]; /* +1 for ending '\0' */ } RN; /* ** Add current char to buffer (if not out of space) and read next one */ static int nextc (RN *rn) { if (rn->n >= MAXRN) { /* buffer overflow? */ rn->buff[0] = '\0'; /* invalidate result */ return 0; /* fail */ } else { rn->buff[rn->n++] = rn->c; /* save current char */ rn->c = l_getc(rn->f); /* read next one */ return 1; } } /* ** Accept current char if it is in 'set' (of size 1 or 2) */ static int test2 (RN *rn, const char *set) { if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0')) return nextc(rn); else return 0; } /* ** Read a sequence of (hex)digits */ static int readdigits (RN *rn, int hex) { int count = 0; while ((hex ? isxdigit(rn->c) : isdigit(rn->c)) && nextc(rn)) count++; return count; } /* ** Read a number: first reads a valid prefix of a numeral into a buffer. ** Then it calls 'lua_stringtonumber' to check whether the format is ** correct and to convert it to a Lua number */ static int read_number (lua_State *L, FILE *f) { RN rn; int count = 0; int hex = 0; char decp[2]; rn.f = f; rn.n = 0; decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */ decp[1] = '\0'; l_lockfile(rn.f); do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */ test2(&rn, "-+"); /* optional signal */ if (test2(&rn, "0")) { if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */ else count = 1; /* count initial '0' as a valid digit */ } count += readdigits(&rn, hex); /* integral part */ if (test2(&rn, decp)) /* decimal point? */ count += readdigits(&rn, hex); /* fractional part */ if (count > 0 && test2(&rn, (hex ? "pP" : "eE"))) { /* exponent mark? */ test2(&rn, "-+"); /* exponent signal */ readdigits(&rn, 0); /* exponent digits */ } ungetc(rn.c, rn.f); /* unread look-ahead char */ l_unlockfile(rn.f); rn.buff[rn.n] = '\0'; /* finish string */ if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ return 1; /* ok */ else { /* invalid format */ lua_pushnil(L); /* "result" to be removed */ return 0; /* read fails */ } } static int test_eof (lua_State *L, FILE *f) { int c = getc(f); ungetc(c, f); /* no-op when c == EOF */ lua_pushliteral(L, ""); return (c != EOF); } static int read_line (lua_State *L, FILE *f, int chop) { luaL_Buffer b; int c = '\0'; luaL_buffinit(L, &b); while (c != EOF && c != '\n') { /* repeat until end of line */ char *buff = luaL_prepbuffer(&b); /* preallocate buffer */ int i = 0; l_lockfile(f); /* no memory errors can happen inside the lock */ while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n') buff[i++] = c; l_unlockfile(f); luaL_addsize(&b, i); } if (!chop && c == '\n') /* want a newline and have one? */ luaL_addchar(&b, c); /* add ending newline to result */ luaL_pushresult(&b); /* close buffer */ /* return ok if read something (either a newline or something else) */ return (c == '\n' || lua_rawlen(L, -1) > 0); } static void read_all (lua_State *L, FILE *f) { size_t nr; luaL_Buffer b; luaL_buffinit(L, &b); do { /* read file in chunks of LUAL_BUFFERSIZE bytes */ char *p = luaL_prepbuffer(&b); nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f); luaL_addsize(&b, nr); } while (nr == LUAL_BUFFERSIZE); luaL_pushresult(&b); /* close buffer */ } static int read_chars (lua_State *L, FILE *f, size_t n) { size_t nr; /* number of chars actually read */ char *p; luaL_Buffer b; luaL_buffinit(L, &b); p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */ nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */ luaL_addsize(&b, nr); luaL_pushresult(&b); /* close buffer */ return (nr > 0); /* true iff read something */ } static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int success; int n; clearerr(f); if (nargs == 0) { /* no arguments? */ success = read_line(L, f, 1); n = first+1; /* to return 1 result */ } else { /* ensure stack space for all results and for auxlib's buffer */ luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments"); success = 1; for (n = first; nargs-- && success; n++) { if (lua_type(L, n) == LUA_TNUMBER) { size_t l = (size_t)luaL_checkinteger(L, n); success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l); } else { const char *p = luaL_checkstring(L, n); if (*p == '*') p++; /* skip optional '*' (for compatibility) */ switch (*p) { case 'n': /* number */ success = read_number(L, f); break; case 'l': /* line */ success = read_line(L, f, 1); break; case 'L': /* line with end-of-line */ success = read_line(L, f, 0); break; case 'a': /* file */ read_all(L, f); /* read entire file */ success = 1; /* always success */ break; default: return luaL_argerror(L, n, "invalid format"); } } } } if (ferror(f)) return luaL_fileresult(L, 0, NULL); if (!success) { lua_pop(L, 1); /* remove last result */ lua_pushnil(L); /* push nil instead */ } return n - first; } static int io_read (lua_State *L) { return g_read(L, getiofile(L, IO_INPUT), 1); } static int f_read (lua_State *L) { return g_read(L, tofile(L), 2); } static int io_readline (lua_State *L) { LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1)); int i; int n = (int)lua_tointeger(L, lua_upvalueindex(2)); if (isclosed(p)) /* file is already closed? */ return luaL_error(L, "file is already closed"); lua_settop(L , 1); luaL_checkstack(L, n, "too many arguments"); for (i = 1; i <= n; i++) /* push arguments to 'g_read' */ lua_pushvalue(L, lua_upvalueindex(3 + i)); n = g_read(L, p->f, 2); /* 'n' is number of results */ lua_assert(n > 0); /* should return at least a nil */ if (lua_toboolean(L, -n)) /* read at least one value? */ return n; /* return them */ else { /* first result is nil: EOF or error */ if (n > 1) { /* is there error information? */ /* 2nd result is error message */ return luaL_error(L, "%s", lua_tostring(L, -n + 1)); } if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */ lua_settop(L, 0); lua_pushvalue(L, lua_upvalueindex(1)); aux_close(L); /* close it */ } return 0; } } /* }====================================================== */ static int g_write (lua_State *L, FILE *f, int arg) { int nargs = lua_gettop(L) - arg; int status = 1; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ int len = lua_isinteger(L, arg) ? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg)) : fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)); status = status && (len > 0); } else { size_t l; const char *s = luaL_checklstring(L, arg, &l); status = status && (fwrite(s, sizeof(char), l, f) == l); } } if (status) return 1; /* file handle already on stack top */ else return luaL_fileresult(L, status, NULL); } static int io_write (lua_State *L) { return g_write(L, getiofile(L, IO_OUTPUT), 1); } static int f_write (lua_State *L) { FILE *f = tofile(L); lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */ return g_write(L, f, 2); } static int f_seek (lua_State *L) { static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END}; static const char *const modenames[] = {"set", "cur", "end", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, "cur", modenames); lua_Integer p3 = luaL_optinteger(L, 3, 0); l_seeknum offset = (l_seeknum)p3; luaL_argcheck(L, (lua_Integer)offset == p3, 3, "not an integer in proper range"); op = l_fseek(f, offset, mode[op]); if (op) return luaL_fileresult(L, 0, NULL); /* error */ else { lua_pushinteger(L, (lua_Integer)l_ftell(f)); return 1; } } static int f_setvbuf (lua_State *L) { static const int mode[] = {_IONBF, _IOFBF, _IOLBF}; static const char *const modenames[] = {"no", "full", "line", NULL}; FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); int res = setvbuf(f, NULL, mode[op], (size_t)sz); return luaL_fileresult(L, res == 0, NULL); } static int io_flush (lua_State *L) { return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); } static int f_flush (lua_State *L) { return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); } /* ** functions for 'io' library */ static const luaL_Reg iolib[] = { {"close", io_close}, {"flush", io_flush}, {"input", io_input}, {"lines", io_lines}, {"open", io_open}, {"output", io_output}, {"popen", io_popen}, {"read", io_read}, {"tmpfile", io_tmpfile}, {"type", io_type}, {"write", io_write}, {NULL, NULL} }; /* ** methods for file handles */ static const luaL_Reg flib[] = { {"close", io_close}, {"flush", f_flush}, {"lines", f_lines}, {"read", f_read}, {"seek", f_seek}, {"setvbuf", f_setvbuf}, {"write", f_write}, {"__gc", f_gc}, {"__tostring", f_tostring}, {NULL, NULL} }; static void createmeta (lua_State *L) { luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */ lua_pushvalue(L, -1); /* push metatable */ lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */ luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */ lua_pop(L, 1); /* pop new metatable */ } /* ** function to (not) close the standard files stdin, stdout, and stderr */ static int io_noclose (lua_State *L) { LStream *p = tolstream(L); p->closef = &io_noclose; /* keep file opened */ lua_pushnil(L); lua_pushliteral(L, "cannot close standard file"); return 2; } static void createstdfile (lua_State *L, FILE *f, const char *k, const char *fname) { LStream *p = newprefile(L); p->f = f; p->closef = &io_noclose; if (k != NULL) { lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */ } lua_setfield(L, -2, fname); /* add file to module */ } LUAMOD_API int luaopen_io (lua_State *L) { luaL_newlib(L, iolib); /* new module */ createmeta(L); /* create (and set) default files */ createstdfile(L, stdin, IO_INPUT, "stdin"); createstdfile(L, stdout, IO_OUTPUT, "stdout"); createstdfile(L, stderr, NULL, "stderr"); return 1; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lvm.c�����������������������������������������������������������������������������0000644�0001751�0001751�00000125262�12675241401�011756� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lvm.c,v 2.265 2015/11/23 11:30:45 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ #define lvm_c #define LUA_CORE #include "lprefix.h" #include <float.h> #include <limits.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lobject.h" #include "lopcodes.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lvm.h" /* limit for table tag-method chains (to avoid loops) */ #define MAXTAGLOOP 2000 /* ** 'l_intfitsf' checks whether a given integer can be converted to a ** float without rounding. Used in comparisons. Left undefined if ** all integers fit in a float precisely. */ #if !defined(l_intfitsf) /* number of bits in the mantissa of a float */ #define NBM (l_mathlim(MANT_DIG)) /* ** Check whether some integers may not fit in a float, that is, whether ** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger). ** (The shifts are done in parts to avoid shifting by more than the size ** of an integer. In a worst case, NBM == 113 for long double and ** sizeof(integer) == 32.) */ #if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \ >> (NBM - (3 * (NBM / 4)))) > 0 #define l_intfitsf(i) \ (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM)) #endif #endif /* ** Try to convert a value to a float. The float case is already handled ** by the macro 'tonumber'. */ int luaV_tonumber_ (const TValue *obj, lua_Number *n) { TValue v; if (ttisinteger(obj)) { *n = cast_num(ivalue(obj)); return 1; } else if (cvt2num(obj) && /* string convertible to number? */ luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { *n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */ return 1; } else return 0; /* conversion failed */ } /* ** try to convert a value to an integer, rounding according to 'mode': ** mode == 0: accepts only integral values ** mode == 1: takes the floor of the number ** mode == 2: takes the ceil of the number */ int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) { TValue v; again: if (ttisfloat(obj)) { lua_Number n = fltvalue(obj); lua_Number f = l_floor(n); if (n != f) { /* not an integral value? */ if (mode == 0) return 0; /* fails if mode demands integral value */ else if (mode > 1) /* needs ceil? */ f += 1; /* convert floor to ceil (remember: n != f) */ } return lua_numbertointeger(f, p); } else if (ttisinteger(obj)) { *p = ivalue(obj); return 1; } else if (cvt2num(obj) && luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) { obj = &v; goto again; /* convert result from 'luaO_str2num' to an integer */ } return 0; /* conversion failed */ } /* ** Try to convert a 'for' limit to an integer, preserving the ** semantics of the loop. ** (The following explanation assumes a non-negative step; it is valid ** for negative steps mutatis mutandis.) ** If the limit can be converted to an integer, rounding down, that is ** it. ** Otherwise, check whether the limit can be converted to a number. If ** the number is too large, it is OK to set the limit as LUA_MAXINTEGER, ** which means no limit. If the number is too negative, the loop ** should not run, because any initial integer value is larger than the ** limit. So, it sets the limit to LUA_MININTEGER. 'stopnow' corrects ** the extreme case when the initial value is LUA_MININTEGER, in which ** case the LUA_MININTEGER limit would still run the loop once. */ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step, int *stopnow) { *stopnow = 0; /* usually, let loops run */ if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */ lua_Number n; /* try to convert to float */ if (!tonumber(obj, &n)) /* cannot convert to float? */ return 0; /* not a number */ if (luai_numlt(0, n)) { /* if true, float is larger than max integer */ *p = LUA_MAXINTEGER; if (step < 0) *stopnow = 1; } else { /* float is smaller than min integer */ *p = LUA_MININTEGER; if (step >= 0) *stopnow = 1; } } return 1; } /* ** Complete a table access: if 't' is a table, 'tm' has its metamethod; ** otherwise, 'tm' is NULL. */ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *tm) { int loop; /* counter to avoid infinite loops */ lua_assert(tm != NULL || !ttistable(t)); for (loop = 0; loop < MAXTAGLOOP; loop++) { if (tm == NULL) { /* no metamethod (from a table)? */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); /* no metamethod */ } if (ttisfunction(tm)) { /* metamethod is a function */ luaT_callTM(L, tm, t, key, val, 1); /* call it */ return; } t = tm; /* else repeat access over 'tm' */ if (luaV_fastget(L,t,key,tm,luaH_get)) { /* try fast track */ setobj2s(L, val, tm); /* done */ return; } /* else repeat */ } luaG_runerror(L, "gettable chain too long; possible loop"); } /* ** Main function for table assignment (invoking metamethods if needed). ** Compute 't[key] = val' */ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, StkId val, const TValue *oldval) { int loop; /* counter to avoid infinite loops */ for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (oldval != NULL) { lua_assert(ttistable(t) && ttisnil(oldval)); /* must check the metamethod */ if ((tm = fasttm(L, hvalue(t)->metatable, TM_NEWINDEX)) == NULL && /* no metamethod; is there a previous entry in the table? */ (oldval != luaO_nilobject || /* no previous entry; must create one. (The next test is always true; we only need the assignment.) */ (oldval = luaH_newkey(L, hvalue(t), key), 1))) { /* no metamethod and (now) there is an entry with given key */ setobj2t(L, cast(TValue *, oldval), val); invalidateTMcache(hvalue(t)); luaC_barrierback(L, hvalue(t), val); return; } /* else will try the metamethod */ } else { /* not a table; check metamethod */ if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ if (ttisfunction(tm)) { luaT_callTM(L, tm, t, key, val, 0); return; } t = tm; /* else repeat assignment over 'tm' */ if (luaV_fastset(L, t, key, oldval, luaH_get, val)) return; /* done */ /* else loop */ } luaG_runerror(L, "settable chain too long; possible loop"); } /* ** Compare two strings 'ls' x 'rs', returning an integer smaller-equal- ** -larger than zero if 'ls' is smaller-equal-larger than 'rs'. ** The code is a little tricky because it allows '\0' in the strings ** and it uses 'strcoll' (to respect locales) for each segments ** of the strings. */ static int l_strcmp (const TString *ls, const TString *rs) { const char *l = getstr(ls); size_t ll = tsslen(ls); const char *r = getstr(rs); size_t lr = tsslen(rs); for (;;) { /* for each segment */ int temp = strcoll(l, r); if (temp != 0) /* not equal? */ return temp; /* done */ else { /* strings are equal up to a '\0' */ size_t len = strlen(l); /* index of first '\0' in both strings */ if (len == lr) /* 'rs' is finished? */ return (len == ll) ? 0 : 1; /* check 'ls' */ else if (len == ll) /* 'ls' is finished? */ return -1; /* 'ls' is smaller than 'rs' ('rs' is not finished) */ /* both strings longer than 'len'; go on comparing after the '\0' */ len++; l += len; ll -= len; r += len; lr -= len; } } } /* ** Check whether integer 'i' is less than float 'f'. If 'i' has an ** exact representation as a float ('l_intfitsf'), compare numbers as ** floats. Otherwise, if 'f' is outside the range for integers, result ** is trivial. Otherwise, compare them as integers. (When 'i' has no ** float representation, either 'f' is "far away" from 'i' or 'f' has ** no precision left for a fractional part; either way, how 'f' is ** truncated is irrelevant.) When 'f' is NaN, comparisons must result ** in false. */ static int LTintfloat (lua_Integer i, lua_Number f) { #if defined(l_intfitsf) if (!l_intfitsf(i)) { if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ return 1; /* f >= maxint + 1 > i */ else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */ return (i < cast(lua_Integer, f)); /* compare them as integers */ else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */ return 0; } #endif return luai_numlt(cast_num(i), f); /* compare them as floats */ } /* ** Check whether integer 'i' is less than or equal to float 'f'. ** See comments on previous function. */ static int LEintfloat (lua_Integer i, lua_Number f) { #if defined(l_intfitsf) if (!l_intfitsf(i)) { if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */ return 1; /* f >= maxint + 1 > i */ else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */ return (i <= cast(lua_Integer, f)); /* compare them as integers */ else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */ return 0; } #endif return luai_numle(cast_num(i), f); /* compare them as floats */ } /* ** Return 'l < r', for numbers. */ static int LTnum (const TValue *l, const TValue *r) { if (ttisinteger(l)) { lua_Integer li = ivalue(l); if (ttisinteger(r)) return li < ivalue(r); /* both are integers */ else /* 'l' is int and 'r' is float */ return LTintfloat(li, fltvalue(r)); /* l < r ? */ } else { lua_Number lf = fltvalue(l); /* 'l' must be float */ if (ttisfloat(r)) return luai_numlt(lf, fltvalue(r)); /* both are float */ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ return 0; /* NaN < i is always false */ else /* without NaN, (l < r) <--> not(r <= l) */ return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */ } } /* ** Return 'l <= r', for numbers. */ static int LEnum (const TValue *l, const TValue *r) { if (ttisinteger(l)) { lua_Integer li = ivalue(l); if (ttisinteger(r)) return li <= ivalue(r); /* both are integers */ else /* 'l' is int and 'r' is float */ return LEintfloat(li, fltvalue(r)); /* l <= r ? */ } else { lua_Number lf = fltvalue(l); /* 'l' must be float */ if (ttisfloat(r)) return luai_numle(lf, fltvalue(r)); /* both are float */ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */ return 0; /* NaN <= i is always false */ else /* without NaN, (l <= r) <--> not(r < l) */ return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */ } } /* ** Main operation less than; return 'l < r'. */ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ return LTnum(l, r); else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ return l_strcmp(tsvalue(l), tsvalue(r)) < 0; else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ luaG_ordererror(L, l, r); /* error */ return res; } /* ** Main operation less than or equal to; return 'l <= r'. If it needs ** a metamethod and there is no '__le', try '__lt', based on ** l <= r iff !(r < l) (assuming a total order). If the metamethod ** yields during this substitution, the continuation has to know ** about it (to negate the result of r<l); bit CIST_LEQ in the call ** status keeps that information. */ int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */ return LEnum(l, r); else if (ttisstring(l) && ttisstring(r)) /* both are strings? */ return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */ return res; else { /* try 'lt': */ L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ res = luaT_callorderTM(L, r, l, TM_LT); L->ci->callstatus ^= CIST_LEQ; /* clear mark */ if (res < 0) luaG_ordererror(L, l, r); return !res; /* result is negated */ } } /* ** Main operation for equality of Lua values; return 't1 == t2'. ** L == NULL means raw equality (no metamethods) */ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { const TValue *tm; if (ttype(t1) != ttype(t2)) { /* not the same variant? */ if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER) return 0; /* only numbers can be equal with different variants */ else { /* two numbers with different variants */ lua_Integer i1, i2; /* compare them as integers */ return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2); } } /* values have same type and same variant */ switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMINT: return (ivalue(t1) == ivalue(t2)); case LUA_TNUMFLT: return luai_numeq(fltvalue(t1), fltvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); case LUA_TLCF: return fvalue(t1) == fvalue(t2); case LUA_TSHRSTR: return eqshrstr(tsvalue(t1), tsvalue(t2)); case LUA_TLNGSTR: return luaS_eqlngstr(tsvalue(t1), tsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; else if (L == NULL) return 0; tm = fasttm(L, uvalue(t1)->metatable, TM_EQ); if (tm == NULL) tm = fasttm(L, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; else if (L == NULL) return 0; tm = fasttm(L, hvalue(t1)->metatable, TM_EQ); if (tm == NULL) tm = fasttm(L, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); } if (tm == NULL) /* no TM? */ return 0; /* objects are different */ luaT_callTM(L, tm, t1, t2, L->top, 1); /* call TM */ return !l_isfalse(L->top); } /* macro used by 'luaV_concat' to ensure that element at 'o' is a string */ #define tostring(L,o) \ (ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1))) #define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0) /* copy strings in stack from top - n up to top - 1 to buffer */ static void copy2buff (StkId top, int n, char *buff) { size_t tl = 0; /* size already copied */ do { size_t l = vslen(top - n); /* length of string being copied */ memcpy(buff + tl, svalue(top - n), l * sizeof(char)); tl += l; } while (--n > 0); } /* ** Main operation for concatenation: concat 'total' values in the stack, ** from 'L->top - total' up to 'L->top - 1'. */ void luaV_concat (lua_State *L, int total) { lua_assert(total >= 2); do { StkId top = L->top; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1)) luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT); else if (isemptystr(top - 1)) /* second operand is empty? */ cast_void(tostring(L, top - 2)); /* result is first operand */ else if (isemptystr(top - 2)) { /* first operand is an empty string? */ setobjs2s(L, top - 2, top - 1); /* result is second op. */ } else { /* at least two non-empty string values; get as many as possible */ size_t tl = vslen(top - 1); TString *ts; /* collect total length and number of strings */ for (n = 1; n < total && tostring(L, top - n - 1); n++) { size_t l = vslen(top - n - 1); if (l >= (MAX_SIZE/sizeof(char)) - tl) luaG_runerror(L, "string length overflow"); tl += l; } if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ char buff[LUAI_MAXSHORTLEN]; copy2buff(top, n, buff); /* copy strings to buffer */ ts = luaS_newlstr(L, buff, tl); } else { /* long string; copy strings directly to final result */ ts = luaS_createlngstrobj(L, tl); copy2buff(top, n, getstr(ts)); } setsvalue2s(L, top - n, ts); /* create result */ } total -= n-1; /* got 'n' strings to create 1 new */ L->top -= n-1; /* popped 'n' strings and pushed one */ } while (total > 1); /* repeat until only 1 result left */ } /* ** Main operation 'ra' = #rb'. */ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { const TValue *tm; switch (ttype(rb)) { case LUA_TTABLE: { Table *h = hvalue(rb); tm = fasttm(L, h->metatable, TM_LEN); if (tm) break; /* metamethod? break switch to call it */ setivalue(ra, luaH_getn(h)); /* else primitive len */ return; } case LUA_TSHRSTR: { setivalue(ra, tsvalue(rb)->shrlen); return; } case LUA_TLNGSTR: { setivalue(ra, tsvalue(rb)->u.lnglen); return; } default: { /* try metamethod */ tm = luaT_gettmbyobj(L, rb, TM_LEN); if (ttisnil(tm)) /* no metamethod? */ luaG_typeerror(L, rb, "get length of"); break; } } luaT_callTM(L, tm, rb, rb, ra, 1); } /* ** Integer division; return 'm // n', that is, floor(m/n). ** C division truncates its result (rounds towards zero). ** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, ** otherwise 'floor(q) == trunc(q) - 1'. */ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ if (n == 0) luaG_runerror(L, "attempt to divide by zero"); return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ } else { lua_Integer q = m / n; /* perform C division */ if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ q -= 1; /* correct result for different rounding */ return q; } } /* ** Integer modulus; return 'm % n'. (Assume that C '%' with ** negative operands follows C99 behavior. See previous comment ** about luaV_div.) */ lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ if (n == 0) luaG_runerror(L, "attempt to perform 'n%%0'"); return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ } else { lua_Integer r = m % n; if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ r += n; /* correct result for different rounding */ return r; } } /* number of bits in an integer */ #define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) /* ** Shift left operation. (Shift right just negates 'y'.) */ lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { if (y < 0) { /* shift right? */ if (y <= -NBITS) return 0; else return intop(>>, x, -y); } else { /* shift left */ if (y >= NBITS) return 0; else return intop(<<, x, y); } } /* ** check whether cached closure in prototype 'p' may be reused, that is, ** whether there is a cached closure with the same upvalues needed by ** new closure to be created. */ static LClosure *getcached (Proto *p, UpVal **encup, StkId base) { LClosure *c = p->cache; if (c != NULL) { /* is there a cached closure? */ int nup = p->sizeupvalues; Upvaldesc *uv = p->upvalues; int i; for (i = 0; i < nup; i++) { /* check whether it has right upvalues */ TValue *v = uv[i].instack ? base + uv[i].idx : encup[uv[i].idx]->v; if (c->upvals[i]->v != v) return NULL; /* wrong upvalue; cannot reuse closure */ } } return c; /* return cached closure (or NULL if no cached closure) */ } /* ** create a new Lua closure, push it in the stack, and initialize ** its upvalues. Note that the closure is not cached if prototype is ** already black (which means that 'cache' was already cleared by the ** GC). */ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, StkId ra) { int nup = p->sizeupvalues; Upvaldesc *uv = p->upvalues; int i; LClosure *ncl = luaF_newLclosure(L, nup); ncl->p = p; setclLvalue(L, ra, ncl); /* anchor new closure in stack */ for (i = 0; i < nup; i++) { /* fill in its upvalues */ if (uv[i].instack) /* upvalue refers to local variable? */ ncl->upvals[i] = luaF_findupval(L, base + uv[i].idx); else /* get upvalue from enclosing function */ ncl->upvals[i] = encup[uv[i].idx]; ncl->upvals[i]->refcount++; /* new closure is white, so we do not need a barrier here */ } if (!isblack(p)) /* cache will not break GC invariant? */ p->cache = ncl; /* save it on cache for reuse */ } /* ** finish execution of an opcode interrupted by an yield */ void luaV_finishOp (lua_State *L) { CallInfo *ci = L->ci; StkId base = ci->u.l.base; Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ OpCode op = GET_OPCODE(inst); switch (op) { /* finish its execution */ case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: case OP_MOD: case OP_POW: case OP_UNM: case OP_BNOT: case OP_LEN: case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { setobjs2s(L, base + GETARG_A(inst), --L->top); break; } case OP_LE: case OP_LT: case OP_EQ: { int res = !l_isfalse(L->top - 1); L->top--; if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ lua_assert(op == OP_LE); ci->callstatus ^= CIST_LEQ; /* clear mark */ res = !res; /* negate result */ } lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); if (res != GETARG_A(inst)) /* condition failed? */ ci->u.l.savedpc++; /* skip jump instruction */ break; } case OP_CONCAT: { StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ int b = GETARG_B(inst); /* first element to concatenate */ int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ setobj2s(L, top - 2, top); /* put TM result in proper position */ if (total > 1) { /* are there elements to concat? */ L->top = top - 1; /* top is one after last element (at top-2) */ luaV_concat(L, total); /* concat them (may yield again) */ } /* move final result to final position */ setobj2s(L, ci->u.l.base + GETARG_A(inst), L->top - 1); L->top = ci->top; /* restore top */ break; } case OP_TFORCALL: { lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); L->top = ci->top; /* correct top */ break; } case OP_CALL: { if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ L->top = ci->top; /* adjust results */ break; } case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: break; default: lua_assert(0); } } /* ** {================================================================== ** Function 'luaV_execute': main interpreter loop ** =================================================================== */ /* ** some macros for common tasks in 'luaV_execute' */ #define RA(i) (base+GETARG_A(i)) #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) /* execute a jump instruction */ #define dojump(ci,i,e) \ { int a = GETARG_A(i); \ if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \ ci->u.l.savedpc += GETARG_sBx(i) + e; } /* for test instructions, execute the jump instruction that follows it */ #define donextjump(ci) { i = *ci->u.l.savedpc; dojump(ci, i, 1); } #define Protect(x) { {x;}; base = ci->u.l.base; } #define checkGC(L,c) \ { luaC_condGC(L, L->top = (c), /* limit of live values */ \ Protect(L->top = ci->top)); /* restore top */ \ luai_threadyield(L); } #define vmdispatch(o) switch(o) #define vmcase(l) case l: #define vmbreak break /* ** copy of 'luaV_gettable', but protecting call to potential metamethod ** (which can reallocate the stack) */ #define gettableProtected(L,t,k,v) { const TValue *aux; \ if (luaV_fastget(L,t,k,aux,luaH_get)) { setobj2s(L, v, aux); } \ else Protect(luaV_finishget(L,t,k,v,aux)); } /* same for 'luaV_settable' */ #define settableProtected(L,t,k,v) { const TValue *slot; \ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \ Protect(luaV_finishset(L,t,k,v,slot)); } void luaV_execute (lua_State *L) { CallInfo *ci = L->ci; LClosure *cl; TValue *k; StkId base; ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ newframe: /* reentry point when frame changes (call/return) */ lua_assert(ci == L->ci); cl = clLvalue(ci->func); /* local reference to function's closure */ k = cl->p->k; /* local reference to function's constant table */ base = ci->u.l.base; /* local copy of function's base */ /* main loop of interpreter */ for (;;) { Instruction i = *(ci->u.l.savedpc++); StkId ra; if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) Protect(luaG_traceexec(L)); /* WARNING: several calls may realloc the stack and invalidate 'ra' */ ra = RA(i); lua_assert(base == ci->u.l.base); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); vmdispatch (GET_OPCODE(i)) { vmcase(OP_MOVE) { setobjs2s(L, ra, RB(i)); vmbreak; } vmcase(OP_LOADK) { TValue *rb = k + GETARG_Bx(i); setobj2s(L, ra, rb); vmbreak; } vmcase(OP_LOADKX) { TValue *rb; lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); rb = k + GETARG_Ax(*ci->u.l.savedpc++); setobj2s(L, ra, rb); vmbreak; } vmcase(OP_LOADBOOL) { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ vmbreak; } vmcase(OP_LOADNIL) { int b = GETARG_B(i); do { setnilvalue(ra++); } while (b--); vmbreak; } vmcase(OP_GETUPVAL) { int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); vmbreak; } vmcase(OP_GETTABUP) { TValue *upval = cl->upvals[GETARG_B(i)]->v; TValue *rc = RKC(i); gettableProtected(L, upval, rc, ra); vmbreak; } vmcase(OP_GETTABLE) { StkId rb = RB(i); TValue *rc = RKC(i); gettableProtected(L, rb, rc, ra); vmbreak; } vmcase(OP_SETTABUP) { TValue *upval = cl->upvals[GETARG_A(i)]->v; TValue *rb = RKB(i); TValue *rc = RKC(i); settableProtected(L, upval, rb, rc); vmbreak; } vmcase(OP_SETUPVAL) { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_upvalbarrier(L, uv); vmbreak; } vmcase(OP_SETTABLE) { TValue *rb = RKB(i); TValue *rc = RKC(i); settableProtected(L, ra, rb, rc); vmbreak; } vmcase(OP_NEWTABLE) { int b = GETARG_B(i); int c = GETARG_C(i); Table *t = luaH_new(L); sethvalue(L, ra, t); if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); checkGC(L, ra + 1); vmbreak; } vmcase(OP_SELF) { const TValue *aux; StkId rb = RB(i); TValue *rc = RKC(i); TString *key = tsvalue(rc); /* key must be a string */ setobjs2s(L, ra + 1, rb); if (luaV_fastget(L, rb, key, aux, luaH_getstr)) { setobj2s(L, ra, aux); } else Protect(luaV_finishget(L, rb, rc, ra, aux)); vmbreak; } vmcase(OP_ADD) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(ra, intop(+, ib, ic)); } else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { setfltvalue(ra, luai_numadd(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); } vmbreak; } vmcase(OP_SUB) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(ra, intop(-, ib, ic)); } else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { setfltvalue(ra, luai_numsub(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); } vmbreak; } vmcase(OP_MUL) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(ra, intop(*, ib, ic)); } else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { setfltvalue(ra, luai_nummul(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); } vmbreak; } vmcase(OP_DIV) { /* float division (always with floats) */ TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; if (tonumber(rb, &nb) && tonumber(rc, &nc)) { setfltvalue(ra, luai_numdiv(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } vmbreak; } vmcase(OP_BAND) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Integer ib; lua_Integer ic; if (tointeger(rb, &ib) && tointeger(rc, &ic)) { setivalue(ra, intop(&, ib, ic)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); } vmbreak; } vmcase(OP_BOR) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Integer ib; lua_Integer ic; if (tointeger(rb, &ib) && tointeger(rc, &ic)) { setivalue(ra, intop(|, ib, ic)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); } vmbreak; } vmcase(OP_BXOR) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Integer ib; lua_Integer ic; if (tointeger(rb, &ib) && tointeger(rc, &ic)) { setivalue(ra, intop(^, ib, ic)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); } vmbreak; } vmcase(OP_SHL) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Integer ib; lua_Integer ic; if (tointeger(rb, &ib) && tointeger(rc, &ic)) { setivalue(ra, luaV_shiftl(ib, ic)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); } vmbreak; } vmcase(OP_SHR) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Integer ib; lua_Integer ic; if (tointeger(rb, &ib) && tointeger(rc, &ic)) { setivalue(ra, luaV_shiftl(ib, -ic)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); } vmbreak; } vmcase(OP_MOD) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(ra, luaV_mod(L, ib, ic)); } else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { lua_Number m; luai_nummod(L, nb, nc, m); setfltvalue(ra, m); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } vmbreak; } vmcase(OP_IDIV) { /* floor division */ TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); setivalue(ra, luaV_div(L, ib, ic)); } else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { setfltvalue(ra, luai_numidiv(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } vmbreak; } vmcase(OP_POW) { TValue *rb = RKB(i); TValue *rc = RKC(i); lua_Number nb; lua_Number nc; if (tonumber(rb, &nb) && tonumber(rc, &nc)) { setfltvalue(ra, luai_numpow(L, nb, nc)); } else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); } vmbreak; } vmcase(OP_UNM) { TValue *rb = RB(i); lua_Number nb; if (ttisinteger(rb)) { lua_Integer ib = ivalue(rb); setivalue(ra, intop(-, 0, ib)); } else if (tonumber(rb, &nb)) { setfltvalue(ra, luai_numunm(L, nb)); } else { Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); } vmbreak; } vmcase(OP_BNOT) { TValue *rb = RB(i); lua_Integer ib; if (tointeger(rb, &ib)) { setivalue(ra, intop(^, ~l_castS2U(0), ib)); } else { Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); } vmbreak; } vmcase(OP_NOT) { TValue *rb = RB(i); int res = l_isfalse(rb); /* next assignment may change this value */ setbvalue(ra, res); vmbreak; } vmcase(OP_LEN) { Protect(luaV_objlen(L, ra, RB(i))); vmbreak; } vmcase(OP_CONCAT) { int b = GETARG_B(i); int c = GETARG_C(i); StkId rb; L->top = base + c + 1; /* mark the end of concat operands */ Protect(luaV_concat(L, c - b + 1)); ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */ rb = base + b; setobjs2s(L, ra, rb); checkGC(L, (ra >= rb ? ra + 1 : rb)); L->top = ci->top; /* restore top */ vmbreak; } vmcase(OP_JMP) { dojump(ci, i, 0); vmbreak; } vmcase(OP_EQ) { TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( if (luaV_equalobj(L, rb, rc) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) vmbreak; } vmcase(OP_LT) { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) vmbreak; } vmcase(OP_LE) { Protect( if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) ci->u.l.savedpc++; else donextjump(ci); ) vmbreak; } vmcase(OP_TEST) { if (GETARG_C(i) ? l_isfalse(ra) : !l_isfalse(ra)) ci->u.l.savedpc++; else donextjump(ci); vmbreak; } vmcase(OP_TESTSET) { TValue *rb = RB(i); if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) ci->u.l.savedpc++; else { setobjs2s(L, ra, rb); donextjump(ci); } vmbreak; } vmcase(OP_CALL) { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; if (b != 0) L->top = ra+b; /* else previous instruction set top */ if (luaD_precall(L, ra, nresults)) { /* C function? */ if (nresults >= 0) L->top = ci->top; /* adjust results */ Protect((void)0); /* update 'base' */ } else { /* Lua function */ ci = L->ci; goto newframe; /* restart luaV_execute over new Lua function */ } vmbreak; } vmcase(OP_TAILCALL) { int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ Protect((void)0); /* update 'base' */ } else { /* tail call: put called frame (n) in place of caller one (o) */ CallInfo *nci = L->ci; /* called frame */ CallInfo *oci = nci->previous; /* caller frame */ StkId nfunc = nci->func; /* called function */ StkId ofunc = oci->func; /* caller function */ /* last stack slot filled by 'precall' */ StkId lim = nci->u.l.base + getproto(nfunc)->numparams; int aux; /* close all upvalues from previous call */ if (cl->p->sizep > 0) luaF_close(L, oci->u.l.base); /* move new frame into old one */ for (aux = 0; nfunc + aux < lim; aux++) setobjs2s(L, ofunc + aux, nfunc + aux); oci->u.l.base = ofunc + (nci->u.l.base - nfunc); /* correct base */ oci->top = L->top = ofunc + (L->top - nfunc); /* correct top */ oci->u.l.savedpc = nci->u.l.savedpc; oci->callstatus |= CIST_TAIL; /* function was tail called */ ci = L->ci = oci; /* remove new frame */ lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); goto newframe; /* restart luaV_execute over new Lua function */ } vmbreak; } vmcase(OP_RETURN) { int b = GETARG_B(i); if (cl->p->sizep > 0) luaF_close(L, base); b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ return; /* external invocation: return */ else { /* invocation via reentry: continue execution */ ci = L->ci; if (b) L->top = ci->top; lua_assert(isLua(ci)); lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); goto newframe; /* restart luaV_execute over new Lua function */ } } vmcase(OP_FORLOOP) { if (ttisinteger(ra)) { /* integer loop? */ lua_Integer step = ivalue(ra + 2); lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */ lua_Integer limit = ivalue(ra + 1); if ((0 < step) ? (idx <= limit) : (limit <= idx)) { ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ chgivalue(ra, idx); /* update internal index... */ setivalue(ra + 3, idx); /* ...and external index */ } } else { /* floating loop */ lua_Number step = fltvalue(ra + 2); lua_Number idx = luai_numadd(L, fltvalue(ra), step); /* inc. index */ lua_Number limit = fltvalue(ra + 1); if (luai_numlt(0, step) ? luai_numle(idx, limit) : luai_numle(limit, idx)) { ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ chgfltvalue(ra, idx); /* update internal index... */ setfltvalue(ra + 3, idx); /* ...and external index */ } } vmbreak; } vmcase(OP_FORPREP) { TValue *init = ra; TValue *plimit = ra + 1; TValue *pstep = ra + 2; lua_Integer ilimit; int stopnow; if (ttisinteger(init) && ttisinteger(pstep) && forlimit(plimit, &ilimit, ivalue(pstep), &stopnow)) { /* all values are integer */ lua_Integer initv = (stopnow ? 0 : ivalue(init)); setivalue(plimit, ilimit); setivalue(init, intop(-, initv, ivalue(pstep))); } else { /* try making all values floats */ lua_Number ninit; lua_Number nlimit; lua_Number nstep; if (!tonumber(plimit, &nlimit)) luaG_runerror(L, "'for' limit must be a number"); setfltvalue(plimit, nlimit); if (!tonumber(pstep, &nstep)) luaG_runerror(L, "'for' step must be a number"); setfltvalue(pstep, nstep); if (!tonumber(init, &ninit)) luaG_runerror(L, "'for' initial value must be a number"); setfltvalue(init, luai_numsub(L, ninit, nstep)); } ci->u.l.savedpc += GETARG_sBx(i); vmbreak; } vmcase(OP_TFORCALL) { StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); setobjs2s(L, cb, ra); L->top = cb + 3; /* func. + 2 args (state and index) */ Protect(luaD_call(L, cb, GETARG_C(i))); L->top = ci->top; i = *(ci->u.l.savedpc++); /* go to next instruction */ ra = RA(i); lua_assert(GET_OPCODE(i) == OP_TFORLOOP); goto l_tforloop; } vmcase(OP_TFORLOOP) { l_tforloop: if (!ttisnil(ra + 1)) { /* continue loop? */ setobjs2s(L, ra, ra + 1); /* save control variable */ ci->u.l.savedpc += GETARG_sBx(i); /* jump back */ } vmbreak; } vmcase(OP_SETLIST) { int n = GETARG_B(i); int c = GETARG_C(i); unsigned int last; Table *h; if (n == 0) n = cast_int(L->top - ra) - 1; if (c == 0) { lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG); c = GETARG_Ax(*ci->u.l.savedpc++); } h = hvalue(ra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* preallocate it at once */ for (; n > 0; n--) { TValue *val = ra+n; luaH_setint(L, h, last--, val); luaC_barrierback(L, h, val); } L->top = ci->top; /* correct top (in case of previous open call) */ vmbreak; } vmcase(OP_CLOSURE) { Proto *p = cl->p->p[GETARG_Bx(i)]; LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ if (ncl == NULL) /* no match? */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ else setclLvalue(L, ra, ncl); /* push cashed closure */ checkGC(L, ra + 1); vmbreak; } vmcase(OP_VARARG) { int b = GETARG_B(i) - 1; /* required results */ int j; int n = cast_int(base - ci->func) - cl->p->numparams - 1; if (n < 0) /* less arguments than parameters? */ n = 0; /* no vararg arguments */ if (b < 0) { /* B == 0? */ b = n; /* get all var. arguments */ Protect(luaD_checkstack(L, n)); ra = RA(i); /* previous call may change the stack */ L->top = ra + n; } for (j = 0; j < b && j < n; j++) setobjs2s(L, ra + j, base - n + j); for (; j < b; j++) /* complete required results with nil */ setnilvalue(ra + j); vmbreak; } vmcase(OP_EXTRAARG) { lua_assert(0); vmbreak; } } } } /* }================================================================== */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lualib.h��������������������������������������������������������������������������0000644�0001751�0001751�00000002225�12675241401�012426� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $ ** Lua standard libraries ** See Copyright Notice in lua.h */ #ifndef lualib_h #define lualib_h #include "lua.h" LUAMOD_API int (luaopen_base) (lua_State *L); #define LUA_COLIBNAME "coroutine" LUAMOD_API int (luaopen_coroutine) (lua_State *L); #define LUA_TABLIBNAME "table" LUAMOD_API int (luaopen_table) (lua_State *L); #define LUA_IOLIBNAME "io" LUAMOD_API int (luaopen_io) (lua_State *L); #define LUA_OSLIBNAME "os" LUAMOD_API int (luaopen_os) (lua_State *L); #define LUA_STRLIBNAME "string" LUAMOD_API int (luaopen_string) (lua_State *L); #define LUA_UTF8LIBNAME "utf8" LUAMOD_API int (luaopen_utf8) (lua_State *L); #define LUA_BITLIBNAME "bit32" LUAMOD_API int (luaopen_bit32) (lua_State *L); #define LUA_MATHLIBNAME "math" LUAMOD_API int (luaopen_math) (lua_State *L); #define LUA_DBLIBNAME "debug" LUAMOD_API int (luaopen_debug) (lua_State *L); #define LUA_LOADLIBNAME "package" LUAMOD_API int (luaopen_package) (lua_State *L); /* open all previous libraries */ LUALIB_API void (luaL_openlibs) (lua_State *L); #if !defined(lua_assert) #define lua_assert(x) ((void)0) #endif #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/Makefile��������������������������������������������������������������������������0000644�0001751�0001751�00000010507�12675241401�012447� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# A simplified Makefile for building the Lua library on Mac OS X or Linux. LUA_LIB = liblua.a CC = cc PLATFORM = $(shell uname) ifeq "$(PLATFORM)" "Darwin" CFLAGS = -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_MACOSX -arch x86_64 else CFLAGS = -O2 -Wall -Wextra -DLUA_COMPAT_5_2 -DLUA_USE_LINUX endif OBJ_FILES = lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o \ lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o \ ltm.o lundump.o lvm.o lzio.o \ lauxlib.o lbaselib.o lbitlib.o lcorolib.o ldblib.o liolib.o \ lmathlib.o loslib.o lstrlib.o ltablib.o lutf8lib.o loadlib.o linit.o all: $(LUA_LIB) $(LUA_LIB): $(OBJ_FILES) ar rcu $@ $(OBJ_FILES) ranlib $@ clean: rm -f $(LUA_LIB) $(OBJ_FILES) depend: @$(CC) $(CFLAGS) -MM l*.c lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \ ltable.h lundump.h lvm.h lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h lbitlib.o: lbitlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \ llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \ ldo.h lgc.h lstring.h ltable.h lvm.h lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \ ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \ lparser.h lstring.h ltable.h lundump.h lvm.h ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \ ltm.h lzio.h lmem.h lundump.h lfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \ lgc.h lstate.h ltm.h lzio.h lmem.h lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \ lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \ lstring.h ltable.h lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \ ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \ lvm.h lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \ llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \ ldo.h lfunc.h lstring.h lgc.h ltable.h lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \ lstring.h ltable.h lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \ lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \ lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \ lundump.h lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \ ltable.h lvm.h lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \ lobject.h ltm.h lzio.h �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lcode.c���������������������������������������������������������������������������0000644�0001751�0001751�00000060274�12675241401�012247� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lcode.c,v 2.103 2015/11/19 19:16:22 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ #define lcode_c #define LUA_CORE #include "lprefix.h" #include <math.h> #include <stdlib.h> #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstring.h" #include "ltable.h" #include "lvm.h" /* Maximum number of registers in a Lua function (must fit in 8 bits) */ #define MAXREGS 255 #define hasjumps(e) ((e)->t != (e)->f) static int tonumeral(expdesc *e, TValue *v) { if (hasjumps(e)) return 0; /* not a numeral */ switch (e->k) { case VKINT: if (v) setivalue(v, e->u.ival); return 1; case VKFLT: if (v) setfltvalue(v, e->u.nval); return 1; default: return 0; } } void luaK_nil (FuncState *fs, int from, int n) { Instruction *previous; int l = from + n - 1; /* last register to set nil */ if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ previous = &fs->f->code[fs->pc-1]; if (GET_OPCODE(*previous) == OP_LOADNIL) { int pfrom = GETARG_A(*previous); int pl = pfrom + GETARG_B(*previous); if ((pfrom <= from && from <= pl + 1) || (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ if (pl > l) l = pl; /* l = max(l, pl) */ SETARG_A(*previous, from); SETARG_B(*previous, l - from); return; } } /* else go through */ } luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ } int luaK_jump (FuncState *fs) { int jpc = fs->jpc; /* save list of jumps to here */ int j; fs->jpc = NO_JUMP; j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); luaK_concat(fs, &j, jpc); /* keep them on hold */ return j; } void luaK_ret (FuncState *fs, int first, int nret) { luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); } static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { luaK_codeABC(fs, op, A, B, C); return luaK_jump(fs); } static void fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; int offset = dest-(pc+1); lua_assert(dest != NO_JUMP); if (abs(offset) > MAXARG_sBx) luaX_syntaxerror(fs->ls, "control structure too long"); SETARG_sBx(*jmp, offset); } /* ** returns current 'pc' and marks it as a jump target (to avoid wrong ** optimizations with consecutive instructions not in the same basic block). */ int luaK_getlabel (FuncState *fs) { fs->lasttarget = fs->pc; return fs->pc; } static int getjump (FuncState *fs, int pc) { int offset = GETARG_sBx(fs->f->code[pc]); if (offset == NO_JUMP) /* point to itself represents end of list */ return NO_JUMP; /* end of list */ else return (pc+1)+offset; /* turn offset into absolute position */ } static Instruction *getjumpcontrol (FuncState *fs, int pc) { Instruction *pi = &fs->f->code[pc]; if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) return pi-1; else return pi; } /* ** check whether list has any jump that do not produce a value ** (or produce an inverted value) */ static int need_value (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) { Instruction i = *getjumpcontrol(fs, list); if (GET_OPCODE(i) != OP_TESTSET) return 1; } return 0; /* not found */ } static int patchtestreg (FuncState *fs, int node, int reg) { Instruction *i = getjumpcontrol(fs, node); if (GET_OPCODE(*i) != OP_TESTSET) return 0; /* cannot patch other instructions */ if (reg != NO_REG && reg != GETARG_B(*i)) SETARG_A(*i, reg); else /* no register to put value or register already has the value */ *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); return 1; } static void removevalues (FuncState *fs, int list) { for (; list != NO_JUMP; list = getjump(fs, list)) patchtestreg(fs, list, NO_REG); } static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget) { while (list != NO_JUMP) { int next = getjump(fs, list); if (patchtestreg(fs, list, reg)) fixjump(fs, list, vtarget); else fixjump(fs, list, dtarget); /* jump to default target */ list = next; } } static void dischargejpc (FuncState *fs) { patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); fs->jpc = NO_JUMP; } void luaK_patchlist (FuncState *fs, int list, int target) { if (target == fs->pc) luaK_patchtohere(fs, list); else { lua_assert(target < fs->pc); patchlistaux(fs, list, target, NO_REG, target); } } void luaK_patchclose (FuncState *fs, int list, int level) { level++; /* argument is +1 to reserve 0 as non-op */ while (list != NO_JUMP) { int next = getjump(fs, list); lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP && (GETARG_A(fs->f->code[list]) == 0 || GETARG_A(fs->f->code[list]) >= level)); SETARG_A(fs->f->code[list], level); list = next; } } void luaK_patchtohere (FuncState *fs, int list) { luaK_getlabel(fs); luaK_concat(fs, &fs->jpc, list); } void luaK_concat (FuncState *fs, int *l1, int l2) { if (l2 == NO_JUMP) return; else if (*l1 == NO_JUMP) *l1 = l2; else { int list = *l1; int next; while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ list = next; fixjump(fs, list, l2); } } static int luaK_code (FuncState *fs, Instruction i) { Proto *f = fs->f; dischargejpc(fs); /* 'pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "opcodes"); f->code[fs->pc] = i; /* save corresponding line information */ luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int, MAX_INT, "opcodes"); f->lineinfo[fs->pc] = fs->ls->lastline; return fs->pc++; } int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { lua_assert(getOpMode(o) == iABC); lua_assert(getBMode(o) != OpArgN || b == 0); lua_assert(getCMode(o) != OpArgN || c == 0); lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C); return luaK_code(fs, CREATE_ABC(o, a, b, c)); } int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); lua_assert(getCMode(o) == OpArgN); lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx); return luaK_code(fs, CREATE_ABx(o, a, bc)); } static int codeextraarg (FuncState *fs, int a) { lua_assert(a <= MAXARG_Ax); return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a)); } int luaK_codek (FuncState *fs, int reg, int k) { if (k <= MAXARG_Bx) return luaK_codeABx(fs, OP_LOADK, reg, k); else { int p = luaK_codeABx(fs, OP_LOADKX, reg, 0); codeextraarg(fs, k); return p; } } void luaK_checkstack (FuncState *fs, int n) { int newstack = fs->freereg + n; if (newstack > fs->f->maxstacksize) { if (newstack >= MAXREGS) luaX_syntaxerror(fs->ls, "function or expression needs too many registers"); fs->f->maxstacksize = cast_byte(newstack); } } void luaK_reserveregs (FuncState *fs, int n) { luaK_checkstack(fs, n); fs->freereg += n; } static void freereg (FuncState *fs, int reg) { if (!ISK(reg) && reg >= fs->nactvar) { fs->freereg--; lua_assert(reg == fs->freereg); } } static void freeexp (FuncState *fs, expdesc *e) { if (e->k == VNONRELOC) freereg(fs, e->u.info); } /* ** Use scanner's table to cache position of constants in constant list ** and try to reuse constants */ static int addk (FuncState *fs, TValue *key, TValue *v) { lua_State *L = fs->ls->L; Proto *f = fs->f; TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ int k, oldsize; if (ttisinteger(idx)) { /* is there an index there? */ k = cast_int(ivalue(idx)); /* correct value? (warning: must distinguish floats from integers!) */ if (k < fs->nk && ttype(&f->k[k]) == ttype(v) && luaV_rawequalobj(&f->k[k], v)) return k; /* reuse index */ } /* constant not found; create a new entry */ oldsize = f->sizek; k = fs->nk; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ setivalue(idx, k); luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[k], v); fs->nk++; luaC_barrier(L, f, v); return k; } int luaK_stringK (FuncState *fs, TString *s) { TValue o; setsvalue(fs->ls->L, &o, s); return addk(fs, &o, &o); } /* ** Integers use userdata as keys to avoid collision with floats with same ** value; conversion to 'void*' used only for hashing, no "precision" ** problems */ int luaK_intK (FuncState *fs, lua_Integer n) { TValue k, o; setpvalue(&k, cast(void*, cast(size_t, n))); setivalue(&o, n); return addk(fs, &k, &o); } static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; setfltvalue(&o, r); return addk(fs, &o, &o); } static int boolK (FuncState *fs, int b) { TValue o; setbvalue(&o, b); return addk(fs, &o, &o); } static int nilK (FuncState *fs) { TValue k, v; setnilvalue(&v); /* cannot use nil as key; instead use table itself to represent nil */ sethvalue(fs->ls->L, &k, fs->ls->h); return addk(fs, &k, &v); } void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { if (e->k == VCALL) { /* expression is an open function call? */ SETARG_C(getcode(fs, e), nresults+1); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), nresults+1); SETARG_A(getcode(fs, e), fs->freereg); luaK_reserveregs(fs, 1); } } void luaK_setoneret (FuncState *fs, expdesc *e) { if (e->k == VCALL) { /* expression is an open function call? */ e->k = VNONRELOC; e->u.info = GETARG_A(getcode(fs, e)); } else if (e->k == VVARARG) { SETARG_B(getcode(fs, e), 2); e->k = VRELOCABLE; /* can relocate its simple result */ } } void luaK_dischargevars (FuncState *fs, expdesc *e) { switch (e->k) { case VLOCAL: { e->k = VNONRELOC; break; } case VUPVAL: { e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); e->k = VRELOCABLE; break; } case VINDEXED: { OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ freereg(fs, e->u.ind.idx); if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ freereg(fs, e->u.ind.t); op = OP_GETTABLE; } e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); e->k = VRELOCABLE; break; } case VVARARG: case VCALL: { luaK_setoneret(fs, e); break; } default: break; /* there is one value available (somewhere) */ } } static int code_label (FuncState *fs, int A, int b, int jump) { luaK_getlabel(fs); /* those instructions may be jump targets */ return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); } static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: { luaK_nil(fs, reg, 1); break; } case VFALSE: case VTRUE: { luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); break; } case VK: { luaK_codek(fs, reg, e->u.info); break; } case VKFLT: { luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval)); break; } case VKINT: { luaK_codek(fs, reg, luaK_intK(fs, e->u.ival)); break; } case VRELOCABLE: { Instruction *pc = &getcode(fs, e); SETARG_A(*pc, reg); break; } case VNONRELOC: { if (reg != e->u.info) luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0); break; } default: { lua_assert(e->k == VVOID || e->k == VJMP); return; /* nothing to do... */ } } e->u.info = reg; e->k = VNONRELOC; } static void discharge2anyreg (FuncState *fs, expdesc *e) { if (e->k != VNONRELOC) { luaK_reserveregs(fs, 1); discharge2reg(fs, e, fs->freereg-1); } } static void exp2reg (FuncState *fs, expdesc *e, int reg) { discharge2reg(fs, e, reg); if (e->k == VJMP) luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */ if (hasjumps(e)) { int final; /* position after whole expression */ int p_f = NO_JUMP; /* position of an eventual LOAD false */ int p_t = NO_JUMP; /* position of an eventual LOAD true */ if (need_value(fs, e->t) || need_value(fs, e->f)) { int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); p_f = code_label(fs, reg, 0, 1); p_t = code_label(fs, reg, 1, 0); luaK_patchtohere(fs, fj); } final = luaK_getlabel(fs); patchlistaux(fs, e->f, final, reg, p_f); patchlistaux(fs, e->t, final, reg, p_t); } e->f = e->t = NO_JUMP; e->u.info = reg; e->k = VNONRELOC; } void luaK_exp2nextreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); freeexp(fs, e); luaK_reserveregs(fs, 1); exp2reg(fs, e, fs->freereg - 1); } int luaK_exp2anyreg (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); if (e->k == VNONRELOC) { if (!hasjumps(e)) return e->u.info; /* exp is already in a register */ if (e->u.info >= fs->nactvar) { /* reg. is not a local? */ exp2reg(fs, e, e->u.info); /* put value on it */ return e->u.info; } } luaK_exp2nextreg(fs, e); /* default */ return e->u.info; } void luaK_exp2anyregup (FuncState *fs, expdesc *e) { if (e->k != VUPVAL || hasjumps(e)) luaK_exp2anyreg(fs, e); } void luaK_exp2val (FuncState *fs, expdesc *e) { if (hasjumps(e)) luaK_exp2anyreg(fs, e); else luaK_dischargevars(fs, e); } int luaK_exp2RK (FuncState *fs, expdesc *e) { luaK_exp2val(fs, e); switch (e->k) { case VTRUE: case VFALSE: case VNIL: { if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); e->k = VK; return RKASK(e->u.info); } else break; } case VKINT: { e->u.info = luaK_intK(fs, e->u.ival); e->k = VK; goto vk; } case VKFLT: { e->u.info = luaK_numberK(fs, e->u.nval); e->k = VK; } /* FALLTHROUGH */ case VK: { vk: if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ return RKASK(e->u.info); else break; } default: break; } /* not a constant in the right range: put it in a register */ return luaK_exp2anyreg(fs, e); } void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); exp2reg(fs, ex, var->u.info); return; } case VUPVAL: { int e = luaK_exp2anyreg(fs, ex); luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0); break; } case VINDEXED: { OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP; int e = luaK_exp2RK(fs, ex); luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e); break; } default: { lua_assert(0); /* invalid var kind to store */ break; } } freeexp(fs, ex); } void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { int ereg; luaK_exp2anyreg(fs, e); ereg = e->u.info; /* register where 'e' was placed */ freeexp(fs, e); e->u.info = fs->freereg; /* base register for op_self */ e->k = VNONRELOC; luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */ luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key)); freeexp(fs, key); } static void invertjump (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->u.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); SETARG_A(*pc, !(GETARG_A(*pc))); } static int jumponcond (FuncState *fs, expdesc *e, int cond) { if (e->k == VRELOCABLE) { Instruction ie = getcode(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); } void luaK_goiftrue (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { case VJMP: { invertjump(fs, e); pc = e->u.info; break; } case VK: case VKFLT: case VKINT: case VTRUE: { pc = NO_JUMP; /* always true; do nothing */ break; } default: { pc = jumponcond(fs, e, 0); break; } } luaK_concat(fs, &e->f, pc); /* insert last jump in 'f' list */ luaK_patchtohere(fs, e->t); e->t = NO_JUMP; } void luaK_goiffalse (FuncState *fs, expdesc *e) { int pc; /* pc of last jump */ luaK_dischargevars(fs, e); switch (e->k) { case VJMP: { pc = e->u.info; break; } case VNIL: case VFALSE: { pc = NO_JUMP; /* always false; do nothing */ break; } default: { pc = jumponcond(fs, e, 1); break; } } luaK_concat(fs, &e->t, pc); /* insert last jump in 't' list */ luaK_patchtohere(fs, e->f); e->f = NO_JUMP; } static void codenot (FuncState *fs, expdesc *e) { luaK_dischargevars(fs, e); switch (e->k) { case VNIL: case VFALSE: { e->k = VTRUE; break; } case VK: case VKFLT: case VKINT: case VTRUE: { e->k = VFALSE; break; } case VJMP: { invertjump(fs, e); break; } case VRELOCABLE: case VNONRELOC: { discharge2anyreg(fs, e); freeexp(fs, e); e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); e->k = VRELOCABLE; break; } default: { lua_assert(0); /* cannot happen */ break; } } /* interchange true and false lists */ { int temp = e->f; e->f = e->t; e->t = temp; } removevalues(fs, e->f); removevalues(fs, e->t); } void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { lua_assert(!hasjumps(t)); t->u.ind.t = t->u.info; t->u.ind.idx = luaK_exp2RK(fs, k); t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : check_exp(vkisinreg(t->k), VLOCAL); t->k = VINDEXED; } /* ** return false if folding can raise an error */ static int validop (int op, TValue *v1, TValue *v2) { switch (op) { case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ lua_Integer i; return (tointeger(v1, &i) && tointeger(v2, &i)); } case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ return (nvalue(v2) != 0); default: return 1; /* everything else is valid */ } } /* ** Try to "constant-fold" an operation; return 1 iff successful */ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) { TValue v1, v2, res; if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2)) return 0; /* non-numeric operands or not safe to fold */ luaO_arith(fs->ls->L, op, &v1, &v2, &res); /* does operation */ if (ttisinteger(&res)) { e1->k = VKINT; e1->u.ival = ivalue(&res); } else { /* folds neither NaN nor 0.0 (to avoid collapsing with -0.0) */ lua_Number n = fltvalue(&res); if (luai_numisnan(n) || n == 0) return 0; e1->k = VKFLT; e1->u.nval = n; } return 1; } /* ** Code for binary and unary expressions that "produce values" ** (arithmetic operations, bitwise operations, concat, length). First ** try to do constant folding (only for numeric [arithmetic and ** bitwise] operations, which is what 'lua_arith' accepts). ** Expression to produce final result will be encoded in 'e1'. */ static void codeexpval (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2, int line) { lua_assert(op >= OP_ADD); if (op <= OP_BNOT && constfolding(fs, (op - OP_ADD) + LUA_OPADD, e1, e2)) return; /* result has been folded */ else { int o1, o2; /* move operands to registers (if needed) */ if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */ o2 = 0; /* no second expression */ o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */ } else { /* regular case (binary operators) */ o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ o1 = luaK_exp2RK(fs, e1); } if (o1 > o2) { /* free registers in proper order */ freeexp(fs, e1); freeexp(fs, e2); } else { freeexp(fs, e2); freeexp(fs, e1); } e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */ e1->k = VRELOCABLE; /* all those operations are relocatable */ luaK_fixline(fs, line); } } static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, expdesc *e2) { int o1 = luaK_exp2RK(fs, e1); int o2 = luaK_exp2RK(fs, e2); freeexp(fs, e2); freeexp(fs, e1); if (cond == 0 && op != OP_EQ) { int temp; /* exchange args to replace by '<' or '<=' */ temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ cond = 1; } e1->u.info = condjump(fs, op, cond, o1, o2); e1->k = VJMP; } void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { expdesc e2; e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0; switch (op) { case OPR_MINUS: case OPR_BNOT: case OPR_LEN: { codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line); break; } case OPR_NOT: codenot(fs, e); break; default: lua_assert(0); } } void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { switch (op) { case OPR_AND: { luaK_goiftrue(fs, v); break; } case OPR_OR: { luaK_goiffalse(fs, v); break; } case OPR_CONCAT: { luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: case OPR_BAND: case OPR_BOR: case OPR_BXOR: case OPR_SHL: case OPR_SHR: { if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v); break; } default: { luaK_exp2RK(fs, v); break; } } } void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2, int line) { switch (op) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->f, e1->f); *e1 = *e2; break; } case OPR_OR: { lua_assert(e1->f == NO_JUMP); /* list must be closed */ luaK_dischargevars(fs, e2); luaK_concat(fs, &e2->t, e1->t); *e1 = *e2; break; } case OPR_CONCAT: { luaK_exp2val(fs, e2); if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1); freeexp(fs, e1); SETARG_B(getcode(fs, e2), e1->u.info); e1->k = VRELOCABLE; e1->u.info = e2->u.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ codeexpval(fs, OP_CONCAT, e1, e2, line); } break; } case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: case OPR_BAND: case OPR_BOR: case OPR_BXOR: case OPR_SHL: case OPR_SHR: { codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line); break; } case OPR_EQ: case OPR_LT: case OPR_LE: { codecomp(fs, cast(OpCode, (op - OPR_EQ) + OP_EQ), 1, e1, e2); break; } case OPR_NE: case OPR_GT: case OPR_GE: { codecomp(fs, cast(OpCode, (op - OPR_NE) + OP_EQ), 0, e1, e2); break; } default: lua_assert(0); } } void luaK_fixline (FuncState *fs, int line) { fs->f->lineinfo[fs->pc - 1] = line; } void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; int b = (tostore == LUA_MULTRET) ? 0 : tostore; lua_assert(tostore != 0); if (c <= MAXARG_C) luaK_codeABC(fs, OP_SETLIST, base, b, c); else if (c <= MAXARG_Ax) { luaK_codeABC(fs, OP_SETLIST, base, b, 0); codeextraarg(fs, c); } else luaX_syntaxerror(fs->ls, "constructor too long"); fs->freereg = base + 1; /* free registers with list values */ } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lprefix.h�������������������������������������������������������������������������0000644�0001751�0001751�00000001543�12675241401�012631� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lprefix.h,v 1.2 2014/12/29 16:54:13 roberto Exp $ ** Definitions for Lua code that must come before any other header file ** See Copyright Notice in lua.h */ #ifndef lprefix_h #define lprefix_h /* ** Allows POSIX/XSI stuff */ #if !defined(LUA_USE_C89) /* { */ #if !defined(_XOPEN_SOURCE) #define _XOPEN_SOURCE 600 #elif _XOPEN_SOURCE == 0 #undef _XOPEN_SOURCE /* use -D_XOPEN_SOURCE=0 to undefine it */ #endif /* ** Allows manipulation of large files in gcc and some other compilers */ #if !defined(LUA_32BITS) && !defined(_FILE_OFFSET_BITS) #define _LARGEFILE_SOURCE 1 #define _FILE_OFFSET_BITS 64 #endif #endif /* } */ /* ** Windows stuff */ #if defined(_WIN32) /* { */ #if !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS /* avoid warnings about ISO C functions */ #endif #endif /* } */ #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lstate.c��������������������������������������������������������������������������0000644�0001751�0001751�00000020453�12675241401�012450� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ #define lstate_c #define LUA_CORE #include "lprefix.h" #include <stddef.h> #include <string.h> #include "lua.h" #include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "llex.h" #include "lmem.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #if !defined(LUAI_GCPAUSE) #define LUAI_GCPAUSE 200 /* 200% */ #endif #if !defined(LUAI_GCMUL) #define LUAI_GCMUL 200 /* GC runs 'twice the speed' of memory allocation */ #endif /* ** a macro to help the creation of a unique random seed when a state is ** created; the seed is used to randomize hashes. */ #if !defined(luai_makeseed) #include <time.h> #define luai_makeseed() cast(unsigned int, time(NULL)) #endif /* ** thread state + extra space */ typedef struct LX { lu_byte extra_[LUA_EXTRASPACE]; lua_State l; } LX; /* ** Main thread combines a thread state and the global state */ typedef struct LG { LX l; global_State g; } LG; #define fromstate(L) (cast(LX *, cast(lu_byte *, (L)) - offsetof(LX, l))) /* ** Compute an initial seed as random as possible. Rely on Address Space ** Layout Randomization (if present) to increase randomness.. */ #define addbuff(b,p,e) \ { size_t t = cast(size_t, e); \ memcpy(b + p, &t, sizeof(t)); p += sizeof(t); } static unsigned int makeseed (lua_State *L) { char buff[4 * sizeof(size_t)]; unsigned int h = luai_makeseed(); int p = 0; addbuff(buff, p, L); /* heap variable */ addbuff(buff, p, &h); /* local variable */ addbuff(buff, p, luaO_nilobject); /* global variable */ addbuff(buff, p, &lua_newstate); /* public function */ lua_assert(p == sizeof(buff)); return luaS_hash(buff, p, h); } /* ** set GCdebt to a new value keeping the value (totalbytes + GCdebt) ** invariant (and avoiding underflows in 'totalbytes') */ void luaE_setdebt (global_State *g, l_mem debt) { l_mem tb = gettotalbytes(g); lua_assert(tb > 0); if (debt < tb - MAX_LMEM) debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */ g->totalbytes = tb - debt; g->GCdebt = debt; } CallInfo *luaE_extendCI (lua_State *L) { CallInfo *ci = luaM_new(L, CallInfo); lua_assert(L->ci->next == NULL); L->ci->next = ci; ci->previous = L->ci; ci->next = NULL; L->nci++; return ci; } /* ** free all CallInfo structures not in use by a thread */ void luaE_freeCI (lua_State *L) { CallInfo *ci = L->ci; CallInfo *next = ci->next; ci->next = NULL; while ((ci = next) != NULL) { next = ci->next; luaM_free(L, ci); L->nci--; } } /* ** free half of the CallInfo structures not in use by a thread */ void luaE_shrinkCI (lua_State *L) { CallInfo *ci = L->ci; CallInfo *next2; /* next's next */ /* while there are two nexts */ while (ci->next != NULL && (next2 = ci->next->next) != NULL) { luaM_free(L, ci->next); /* free next */ L->nci--; ci->next = next2; /* remove 'next' from the list */ next2->previous = ci; ci = next2; /* keep next's next */ } } static void stack_init (lua_State *L1, lua_State *L) { int i; CallInfo *ci; /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE, TValue); L1->stacksize = BASIC_STACK_SIZE; for (i = 0; i < BASIC_STACK_SIZE; i++) setnilvalue(L1->stack + i); /* erase new stack */ L1->top = L1->stack; L1->stack_last = L1->stack + L1->stacksize - EXTRA_STACK; /* initialize first ci */ ci = &L1->base_ci; ci->next = ci->previous = NULL; ci->callstatus = 0; ci->func = L1->top; setnilvalue(L1->top++); /* 'function' entry for this 'ci' */ ci->top = L1->top + LUA_MINSTACK; L1->ci = ci; } static void freestack (lua_State *L) { if (L->stack == NULL) return; /* stack not completely built yet */ L->ci = &L->base_ci; /* free the entire 'ci' list */ luaE_freeCI(L); lua_assert(L->nci == 0); luaM_freearray(L, L->stack, L->stacksize); /* free stack array */ } /* ** Create registry table and its predefined values */ static void init_registry (lua_State *L, global_State *g) { TValue temp; /* create registry */ Table *registry = luaH_new(L); sethvalue(L, &g->l_registry, registry); luaH_resize(L, registry, LUA_RIDX_LAST, 0); /* registry[LUA_RIDX_MAINTHREAD] = L */ setthvalue(L, &temp, L); /* temp = L */ luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); /* registry[LUA_RIDX_GLOBALS] = table of globals */ sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); } /* ** open parts of the state that may cause memory-allocation errors. ** ('g->version' != NULL flags that the state was completely build) */ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ init_registry(L, g); luaS_init(L); luaT_init(L); luaX_init(L); g->gcrunning = 1; /* allow gc */ g->version = lua_version(NULL); luai_userstateopen(L); } /* ** preinitialize a thread with consistent values without allocating ** any memory (to avoid errors) */ static void preinit_thread (lua_State *L, global_State *g) { G(L) = g; L->stack = NULL; L->ci = NULL; L->nci = 0; L->stacksize = 0; L->twups = L; /* thread has no upvalues */ L->errorJmp = NULL; L->nCcalls = 0; L->hook = NULL; L->hookmask = 0; L->basehookcount = 0; L->allowhook = 1; resethookcount(L); L->openupval = NULL; L->nny = 1; L->status = LUA_OK; L->errfunc = 0; } static void close_state (lua_State *L) { global_State *g = G(L); luaF_close(L, L->stack); /* close all upvalues for this thread */ luaC_freeallobjects(L); /* collect all objects */ if (g->version) /* closing a fully built state? */ luai_userstateclose(L); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); freestack(L); lua_assert(gettotalbytes(g) == sizeof(LG)); (*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */ } LUA_API lua_State *lua_newthread (lua_State *L) { global_State *g = G(L); lua_State *L1; lua_lock(L); luaC_checkGC(L); /* create new thread */ L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; L1->marked = luaC_white(g); L1->tt = LUA_TTHREAD; /* link it on list 'allgc' */ L1->next = g->allgc; g->allgc = obj2gco(L1); /* anchor it on L stack */ setthvalue(L, L->top, L1); api_incr_top(L); preinit_thread(L1, g); L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; resethookcount(L1); /* initialize L1 extra space */ memcpy(lua_getextraspace(L1), lua_getextraspace(g->mainthread), LUA_EXTRASPACE); luai_userstatethread(L, L1); stack_init(L1, L); /* init stack */ lua_unlock(L); return L1; } void luaE_freethread (lua_State *L, lua_State *L1) { LX *l = fromstate(L1); luaF_close(L1, L1->stack); /* close all upvalues for this thread */ lua_assert(L1->openupval == NULL); luai_userstatefree(L, L1); freestack(L1); luaM_free(L, l); } LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { int i; lua_State *L; global_State *g; LG *l = cast(LG *, (*f)(ud, NULL, LUA_TTHREAD, sizeof(LG))); if (l == NULL) return NULL; L = &l->l.l; g = &l->g; L->next = NULL; L->tt = LUA_TTHREAD; g->currentwhite = bitmask(WHITE0BIT); L->marked = luaC_white(g); preinit_thread(L, g); g->frealloc = f; g->ud = ud; g->mainthread = L; g->seed = makeseed(L); g->gcrunning = 0; /* no GC while building state */ g->GCestimate = 0; g->strt.size = g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(&g->l_registry); g->panic = NULL; g->version = NULL; g->gcstate = GCSpause; g->gckind = KGC_NORMAL; g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; g->sweepgc = NULL; g->gray = g->grayagain = NULL; g->weak = g->ephemeron = g->allweak = NULL; g->twups = NULL; g->totalbytes = sizeof(LG); g->GCdebt = 0; g->gcfinnum = 0; g->gcpause = LUAI_GCPAUSE; g->gcstepmul = LUAI_GCMUL; for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; if (luaD_rawrunprotected(L, f_luaopen, NULL) != LUA_OK) { /* memory allocation error: free partial state */ close_state(L); L = NULL; } return L; } LUA_API void lua_close (lua_State *L) { L = G(L)->mainthread; /* only the main thread can be closed */ lua_lock(L); close_state(L); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lstate.h��������������������������������������������������������������������������0000644�0001751�0001751�00000016675�12675241401�012470� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lstate.h,v 2.128 2015/11/13 12:16:51 roberto Exp $ ** Global State ** See Copyright Notice in lua.h */ #ifndef lstate_h #define lstate_h #include "lua.h" #include "lobject.h" #include "ltm.h" #include "lzio.h" /* ** Some notes about garbage-collected objects: All objects in Lua must ** be kept somehow accessible until being freed, so all objects always ** belong to one (and only one) of these lists, using field 'next' of ** the 'CommonHeader' for the link: ** ** 'allgc': all objects not marked for finalization; ** 'finobj': all objects marked for finalization; ** 'tobefnz': all objects ready to be finalized; ** 'fixedgc': all objects that are not to be collected (currently ** only small strings, such as reserved words). */ struct lua_longjmp; /* defined in ldo.c */ /* extra stack space to handle TM calls and some other extras */ #define EXTRA_STACK 5 #define BASIC_STACK_SIZE (2*LUA_MINSTACK) /* kinds of Garbage Collection */ #define KGC_NORMAL 0 #define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */ typedef struct stringtable { TString **hash; int nuse; /* number of elements */ int size; } stringtable; /* ** Information about a call. ** When a thread yields, 'func' is adjusted to pretend that the ** top function has only the yielded values in its stack; in that ** case, the actual 'func' value is saved in field 'extra'. ** When a function calls another with a continuation, 'extra' keeps ** the function index so that, in case of errors, the continuation ** function can be called with the correct top. */ typedef struct CallInfo { StkId func; /* function index in the stack */ StkId top; /* top for this function */ struct CallInfo *previous, *next; /* dynamic call link */ union { struct { /* only for Lua functions */ StkId base; /* base for this function */ const Instruction *savedpc; } l; struct { /* only for C functions */ lua_KFunction k; /* continuation in case of yields */ ptrdiff_t old_errfunc; lua_KContext ctx; /* context info. in case of yields */ } c; } u; ptrdiff_t extra; short nresults; /* expected number of results from this function */ lu_byte callstatus; } CallInfo; /* ** Bits in CallInfo status */ #define CIST_OAH (1<<0) /* original value of 'allowhook' */ #define CIST_LUA (1<<1) /* call is running a Lua function */ #define CIST_HOOKED (1<<2) /* call is running a debug hook */ #define CIST_FRESH (1<<3) /* call is running on a fresh invocation of luaV_execute */ #define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ #define CIST_TAIL (1<<5) /* call was tail called */ #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ #define CIST_LEQ (1<<7) /* using __lt for __le */ #define isLua(ci) ((ci)->callstatus & CIST_LUA) /* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ #define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) #define getoah(st) ((st) & CIST_OAH) /* ** 'global state', shared by all threads of this state */ typedef struct global_State { lua_Alloc frealloc; /* function to reallocate memory */ void *ud; /* auxiliary data to 'frealloc' */ l_mem totalbytes; /* number of bytes currently allocated - GCdebt */ l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ lu_mem GCmemtrav; /* memory traversed by the GC */ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ stringtable strt; /* hash table for strings */ TValue l_registry; unsigned int seed; /* randomized seed for hashes */ lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ lu_byte gcrunning; /* true if GC is running */ GCObject *allgc; /* list of all collectable objects */ GCObject **sweepgc; /* current position of sweep in list */ GCObject *finobj; /* list of collectable objects with finalizers */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of tables with weak values */ GCObject *ephemeron; /* list of ephemeron tables (weak keys) */ GCObject *allweak; /* list of all-weak tables */ GCObject *tobefnz; /* list of userdata to be GC */ GCObject *fixedgc; /* list of objects not to be collected */ struct lua_State *twups; /* list of threads with open upvalues */ unsigned int gcfinnum; /* number of finalizers to call in each GC step */ int gcpause; /* size of pause between successive GCs */ int gcstepmul; /* GC 'granularity' */ lua_CFunction panic; /* to be called in unprotected errors */ struct lua_State *mainthread; const lua_Number *version; /* pointer to version number */ TString *memerrmsg; /* memory-error message */ TString *tmname[TM_N]; /* array with tag-method names */ struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ } global_State; /* ** 'per thread' state */ struct lua_State { CommonHeader; unsigned short nci; /* number of items in 'ci' list */ lu_byte status; StkId top; /* first free slot in the stack */ global_State *l_G; CallInfo *ci; /* call info for current function */ const Instruction *oldpc; /* last pc traced */ StkId stack_last; /* last free slot in the stack */ StkId stack; /* stack base */ UpVal *openupval; /* list of open upvalues in this stack */ GCObject *gclist; struct lua_State *twups; /* list of threads with open upvalues */ struct lua_longjmp *errorJmp; /* current error recover point */ CallInfo base_ci; /* CallInfo for first level (C calling Lua) */ lua_Hook hook; ptrdiff_t errfunc; /* current error handling function (stack index) */ int stacksize; int basehookcount; int hookcount; unsigned short nny; /* number of non-yieldable calls in stack */ unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; }; #define G(L) (L->l_G) /* ** Union of all collectable objects (only for conversions) */ union GCUnion { GCObject gc; /* common header */ struct TString ts; struct Udata u; union Closure cl; struct Table h; struct Proto p; struct lua_State th; /* thread */ }; #define cast_u(o) cast(union GCUnion *, (o)) /* macros to convert a GCObject into a specific value */ #define gco2ts(o) \ check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts)) #define gco2u(o) check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u)) #define gco2lcl(o) check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l)) #define gco2ccl(o) check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c)) #define gco2cl(o) \ check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl)) #define gco2t(o) check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h)) #define gco2p(o) check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p)) #define gco2th(o) check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th)) /* macro to convert a Lua object into a GCObject */ #define obj2gco(v) \ check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc))) /* actual number of total bytes allocated */ #define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt) LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC void luaE_freeCI (lua_State *L); LUAI_FUNC void luaE_shrinkCI (lua_State *L); #endif �������������������������������������������������������������������golly-2.8-src/lua/lundump.c�������������������������������������������������������������������������0000644�0001751�0001751�00000014037�12675241401�012641� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ #define lundump_c #define LUA_CORE #include "lprefix.h" #include <string.h> #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lmem.h" #include "lobject.h" #include "lstring.h" #include "lundump.h" #include "lzio.h" #if !defined(luai_verifycode) #define luai_verifycode(L,b,f) /* empty */ #endif typedef struct { lua_State *L; ZIO *Z; const char *name; } LoadState; static l_noret error(LoadState *S, const char *why) { luaO_pushfstring(S->L, "%s: %s precompiled chunk", S->name, why); luaD_throw(S->L, LUA_ERRSYNTAX); } /* ** All high-level loads go through LoadVector; you can change it to ** adapt to the endianness of the input */ #define LoadVector(S,b,n) LoadBlock(S,b,(n)*sizeof((b)[0])) static void LoadBlock (LoadState *S, void *b, size_t size) { if (luaZ_read(S->Z, b, size) != 0) error(S, "truncated"); } #define LoadVar(S,x) LoadVector(S,&x,1) static lu_byte LoadByte (LoadState *S) { lu_byte x; LoadVar(S, x); return x; } static int LoadInt (LoadState *S) { int x; LoadVar(S, x); return x; } static lua_Number LoadNumber (LoadState *S) { lua_Number x; LoadVar(S, x); return x; } static lua_Integer LoadInteger (LoadState *S) { lua_Integer x; LoadVar(S, x); return x; } static TString *LoadString (LoadState *S) { size_t size = LoadByte(S); if (size == 0xFF) LoadVar(S, size); if (size == 0) return NULL; else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */ char buff[LUAI_MAXSHORTLEN]; LoadVector(S, buff, size); return luaS_newlstr(S->L, buff, size); } else { /* long string */ TString *ts = luaS_createlngstrobj(S->L, size); LoadVector(S, getstr(ts), size); /* load directly in final place */ return ts; } } static void LoadCode (LoadState *S, Proto *f) { int n = LoadInt(S); f->code = luaM_newvector(S->L, n, Instruction); f->sizecode = n; LoadVector(S, f->code, n); } static void LoadFunction(LoadState *S, Proto *f, TString *psource); static void LoadConstants (LoadState *S, Proto *f) { int i; int n = LoadInt(S); f->k = luaM_newvector(S->L, n, TValue); f->sizek = n; for (i = 0; i < n; i++) setnilvalue(&f->k[i]); for (i = 0; i < n; i++) { TValue *o = &f->k[i]; int t = LoadByte(S); switch (t) { case LUA_TNIL: setnilvalue(o); break; case LUA_TBOOLEAN: setbvalue(o, LoadByte(S)); break; case LUA_TNUMFLT: setfltvalue(o, LoadNumber(S)); break; case LUA_TNUMINT: setivalue(o, LoadInteger(S)); break; case LUA_TSHRSTR: case LUA_TLNGSTR: setsvalue2n(S->L, o, LoadString(S)); break; default: lua_assert(0); } } } static void LoadProtos (LoadState *S, Proto *f) { int i; int n = LoadInt(S); f->p = luaM_newvector(S->L, n, Proto *); f->sizep = n; for (i = 0; i < n; i++) f->p[i] = NULL; for (i = 0; i < n; i++) { f->p[i] = luaF_newproto(S->L); LoadFunction(S, f->p[i], f->source); } } static void LoadUpvalues (LoadState *S, Proto *f) { int i, n; n = LoadInt(S); f->upvalues = luaM_newvector(S->L, n, Upvaldesc); f->sizeupvalues = n; for (i = 0; i < n; i++) f->upvalues[i].name = NULL; for (i = 0; i < n; i++) { f->upvalues[i].instack = LoadByte(S); f->upvalues[i].idx = LoadByte(S); } } static void LoadDebug (LoadState *S, Proto *f) { int i, n; n = LoadInt(S); f->lineinfo = luaM_newvector(S->L, n, int); f->sizelineinfo = n; LoadVector(S, f->lineinfo, n); n = LoadInt(S); f->locvars = luaM_newvector(S->L, n, LocVar); f->sizelocvars = n; for (i = 0; i < n; i++) f->locvars[i].varname = NULL; for (i = 0; i < n; i++) { f->locvars[i].varname = LoadString(S); f->locvars[i].startpc = LoadInt(S); f->locvars[i].endpc = LoadInt(S); } n = LoadInt(S); for (i = 0; i < n; i++) f->upvalues[i].name = LoadString(S); } static void LoadFunction (LoadState *S, Proto *f, TString *psource) { f->source = LoadString(S); if (f->source == NULL) /* no source in dump? */ f->source = psource; /* reuse parent's source */ f->linedefined = LoadInt(S); f->lastlinedefined = LoadInt(S); f->numparams = LoadByte(S); f->is_vararg = LoadByte(S); f->maxstacksize = LoadByte(S); LoadCode(S, f); LoadConstants(S, f); LoadUpvalues(S, f); LoadProtos(S, f); LoadDebug(S, f); } static void checkliteral (LoadState *S, const char *s, const char *msg) { char buff[sizeof(LUA_SIGNATURE) + sizeof(LUAC_DATA)]; /* larger than both */ size_t len = strlen(s); LoadVector(S, buff, len); if (memcmp(s, buff, len) != 0) error(S, msg); } static void fchecksize (LoadState *S, size_t size, const char *tname) { if (LoadByte(S) != size) error(S, luaO_pushfstring(S->L, "%s size mismatch in", tname)); } #define checksize(S,t) fchecksize(S,sizeof(t),#t) static void checkHeader (LoadState *S) { checkliteral(S, LUA_SIGNATURE + 1, "not a"); /* 1st char already checked */ if (LoadByte(S) != LUAC_VERSION) error(S, "version mismatch in"); if (LoadByte(S) != LUAC_FORMAT) error(S, "format mismatch in"); checkliteral(S, LUAC_DATA, "corrupted"); checksize(S, int); checksize(S, size_t); checksize(S, Instruction); checksize(S, lua_Integer); checksize(S, lua_Number); if (LoadInteger(S) != LUAC_INT) error(S, "endianness mismatch in"); if (LoadNumber(S) != LUAC_NUM) error(S, "float format mismatch in"); } /* ** load precompiled chunk */ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) { LoadState S; LClosure *cl; if (*name == '@' || *name == '=') S.name = name + 1; else if (*name == LUA_SIGNATURE[0]) S.name = "binary string"; else S.name = name; S.L = L; S.Z = Z; checkHeader(&S); cl = luaF_newLclosure(L, LoadByte(&S)); setclLvalue(L, L->top, cl); luaD_inctop(L); cl->p = luaF_newproto(L); LoadFunction(&S, cl->p, NULL); lua_assert(cl->nupvalues == cl->p->sizeupvalues); luai_verifycode(L, buff, cl->p); return cl; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lmem.h����������������������������������������������������������������������������0000644�0001751�0001751�00000004603�12675241401�012112� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lmem.h,v 1.43 2014/12/19 17:26:14 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ #ifndef lmem_h #define lmem_h #include <stddef.h> #include "llimits.h" #include "lua.h" /* ** This macro reallocs a vector 'b' from 'on' to 'n' elements, where ** each element has size 'e'. In case of arithmetic overflow of the ** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because ** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). ** ** (The macro is somewhat complex to avoid warnings: The 'sizeof' ** comparison avoids a runtime comparison when overflow cannot occur. ** The compiler should be able to optimize the real test by itself, but ** when it does it, it may give a warning about "comparison is always ** false due to limited range of data type"; the +1 tricks the compiler, ** avoiding this warning but also this optimization.) */ #define luaM_reallocv(L,b,on,n,e) \ (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ ? luaM_toobig(L) : cast_void(0)) , \ luaM_realloc_(L, (b), (on)*(e), (n)*(e))) /* ** Arrays of chars do not need any test */ #define luaM_reallocvchar(L,b,on,n) \ cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) #define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) #define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) #define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) #define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) #define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) #define luaM_newvector(L,n,t) \ cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) #define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) #define luaM_growvector(L,v,nelems,size,t,limit,e) \ if ((nelems)+1 > (size)) \ ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) #define luaM_reallocvector(L, v,oldn,n,t) \ ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) LUAI_FUNC l_noret luaM_toobig (lua_State *L); /* not to be called directly */ LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, size_t size); LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elem, int limit, const char *what); #endif �����������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lzio.h����������������������������������������������������������������������������0000644�0001751�0001751�00000002705�12675241401�012136� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ #ifndef lzio_h #define lzio_h #include "lua.h" #include "lmem.h" #define EOZ (-1) /* end of stream */ typedef struct Zio ZIO; #define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z)) typedef struct Mbuffer { char *buffer; size_t n; size_t buffsize; } Mbuffer; #define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0) #define luaZ_buffer(buff) ((buff)->buffer) #define luaZ_sizebuffer(buff) ((buff)->buffsize) #define luaZ_bufflen(buff) ((buff)->n) #define luaZ_buffremove(buff,i) ((buff)->n -= (i)) #define luaZ_resetbuffer(buff) ((buff)->n = 0) #define luaZ_resizebuffer(L, buff, size) \ ((buff)->buffer = luaM_reallocvchar(L, (buff)->buffer, \ (buff)->buffsize, size), \ (buff)->buffsize = size) #define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0) LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data); LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */ /* --------- Private Part ------------------ */ struct Zio { size_t n; /* bytes still unread */ const char *p; /* current position in buffer */ lua_Reader reader; /* reader function */ void *data; /* additional data */ lua_State *L; /* Lua state (for reader) */ }; LUAI_FUNC int luaZ_fill (ZIO *z); #endif �����������������������������������������������������������golly-2.8-src/lua/lobject.h�������������������������������������������������������������������������0000644�0001751�0001751�00000034302�12675241401�012601� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ #ifndef lobject_h #define lobject_h #include <stdarg.h> #include "llimits.h" #include "lua.h" /* ** Extra tags for non-values */ #define LUA_TPROTO LUA_NUMTAGS /* function prototypes */ #define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */ /* ** number of all possible tags (including LUA_TNONE but excluding DEADKEY) */ #define LUA_TOTALTAGS (LUA_TPROTO + 2) /* ** tags for Tagged Values have the following use of bits: ** bits 0-3: actual tag (a LUA_T* value) ** bits 4-5: variant bits ** bit 6: whether value is collectable */ /* ** LUA_TFUNCTION variants: ** 0 - Lua function ** 1 - light C function ** 2 - regular C function (closure) */ /* Variant tags for functions */ #define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */ #define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */ #define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */ /* Variant tags for strings */ #define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */ #define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */ /* Variant tags for numbers */ #define LUA_TNUMFLT (LUA_TNUMBER | (0 << 4)) /* float numbers */ #define LUA_TNUMINT (LUA_TNUMBER | (1 << 4)) /* integer numbers */ /* Bit mark for collectable types */ #define BIT_ISCOLLECTABLE (1 << 6) /* mark a tag as collectable */ #define ctb(t) ((t) | BIT_ISCOLLECTABLE) /* ** Common type for all collectable objects */ typedef struct GCObject GCObject; /* ** Common Header for all collectable objects (in macro form, to be ** included in other objects) */ #define CommonHeader GCObject *next; lu_byte tt; lu_byte marked /* ** Common type has only the common header */ struct GCObject { CommonHeader; }; /* ** Tagged Values. This is the basic representation of values in Lua, ** an actual value plus a tag with its type. */ /* ** Union of all Lua values */ typedef union Value { GCObject *gc; /* collectable objects */ void *p; /* light userdata */ int b; /* booleans */ lua_CFunction f; /* light C functions */ lua_Integer i; /* integer numbers */ lua_Number n; /* float numbers */ } Value; #define TValuefields Value value_; int tt_ typedef struct lua_TValue { TValuefields; } TValue; /* macro defining a nil value */ #define NILCONSTANT {NULL}, LUA_TNIL #define val_(o) ((o)->value_) /* raw type tag of a TValue */ #define rttype(o) ((o)->tt_) /* tag with no variants (bits 0-3) */ #define novariant(x) ((x) & 0x0F) /* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */ #define ttype(o) (rttype(o) & 0x3F) /* type tag of a TValue with no variants (bits 0-3) */ #define ttnov(o) (novariant(rttype(o))) /* Macros to test type */ #define checktag(o,t) (rttype(o) == (t)) #define checktype(o,t) (ttnov(o) == (t)) #define ttisnumber(o) checktype((o), LUA_TNUMBER) #define ttisfloat(o) checktag((o), LUA_TNUMFLT) #define ttisinteger(o) checktag((o), LUA_TNUMINT) #define ttisnil(o) checktag((o), LUA_TNIL) #define ttisboolean(o) checktag((o), LUA_TBOOLEAN) #define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA) #define ttisstring(o) checktype((o), LUA_TSTRING) #define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR)) #define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR)) #define ttistable(o) checktag((o), ctb(LUA_TTABLE)) #define ttisfunction(o) checktype(o, LUA_TFUNCTION) #define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION) #define ttisCclosure(o) checktag((o), ctb(LUA_TCCL)) #define ttisLclosure(o) checktag((o), ctb(LUA_TLCL)) #define ttislcf(o) checktag((o), LUA_TLCF) #define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA)) #define ttisthread(o) checktag((o), ctb(LUA_TTHREAD)) #define ttisdeadkey(o) checktag((o), LUA_TDEADKEY) /* Macros to access values */ #define ivalue(o) check_exp(ttisinteger(o), val_(o).i) #define fltvalue(o) check_exp(ttisfloat(o), val_(o).n) #define nvalue(o) check_exp(ttisnumber(o), \ (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o))) #define gcvalue(o) check_exp(iscollectable(o), val_(o).gc) #define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p) #define tsvalue(o) check_exp(ttisstring(o), gco2ts(val_(o).gc)) #define uvalue(o) check_exp(ttisfulluserdata(o), gco2u(val_(o).gc)) #define clvalue(o) check_exp(ttisclosure(o), gco2cl(val_(o).gc)) #define clLvalue(o) check_exp(ttisLclosure(o), gco2lcl(val_(o).gc)) #define clCvalue(o) check_exp(ttisCclosure(o), gco2ccl(val_(o).gc)) #define fvalue(o) check_exp(ttislcf(o), val_(o).f) #define hvalue(o) check_exp(ttistable(o), gco2t(val_(o).gc)) #define bvalue(o) check_exp(ttisboolean(o), val_(o).b) #define thvalue(o) check_exp(ttisthread(o), gco2th(val_(o).gc)) /* a dead value may get the 'gc' field, but cannot access its contents */ #define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc)) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) #define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE) /* Macros for internal tests */ #define righttt(obj) (ttype(obj) == gcvalue(obj)->tt) #define checkliveness(L,obj) \ lua_longassert(!iscollectable(obj) || \ (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj))))) /* Macros to set values */ #define settt_(o,t) ((o)->tt_=(t)) #define setfltvalue(obj,x) \ { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); } #define chgfltvalue(obj,x) \ { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); } #define setivalue(obj,x) \ { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); } #define chgivalue(obj,x) \ { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); } #define setnilvalue(obj) settt_(obj, LUA_TNIL) #define setfvalue(obj,x) \ { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); } #define setpvalue(obj,x) \ { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); } #define setbvalue(obj,x) \ { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); } #define setgcovalue(L,obj,x) \ { TValue *io = (obj); GCObject *i_g=(x); \ val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); } #define setsvalue(L,obj,x) \ { TValue *io = (obj); TString *x_ = (x); \ val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \ checkliveness(L,io); } #define setuvalue(L,obj,x) \ { TValue *io = (obj); Udata *x_ = (x); \ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \ checkliveness(L,io); } #define setthvalue(L,obj,x) \ { TValue *io = (obj); lua_State *x_ = (x); \ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \ checkliveness(L,io); } #define setclLvalue(L,obj,x) \ { TValue *io = (obj); LClosure *x_ = (x); \ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \ checkliveness(L,io); } #define setclCvalue(L,obj,x) \ { TValue *io = (obj); CClosure *x_ = (x); \ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \ checkliveness(L,io); } #define sethvalue(L,obj,x) \ { TValue *io = (obj); Table *x_ = (x); \ val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \ checkliveness(L,io); } #define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY) #define setobj(L,obj1,obj2) \ { TValue *io1=(obj1); *io1 = *(obj2); \ (void)L; checkliveness(L,io1); } /* ** different types of assignments, according to destination */ /* from stack to (same) stack */ #define setobjs2s setobj /* to stack (not from same stack) */ #define setobj2s setobj #define setsvalue2s setsvalue #define sethvalue2s sethvalue #define setptvalue2s setptvalue /* from table to same table */ #define setobjt2t setobj /* to new object */ #define setobj2n setobj #define setsvalue2n setsvalue /* to table (define it as an expression to be used in macros) */ #define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1))) /* ** {====================================================== ** types and prototypes ** ======================================================= */ typedef TValue *StkId; /* index to stack elements */ /* ** Header for string value; string bytes follow the end of this structure ** (aligned according to 'UTString'; see next). */ typedef struct TString { CommonHeader; lu_byte extra; /* reserved words for short strings; "has hash" for longs */ lu_byte shrlen; /* length for short strings */ unsigned int hash; union { size_t lnglen; /* length for long strings */ struct TString *hnext; /* linked list for hash table */ } u; } TString; /* ** Ensures that address after this type is always fully aligned. */ typedef union UTString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ TString tsv; } UTString; /* ** Get the actual string (array of bytes) from a 'TString'. ** (Access to 'extra' ensures that value is really a 'TString'.) */ #define getstr(ts) \ check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString)) /* get the actual string (array of bytes) from a Lua value */ #define svalue(o) getstr(tsvalue(o)) /* get string length from 'TString *s' */ #define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen) /* get string length from 'TValue *o' */ #define vslen(o) tsslen(tsvalue(o)) /* ** Header for userdata; memory area follows the end of this structure ** (aligned according to 'UUdata'; see next). */ typedef struct Udata { CommonHeader; lu_byte ttuv_; /* user value's tag */ struct Table *metatable; size_t len; /* number of bytes */ union Value user_; /* user value */ } Udata; /* ** Ensures that address after this type is always fully aligned. */ typedef union UUdata { L_Umaxalign dummy; /* ensures maximum alignment for 'local' udata */ Udata uv; } UUdata; /* ** Get the address of memory block inside 'Udata'. ** (Access to 'ttuv_' ensures that value is really a 'Udata'.) */ #define getudatamem(u) \ check_exp(sizeof((u)->ttuv_), (cast(char*, (u)) + sizeof(UUdata))) #define setuservalue(L,u,o) \ { const TValue *io=(o); Udata *iu = (u); \ iu->user_ = io->value_; iu->ttuv_ = rttype(io); \ checkliveness(L,io); } #define getuservalue(L,u,o) \ { TValue *io=(o); const Udata *iu = (u); \ io->value_ = iu->user_; settt_(io, iu->ttuv_); \ checkliveness(L,io); } /* ** Description of an upvalue for function prototypes */ typedef struct Upvaldesc { TString *name; /* upvalue name (for debug information) */ lu_byte instack; /* whether it is in stack (register) */ lu_byte idx; /* index of upvalue (in stack or in outer function's list) */ } Upvaldesc; /* ** Description of a local variable for function prototypes ** (used for debug information) */ typedef struct LocVar { TString *varname; int startpc; /* first point where variable is active */ int endpc; /* first point where variable is dead */ } LocVar; /* ** Function Prototypes */ typedef struct Proto { CommonHeader; lu_byte numparams; /* number of fixed parameters */ lu_byte is_vararg; /* 2: declared vararg; 1: uses vararg */ lu_byte maxstacksize; /* number of registers needed by this function */ int sizeupvalues; /* size of 'upvalues' */ int sizek; /* size of 'k' */ int sizecode; int sizelineinfo; int sizep; /* size of 'p' */ int sizelocvars; int linedefined; /* debug information */ int lastlinedefined; /* debug information */ TValue *k; /* constants used by the function */ Instruction *code; /* opcodes */ struct Proto **p; /* functions defined inside the function */ int *lineinfo; /* map from opcodes to source lines (debug information) */ LocVar *locvars; /* information about local variables (debug information) */ Upvaldesc *upvalues; /* upvalue information */ struct LClosure *cache; /* last-created closure with this prototype */ TString *source; /* used for debug information */ GCObject *gclist; } Proto; /* ** Lua Upvalues */ typedef struct UpVal UpVal; /* ** Closures */ #define ClosureHeader \ CommonHeader; lu_byte nupvalues; GCObject *gclist typedef struct CClosure { ClosureHeader; lua_CFunction f; TValue upvalue[1]; /* list of upvalues */ } CClosure; typedef struct LClosure { ClosureHeader; struct Proto *p; UpVal *upvals[1]; /* list of upvalues */ } LClosure; typedef union Closure { CClosure c; LClosure l; } Closure; #define isLfunction(o) ttisLclosure(o) #define getproto(o) (clLvalue(o)->p) /* ** Tables */ typedef union TKey { struct { TValuefields; int next; /* for chaining (offset for next node) */ } nk; TValue tvk; } TKey; /* copy a value into a key without messing up field 'next' */ #define setnodekey(L,key,obj) \ { TKey *k_=(key); const TValue *io_=(obj); \ k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \ (void)L; checkliveness(L,io_); } typedef struct Node { TValue i_val; TKey i_key; } Node; typedef struct Table { CommonHeader; lu_byte flags; /* 1<<p means tagmethod(p) is not present */ lu_byte lsizenode; /* log2 of size of 'node' array */ unsigned int sizearray; /* size of 'array' array */ TValue *array; /* array part */ Node *node; Node *lastfree; /* any free position is before this position */ struct Table *metatable; GCObject *gclist; } Table; /* ** 'module' operation for hashing (size is always a power of 2) */ #define lmod(s,size) \ (check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1))))) #define twoto(x) (1<<(x)) #define sizenode(t) (twoto((t)->lsizenode)) /* ** (address of) a fixed nil value */ #define luaO_nilobject (&luaO_nilobject_) LUAI_DDEC const TValue luaO_nilobject_; /* size of buffer for 'luaO_utf8esc' function */ #define UTF8BUFFSZ 8 LUAI_FUNC int luaO_int2fb (unsigned int x); LUAI_FUNC int luaO_fb2int (int x); LUAI_FUNC int luaO_utf8esc (char *buff, unsigned long x); LUAI_FUNC int luaO_ceillog2 (unsigned int x); LUAI_FUNC void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, TValue *res); LUAI_FUNC size_t luaO_str2num (const char *s, TValue *o); LUAI_FUNC int luaO_hexavalue (int c); LUAI_FUNC void luaO_tostring (lua_State *L, StkId obj); LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp); LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...); LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lfunc.c���������������������������������������������������������������������������0000644�0001751�0001751�00000007153�12675241401�012265� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lfunc.c,v 2.45 2014/11/02 19:19:04 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ #define lfunc_c #define LUA_CORE #include "lprefix.h" #include <stddef.h> #include "lua.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" CClosure *luaF_newCclosure (lua_State *L, int n) { GCObject *o = luaC_newobj(L, LUA_TCCL, sizeCclosure(n)); CClosure *c = gco2ccl(o); c->nupvalues = cast_byte(n); return c; } LClosure *luaF_newLclosure (lua_State *L, int n) { GCObject *o = luaC_newobj(L, LUA_TLCL, sizeLclosure(n)); LClosure *c = gco2lcl(o); c->p = NULL; c->nupvalues = cast_byte(n); while (n--) c->upvals[n] = NULL; return c; } /* ** fill a closure with new closed upvalues */ void luaF_initupvals (lua_State *L, LClosure *cl) { int i; for (i = 0; i < cl->nupvalues; i++) { UpVal *uv = luaM_new(L, UpVal); uv->refcount = 1; uv->v = &uv->u.value; /* make it closed */ setnilvalue(uv->v); cl->upvals[i] = uv; } } UpVal *luaF_findupval (lua_State *L, StkId level) { UpVal **pp = &L->openupval; UpVal *p; UpVal *uv; lua_assert(isintwups(L) || L->openupval == NULL); while (*pp != NULL && (p = *pp)->v >= level) { lua_assert(upisopen(p)); if (p->v == level) /* found a corresponding upvalue? */ return p; /* return it */ pp = &p->u.open.next; } /* not found: create a new upvalue */ uv = luaM_new(L, UpVal); uv->refcount = 0; uv->u.open.next = *pp; /* link it to list of open upvalues */ uv->u.open.touched = 1; *pp = uv; uv->v = level; /* current value lives in the stack */ if (!isintwups(L)) { /* thread not in list of threads with upvalues? */ L->twups = G(L)->twups; /* link it to the list */ G(L)->twups = L; } return uv; } void luaF_close (lua_State *L, StkId level) { UpVal *uv; while (L->openupval != NULL && (uv = L->openupval)->v >= level) { lua_assert(upisopen(uv)); L->openupval = uv->u.open.next; /* remove from 'open' list */ if (uv->refcount == 0) /* no references? */ luaM_free(L, uv); /* free upvalue */ else { setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */ uv->v = &uv->u.value; /* now current value lives here */ luaC_upvalbarrier(L, uv); } } } Proto *luaF_newproto (lua_State *L) { GCObject *o = luaC_newobj(L, LUA_TPROTO, sizeof(Proto)); Proto *f = gco2p(o); f->k = NULL; f->sizek = 0; f->p = NULL; f->sizep = 0; f->code = NULL; f->cache = NULL; f->sizecode = 0; f->lineinfo = NULL; f->sizelineinfo = 0; f->upvalues = NULL; f->sizeupvalues = 0; f->numparams = 0; f->is_vararg = 0; f->maxstacksize = 0; f->locvars = NULL; f->sizelocvars = 0; f->linedefined = 0; f->lastlinedefined = 0; f->source = NULL; return f; } void luaF_freeproto (lua_State *L, Proto *f) { luaM_freearray(L, f->code, f->sizecode); luaM_freearray(L, f->p, f->sizep); luaM_freearray(L, f->k, f->sizek); luaM_freearray(L, f->lineinfo, f->sizelineinfo); luaM_freearray(L, f->locvars, f->sizelocvars); luaM_freearray(L, f->upvalues, f->sizeupvalues); luaM_free(L, f); } /* ** Look for n-th local variable at line 'line' in function 'func'. ** Returns NULL if not found. */ const char *luaF_getlocalname (const Proto *f, int local_number, int pc) { int i; for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) { if (pc < f->locvars[i].endpc) { /* is variable active? */ local_number--; if (local_number == 0) return getstr(f->locvars[i].varname); } } return NULL; /* not found */ } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lgc.c�����������������������������������������������������������������������������0000644�0001751�0001751�00000107474�12675241401�011732� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lgc.c,v 2.210 2015/11/03 18:10:44 roberto Exp $ ** Garbage Collector ** See Copyright Notice in lua.h */ #define lgc_c #define LUA_CORE #include "lprefix.h" #include <string.h> #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" /* ** internal state for collector while inside the atomic phase. The ** collector should never be in this state while running regular code. */ #define GCSinsideatomic (GCSpause + 1) /* ** cost of sweeping one element (the size of a small object divided ** by some adjust for the sweep speed) */ #define GCSWEEPCOST ((sizeof(TString) + 4) / 4) /* maximum number of elements to sweep in each single step */ #define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) /* cost of calling one finalizer */ #define GCFINALIZECOST GCSWEEPCOST /* ** macro to adjust 'stepmul': 'stepmul' is actually used like ** 'stepmul / STEPMULADJ' (value chosen by tests) */ #define STEPMULADJ 200 /* ** macro to adjust 'pause': 'pause' is actually used like ** 'pause / PAUSEADJ' (value chosen by tests) */ #define PAUSEADJ 100 /* ** 'makewhite' erases all color bits then sets only the current white ** bit */ #define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS)) #define makewhite(g,x) \ (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g))) #define white2gray(x) resetbits(x->marked, WHITEBITS) #define black2gray(x) resetbit(x->marked, BLACKBIT) #define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x))) #define checkdeadkey(n) lua_assert(!ttisdeadkey(gkey(n)) || ttisnil(gval(n))) #define checkconsistency(obj) \ lua_longassert(!iscollectable(obj) || righttt(obj)) #define markvalue(g,o) { checkconsistency(o); \ if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); } #define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); } /* ** mark an object that can be NULL (either because it is really optional, ** or it was stripped as debug info, or inside an uncompleted structure) */ #define markobjectN(g,t) { if (t) markobject(g,t); } static void reallymarkobject (global_State *g, GCObject *o); /* ** {====================================================== ** Generic functions ** ======================================================= */ /* ** one after last element in a hash array */ #define gnodelast(h) gnode(h, cast(size_t, sizenode(h))) /* ** link collectable object 'o' into list pointed by 'p' */ #define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o)) /* ** If key is not marked, mark its entry as dead. This allows key to be ** collected, but keeps its entry in the table. A dead node is needed ** when Lua looks up for a key (it may be part of a chain) and when ** traversing a weak table (key might be removed from the table during ** traversal). Other places never manipulate dead keys, because its ** associated nil value is enough to signal that the entry is logically ** empty. */ static void removeentry (Node *n) { lua_assert(ttisnil(gval(n))); if (valiswhite(gkey(n))) setdeadvalue(wgkey(n)); /* unused and unmarked key; remove it */ } /* ** tells whether a key or value can be cleared from a weak ** table. Non-collectable objects are never removed from weak ** tables. Strings behave as 'values', so are never removed too. for ** other objects: if really collected, cannot keep them; for objects ** being finalized, keep them in keys, but not in values */ static int iscleared (global_State *g, const TValue *o) { if (!iscollectable(o)) return 0; else if (ttisstring(o)) { markobject(g, tsvalue(o)); /* strings are 'values', so are never weak */ return 0; } else return iswhite(gcvalue(o)); } /* ** barrier that moves collector forward, that is, mark the white object ** being pointed by a black object. (If in sweep phase, clear the black ** object to white [sweep it] to avoid other barrier calls for this ** same object.) */ void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); if (keepinvariant(g)) /* must keep invariant? */ reallymarkobject(g, v); /* restore invariant */ else { /* sweep phase */ lua_assert(issweepphase(g)); makewhite(g, o); /* mark main obj. as white to avoid other barriers */ } } /* ** barrier that moves collector backward, that is, mark the black object ** pointing to a white object as gray again. */ void luaC_barrierback_ (lua_State *L, Table *t) { global_State *g = G(L); lua_assert(isblack(t) && !isdead(g, t)); black2gray(t); /* make table gray (again) */ linkgclist(t, g->grayagain); } /* ** barrier for assignments to closed upvalues. Because upvalues are ** shared among closures, it is impossible to know the color of all ** closures pointing to it. So, we assume that the object being assigned ** must be marked. */ void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) { global_State *g = G(L); GCObject *o = gcvalue(uv->v); lua_assert(!upisopen(uv)); /* ensured by macro luaC_upvalbarrier */ if (keepinvariant(g)) markobject(g, o); } void luaC_fix (lua_State *L, GCObject *o) { global_State *g = G(L); lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */ white2gray(o); /* they will be gray forever */ g->allgc = o->next; /* remove object from 'allgc' list */ o->next = g->fixedgc; /* link it to 'fixedgc' list */ g->fixedgc = o; } /* ** create a new collectable object (with given type and size) and link ** it to 'allgc' list. */ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { global_State *g = G(L); GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); o->marked = luaC_white(g); o->tt = tt; o->next = g->allgc; g->allgc = o; return o; } /* }====================================================== */ /* ** {====================================================== ** Mark functions ** ======================================================= */ /* ** mark an object. Userdata, strings, and closed upvalues are visited ** and turned black here. Other objects are marked gray and added ** to appropriate list to be visited (and turned black) later. (Open ** upvalues are already linked in 'headuv' list.) */ static void reallymarkobject (global_State *g, GCObject *o) { reentry: white2gray(o); switch (o->tt) { case LUA_TSHRSTR: { gray2black(o); g->GCmemtrav += sizelstring(gco2ts(o)->shrlen); break; } case LUA_TLNGSTR: { gray2black(o); g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen); break; } case LUA_TUSERDATA: { TValue uvalue; markobjectN(g, gco2u(o)->metatable); /* mark its metatable */ gray2black(o); g->GCmemtrav += sizeudata(gco2u(o)); getuservalue(g->mainthread, gco2u(o), &uvalue); if (valiswhite(&uvalue)) { /* markvalue(g, &uvalue); */ o = gcvalue(&uvalue); goto reentry; } break; } case LUA_TLCL: { linkgclist(gco2lcl(o), g->gray); break; } case LUA_TCCL: { linkgclist(gco2ccl(o), g->gray); break; } case LUA_TTABLE: { linkgclist(gco2t(o), g->gray); break; } case LUA_TTHREAD: { linkgclist(gco2th(o), g->gray); break; } case LUA_TPROTO: { linkgclist(gco2p(o), g->gray); break; } default: lua_assert(0); break; } } /* ** mark metamethods for basic types */ static void markmt (global_State *g) { int i; for (i=0; i < LUA_NUMTAGS; i++) markobjectN(g, g->mt[i]); } /* ** mark all objects in list of being-finalized */ static void markbeingfnz (global_State *g) { GCObject *o; for (o = g->tobefnz; o != NULL; o = o->next) markobject(g, o); } /* ** Mark all values stored in marked open upvalues from non-marked threads. ** (Values from marked threads were already marked when traversing the ** thread.) Remove from the list threads that no longer have upvalues and ** not-marked threads. */ static void remarkupvals (global_State *g) { lua_State *thread; lua_State **p = &g->twups; while ((thread = *p) != NULL) { lua_assert(!isblack(thread)); /* threads are never black */ if (isgray(thread) && thread->openupval != NULL) p = &thread->twups; /* keep marked thread with upvalues in the list */ else { /* thread is not marked or without upvalues */ UpVal *uv; *p = thread->twups; /* remove thread from the list */ thread->twups = thread; /* mark that it is out of list */ for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) { if (uv->u.open.touched) { markvalue(g, uv->v); /* remark upvalue's value */ uv->u.open.touched = 0; } } } } } /* ** mark root set and reset all gray lists, to start a new collection */ static void restartcollection (global_State *g) { g->gray = g->grayagain = NULL; g->weak = g->allweak = g->ephemeron = NULL; markobject(g, g->mainthread); markvalue(g, &g->l_registry); markmt(g); markbeingfnz(g); /* mark any finalizing object left from previous cycle */ } /* }====================================================== */ /* ** {====================================================== ** Traverse functions ** ======================================================= */ /* ** Traverse a table with weak values and link it to proper list. During ** propagate phase, keep it in 'grayagain' list, to be revisited in the ** atomic phase. In the atomic phase, if table has any white value, ** put it in 'weak' list, to be cleared. */ static void traverseweakvalue (global_State *g, Table *h) { Node *n, *limit = gnodelast(h); /* if there is array part, assume it may have white values (it is not worth traversing it now just to check) */ int hasclears = (h->sizearray > 0); for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); markvalue(g, gkey(n)); /* mark key */ if (!hasclears && iscleared(g, gval(n))) /* is there a white value? */ hasclears = 1; /* table will have to be cleared */ } } if (g->gcstate == GCSpropagate) linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ else if (hasclears) linkgclist(h, g->weak); /* has to be cleared later */ } /* ** Traverse an ephemeron table and link it to proper list. Returns true ** iff any object was marked during this traversal (which implies that ** convergence has to continue). During propagation phase, keep table ** in 'grayagain' list, to be visited again in the atomic phase. In ** the atomic phase, if table has any white->white entry, it has to ** be revisited during ephemeron convergence (as that key may turn ** black). Otherwise, if it has any white key, table has to be cleared ** (in the atomic phase). */ static int traverseephemeron (global_State *g, Table *h) { int marked = 0; /* true if an object is marked in this traversal */ int hasclears = 0; /* true if table has white keys */ int hasww = 0; /* true if table has entry "white-key -> white-value" */ Node *n, *limit = gnodelast(h); unsigned int i; /* traverse array part */ for (i = 0; i < h->sizearray; i++) { if (valiswhite(&h->array[i])) { marked = 1; reallymarkobject(g, gcvalue(&h->array[i])); } } /* traverse hash part */ for (n = gnode(h, 0); n < limit; n++) { checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ else if (iscleared(g, gkey(n))) { /* key is not marked (yet)? */ hasclears = 1; /* table must be cleared */ if (valiswhite(gval(n))) /* value not marked yet? */ hasww = 1; /* white-white entry */ } else if (valiswhite(gval(n))) { /* value not marked yet? */ marked = 1; reallymarkobject(g, gcvalue(gval(n))); /* mark it now */ } } /* link table into proper list */ if (g->gcstate == GCSpropagate) linkgclist(h, g->grayagain); /* must retraverse it in atomic phase */ else if (hasww) /* table has white->white entries? */ linkgclist(h, g->ephemeron); /* have to propagate again */ else if (hasclears) /* table has white keys? */ linkgclist(h, g->allweak); /* may have to clean white keys */ return marked; } static void traversestrongtable (global_State *g, Table *h) { Node *n, *limit = gnodelast(h); unsigned int i; for (i = 0; i < h->sizearray; i++) /* traverse array part */ markvalue(g, &h->array[i]); for (n = gnode(h, 0); n < limit; n++) { /* traverse hash part */ checkdeadkey(n); if (ttisnil(gval(n))) /* entry is empty? */ removeentry(n); /* remove it */ else { lua_assert(!ttisnil(gkey(n))); markvalue(g, gkey(n)); /* mark key */ markvalue(g, gval(n)); /* mark value */ } } } static lu_mem traversetable (global_State *g, Table *h) { const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); markobjectN(g, h->metatable); if (mode && ttisstring(mode) && /* is there a weak mode? */ ((weakkey = strchr(svalue(mode), 'k')), (weakvalue = strchr(svalue(mode), 'v')), (weakkey || weakvalue))) { /* is really weak? */ black2gray(h); /* keep table gray */ if (!weakkey) /* strong keys? */ traverseweakvalue(g, h); else if (!weakvalue) /* strong values? */ traverseephemeron(g, h); else /* all weak */ linkgclist(h, g->allweak); /* nothing to traverse now */ } else /* not weak */ traversestrongtable(g, h); return sizeof(Table) + sizeof(TValue) * h->sizearray + sizeof(Node) * cast(size_t, sizenode(h)); } /* ** Traverse a prototype. (While a prototype is being build, its ** arrays can be larger than needed; the extra slots are filled with ** NULL, so the use of 'markobjectN') */ static int traverseproto (global_State *g, Proto *f) { int i; if (f->cache && iswhite(f->cache)) f->cache = NULL; /* allow cache to be collected */ markobjectN(g, f->source); for (i = 0; i < f->sizek; i++) /* mark literals */ markvalue(g, &f->k[i]); for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */ markobjectN(g, f->upvalues[i].name); for (i = 0; i < f->sizep; i++) /* mark nested protos */ markobjectN(g, f->p[i]); for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ markobjectN(g, f->locvars[i].varname); return sizeof(Proto) + sizeof(Instruction) * f->sizecode + sizeof(Proto *) * f->sizep + sizeof(TValue) * f->sizek + sizeof(int) * f->sizelineinfo + sizeof(LocVar) * f->sizelocvars + sizeof(Upvaldesc) * f->sizeupvalues; } static lu_mem traverseCclosure (global_State *g, CClosure *cl) { int i; for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ markvalue(g, &cl->upvalue[i]); return sizeCclosure(cl->nupvalues); } /* ** open upvalues point to values in a thread, so those values should ** be marked when the thread is traversed except in the atomic phase ** (because then the value cannot be changed by the thread and the ** thread may not be traversed again) */ static lu_mem traverseLclosure (global_State *g, LClosure *cl) { int i; markobjectN(g, cl->p); /* mark its prototype */ for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */ UpVal *uv = cl->upvals[i]; if (uv != NULL) { if (upisopen(uv) && g->gcstate != GCSinsideatomic) uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */ else markvalue(g, uv->v); } } return sizeLclosure(cl->nupvalues); } static lu_mem traversethread (global_State *g, lua_State *th) { StkId o = th->stack; if (o == NULL) return 1; /* stack not completely built yet */ lua_assert(g->gcstate == GCSinsideatomic || th->openupval == NULL || isintwups(th)); for (; o < th->top; o++) /* mark live elements in the stack */ markvalue(g, o); if (g->gcstate == GCSinsideatomic) { /* final traversal? */ StkId lim = th->stack + th->stacksize; /* real end of stack */ for (; o < lim; o++) /* clear not-marked stack slice */ setnilvalue(o); /* 'remarkupvals' may have removed thread from 'twups' list */ if (!isintwups(th) && th->openupval != NULL) { th->twups = g->twups; /* link it back to the list */ g->twups = th; } } else if (g->gckind != KGC_EMERGENCY) luaD_shrinkstack(th); /* do not change stack in emergency cycle */ return (sizeof(lua_State) + sizeof(TValue) * th->stacksize + sizeof(CallInfo) * th->nci); } /* ** traverse one gray object, turning it to black (except for threads, ** which are always gray). */ static void propagatemark (global_State *g) { lu_mem size; GCObject *o = g->gray; lua_assert(isgray(o)); gray2black(o); switch (o->tt) { case LUA_TTABLE: { Table *h = gco2t(o); g->gray = h->gclist; /* remove from 'gray' list */ size = traversetable(g, h); break; } case LUA_TLCL: { LClosure *cl = gco2lcl(o); g->gray = cl->gclist; /* remove from 'gray' list */ size = traverseLclosure(g, cl); break; } case LUA_TCCL: { CClosure *cl = gco2ccl(o); g->gray = cl->gclist; /* remove from 'gray' list */ size = traverseCclosure(g, cl); break; } case LUA_TTHREAD: { lua_State *th = gco2th(o); g->gray = th->gclist; /* remove from 'gray' list */ linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ black2gray(o); size = traversethread(g, th); break; } case LUA_TPROTO: { Proto *p = gco2p(o); g->gray = p->gclist; /* remove from 'gray' list */ size = traverseproto(g, p); break; } default: lua_assert(0); return; } g->GCmemtrav += size; } static void propagateall (global_State *g) { while (g->gray) propagatemark(g); } static void convergeephemerons (global_State *g) { int changed; do { GCObject *w; GCObject *next = g->ephemeron; /* get ephemeron list */ g->ephemeron = NULL; /* tables may return to this list when traversed */ changed = 0; while ((w = next) != NULL) { next = gco2t(w)->gclist; if (traverseephemeron(g, gco2t(w))) { /* traverse marked some value? */ propagateall(g); /* propagate changes */ changed = 1; /* will have to revisit all ephemeron tables */ } } } while (changed); } /* }====================================================== */ /* ** {====================================================== ** Sweep Functions ** ======================================================= */ /* ** clear entries with unmarked keys from all weaktables in list 'l' up ** to element 'f' */ static void clearkeys (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); for (n = gnode(h, 0); n < limit; n++) { if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } } } } /* ** clear entries with unmarked values from all weaktables in list 'l' up ** to element 'f' */ static void clearvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); unsigned int i; for (i = 0; i < h->sizearray; i++) { TValue *o = &h->array[i]; if (iscleared(g, o)) /* value was collected? */ setnilvalue(o); /* remove value */ } for (n = gnode(h, 0); n < limit; n++) { if (!ttisnil(gval(n)) && iscleared(g, gval(n))) { setnilvalue(gval(n)); /* remove value ... */ removeentry(n); /* and remove entry from table */ } } } } void luaC_upvdeccount (lua_State *L, UpVal *uv) { lua_assert(uv->refcount > 0); uv->refcount--; if (uv->refcount == 0 && !upisopen(uv)) luaM_free(L, uv); } static void freeLclosure (lua_State *L, LClosure *cl) { int i; for (i = 0; i < cl->nupvalues; i++) { UpVal *uv = cl->upvals[i]; if (uv) luaC_upvdeccount(L, uv); } luaM_freemem(L, cl, sizeLclosure(cl->nupvalues)); } static void freeobj (lua_State *L, GCObject *o) { switch (o->tt) { case LUA_TPROTO: luaF_freeproto(L, gco2p(o)); break; case LUA_TLCL: { freeLclosure(L, gco2lcl(o)); break; } case LUA_TCCL: { luaM_freemem(L, o, sizeCclosure(gco2ccl(o)->nupvalues)); break; } case LUA_TTABLE: luaH_free(L, gco2t(o)); break; case LUA_TTHREAD: luaE_freethread(L, gco2th(o)); break; case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; case LUA_TSHRSTR: luaS_remove(L, gco2ts(o)); /* remove it from hash table */ luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen)); break; case LUA_TLNGSTR: { luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen)); break; } default: lua_assert(0); } } #define sweepwholelist(L,p) sweeplist(L,p,MAX_LUMEM) static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count); /* ** sweep at most 'count' elements from a list of GCObjects erasing dead ** objects, where a dead object is one marked with the old (non current) ** white; change all non-dead objects back to white, preparing for next ** collection cycle. Return where to continue the traversal or NULL if ** list is finished. */ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { global_State *g = G(L); int ow = otherwhite(g); int white = luaC_white(g); /* current white */ while (*p != NULL && count-- > 0) { GCObject *curr = *p; int marked = curr->marked; if (isdeadm(ow, marked)) { /* is 'curr' dead? */ *p = curr->next; /* remove 'curr' from list */ freeobj(L, curr); /* erase 'curr' */ } else { /* change mark to 'white' */ curr->marked = cast_byte((marked & maskcolors) | white); p = &curr->next; /* go to next element */ } } return (*p == NULL) ? NULL : p; } /* ** sweep a list until a live object (or end of list) */ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) { GCObject **old = p; int i = 0; do { i++; p = sweeplist(L, p, 1); } while (p == old); if (n) *n += i; return p; } /* }====================================================== */ /* ** {====================================================== ** Finalization ** ======================================================= */ /* ** If possible, shrink string table */ static void checkSizes (lua_State *L, global_State *g) { if (g->gckind != KGC_EMERGENCY) { l_mem olddebt = g->GCdebt; if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ luaS_resize(L, g->strt.size / 2); /* shrink it a little */ g->GCestimate += g->GCdebt - olddebt; /* update estimate */ } } static GCObject *udata2finalize (global_State *g) { GCObject *o = g->tobefnz; /* get first element */ lua_assert(tofinalize(o)); g->tobefnz = o->next; /* remove it from 'tobefnz' list */ o->next = g->allgc; /* return it to 'allgc' list */ g->allgc = o; resetbit(o->marked, FINALIZEDBIT); /* object is "normal" again */ if (issweepphase(g)) makewhite(g, o); /* "sweep" object */ return o; } static void dothecall (lua_State *L, void *ud) { UNUSED(ud); luaD_callnoyield(L, L->top - 2, 0); } static void GCTM (lua_State *L, int propagateerrors) { global_State *g = G(L); const TValue *tm; TValue v; setgcovalue(L, &v, udata2finalize(g)); tm = luaT_gettmbyobj(L, &v, TM_GC); if (tm != NULL && ttisfunction(tm)) { /* is there a finalizer? */ int status; lu_byte oldah = L->allowhook; int running = g->gcrunning; L->allowhook = 0; /* stop debug hooks during GC metamethod */ g->gcrunning = 0; /* avoid GC steps */ setobj2s(L, L->top, tm); /* push finalizer... */ setobj2s(L, L->top + 1, &v); /* ... and its argument */ L->top += 2; /* and (next line) call the finalizer */ status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); L->allowhook = oldah; /* restore hooks */ g->gcrunning = running; /* restore state */ if (status != LUA_OK && propagateerrors) { /* error while running __gc? */ if (status == LUA_ERRRUN) { /* is there an error object? */ const char *msg = (ttisstring(L->top - 1)) ? svalue(L->top - 1) : "no message"; luaO_pushfstring(L, "error in __gc metamethod (%s)", msg); status = LUA_ERRGCMM; /* error in __gc metamethod */ } luaD_throw(L, status); /* re-throw error */ } } } /* ** call a few (up to 'g->gcfinnum') finalizers */ static int runafewfinalizers (lua_State *L) { global_State *g = G(L); unsigned int i; lua_assert(!g->tobefnz || g->gcfinnum > 0); for (i = 0; g->tobefnz && i < g->gcfinnum; i++) GCTM(L, 1); /* call one finalizer */ g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */ : g->gcfinnum * 2; /* else call a few more next time */ return i; } /* ** call all pending finalizers */ static void callallpendingfinalizers (lua_State *L, int propagateerrors) { global_State *g = G(L); while (g->tobefnz) GCTM(L, propagateerrors); } /* ** find last 'next' field in list 'p' list (to add elements in its end) */ static GCObject **findlast (GCObject **p) { while (*p != NULL) p = &(*p)->next; return p; } /* ** move all unreachable objects (or 'all' objects) that need ** finalization from list 'finobj' to list 'tobefnz' (to be finalized) */ static void separatetobefnz (global_State *g, int all) { GCObject *curr; GCObject **p = &g->finobj; GCObject **lastnext = findlast(&g->tobefnz); while ((curr = *p) != NULL) { /* traverse all finalizable objects */ lua_assert(tofinalize(curr)); if (!(iswhite(curr) || all)) /* not being collected? */ p = &curr->next; /* don't bother with it */ else { *p = curr->next; /* remove 'curr' from 'finobj' list */ curr->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; lastnext = &curr->next; } } } /* ** if object 'o' has a finalizer, remove it from 'allgc' list (must ** search the list to find it) and link it in 'finobj' list. */ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { global_State *g = G(L); if (tofinalize(o) || /* obj. is already marked... */ gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ return; /* nothing to be done */ else { /* move 'o' to 'finobj' list */ GCObject **p; if (issweepphase(g)) { makewhite(g, o); /* "sweep" object 'o' */ if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */ g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */ } /* search for pointer pointing to 'o' */ for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ } *p = o->next; /* remove 'o' from 'allgc' list */ o->next = g->finobj; /* link it in 'finobj' list */ g->finobj = o; l_setbit(o->marked, FINALIZEDBIT); /* mark it as such */ } } /* }====================================================== */ /* ** {====================================================== ** GC control ** ======================================================= */ /* ** Set a reasonable "time" to wait before starting a new GC cycle; cycle ** will start when memory use hits threshold. (Division by 'estimate' ** should be OK: it cannot be zero (because Lua cannot even start with ** less than PAUSEADJ bytes). */ static void setpause (global_State *g) { l_mem threshold, debt; l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */ lua_assert(estimate > 0); threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ ? estimate * g->gcpause /* no overflow */ : MAX_LMEM; /* overflow; truncate to maximum */ debt = gettotalbytes(g) - threshold; luaE_setdebt(g, debt); } /* ** Enter first sweep phase. ** The call to 'sweeptolive' makes pointer point to an object inside ** the list (instead of to the header), so that the real sweep do not ** need to skip objects created between "now" and the start of the real ** sweep. ** Returns how many objects it swept. */ static int entersweep (lua_State *L) { global_State *g = G(L); int n = 0; g->gcstate = GCSswpallgc; lua_assert(g->sweepgc == NULL); g->sweepgc = sweeptolive(L, &g->allgc, &n); return n; } void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); separatetobefnz(g, 1); /* separate all objects with finalizers */ lua_assert(g->finobj == NULL); callallpendingfinalizers(L, 0); lua_assert(g->tobefnz == NULL); g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->gckind = KGC_NORMAL; sweepwholelist(L, &g->finobj); sweepwholelist(L, &g->allgc); sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ lua_assert(g->strt.nuse == 0); } static l_mem atomic (lua_State *L) { global_State *g = G(L); l_mem work; GCObject *origweak, *origall; GCObject *grayagain = g->grayagain; /* save original list */ lua_assert(g->ephemeron == NULL && g->weak == NULL); lua_assert(!iswhite(g->mainthread)); g->gcstate = GCSinsideatomic; g->GCmemtrav = 0; /* start counting work */ markobject(g, L); /* mark running thread */ /* registry and global metatables may be changed by API */ markvalue(g, &g->l_registry); markmt(g); /* mark global metatables */ /* remark occasional upvalues of (maybe) dead threads */ remarkupvals(g); propagateall(g); /* propagate changes */ work = g->GCmemtrav; /* stop counting (do not recount 'grayagain') */ g->gray = grayagain; propagateall(g); /* traverse 'grayagain' list */ g->GCmemtrav = 0; /* restart counting */ convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ /* Clear values from weak tables, before checking finalizers */ clearvalues(g, g->weak, NULL); clearvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; work += g->GCmemtrav; /* stop counting (objects being finalized) */ separatetobefnz(g, 0); /* separate objects to be finalized */ g->gcfinnum = 1; /* there may be objects to be finalized */ markbeingfnz(g); /* mark objects that will be finalized */ propagateall(g); /* remark, to propagate 'resurrection' */ g->GCmemtrav = 0; /* restart counting */ convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ clearkeys(g, g->ephemeron, NULL); /* clear keys from all ephemeron tables */ clearkeys(g, g->allweak, NULL); /* clear keys from all 'allweak' tables */ /* clear values from resurrected weak tables */ clearvalues(g, g->weak, origweak); clearvalues(g, g->allweak, origall); luaS_clearcache(g); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ work += g->GCmemtrav; /* complete counting */ return work; /* estimate of memory marked by 'atomic' */ } static lu_mem sweepstep (lua_State *L, global_State *g, int nextstate, GCObject **nextlist) { if (g->sweepgc) { l_mem olddebt = g->GCdebt; g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX); g->GCestimate += g->GCdebt - olddebt; /* update estimate */ if (g->sweepgc) /* is there still something to sweep? */ return (GCSWEEPMAX * GCSWEEPCOST); } /* else enter next state */ g->gcstate = nextstate; g->sweepgc = nextlist; return 0; } static lu_mem singlestep (lua_State *L) { global_State *g = G(L); switch (g->gcstate) { case GCSpause: { g->GCmemtrav = g->strt.size * sizeof(GCObject*); restartcollection(g); g->gcstate = GCSpropagate; return g->GCmemtrav; } case GCSpropagate: { g->GCmemtrav = 0; lua_assert(g->gray); propagatemark(g); if (g->gray == NULL) /* no more gray objects? */ g->gcstate = GCSatomic; /* finish propagate phase */ return g->GCmemtrav; /* memory traversed in this step */ } case GCSatomic: { lu_mem work; int sw; propagateall(g); /* make sure gray list is empty */ work = atomic(L); /* work is what was traversed by 'atomic' */ sw = entersweep(L); g->GCestimate = gettotalbytes(g); /* first estimate */; return work + sw * GCSWEEPCOST; } case GCSswpallgc: { /* sweep "regular" objects */ return sweepstep(L, g, GCSswpfinobj, &g->finobj); } case GCSswpfinobj: { /* sweep objects with finalizers */ return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); } case GCSswptobefnz: { /* sweep objects to be finalized */ return sweepstep(L, g, GCSswpend, NULL); } case GCSswpend: { /* finish sweeps */ makewhite(g, g->mainthread); /* sweep main thread */ checkSizes(L, g); g->gcstate = GCScallfin; return 0; } case GCScallfin: { /* call remaining finalizers */ if (g->tobefnz && g->gckind != KGC_EMERGENCY) { int n = runafewfinalizers(L); return (n * GCFINALIZECOST); } else { /* emergency mode or no more finalizers */ g->gcstate = GCSpause; /* finish collection */ return 0; } } default: lua_assert(0); return 0; } } /* ** advances the garbage collector until it reaches a state allowed ** by 'statemask' */ void luaC_runtilstate (lua_State *L, int statesmask) { global_State *g = G(L); while (!testbit(statesmask, g->gcstate)) singlestep(L); } /* ** get GC debt and convert it from Kb to 'work units' (avoid zero debt ** and overflows) */ static l_mem getdebt (global_State *g) { l_mem debt = g->GCdebt; int stepmul = g->gcstepmul; if (debt <= 0) return 0; /* minimal debt */ else { debt = (debt / STEPMULADJ) + 1; debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; return debt; } } /* ** performs a basic GC step when collector is running */ void luaC_step (lua_State *L) { global_State *g = G(L); l_mem debt = getdebt(g); /* GC deficit (be paid now) */ if (!g->gcrunning) { /* not running? */ luaE_setdebt(g, -GCSTEPSIZE * 10); /* avoid being called too often */ return; } do { /* repeat until pause or enough "credit" (negative debt) */ lu_mem work = singlestep(L); /* perform one single step */ debt -= work; } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause); if (g->gcstate == GCSpause) setpause(g); /* pause until next cycle */ else { debt = (debt / g->gcstepmul) * STEPMULADJ; /* convert 'work units' to Kb */ luaE_setdebt(g, debt); runafewfinalizers(L); } } /* ** Performs a full GC cycle; if 'isemergency', set a flag to avoid ** some operations which could change the interpreter state in some ** unexpected ways (running finalizers and shrinking some structures). ** Before running the collection, check 'keepinvariant'; if it is true, ** there may be some objects marked as black, so the collector has ** to sweep all objects to turn them back to white (as white has not ** changed, nothing will be collected). */ void luaC_fullgc (lua_State *L, int isemergency) { global_State *g = G(L); lua_assert(g->gckind == KGC_NORMAL); if (isemergency) g->gckind = KGC_EMERGENCY; /* set flag */ if (keepinvariant(g)) { /* black objects? */ entersweep(L); /* sweep everything to turn them back to white */ } /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, ~bitmask(GCSpause)); /* start new collection */ luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ /* estimate must be correct after a full GC cycle */ lua_assert(g->GCestimate == gettotalbytes(g)); luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ g->gckind = KGC_NORMAL; setpause(g); } /* }====================================================== */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lmem.c����������������������������������������������������������������������������0000644�0001751�0001751�00000005157�12675241401�012112� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ #define lmem_c #define LUA_CORE #include "lprefix.h" #include <stddef.h> #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" /* ** About the realloc function: ** void * frealloc (void *ud, void *ptr, size_t osize, size_t nsize); ** ('osize' is the old size, 'nsize' is the new size) ** ** * frealloc(ud, NULL, x, s) creates a new block of size 's' (no ** matter 'x'). ** ** * frealloc(ud, p, x, 0) frees the block 'p' ** (in this specific case, frealloc must return NULL); ** particularly, frealloc(ud, NULL, 0, 0) does nothing ** (which is equivalent to free(NULL) in ISO C) ** ** frealloc returns NULL if it cannot create or reallocate the area ** (any reallocation to an equal or smaller size cannot fail!) */ #define MINSIZEARRAY 4 void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, int limit, const char *what) { void *newblock; int newsize; if (*size >= limit/2) { /* cannot double it? */ if (*size >= limit) /* cannot grow even a little? */ luaG_runerror(L, "too many %s (limit is %d)", what, limit); newsize = limit; /* still have at least one free place */ } else { newsize = (*size)*2; if (newsize < MINSIZEARRAY) newsize = MINSIZEARRAY; /* minimum size */ } newblock = luaM_reallocv(L, block, *size, newsize, size_elems); *size = newsize; /* update only when everything else is OK */ return newblock; } l_noret luaM_toobig (lua_State *L) { luaG_runerror(L, "memory allocation error: block too big"); } /* ** generic allocation routine. */ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *newblock; global_State *g = G(L); size_t realosize = (block) ? osize : 0; lua_assert((realosize == 0) == (block == NULL)); #if defined(HARDMEMTESTS) if (nsize > realosize && g->gcrunning) luaC_fullgc(L, 1); /* force a GC whenever possible */ #endif newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ if (g->version) { /* is state fully built? */ luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } if (newblock == NULL) luaD_throw(L, LUA_ERRMEM); } lua_assert((nsize == 0) == (newblock == NULL)); g->GCdebt = (g->GCdebt + nsize) - realosize; return newblock; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lauxlib.c�������������������������������������������������������������������������0000644�0001751�0001751�00000071633�12675241401�012622� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lauxlib.c,v 1.284 2015/11/19 19:16:22 roberto Exp $ ** Auxiliary functions for building Lua libraries ** See Copyright Notice in lua.h */ #define lauxlib_c #define LUA_LIB #include "lprefix.h" #include <errno.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> /* This file uses only the official API of Lua. ** Any function declared here could be written as an application function. */ #include "lua.h" #include "lauxlib.h" /* ** {====================================================== ** Traceback ** ======================================================= */ #define LEVELS1 10 /* size of the first part of the stack */ #define LEVELS2 11 /* size of the second part of the stack */ /* ** search for 'objidx' in table at index -1. ** return 1 + string at top if find a good name. */ static int findfield (lua_State *L, int objidx, int level) { if (level == 0 || !lua_istable(L, -1)) return 0; /* not found */ lua_pushnil(L); /* start 'next' loop */ while (lua_next(L, -2)) { /* for each pair in table */ if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */ if (lua_rawequal(L, objidx, -1)) { /* found object? */ lua_pop(L, 1); /* remove value (but keep name) */ return 1; } else if (findfield(L, objidx, level - 1)) { /* try recursively */ lua_remove(L, -2); /* remove table (but keep name) */ lua_pushliteral(L, "."); lua_insert(L, -2); /* place '.' between the two names */ lua_concat(L, 3); return 1; } } lua_pop(L, 1); /* remove value */ } return 0; /* not found */ } /* ** Search for a name for a function in all loaded modules ** (registry._LOADED). */ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); if (findfield(L, top + 1, 2)) { const char *name = lua_tostring(L, -1); if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */ lua_pushstring(L, name + 3); /* push name without prefix */ lua_remove(L, -2); /* remove original name */ } lua_copy(L, -1, top + 1); /* move name to proper place */ lua_pop(L, 2); /* remove pushed values */ return 1; } else { lua_settop(L, top); /* remove function and global table */ return 0; } } static void pushfuncname (lua_State *L, lua_Debug *ar) { if (pushglobalfuncname(L, ar)) { /* try first a global name */ lua_pushfstring(L, "function '%s'", lua_tostring(L, -1)); lua_remove(L, -2); /* remove name */ } else if (*ar->namewhat != '\0') /* is there a name from code? */ lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */ else if (*ar->what == 'm') /* main? */ lua_pushliteral(L, "main chunk"); else if (*ar->what != 'C') /* for Lua functions, use <file:line> */ lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined); else /* nothing left... */ lua_pushliteral(L, "?"); } static int lastlevel (lua_State *L) { lua_Debug ar; int li = 1, le = 1; /* find an upper bound */ while (lua_getstack(L, le, &ar)) { li = le; le *= 2; } /* do a binary search */ while (li < le) { int m = (li + le)/2; if (lua_getstack(L, m, &ar)) li = m + 1; else le = m; } return le - 1; } LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level) { lua_Debug ar; int top = lua_gettop(L); int last = lastlevel(L1); int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1; if (msg) lua_pushfstring(L, "%s\n", msg); luaL_checkstack(L, 10, NULL); lua_pushliteral(L, "stack traceback:"); while (lua_getstack(L1, level++, &ar)) { if (n1-- == 0) { /* too many levels? */ lua_pushliteral(L, "\n\t..."); /* add a '...' */ level = last - LEVELS2 + 1; /* and skip to last ones */ } else { lua_getinfo(L1, "Slnt", &ar); lua_pushfstring(L, "\n\t%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); lua_pushliteral(L, " in "); pushfuncname(L, &ar); if (ar.istailcall) lua_pushliteral(L, "\n\t(...tail calls...)"); lua_concat(L, lua_gettop(L) - top); } } lua_concat(L, lua_gettop(L) - top); } /* }====================================================== */ /* ** {====================================================== ** Error-report functions ** ======================================================= */ LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ return luaL_error(L, "bad argument #%d (%s)", arg, extramsg); lua_getinfo(L, "n", &ar); if (strcmp(ar.namewhat, "method") == 0) { arg--; /* do not count 'self' */ if (arg == 0) /* error is in the self argument itself? */ return luaL_error(L, "calling '%s' on bad self (%s)", ar.name, extramsg); } if (ar.name == NULL) ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?"; return luaL_error(L, "bad argument #%d to '%s' (%s)", arg, ar.name, extramsg); } static int typeerror (lua_State *L, int arg, const char *tname) { const char *msg; const char *typearg; /* name for the type of the actual argument */ if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) typearg = lua_tostring(L, -1); /* use the given type name */ else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA) typearg = "light userdata"; /* special name for messages */ else typearg = luaL_typename(L, arg); /* standard name */ msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg); return luaL_argerror(L, arg, msg); } static void tag_error (lua_State *L, int arg, int tag) { typeerror(L, arg, lua_typename(L, tag)); } LUALIB_API void luaL_where (lua_State *L, int level) { lua_Debug ar; if (lua_getstack(L, level, &ar)) { /* check function at level */ lua_getinfo(L, "Sl", &ar); /* get info about it */ if (ar.currentline > 0) { /* is there info? */ lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline); return; } } lua_pushliteral(L, ""); /* else, no information available... */ } LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { va_list argp; va_start(argp, fmt); luaL_where(L, 1); lua_pushvfstring(L, fmt, argp); va_end(argp); lua_concat(L, 2); return lua_error(L); } LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { int en = errno; /* calls to Lua API may change this value */ if (stat) { lua_pushboolean(L, 1); return 1; } else { lua_pushnil(L); if (fname) lua_pushfstring(L, "%s: %s", fname, strerror(en)); else lua_pushstring(L, strerror(en)); lua_pushinteger(L, en); return 3; } } #if !defined(l_inspectstat) /* { */ #if defined(LUA_USE_POSIX) #include <sys/wait.h> /* ** use appropriate macros to interpret 'pclose' return status */ #define l_inspectstat(stat,what) \ if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \ else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; } #else #define l_inspectstat(stat,what) /* no op */ #endif #endif /* } */ LUALIB_API int luaL_execresult (lua_State *L, int stat) { const char *what = "exit"; /* type of termination */ if (stat == -1) /* error? */ return luaL_fileresult(L, 0, NULL); else { l_inspectstat(stat, what); /* interpret result */ if (*what == 'e' && stat == 0) /* successful termination? */ lua_pushboolean(L, 1); else lua_pushnil(L); lua_pushstring(L, what); lua_pushinteger(L, stat); return 3; /* return true/nil,what,code */ } } /* }====================================================== */ /* ** {====================================================== ** Userdata's metatable manipulation ** ======================================================= */ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */ return 0; /* leave previous value on top, but return 0 */ lua_pop(L, 1); lua_createtable(L, 0, 2); /* create metatable */ lua_pushstring(L, tname); lua_setfield(L, -2, "__name"); /* metatable.__name = tname */ lua_pushvalue(L, -1); lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */ return 1; } LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) { luaL_getmetatable(L, tname); lua_setmetatable(L, -2); } LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) { void *p = lua_touserdata(L, ud); if (p != NULL) { /* value is a userdata? */ if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ luaL_getmetatable(L, tname); /* get correct metatable */ if (!lua_rawequal(L, -1, -2)) /* not the same? */ p = NULL; /* value is a userdata with wrong metatable */ lua_pop(L, 2); /* remove both metatables */ return p; } } return NULL; /* value is not a userdata with a metatable */ } LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { void *p = luaL_testudata(L, ud, tname); if (p == NULL) typeerror(L, ud, tname); return p; } /* }====================================================== */ /* ** {====================================================== ** Argument check functions ** ======================================================= */ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, const char *const lst[]) { const char *name = (def) ? luaL_optstring(L, arg, def) : luaL_checkstring(L, arg); int i; for (i=0; lst[i]; i++) if (strcmp(lst[i], name) == 0) return i; return luaL_argerror(L, arg, lua_pushfstring(L, "invalid option '%s'", name)); } LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { /* keep some extra space to run error routines, if needed */ const int extra = LUA_MINSTACK; if (!lua_checkstack(L, space + extra)) { if (msg) luaL_error(L, "stack overflow (%s)", msg); else luaL_error(L, "stack overflow"); } } LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { if (lua_type(L, arg) != t) tag_error(L, arg, t); } LUALIB_API void luaL_checkany (lua_State *L, int arg) { if (lua_type(L, arg) == LUA_TNONE) luaL_argerror(L, arg, "value expected"); } LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { const char *s = lua_tolstring(L, arg, len); if (!s) tag_error(L, arg, LUA_TSTRING); return s; } LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, const char *def, size_t *len) { if (lua_isnoneornil(L, arg)) { if (len) *len = (def ? strlen(def) : 0); return def; } else return luaL_checklstring(L, arg, len); } LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { int isnum; lua_Number d = lua_tonumberx(L, arg, &isnum); if (!isnum) tag_error(L, arg, LUA_TNUMBER); return d; } LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) { return luaL_opt(L, luaL_checknumber, arg, def); } static void interror (lua_State *L, int arg) { if (lua_isnumber(L, arg)) luaL_argerror(L, arg, "number has no integer representation"); else tag_error(L, arg, LUA_TNUMBER); } LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { int isnum; lua_Integer d = lua_tointegerx(L, arg, &isnum); if (!isnum) { interror(L, arg); } return d; } LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg, lua_Integer def) { return luaL_opt(L, luaL_checkinteger, arg, def); } /* }====================================================== */ /* ** {====================================================== ** Generic Buffer manipulation ** ======================================================= */ /* userdata to box arbitrary data */ typedef struct UBox { void *box; size_t bsize; } UBox; static void *resizebox (lua_State *L, int idx, size_t newsize) { void *ud; lua_Alloc allocf = lua_getallocf(L, &ud); UBox *box = (UBox *)lua_touserdata(L, idx); void *temp = allocf(ud, box->box, box->bsize, newsize); if (temp == NULL && newsize > 0) { /* allocation error? */ resizebox(L, idx, 0); /* free buffer */ luaL_error(L, "not enough memory for buffer allocation"); } box->box = temp; box->bsize = newsize; return temp; } static int boxgc (lua_State *L) { resizebox(L, 1, 0); return 0; } static void *newbox (lua_State *L, size_t newsize) { UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox)); box->box = NULL; box->bsize = 0; if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */ lua_pushcfunction(L, boxgc); lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */ } lua_setmetatable(L, -2); return resizebox(L, -1, newsize); } /* ** check whether buffer is using a userdata on the stack as a temporary ** buffer */ #define buffonstack(B) ((B)->b != (B)->initb) /* ** returns a pointer to a free area with at least 'sz' bytes */ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { lua_State *L = B->L; if (B->size - B->n < sz) { /* not enough space? */ char *newbuff; size_t newsize = B->size * 2; /* double buffer size */ if (newsize - B->n < sz) /* not big enough? */ newsize = B->n + sz; if (newsize < B->n || newsize - B->n < sz) luaL_error(L, "buffer too large"); /* create larger buffer */ if (buffonstack(B)) newbuff = (char *)resizebox(L, -1, newsize); else { /* no buffer yet */ newbuff = (char *)newbox(L, newsize); memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ } B->b = newbuff; B->size = newsize; } return &B->b[B->n]; } LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */ char *b = luaL_prepbuffsize(B, l); memcpy(b, s, l * sizeof(char)); luaL_addsize(B, l); } } LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { luaL_addlstring(B, s, strlen(s)); } LUALIB_API void luaL_pushresult (luaL_Buffer *B) { lua_State *L = B->L; lua_pushlstring(L, B->b, B->n); if (buffonstack(B)) { resizebox(L, -2, 0); /* delete old buffer */ lua_remove(L, -2); /* remove its header from the stack */ } } LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { luaL_addsize(B, sz); luaL_pushresult(B); } LUALIB_API void luaL_addvalue (luaL_Buffer *B) { lua_State *L = B->L; size_t l; const char *s = lua_tolstring(L, -1, &l); if (buffonstack(B)) lua_insert(L, -2); /* put value below buffer */ luaL_addlstring(B, s, l); lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ } LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { B->L = L; B->b = B->initb; B->n = 0; B->size = LUAL_BUFFERSIZE; } LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { luaL_buffinit(L, B); return luaL_prepbuffsize(B, sz); } /* }====================================================== */ /* ** {====================================================== ** Reference system ** ======================================================= */ /* index of free-list header */ #define freelist 0 LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; if (lua_isnil(L, -1)) { lua_pop(L, 1); /* remove from stack */ return LUA_REFNIL; /* 'nil' has a unique fixed reference */ } t = lua_absindex(L, t); lua_rawgeti(L, t, freelist); /* get first free element */ ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ lua_pop(L, 1); /* remove it from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ } else /* no free elements */ ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */ lua_rawseti(L, t, ref); return ref; } LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { if (ref >= 0) { t = lua_absindex(L, t); lua_rawgeti(L, t, freelist); lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ lua_pushinteger(L, ref); lua_rawseti(L, t, freelist); /* t[freelist] = ref */ } } /* }====================================================== */ /* ** {====================================================== ** Load functions ** ======================================================= */ typedef struct LoadF { int n; /* number of pre-read characters */ FILE *f; /* file being read */ char buff[BUFSIZ]; /* area for reading file */ } LoadF; static const char *getF (lua_State *L, void *ud, size_t *size) { LoadF *lf = (LoadF *)ud; (void)L; /* not used */ if (lf->n > 0) { /* are there pre-read characters to be read? */ *size = lf->n; /* return them (chars already in buffer) */ lf->n = 0; /* no more pre-read characters */ } else { /* read a block from file */ /* 'fread' can return > 0 *and* set the EOF flag. If next call to 'getF' called 'fread', it might still wait for user input. The next check avoids this problem. */ if (feof(lf->f)) return NULL; *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */ } return lf->buff; } static int errfile (lua_State *L, const char *what, int fnameindex) { const char *serr = strerror(errno); const char *filename = lua_tostring(L, fnameindex) + 1; lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); lua_remove(L, fnameindex); return LUA_ERRFILE; } static int skipBOM (LoadF *lf) { const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ int c; lf->n = 0; do { c = getc(lf->f); if (c == EOF || c != *(const unsigned char *)p++) return c; lf->buff[lf->n++] = c; /* to be read by the parser */ } while (*p != '\0'); lf->n = 0; /* prefix matched; discard it */ return getc(lf->f); /* return next character */ } /* ** reads the first character of file 'f' and skips an optional BOM mark ** in its beginning plus its first line if it starts with '#'. Returns ** true if it skipped the first line. In any case, '*cp' has the ** first "valid" character of the file (after the optional BOM and ** a first-line comment). */ static int skipcomment (LoadF *lf, int *cp) { int c = *cp = skipBOM(lf); if (c == '#') { /* first line is a comment (Unix exec. file)? */ do { /* skip first line */ c = getc(lf->f); } while (c != EOF && c != '\n') ; *cp = getc(lf->f); /* skip end-of-line, if present */ return 1; /* there was a comment */ } else return 0; /* no comment */ } LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, const char *mode) { LoadF lf; int status, readstatus; int c; int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */ if (filename == NULL) { lua_pushliteral(L, "=stdin"); lf.f = stdin; } else { lua_pushfstring(L, "@%s", filename); lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } if (skipcomment(&lf, &c)) /* read initial portion */ lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); skipcomment(&lf, &c); /* re-read initial portion */ } if (c != EOF) lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ if (readstatus) { lua_settop(L, fnameindex); /* ignore results from 'lua_load' */ return errfile(L, "read", fnameindex); } lua_remove(L, fnameindex); return status; } typedef struct LoadS { const char *s; size_t size; } LoadS; static const char *getS (lua_State *L, void *ud, size_t *size) { LoadS *ls = (LoadS *)ud; (void)L; /* not used */ if (ls->size == 0) return NULL; *size = ls->size; ls->size = 0; return ls->s; } LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size, const char *name, const char *mode) { LoadS ls; ls.s = buff; ls.size = size; return lua_load(L, getS, &ls, name, mode); } LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { return luaL_loadbuffer(L, s, strlen(s), s); } /* }====================================================== */ LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { if (!lua_getmetatable(L, obj)) /* no metatable? */ return LUA_TNIL; else { int tt; lua_pushstring(L, event); tt = lua_rawget(L, -2); if (tt == LUA_TNIL) /* is metafield nil? */ lua_pop(L, 2); /* remove metatable and metafield */ else lua_remove(L, -2); /* remove only metatable */ return tt; /* return metafield type */ } } LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { obj = lua_absindex(L, obj); if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */ return 0; lua_pushvalue(L, obj); lua_call(L, 1, 1); return 1; } LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { lua_Integer l; int isnum; lua_len(L, idx); l = lua_tointegerx(L, -1, &isnum); if (!isnum) luaL_error(L, "object length is not an integer"); lua_pop(L, 1); /* remove object */ return l; } LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ switch (lua_type(L, idx)) { case LUA_TNUMBER: { if (lua_isinteger(L, idx)) lua_pushfstring(L, "%I", lua_tointeger(L, idx)); else lua_pushfstring(L, "%f", lua_tonumber(L, idx)); break; } case LUA_TSTRING: lua_pushvalue(L, idx); break; case LUA_TBOOLEAN: lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); break; case LUA_TNIL: lua_pushliteral(L, "nil"); break; default: lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), lua_topointer(L, idx)); break; } } return lua_tolstring(L, -1, len); } /* ** {====================================================== ** Compatibility with 5.1 module functions ** ======================================================= */ #if defined(LUA_COMPAT_MODULE) static const char *luaL_findtable (lua_State *L, int idx, const char *fname, int szhint) { const char *e; if (idx) lua_pushvalue(L, idx); do { e = strchr(fname, '.'); if (e == NULL) e = fname + strlen(fname); lua_pushlstring(L, fname, e - fname); if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */ lua_pop(L, 1); /* remove this nil */ lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ lua_pushlstring(L, fname, e - fname); lua_pushvalue(L, -2); lua_settable(L, -4); /* set new table into field */ } else if (!lua_istable(L, -1)) { /* field has a non-table value? */ lua_pop(L, 2); /* remove table and value */ return fname; /* return problematic part of the name */ } lua_remove(L, -2); /* remove previous table */ fname = e + 1; } while (*e == '.'); return NULL; } /* ** Count number of elements in a luaL_Reg list. */ static int libsize (const luaL_Reg *l) { int size = 0; for (; l && l->name; l++) size++; return size; } /* ** Find or create a module table with a given name. The function ** first looks at the _LOADED table and, if that fails, try a ** global variable with that name. In any case, leaves on the stack ** the module table. */ LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname, int sizehint) { luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */ if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */ lua_pop(L, 1); /* remove previous result */ /* try global variable (and create one if it does not exist) */ lua_pushglobaltable(L); if (luaL_findtable(L, 0, modname, sizehint) != NULL) luaL_error(L, "name conflict for module '%s'", modname); lua_pushvalue(L, -1); lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */ } lua_remove(L, -2); /* remove _LOADED table */ } LUALIB_API void luaL_openlib (lua_State *L, const char *libname, const luaL_Reg *l, int nup) { luaL_checkversion(L); if (libname) { luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */ lua_insert(L, -(nup + 1)); /* move library table to below upvalues */ } if (l) luaL_setfuncs(L, l, nup); else lua_pop(L, nup); /* remove upvalues */ } #endif /* }====================================================== */ /* ** set functions from list 'l' into table at top - 'nup'; each ** function gets the 'nup' elements at the top as upvalues. ** Returns with only the table at the stack. */ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ int i; for (i = 0; i < nup; i++) /* copy upvalues to the top */ lua_pushvalue(L, -nup); lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ lua_setfield(L, -(nup + 2), l->name); } lua_pop(L, nup); /* remove upvalues */ } /* ** ensure that stack[idx][fname] has a table and push that table ** into the stack */ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) { if (lua_getfield(L, idx, fname) == LUA_TTABLE) return 1; /* table already there */ else { lua_pop(L, 1); /* remove previous result */ idx = lua_absindex(L, idx); lua_newtable(L); lua_pushvalue(L, -1); /* copy to be left at top */ lua_setfield(L, idx, fname); /* assign new table to field */ return 0; /* false, because did not find table there */ } } /* ** Stripped-down 'require': After checking "loaded" table, calls 'openf' ** to open a module, registers the result in 'package.loaded' table and, ** if 'glb' is true, also registers the result in the global table. ** Leaves resulting module on the top. */ LUALIB_API void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb) { luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, -1, modname); /* _LOADED[modname] */ if (!lua_toboolean(L, -1)) { /* package not already loaded? */ lua_pop(L, 1); /* remove field */ lua_pushcfunction(L, openf); lua_pushstring(L, modname); /* argument to open function */ lua_call(L, 1, 1); /* call 'openf' to open module */ lua_pushvalue(L, -1); /* make copy of module (call result) */ lua_setfield(L, -3, modname); /* _LOADED[modname] = module */ } lua_remove(L, -2); /* remove _LOADED table */ if (glb) { lua_pushvalue(L, -1); /* copy of module */ lua_setglobal(L, modname); /* _G[modname] = module */ } } LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r) { const char *wild; size_t l = strlen(p); luaL_Buffer b; luaL_buffinit(L, &b); while ((wild = strstr(s, p)) != NULL) { luaL_addlstring(&b, s, wild - s); /* push prefix */ luaL_addstring(&b, r); /* push replacement in place of pattern */ s = wild + l; /* continue after 'p' */ } luaL_addstring(&b, s); /* push last suffix */ luaL_pushresult(&b); return lua_tostring(L, -1); } static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; /* not used */ if (nsize == 0) { free(ptr); return NULL; } else return realloc(ptr, nsize); } static int panic (lua_State *L) { lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", lua_tostring(L, -1)); return 0; /* return to Lua to abort */ } LUALIB_API lua_State *luaL_newstate (void) { lua_State *L = lua_newstate(l_alloc, NULL); if (L) lua_atpanic(L, &panic); return L; } LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) { const lua_Number *v = lua_version(L); if (sz != LUAL_NUMSIZES) /* check numeric types */ luaL_error(L, "core and library have incompatible numeric types"); if (v != lua_version(NULL)) luaL_error(L, "multiple Lua VMs detected"); else if (*v != ver) luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f", ver, *v); } �����������������������������������������������������������������������������������������������������golly-2.8-src/lua/loslib.c��������������������������������������������������������������������������0000644�0001751�0001751�00000023640�12675241401�012441� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: loslib.c,v 1.60 2015/11/19 19:16:22 roberto Exp $ ** Standard Operating System library ** See Copyright Notice in lua.h */ #define loslib_c #define LUA_LIB #include "lprefix.h" #include <errno.h> #include <locale.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** {================================================================== ** list of valid conversion specifiers for the 'strftime' function ** =================================================================== */ #if !defined(LUA_STRFTIMEOPTIONS) /* { */ #if defined(LUA_USE_C89) #define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" } #else /* C99 specification */ #define LUA_STRFTIMEOPTIONS \ { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \ "E", "cCxXyY", \ "O", "deHImMSuUVwWy" } #endif #endif /* } */ /* }================================================================== */ /* ** {================================================================== ** Configuration for time-related stuff ** =================================================================== */ #if !defined(l_time_t) /* { */ /* ** type to represent time_t in Lua */ #define l_timet lua_Integer #define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t)) static time_t l_checktime (lua_State *L, int arg) { lua_Integer t = luaL_checkinteger(L, arg); luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds"); return (time_t)t; } #endif /* } */ #if !defined(l_gmtime) /* { */ /* ** By default, Lua uses gmtime/localtime, except when POSIX is available, ** where it uses gmtime_r/localtime_r */ #if defined(LUA_USE_POSIX) /* { */ #define l_gmtime(t,r) gmtime_r(t,r) #define l_localtime(t,r) localtime_r(t,r) #else /* }{ */ /* ISO C definitions */ #define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t)) #define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t)) #endif /* } */ #endif /* } */ /* }================================================================== */ /* ** {================================================================== ** Configuration for 'tmpnam': ** By default, Lua uses tmpnam except when POSIX is available, where ** it uses mkstemp. ** =================================================================== */ #if !defined(lua_tmpnam) /* { */ #if defined(LUA_USE_POSIX) /* { */ #include <unistd.h> #define LUA_TMPNAMBUFSIZE 32 #if !defined(LUA_TMPNAMTEMPLATE) #define LUA_TMPNAMTEMPLATE "/tmp/lua_XXXXXX" #endif #define lua_tmpnam(b,e) { \ strcpy(b, LUA_TMPNAMTEMPLATE); \ e = mkstemp(b); \ if (e != -1) close(e); \ e = (e == -1); } #else /* }{ */ /* ISO C definitions */ #define LUA_TMPNAMBUFSIZE L_tmpnam #define lua_tmpnam(b,e) { e = (tmpnam(b) == NULL); } #endif /* } */ #endif /* } */ /* }================================================================== */ static int os_execute (lua_State *L) { const char *cmd = luaL_optstring(L, 1, NULL); int stat = system(cmd); if (cmd != NULL) return luaL_execresult(L, stat); else { lua_pushboolean(L, stat); /* true if there is a shell */ return 1; } } static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); return luaL_fileresult(L, remove(filename) == 0, filename); } static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); } static int os_tmpname (lua_State *L) { char buff[LUA_TMPNAMBUFSIZE]; int err; lua_tmpnam(buff, err); if (err) return luaL_error(L, "unable to generate a unique filename"); lua_pushstring(L, buff); return 1; } static int os_getenv (lua_State *L) { lua_pushstring(L, getenv(luaL_checkstring(L, 1))); /* if NULL push nil */ return 1; } static int os_clock (lua_State *L) { lua_pushnumber(L, ((lua_Number)clock())/(lua_Number)CLOCKS_PER_SEC); return 1; } /* ** {====================================================== ** Time/Date operations ** { year=%Y, month=%m, day=%d, hour=%H, min=%M, sec=%S, ** wday=%w+1, yday=%j, isdst=? } ** ======================================================= */ static void setfield (lua_State *L, const char *key, int value) { lua_pushinteger(L, value); lua_setfield(L, -2, key); } static void setboolfield (lua_State *L, const char *key, int value) { if (value < 0) /* undefined? */ return; /* does not set field */ lua_pushboolean(L, value); lua_setfield(L, -2, key); } static int getboolfield (lua_State *L, const char *key) { int res; res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1); lua_pop(L, 1); return res; } /* maximum value for date fields (to avoid arithmetic overflows with 'int') */ #if !defined(L_MAXDATEFIELD) #define L_MAXDATEFIELD (INT_MAX / 2) #endif static int getfield (lua_State *L, const char *key, int d, int delta) { int isnum; int t = lua_getfield(L, -1, key); lua_Integer res = lua_tointegerx(L, -1, &isnum); if (!isnum) { /* field is not a number? */ if (t != LUA_TNIL) /* some other value? */ return luaL_error(L, "field '%s' not an integer", key); else if (d < 0) /* absent field; no default? */ return luaL_error(L, "field '%s' missing in date table", key); res = d; } else { if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD)) return luaL_error(L, "field '%s' out-of-bounds", key); res -= delta; } lua_pop(L, 1); return (int)res; } static const char *checkoption (lua_State *L, const char *conv, char *buff) { static const char *const options[] = LUA_STRFTIMEOPTIONS; unsigned int i; for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) { if (*conv != '\0' && strchr(options[i], *conv) != NULL) { buff[1] = *conv; if (*options[i + 1] == '\0') { /* one-char conversion specifier? */ buff[2] = '\0'; /* end buffer */ return conv + 1; } else if (*(conv + 1) != '\0' && strchr(options[i + 1], *(conv + 1)) != NULL) { buff[2] = *(conv + 1); /* valid two-char conversion specifier */ buff[3] = '\0'; /* end buffer */ return conv + 2; } } } luaL_argerror(L, 1, lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv)); return conv; /* to avoid warnings */ } /* maximum size for an individual 'strftime' item */ #define SIZETIMEFMT 250 static int os_date (lua_State *L) { const char *s = luaL_optstring(L, 1, "%c"); time_t t = luaL_opt(L, l_checktime, 2, time(NULL)); struct tm tmr, *stm; if (*s == '!') { /* UTC? */ stm = l_gmtime(&t, &tmr); s++; /* skip '!' */ } else stm = l_localtime(&t, &tmr); if (stm == NULL) /* invalid date? */ luaL_error(L, "time result cannot be represented in this installation"); if (strcmp(s, "*t") == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ setfield(L, "sec", stm->tm_sec); setfield(L, "min", stm->tm_min); setfield(L, "hour", stm->tm_hour); setfield(L, "day", stm->tm_mday); setfield(L, "month", stm->tm_mon+1); setfield(L, "year", stm->tm_year+1900); setfield(L, "wday", stm->tm_wday+1); setfield(L, "yday", stm->tm_yday+1); setboolfield(L, "isdst", stm->tm_isdst); } else { char cc[4]; luaL_Buffer b; cc[0] = '%'; luaL_buffinit(L, &b); while (*s) { if (*s != '%') /* not a conversion specifier? */ luaL_addchar(&b, *s++); else { size_t reslen; char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); s = checkoption(L, s + 1, cc); reslen = strftime(buff, SIZETIMEFMT, cc, stm); luaL_addsize(&b, reslen); } } luaL_pushresult(&b); } return 1; } static int os_time (lua_State *L) { time_t t; if (lua_isnoneornil(L, 1)) /* called without args? */ t = time(NULL); /* get current time */ else { struct tm ts; luaL_checktype(L, 1, LUA_TTABLE); lua_settop(L, 1); /* make sure table is at the top */ ts.tm_sec = getfield(L, "sec", 0, 0); ts.tm_min = getfield(L, "min", 0, 0); ts.tm_hour = getfield(L, "hour", 12, 0); ts.tm_mday = getfield(L, "day", -1, 0); ts.tm_mon = getfield(L, "month", -1, 1); ts.tm_year = getfield(L, "year", -1, 1900); ts.tm_isdst = getboolfield(L, "isdst"); t = mktime(&ts); } if (t != (time_t)(l_timet)t || t == (time_t)(-1)) luaL_error(L, "time result cannot be represented in this installation"); l_pushtime(L, t); return 1; } static int os_difftime (lua_State *L) { time_t t1 = l_checktime(L, 1); time_t t2 = l_checktime(L, 2); lua_pushnumber(L, (lua_Number)difftime(t1, t2)); return 1; } /* }====================================================== */ static int os_setlocale (lua_State *L) { static const int cat[] = {LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME}; static const char *const catnames[] = {"all", "collate", "ctype", "monetary", "numeric", "time", NULL}; const char *l = luaL_optstring(L, 1, NULL); int op = luaL_checkoption(L, 2, "all", catnames); lua_pushstring(L, setlocale(cat[op], l)); return 1; } static int os_exit (lua_State *L) { int status; if (lua_isboolean(L, 1)) status = (lua_toboolean(L, 1) ? EXIT_SUCCESS : EXIT_FAILURE); else status = (int)luaL_optinteger(L, 1, EXIT_SUCCESS); if (lua_toboolean(L, 2)) lua_close(L); if (L) exit(status); /* 'if' to avoid warnings for unreachable 'return' */ return 0; } static const luaL_Reg syslib[] = { {"clock", os_clock}, {"date", os_date}, {"difftime", os_difftime}, {"execute", os_execute}, {"exit", os_exit}, {"getenv", os_getenv}, {"remove", os_remove}, {"rename", os_rename}, {"setlocale", os_setlocale}, {"time", os_time}, {"tmpname", os_tmpname}, {NULL, NULL} }; /* }====================================================== */ LUAMOD_API int luaopen_os (lua_State *L) { luaL_newlib(L, syslib); return 1; } ������������������������������������������������������������������������������������������������golly-2.8-src/lua/lctype.c��������������������������������������������������������������������������0000644�0001751�0001751�00000004416�12675241401�012455� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lctype.c,v 1.12 2014/11/02 19:19:04 roberto Exp $ ** 'ctype' functions for Lua ** See Copyright Notice in lua.h */ #define lctype_c #define LUA_CORE #include "lprefix.h" #include "lctype.h" #if !LUA_USE_CTYPE /* { */ #include <limits.h> LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = { 0x00, /* EOZ */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */ 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */ 0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */ 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, 0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */ 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #endif /* } */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lzio.c����������������������������������������������������������������������������0000644�0001751�0001751�00000002521�12675241401�012125� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $ ** Buffered streams ** See Copyright Notice in lua.h */ #define lzio_c #define LUA_CORE #include "lprefix.h" #include <string.h> #include "lua.h" #include "llimits.h" #include "lmem.h" #include "lstate.h" #include "lzio.h" int luaZ_fill (ZIO *z) { size_t size; lua_State *L = z->L; const char *buff; lua_unlock(L); buff = z->reader(L, z->data, &size); lua_lock(L); if (buff == NULL || size == 0) return EOZ; z->n = size - 1; /* discount char being returned */ z->p = buff; return cast_uchar(*(z->p++)); } void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader, void *data) { z->L = L; z->reader = reader; z->data = data; z->n = 0; z->p = NULL; } /* --------------------------------------------------------------- read --- */ size_t luaZ_read (ZIO *z, void *b, size_t n) { while (n) { size_t m; if (z->n == 0) { /* no bytes in buffer? */ if (luaZ_fill(z) == EOZ) /* try to read more */ return n; /* no more input; return number of missing bytes */ else { z->n++; /* luaZ_fill consumed first byte; put it back */ z->p--; } } m = (n <= z->n) ? n : z->n; /* min. between n and z->n */ memcpy(b, z->p, m); z->n -= m; z->p += m; b = (char *)b + m; n -= m; } return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/ldebug.h��������������������������������������������������������������������������0000644�0001751�0001751�00000002654�12675241401�012426� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $ ** Auxiliary functions from Debug Interface module ** See Copyright Notice in lua.h */ #ifndef ldebug_h #define ldebug_h #include "lstate.h" #define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1) #define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : -1) #define resethookcount(L) (L->hookcount = L->basehookcount) LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *opname); LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_opinterror (lua_State *L, const TValue *p1, const TValue *p2, const char *msg); LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2); LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...); LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, int line); LUAI_FUNC l_noret luaG_errormsg (lua_State *L); LUAI_FUNC void luaG_traceexec (lua_State *L); #endif ������������������������������������������������������������������������������������golly-2.8-src/lua/ldo.c�����������������������������������������������������������������������������0000644�0001751�0001751�00000061126�12675241401�011734� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ldo.c,v 2.150 2015/11/19 19:16:22 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #define ldo_c #define LUA_CORE #include "lprefix.h" #include <setjmp.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lundump.h" #include "lvm.h" #include "lzio.h" #define errorstatus(s) ((s) > LUA_YIELD) /* ** {====================================================== ** Error-recovery functions ** ======================================================= */ /* ** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By ** default, Lua handles errors with exceptions when compiling as ** C++ code, with _longjmp/_setjmp when asked to use them, and with ** longjmp/setjmp otherwise. */ #if !defined(LUAI_THROW) /* { */ #if defined(__cplusplus) && !defined(LUA_USE_LONGJMP) /* { */ /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) #define LUAI_TRY(L,c,a) \ try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; } #define luai_jmpbuf int /* dummy variable */ #elif defined(LUA_USE_POSIX) /* }{ */ /* in POSIX, try _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #else /* }{ */ /* ISO C handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a } #define luai_jmpbuf jmp_buf #endif /* } */ #endif /* } */ /* chain list of long jump buffers */ struct lua_longjmp { struct lua_longjmp *previous; luai_jmpbuf b; volatile int status; /* error code */ }; static void seterrorobj (lua_State *L, int errcode, StkId oldtop) { switch (errcode) { case LUA_ERRMEM: { /* memory error? */ setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ break; } case LUA_ERRERR: { setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } default: { setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } } L->top = oldtop + 1; } l_noret luaD_throw (lua_State *L, int errcode) { if (L->errorJmp) { /* thread has an error handler? */ L->errorJmp->status = errcode; /* set status */ LUAI_THROW(L, L->errorJmp); /* jump to it */ } else { /* thread has no error handler */ global_State *g = G(L); L->status = cast_byte(errcode); /* mark it as dead */ if (g->mainthread->errorJmp) { /* main thread has a handler? */ setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ } else { /* no handler at all; abort */ if (g->panic) { /* panic function? */ seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ if (L->ci->top < L->top) L->ci->top = L->top; /* pushing msg. can break this invariant */ lua_unlock(L); g->panic(L); /* call panic function (last chance to jump out) */ } abort(); } } } int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { unsigned short oldnCcalls = L->nCcalls; struct lua_longjmp lj; lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; LUAI_TRY(L, &lj, (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ L->nCcalls = oldnCcalls; return lj.status; } /* }====================================================== */ /* ** {================================================================== ** Stack reallocation ** =================================================================== */ static void correctstack (lua_State *L, TValue *oldstack) { CallInfo *ci; UpVal *up; L->top = (L->top - oldstack) + L->stack; for (up = L->openupval; up != NULL; up = up->u.open.next) up->v = (up->v - oldstack) + L->stack; for (ci = L->ci; ci != NULL; ci = ci->previous) { ci->top = (ci->top - oldstack) + L->stack; ci->func = (ci->func - oldstack) + L->stack; if (isLua(ci)) ci->u.l.base = (ci->u.l.base - oldstack) + L->stack; } } /* some space for error handling */ #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) void luaD_reallocstack (lua_State *L, int newsize) { TValue *oldstack = L->stack; int lim = L->stacksize; lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue); for (; lim < newsize; lim++) setnilvalue(L->stack + lim); /* erase new segment */ L->stacksize = newsize; L->stack_last = L->stack + newsize - EXTRA_STACK; correctstack(L, oldstack); } void luaD_growstack (lua_State *L, int n) { int size = L->stacksize; if (size > LUAI_MAXSTACK) /* error after extra size? */ luaD_throw(L, LUA_ERRERR); else { int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; int newsize = 2 * size; if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; if (newsize < needed) newsize = needed; if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ luaD_reallocstack(L, ERRORSTACKSIZE); luaG_runerror(L, "stack overflow"); } else luaD_reallocstack(L, newsize); } } static int stackinuse (lua_State *L) { CallInfo *ci; StkId lim = L->top; for (ci = L->ci; ci != NULL; ci = ci->previous) { lua_assert(ci->top <= L->stack_last); if (lim < ci->top) lim = ci->top; } return cast_int(lim - L->stack) + 1; /* part of stack in use */ } void luaD_shrinkstack (lua_State *L) { int inuse = stackinuse(L); int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */ luaE_freeCI(L); /* free all CIs (list grew because of an error) */ else luaE_shrinkCI(L); /* shrink list */ if (inuse <= LUAI_MAXSTACK && /* not handling stack overflow? */ goodsize < L->stacksize) /* trying to shrink? */ luaD_reallocstack(L, goodsize); /* shrink it */ else condmovestack(L,,); /* don't change stack (change only for debugging) */ } void luaD_inctop (lua_State *L) { luaD_checkstack(L, 1); L->top++; } /* }================================================================== */ void luaD_hook (lua_State *L, int event, int line) { lua_Hook hook = L->hook; if (hook && L->allowhook) { CallInfo *ci = L->ci; ptrdiff_t top = savestack(L, L->top); ptrdiff_t ci_top = savestack(L, ci->top); lua_Debug ar; ar.event = event; ar.currentline = line; ar.i_ci = ci; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); L->allowhook = 0; /* cannot call hooks inside a hook */ ci->callstatus |= CIST_HOOKED; lua_unlock(L); (*hook)(L, &ar); lua_lock(L); lua_assert(!L->allowhook); L->allowhook = 1; ci->top = restorestack(L, ci_top); L->top = restorestack(L, top); ci->callstatus &= ~CIST_HOOKED; } } static void callhook (lua_State *L, CallInfo *ci) { int hook = LUA_HOOKCALL; ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ if (isLua(ci->previous) && GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) { ci->callstatus |= CIST_TAIL; hook = LUA_HOOKTAILCALL; } luaD_hook(L, hook, -1); ci->u.l.savedpc--; /* correct 'pc' */ } static StkId adjust_varargs (lua_State *L, Proto *p, int actual) { int i; int nfixargs = p->numparams; StkId base, fixed; /* move fixed parameters to final position */ fixed = L->top - actual; /* first fixed argument */ base = L->top; /* final position of first argument */ for (i = 0; i < nfixargs && i < actual; i++) { setobjs2s(L, L->top++, fixed + i); setnilvalue(fixed + i); /* erase original copy (for GC) */ } for (; i < nfixargs; i++) setnilvalue(L->top++); /* complete missing arguments */ return base; } /* ** Check whether __call metafield of 'func' is a function. If so, put ** it in stack below original 'func' so that 'luaD_precall' can call ** it. Raise an error if __call metafield is not a function. */ static void tryfuncTM (lua_State *L, StkId func) { const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL); StkId p; if (!ttisfunction(tm)) luaG_typeerror(L, func, "call"); /* Open a hole inside the stack at 'func' */ for (p = L->top; p > func; p--) setobjs2s(L, p, p-1); L->top++; /* slot ensured by caller */ setobj2s(L, func, tm); /* tag method is the new function to be called */ } #define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L))) /* macro to check stack size, preserving 'p' */ #define checkstackp(L,n,p) \ luaD_checkstackaux(L, n, \ ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ luaC_checkGC(L), /* stack grow uses memory */ \ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */ /* ** Prepares a function call: checks the stack, creates a new CallInfo ** entry, fills in the relevant information, calls hook if needed. ** If function is a C function, does the call, too. (Otherwise, leave ** the execution ('luaV_execute') to the caller, to allow stackless ** calls.) Returns true iff function has been executed (C function). */ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_CFunction f; CallInfo *ci; switch (ttype(func)) { case LUA_TCCL: /* C closure */ f = clCvalue(func)->f; goto Cfunc; case LUA_TLCF: /* light C function */ f = fvalue(func); Cfunc: { int n; /* number of returns */ checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; ci->func = func; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); ci->callstatus = 0; if (L->hookmask & LUA_MASKCALL) luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); n = (*f)(L); /* do the actual call */ lua_lock(L); api_checknelems(L, n); luaD_poscall(L, ci, L->top - n, n); return 1; } case LUA_TLCL: { /* Lua function: prepare its call */ StkId base; Proto *p = clLvalue(func)->p; int n = cast_int(L->top - func) - 1; /* number of real arguments */ int fsize = p->maxstacksize; /* frame size */ checkstackp(L, fsize, func); if (p->is_vararg != 1) { /* do not use vararg? */ for (; n < p->numparams; n++) setnilvalue(L->top++); /* complete missing arguments */ base = func + 1; } else base = adjust_varargs(L, p, n); ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; ci->func = func; ci->u.l.base = base; L->top = ci->top = base + fsize; lua_assert(ci->top <= L->stack_last); ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus = CIST_LUA; if (L->hookmask & LUA_MASKCALL) callhook(L, ci); return 0; } default: { /* not a function */ checkstackp(L, 1, func); /* ensure space for metamethod */ tryfuncTM(L, func); /* try to get '__call' metamethod */ return luaD_precall(L, func, nresults); /* now it must be a function */ } } } /* ** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'. ** Handle most typical cases (zero results for commands, one result for ** expressions, multiple results for tail calls/single parameters) ** separated. */ static int moveresults (lua_State *L, const TValue *firstResult, StkId res, int nres, int wanted) { switch (wanted) { /* handle typical cases separately */ case 0: break; /* nothing to move */ case 1: { /* one result needed */ if (nres == 0) /* no results? */ firstResult = luaO_nilobject; /* adjust with nil */ setobjs2s(L, res, firstResult); /* move it to proper place */ break; } case LUA_MULTRET: { int i; for (i = 0; i < nres; i++) /* move all results to correct place */ setobjs2s(L, res + i, firstResult + i); L->top = res + nres; return 0; /* wanted == LUA_MULTRET */ } default: { int i; if (wanted <= nres) { /* enough results? */ for (i = 0; i < wanted; i++) /* move wanted results to correct place */ setobjs2s(L, res + i, firstResult + i); } else { /* not enough results; use all of them plus nils */ for (i = 0; i < nres; i++) /* move all results to correct place */ setobjs2s(L, res + i, firstResult + i); for (; i < wanted; i++) /* complete wanted number of results */ setnilvalue(res + i); } break; } } L->top = res + wanted; /* top points after the last result */ return 1; } /* ** Finishes a function call: calls hook if necessary, removes CallInfo, ** moves current number of results to proper place; returns 0 iff call ** wanted multiple (variable number of) results. */ int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { StkId res; int wanted = ci->nresults; if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { if (L->hookmask & LUA_MASKRET) { ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ luaD_hook(L, LUA_HOOKRET, -1); firstResult = restorestack(L, fr); } L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */ } res = ci->func; /* res == final position of 1st result */ L->ci = ci->previous; /* back to caller */ /* move results to proper place */ return moveresults(L, firstResult, res, nres, wanted); } /* ** Check appropriate error for stack overflow ("regular" overflow or ** overflow while handling stack overflow). If 'nCalls' is larger than ** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but ** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to ** allow overflow handling to work) */ static void stackerror (lua_State *L) { if (L->nCcalls == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ } /* ** Call a function (C or Lua). The function to be called is at *func. ** The arguments are on the stack, right after the function. ** When returns, all the results are on the stack, starting at the original ** function position. */ void luaD_call (lua_State *L, StkId func, int nResults) { if (++L->nCcalls >= LUAI_MAXCCALLS) stackerror(L); if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ luaV_execute(L); /* call it */ L->nCcalls--; } /* ** Similar to 'luaD_call', but does not allow yields during the call */ void luaD_callnoyield (lua_State *L, StkId func, int nResults) { L->nny++; luaD_call(L, func, nResults); L->nny--; } /* ** Completes the execution of an interrupted C function, calling its ** continuation function. */ static void finishCcall (lua_State *L, int status) { CallInfo *ci = L->ci; int n; /* must have a continuation and must be able to call it */ lua_assert(ci->u.c.k != NULL && L->nny == 0); /* error status can only happen in a protected call */ lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */ L->errfunc = ci->u.c.old_errfunc; } /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already handled */ adjustresults(L, ci->nresults); /* call continuation function */ lua_unlock(L); n = (*ci->u.c.k)(L, status, ci->u.c.ctx); lua_lock(L); api_checknelems(L, n); /* finish 'luaD_precall' */ luaD_poscall(L, ci, L->top - n, n); } /* ** Executes "full continuation" (everything in the stack) of a ** previously interrupted coroutine until the stack is empty (or another ** interruption long-jumps out of the loop). If the coroutine is ** recovering from an error, 'ud' points to the error status, which must ** be passed to the first continuation function (otherwise the default ** status is LUA_YIELD). */ static void unroll (lua_State *L, void *ud) { if (ud != NULL) /* error status? */ finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ while (L->ci != &L->base_ci) { /* something in the stack */ if (!isLua(L->ci)) /* C function? */ finishCcall(L, LUA_YIELD); /* complete its execution */ else { /* Lua function */ luaV_finishOp(L); /* finish interrupted instruction */ luaV_execute(L); /* execute down to higher C 'boundary' */ } } } /* ** Try to find a suspended protected call (a "recover point") for the ** given thread. */ static CallInfo *findpcall (lua_State *L) { CallInfo *ci; for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */ if (ci->callstatus & CIST_YPCALL) return ci; } return NULL; /* no pending pcall */ } /* ** Recovers from an error in a coroutine. Finds a recover point (if ** there is one) and completes the execution of the interrupted ** 'luaD_pcall'. If there is no recover point, returns zero. */ static int recover (lua_State *L, int status) { StkId oldtop; CallInfo *ci = findpcall(L); if (ci == NULL) return 0; /* no recovery point */ /* "finish" luaD_pcall */ oldtop = restorestack(L, ci->extra); luaF_close(L, oldtop); seterrorobj(L, status, oldtop); L->ci = ci; L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ L->nny = 0; /* should be zero to be yieldable */ luaD_shrinkstack(L); L->errfunc = ci->u.c.old_errfunc; return 1; /* continue running the coroutine */ } /* ** signal an error in the call to 'resume', not in the execution of the ** coroutine itself. (Such errors should not be handled by any coroutine ** error handler and should not kill the coroutine.) */ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) { L->top = firstArg; /* remove args from the stack */ setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ api_incr_top(L); luaD_throw(L, -1); /* jump back to 'lua_resume' */ } /* ** Do the work for 'lua_resume' in protected mode. Most of the work ** depends on the status of the coroutine: initial state, suspended ** inside a hook, or regularly suspended (optionally with a continuation ** function), plus erroneous cases: non-suspended coroutine or dead ** coroutine. */ static void resume (lua_State *L, void *ud) { int nCcalls = L->nCcalls; int n = *(cast(int*, ud)); /* number of arguments */ StkId firstArg = L->top - n; /* first argument */ CallInfo *ci = L->ci; if (nCcalls >= LUAI_MAXCCALLS) resume_error(L, "C stack overflow", firstArg); if (L->status == LUA_OK) { /* may be starting a coroutine */ if (ci != &L->base_ci) /* not in base level? */ resume_error(L, "cannot resume non-suspended coroutine", firstArg); /* coroutine is in base level; start running it */ if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ luaV_execute(L); /* call it */ } else if (L->status != LUA_YIELD) resume_error(L, "cannot resume dead coroutine", firstArg); else { /* resuming from previous yield */ L->status = LUA_OK; /* mark that it is running (again) */ ci->func = restorestack(L, ci->extra); if (isLua(ci)) /* yielded inside a hook? */ luaV_execute(L); /* just continue running Lua code */ else { /* 'common' yield */ if (ci->u.c.k != NULL) { /* does it have a continuation function? */ lua_unlock(L); n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */ lua_lock(L); api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ } unroll(L, NULL); /* run continuation */ } lua_assert(nCcalls == L->nCcalls); } LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) { int status; unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */ lua_lock(L); luai_userstateresume(L, nargs); L->nCcalls = (from) ? from->nCcalls + 1 : 1; L->nny = 0; /* allow yields */ api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); status = luaD_rawrunprotected(L, resume, &nargs); if (status == -1) /* error calling 'lua_resume'? */ status = LUA_ERRRUN; else { /* continue running after recoverable errors */ while (errorstatus(status) && recover(L, status)) { /* unroll continuation */ status = luaD_rawrunprotected(L, unroll, &status); } if (errorstatus(status)) { /* unrecoverable error? */ L->status = cast_byte(status); /* mark thread as 'dead' */ seterrorobj(L, status, L->top); /* push error message */ L->ci->top = L->top; } else lua_assert(status == L->status); /* normal end or yield */ } L->nny = oldnny; /* restore 'nny' */ L->nCcalls--; lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); lua_unlock(L); return status; } LUA_API int lua_isyieldable (lua_State *L) { return (L->nny == 0); } LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k) { CallInfo *ci = L->ci; luai_userstateyield(L, nresults); lua_lock(L); api_checknelems(L, nresults); if (L->nny > 0) { if (L != G(L)->mainthread) luaG_runerror(L, "attempt to yield across a C-call boundary"); else luaG_runerror(L, "attempt to yield from outside a coroutine"); } L->status = LUA_YIELD; ci->extra = savestack(L, ci->func); /* save current 'func' */ if (isLua(ci)) { /* inside a hook? */ api_check(L, k == NULL, "hooks cannot continue after yielding"); } else { if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ ci->u.c.ctx = ctx; /* save context */ ci->func = L->top - nresults - 1; /* protect stack below results */ luaD_throw(L, LUA_YIELD); } lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ lua_unlock(L); return 0; /* return to 'luaD_hook' */ } int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef) { int status; CallInfo *old_ci = L->ci; lu_byte old_allowhooks = L->allowhook; unsigned short old_nny = L->nny; ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); if (status != LUA_OK) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close possible pending closures */ seterrorobj(L, status, oldtop); L->ci = old_ci; L->allowhook = old_allowhooks; L->nny = old_nny; luaD_shrinkstack(L); } L->errfunc = old_errfunc; return status; } /* ** Execute a protected parser. */ struct SParser { /* data to 'f_parser' */ ZIO *z; Mbuffer buff; /* dynamic structure used by the scanner */ Dyndata dyd; /* dynamic structures used by the parser */ const char *mode; const char *name; }; static void checkmode (lua_State *L, const char *mode, const char *x) { if (mode && strchr(mode, x[0]) == NULL) { luaO_pushfstring(L, "attempt to load a %s chunk (mode is '%s')", x, mode); luaD_throw(L, LUA_ERRSYNTAX); } } static void f_parser (lua_State *L, void *ud) { LClosure *cl; struct SParser *p = cast(struct SParser *, ud); int c = zgetc(p->z); /* read first character */ if (c == LUA_SIGNATURE[0]) { checkmode(L, p->mode, "binary"); cl = luaU_undump(L, p->z, p->name); } else { checkmode(L, p->mode, "text"); cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); } lua_assert(cl->nupvalues == cl->p->sizeupvalues); luaF_initupvals(L, cl); } int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode) { struct SParser p; int status; L->nny++; /* cannot yield during parsing */ p.z = z; p.name = name; p.mode = mode; p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0; p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; p.dyd.label.arr = NULL; p.dyd.label.size = 0; luaZ_initbuffer(L, &p.buff); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); luaZ_freebuffer(L, &p.buff); luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size); L->nny--; return status; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lparser.h�������������������������������������������������������������������������0000644�0001751�0001751�00000006442�12675241401�012633� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ #ifndef lparser_h #define lparser_h #include "llimits.h" #include "lobject.h" #include "lzio.h" /* ** Expression descriptor */ typedef enum { VVOID, /* no value */ VNIL, VTRUE, VFALSE, VK, /* info = index of constant in 'k' */ VKFLT, /* nval = numerical float value */ VKINT, /* nval = numerical integer value */ VNONRELOC, /* info = result register */ VLOCAL, /* info = local register */ VUPVAL, /* info = index of upvalue in 'upvalues' */ VINDEXED, /* t = table register/upvalue; idx = index R/K */ VJMP, /* info = instruction pc */ VRELOCABLE, /* info = instruction pc */ VCALL, /* info = instruction pc */ VVARARG /* info = instruction pc */ } expkind; #define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED) #define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL) typedef struct expdesc { expkind k; union { struct { /* for indexed variables (VINDEXED) */ short idx; /* index (R/K) */ lu_byte t; /* table (register or upvalue) */ lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */ } ind; int info; /* for generic use */ lua_Number nval; /* for VKFLT */ lua_Integer ival; /* for VKINT */ } u; int t; /* patch list of 'exit when true' */ int f; /* patch list of 'exit when false' */ } expdesc; /* description of active local variable */ typedef struct Vardesc { short idx; /* variable index in stack */ } Vardesc; /* description of pending goto statements and label statements */ typedef struct Labeldesc { TString *name; /* label identifier */ int pc; /* position in code */ int line; /* line where it appeared */ lu_byte nactvar; /* local level where it appears in current block */ } Labeldesc; /* list of labels or gotos */ typedef struct Labellist { Labeldesc *arr; /* array */ int n; /* number of entries in use */ int size; /* array size */ } Labellist; /* dynamic structures used by the parser */ typedef struct Dyndata { struct { /* list of active local variables */ Vardesc *arr; int n; int size; } actvar; Labellist gt; /* list of pending gotos */ Labellist label; /* list of active labels */ } Dyndata; /* control of blocks */ struct BlockCnt; /* defined in lparser.c */ /* state needed to generate code for a given function */ typedef struct FuncState { Proto *f; /* current function header */ struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ struct BlockCnt *bl; /* chain of current blocks */ int pc; /* next position to code (equivalent to 'ncode') */ int lasttarget; /* 'label' of last 'jump label' */ int jpc; /* list of pending jumps to 'pc' */ int nk; /* number of elements in 'k' */ int np; /* number of elements in 'p' */ int firstlocal; /* index of first local var (in Dyndata array) */ short nlocvars; /* number of elements in 'f->locvars' */ lu_byte nactvar; /* number of active local variables */ lu_byte nups; /* number of upvalues */ lu_byte freereg; /* first free register */ } FuncState; LUAI_FUNC LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Dyndata *dyd, const char *name, int firstchar); #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lbitlib.c�������������������������������������������������������������������������0000644�0001751�0001751�00000011537�12675241401�012600� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $ ** Standard library for bitwise operations ** See Copyright Notice in lua.h */ #define lbitlib_c #define LUA_LIB #include "lprefix.h" #include "lua.h" #include "lauxlib.h" #include "lualib.h" #if defined(LUA_COMPAT_BITLIB) /* { */ #define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) #define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i)) /* number of bits to consider in a number */ #if !defined(LUA_NBITS) #define LUA_NBITS 32 #endif /* ** a lua_Unsigned with its first LUA_NBITS bits equal to 1. (Shift must ** be made in two parts to avoid problems when LUA_NBITS is equal to the ** number of bits in a lua_Unsigned.) */ #define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1)) /* macro to trim extra bits */ #define trim(x) ((x) & ALLONES) /* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */ #define mask(n) (~((ALLONES << 1) << ((n) - 1))) static lua_Unsigned andaux (lua_State *L) { int i, n = lua_gettop(L); lua_Unsigned r = ~(lua_Unsigned)0; for (i = 1; i <= n; i++) r &= checkunsigned(L, i); return trim(r); } static int b_and (lua_State *L) { lua_Unsigned r = andaux(L); pushunsigned(L, r); return 1; } static int b_test (lua_State *L) { lua_Unsigned r = andaux(L); lua_pushboolean(L, r != 0); return 1; } static int b_or (lua_State *L) { int i, n = lua_gettop(L); lua_Unsigned r = 0; for (i = 1; i <= n; i++) r |= checkunsigned(L, i); pushunsigned(L, trim(r)); return 1; } static int b_xor (lua_State *L) { int i, n = lua_gettop(L); lua_Unsigned r = 0; for (i = 1; i <= n; i++) r ^= checkunsigned(L, i); pushunsigned(L, trim(r)); return 1; } static int b_not (lua_State *L) { lua_Unsigned r = ~checkunsigned(L, 1); pushunsigned(L, trim(r)); return 1; } static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) { if (i < 0) { /* shift right? */ i = -i; r = trim(r); if (i >= LUA_NBITS) r = 0; else r >>= i; } else { /* shift left */ if (i >= LUA_NBITS) r = 0; else r <<= i; r = trim(r); } pushunsigned(L, r); return 1; } static int b_lshift (lua_State *L) { return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2)); } static int b_rshift (lua_State *L) { return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2)); } static int b_arshift (lua_State *L) { lua_Unsigned r = checkunsigned(L, 1); lua_Integer i = luaL_checkinteger(L, 2); if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1)))) return b_shift(L, r, -i); else { /* arithmetic shift for 'negative' number */ if (i >= LUA_NBITS) r = ALLONES; else r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */ pushunsigned(L, r); return 1; } } static int b_rot (lua_State *L, lua_Integer d) { lua_Unsigned r = checkunsigned(L, 1); int i = d & (LUA_NBITS - 1); /* i = d % NBITS */ r = trim(r); if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */ r = (r << i) | (r >> (LUA_NBITS - i)); pushunsigned(L, trim(r)); return 1; } static int b_lrot (lua_State *L) { return b_rot(L, luaL_checkinteger(L, 2)); } static int b_rrot (lua_State *L) { return b_rot(L, -luaL_checkinteger(L, 2)); } /* ** get field and width arguments for field-manipulation functions, ** checking whether they are valid. ** ('luaL_error' called without 'return' to avoid later warnings about ** 'width' being used uninitialized.) */ static int fieldargs (lua_State *L, int farg, int *width) { lua_Integer f = luaL_checkinteger(L, farg); lua_Integer w = luaL_optinteger(L, farg + 1, 1); luaL_argcheck(L, 0 <= f, farg, "field cannot be negative"); luaL_argcheck(L, 0 < w, farg + 1, "width must be positive"); if (f + w > LUA_NBITS) luaL_error(L, "trying to access non-existent bits"); *width = (int)w; return (int)f; } static int b_extract (lua_State *L) { int w; lua_Unsigned r = trim(checkunsigned(L, 1)); int f = fieldargs(L, 2, &w); r = (r >> f) & mask(w); pushunsigned(L, r); return 1; } static int b_replace (lua_State *L) { int w; lua_Unsigned r = trim(checkunsigned(L, 1)); lua_Unsigned v = trim(checkunsigned(L, 2)); int f = fieldargs(L, 3, &w); lua_Unsigned m = mask(w); r = (r & ~(m << f)) | ((v & m) << f); pushunsigned(L, r); return 1; } static const luaL_Reg bitlib[] = { {"arshift", b_arshift}, {"band", b_and}, {"bnot", b_not}, {"bor", b_or}, {"bxor", b_xor}, {"btest", b_test}, {"extract", b_extract}, {"lrotate", b_lrot}, {"lshift", b_lshift}, {"replace", b_replace}, {"rrotate", b_rrot}, {"rshift", b_rshift}, {NULL, NULL} }; LUAMOD_API int luaopen_bit32 (lua_State *L) { luaL_newlib(L, bitlib); return 1; } #else /* }{ */ LUAMOD_API int luaopen_bit32 (lua_State *L) { return luaL_error(L, "library 'bit32' has been deprecated"); } #endif /* } */ �����������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lutf8lib.c������������������������������������������������������������������������0000644�0001751�0001751�00000015632�12675241401�012710� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lutf8lib.c,v 1.15 2015/03/28 19:16:55 roberto Exp $ ** Standard library for UTF-8 manipulation ** See Copyright Notice in lua.h */ #define lutf8lib_c #define LUA_LIB #include "lprefix.h" #include <assert.h> #include <limits.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" #define MAXUNICODE 0x10FFFF #define iscont(p) ((*(p) & 0xC0) == 0x80) /* from strlib */ /* translate a relative string position: negative means back from end */ static lua_Integer u_posrelat (lua_Integer pos, size_t len) { if (pos >= 0) return pos; else if (0u - (size_t)pos > len) return 0; else return (lua_Integer)len + pos + 1; } /* ** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid. */ static const char *utf8_decode (const char *o, int *val) { static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF}; const unsigned char *s = (const unsigned char *)o; unsigned int c = s[0]; unsigned int res = 0; /* final result */ if (c < 0x80) /* ascii? */ res = c; else { int count = 0; /* to count number of continuation bytes */ while (c & 0x40) { /* still have continuation bytes? */ int cc = s[++count]; /* read next byte */ if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ return NULL; /* invalid byte sequence */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ c <<= 1; /* to test next bit */ } res |= ((c & 0x7F) << (count * 5)); /* add first byte */ if (count > 3 || res > MAXUNICODE || res <= limits[count]) return NULL; /* invalid byte sequence */ s += count; /* skip continuation bytes read */ } if (val) *val = res; return (const char *)s + 1; /* +1 to include first byte */ } /* ** utf8len(s [, i [, j]]) --> number of characters that start in the ** range [i,j], or nil + current position if 's' is not well formed in ** that interval */ static int utflen (lua_State *L) { int n = 0; size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); lua_Integer posj = u_posrelat(luaL_optinteger(L, 3, -1), len); luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 2, "initial position out of string"); luaL_argcheck(L, --posj < (lua_Integer)len, 3, "final position out of string"); while (posi <= posj) { const char *s1 = utf8_decode(s + posi, NULL); if (s1 == NULL) { /* conversion error? */ lua_pushnil(L); /* return nil ... */ lua_pushinteger(L, posi + 1); /* ... and current position */ return 2; } posi = s1 - s; n++; } lua_pushinteger(L, n); return 1; } /* ** codepoint(s, [i, [j]]) -> returns codepoints for all characters ** that start in the range [i,j] */ static int codepoint (lua_State *L) { size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer posi = u_posrelat(luaL_optinteger(L, 2, 1), len); lua_Integer pose = u_posrelat(luaL_optinteger(L, 3, posi), len); int n; const char *se; luaL_argcheck(L, posi >= 1, 2, "out of range"); luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range"); if (posi > pose) return 0; /* empty interval; return no values */ if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */ return luaL_error(L, "string slice too long"); n = (int)(pose - posi) + 1; luaL_checkstack(L, n, "string slice too long"); n = 0; se = s + pose; for (s += posi - 1; s < se;) { int code; s = utf8_decode(s, &code); if (s == NULL) return luaL_error(L, "invalid UTF-8 code"); lua_pushinteger(L, code); n++; } return n; } static void pushutfchar (lua_State *L, int arg) { lua_Integer code = luaL_checkinteger(L, arg); luaL_argcheck(L, 0 <= code && code <= MAXUNICODE, arg, "value out of range"); lua_pushfstring(L, "%U", (long)code); } /* ** utfchar(n1, n2, ...) -> char(n1)..char(n2)... */ static int utfchar (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ if (n == 1) /* optimize common case of single char */ pushutfchar(L, 1); else { int i; luaL_Buffer b; luaL_buffinit(L, &b); for (i = 1; i <= n; i++) { pushutfchar(L, i); luaL_addvalue(&b); } luaL_pushresult(&b); } return 1; } /* ** offset(s, n, [i]) -> index where n-th character counting from ** position 'i' starts; 0 means character at 'i'. */ static int byteoffset (lua_State *L) { size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer n = luaL_checkinteger(L, 2); lua_Integer posi = (n >= 0) ? 1 : len + 1; posi = u_posrelat(luaL_optinteger(L, 3, posi), len); luaL_argcheck(L, 1 <= posi && --posi <= (lua_Integer)len, 3, "position out of range"); if (n == 0) { /* find beginning of current byte sequence */ while (posi > 0 && iscont(s + posi)) posi--; } else { if (iscont(s + posi)) luaL_error(L, "initial position is a continuation byte"); if (n < 0) { while (n < 0 && posi > 0) { /* move back */ do { /* find beginning of previous character */ posi--; } while (posi > 0 && iscont(s + posi)); n++; } } else { n--; /* do not move for 1st character */ while (n > 0 && posi < (lua_Integer)len) { do { /* find beginning of next character */ posi++; } while (iscont(s + posi)); /* (cannot pass final '\0') */ n--; } } } if (n == 0) /* did it find given character? */ lua_pushinteger(L, posi + 1); else /* no such character */ lua_pushnil(L); return 1; } static int iter_aux (lua_State *L) { size_t len; const char *s = luaL_checklstring(L, 1, &len); lua_Integer n = lua_tointeger(L, 2) - 1; if (n < 0) /* first iteration? */ n = 0; /* start from here */ else if (n < (lua_Integer)len) { n++; /* skip current byte */ while (iscont(s + n)) n++; /* and its continuations */ } if (n >= (lua_Integer)len) return 0; /* no more codepoints */ else { int code; const char *next = utf8_decode(s + n, &code); if (next == NULL || iscont(next)) return luaL_error(L, "invalid UTF-8 code"); lua_pushinteger(L, n + 1); lua_pushinteger(L, code); return 2; } } static int iter_codes (lua_State *L) { luaL_checkstring(L, 1); lua_pushcfunction(L, iter_aux); lua_pushvalue(L, 1); lua_pushinteger(L, 0); return 3; } /* pattern to match a single UTF-8 character */ #define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*" static const luaL_Reg funcs[] = { {"offset", byteoffset}, {"codepoint", codepoint}, {"char", utfchar}, {"len", utflen}, {"codes", iter_codes}, /* placeholders */ {"charpattern", NULL}, {NULL, NULL} }; LUAMOD_API int luaopen_utf8 (lua_State *L) { luaL_newlib(L, funcs); lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1); lua_setfield(L, -2, "charpattern"); return 1; } ������������������������������������������������������������������������������������������������������golly-2.8-src/lua/ldump.c���������������������������������������������������������������������������0000644�0001751�0001751�00000010572�12675241401�012276� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ #define ldump_c #define LUA_CORE #include "lprefix.h" #include <stddef.h> #include "lua.h" #include "lobject.h" #include "lstate.h" #include "lundump.h" typedef struct { lua_State *L; lua_Writer writer; void *data; int strip; int status; } DumpState; /* ** All high-level dumps go through DumpVector; you can change it to ** change the endianness of the result */ #define DumpVector(v,n,D) DumpBlock(v,(n)*sizeof((v)[0]),D) #define DumpLiteral(s,D) DumpBlock(s, sizeof(s) - sizeof(char), D) static void DumpBlock (const void *b, size_t size, DumpState *D) { if (D->status == 0 && size > 0) { lua_unlock(D->L); D->status = (*D->writer)(D->L, b, size, D->data); lua_lock(D->L); } } #define DumpVar(x,D) DumpVector(&x,1,D) static void DumpByte (int y, DumpState *D) { lu_byte x = (lu_byte)y; DumpVar(x, D); } static void DumpInt (int x, DumpState *D) { DumpVar(x, D); } static void DumpNumber (lua_Number x, DumpState *D) { DumpVar(x, D); } static void DumpInteger (lua_Integer x, DumpState *D) { DumpVar(x, D); } static void DumpString (const TString *s, DumpState *D) { if (s == NULL) DumpByte(0, D); else { size_t size = tsslen(s) + 1; /* include trailing '\0' */ const char *str = getstr(s); if (size < 0xFF) DumpByte(cast_int(size), D); else { DumpByte(0xFF, D); DumpVar(size, D); } DumpVector(str, size - 1, D); /* no need to save '\0' */ } } static void DumpCode (const Proto *f, DumpState *D) { DumpInt(f->sizecode, D); DumpVector(f->code, f->sizecode, D); } static void DumpFunction(const Proto *f, TString *psource, DumpState *D); static void DumpConstants (const Proto *f, DumpState *D) { int i; int n = f->sizek; DumpInt(n, D); for (i = 0; i < n; i++) { const TValue *o = &f->k[i]; DumpByte(ttype(o), D); switch (ttype(o)) { case LUA_TNIL: break; case LUA_TBOOLEAN: DumpByte(bvalue(o), D); break; case LUA_TNUMFLT: DumpNumber(fltvalue(o), D); break; case LUA_TNUMINT: DumpInteger(ivalue(o), D); break; case LUA_TSHRSTR: case LUA_TLNGSTR: DumpString(tsvalue(o), D); break; default: lua_assert(0); } } } static void DumpProtos (const Proto *f, DumpState *D) { int i; int n = f->sizep; DumpInt(n, D); for (i = 0; i < n; i++) DumpFunction(f->p[i], f->source, D); } static void DumpUpvalues (const Proto *f, DumpState *D) { int i, n = f->sizeupvalues; DumpInt(n, D); for (i = 0; i < n; i++) { DumpByte(f->upvalues[i].instack, D); DumpByte(f->upvalues[i].idx, D); } } static void DumpDebug (const Proto *f, DumpState *D) { int i, n; n = (D->strip) ? 0 : f->sizelineinfo; DumpInt(n, D); DumpVector(f->lineinfo, n, D); n = (D->strip) ? 0 : f->sizelocvars; DumpInt(n, D); for (i = 0; i < n; i++) { DumpString(f->locvars[i].varname, D); DumpInt(f->locvars[i].startpc, D); DumpInt(f->locvars[i].endpc, D); } n = (D->strip) ? 0 : f->sizeupvalues; DumpInt(n, D); for (i = 0; i < n; i++) DumpString(f->upvalues[i].name, D); } static void DumpFunction (const Proto *f, TString *psource, DumpState *D) { if (D->strip || f->source == psource) DumpString(NULL, D); /* no debug info or same source as its parent */ else DumpString(f->source, D); DumpInt(f->linedefined, D); DumpInt(f->lastlinedefined, D); DumpByte(f->numparams, D); DumpByte(f->is_vararg, D); DumpByte(f->maxstacksize, D); DumpCode(f, D); DumpConstants(f, D); DumpUpvalues(f, D); DumpProtos(f, D); DumpDebug(f, D); } static void DumpHeader (DumpState *D) { DumpLiteral(LUA_SIGNATURE, D); DumpByte(LUAC_VERSION, D); DumpByte(LUAC_FORMAT, D); DumpLiteral(LUAC_DATA, D); DumpByte(sizeof(int), D); DumpByte(sizeof(size_t), D); DumpByte(sizeof(Instruction), D); DumpByte(sizeof(lua_Integer), D); DumpByte(sizeof(lua_Number), D); DumpInteger(LUAC_INT, D); DumpNumber(LUAC_NUM, D); } /* ** dump Lua function as precompiled chunk */ int luaU_dump(lua_State *L, const Proto *f, lua_Writer w, void *data, int strip) { DumpState D; D.L = L; D.writer = w; D.data = data; D.strip = strip; D.status = 0; DumpHeader(&D); DumpByte(f->sizeupvalues, &D); DumpFunction(f, NULL, &D); return D.status; } ��������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lua.h�����������������������������������������������������������������������������0000644�0001751�0001751�00000034751�12675241401�011750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lua.h,v 1.329 2015/11/13 17:18:42 roberto Exp $ ** Lua - A Scripting Language ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file */ #ifndef lua_h #define lua_h #include <stdarg.h> #include <stddef.h> #include "luaconf.h" #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "3" #define LUA_VERSION_NUM 503 #define LUA_VERSION_RELEASE "2" #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" /* mark for precompiled code ('<esc>Lua') */ #define LUA_SIGNATURE "\x1bLua" /* option for multiple returns in 'lua_pcall' and 'lua_call' */ #define LUA_MULTRET (-1) /* ** Pseudo-indices ** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty ** space after that to help overflow detection) */ #define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000) #define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i)) /* thread status */ #define LUA_OK 0 #define LUA_YIELD 1 #define LUA_ERRRUN 2 #define LUA_ERRSYNTAX 3 #define LUA_ERRMEM 4 #define LUA_ERRGCMM 5 #define LUA_ERRERR 6 typedef struct lua_State lua_State; /* ** basic types */ #define LUA_TNONE (-1) #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8 #define LUA_NUMTAGS 9 /* minimum Lua stack available to a C function */ #define LUA_MINSTACK 20 /* predefined values in the registry */ #define LUA_RIDX_MAINTHREAD 1 #define LUA_RIDX_GLOBALS 2 #define LUA_RIDX_LAST LUA_RIDX_GLOBALS /* type of numbers in Lua */ typedef LUA_NUMBER lua_Number; /* type for integer functions */ typedef LUA_INTEGER lua_Integer; /* unsigned integer type */ typedef LUA_UNSIGNED lua_Unsigned; /* type for continuation-function contexts */ typedef LUA_KCONTEXT lua_KContext; /* ** Type for C functions registered with Lua */ typedef int (*lua_CFunction) (lua_State *L); /* ** Type for continuation functions */ typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); /* ** Type for functions that read/write blocks when loading/dumping Lua chunks */ typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud); /* ** Type for memory-allocation functions */ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); /* ** generic extra include file */ #if defined(LUA_USER_H) #include LUA_USER_H #endif /* ** RCS ident string */ extern const char lua_ident[]; /* ** state manipulation */ LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API void (lua_close) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); LUA_API const lua_Number *(lua_version) (lua_State *L); /* ** basic stack manipulation */ LUA_API int (lua_absindex) (lua_State *L, int idx); LUA_API int (lua_gettop) (lua_State *L); LUA_API void (lua_settop) (lua_State *L, int idx); LUA_API void (lua_pushvalue) (lua_State *L, int idx); LUA_API void (lua_rotate) (lua_State *L, int idx, int n); LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx); LUA_API int (lua_checkstack) (lua_State *L, int n); LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); /* ** access functions (stack -> C) */ LUA_API int (lua_isnumber) (lua_State *L, int idx); LUA_API int (lua_isstring) (lua_State *L, int idx); LUA_API int (lua_iscfunction) (lua_State *L, int idx); LUA_API int (lua_isinteger) (lua_State *L, int idx); LUA_API int (lua_isuserdata) (lua_State *L, int idx); LUA_API int (lua_type) (lua_State *L, int idx); LUA_API const char *(lua_typename) (lua_State *L, int tp); LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum); LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum); LUA_API int (lua_toboolean) (lua_State *L, int idx); LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); LUA_API size_t (lua_rawlen) (lua_State *L, int idx); LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); LUA_API void *(lua_touserdata) (lua_State *L, int idx); LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); LUA_API const void *(lua_topointer) (lua_State *L, int idx); /* ** Comparison and arithmetic functions */ #define LUA_OPADD 0 /* ORDER TM, ORDER OP */ #define LUA_OPSUB 1 #define LUA_OPMUL 2 #define LUA_OPMOD 3 #define LUA_OPPOW 4 #define LUA_OPDIV 5 #define LUA_OPIDIV 6 #define LUA_OPBAND 7 #define LUA_OPBOR 8 #define LUA_OPBXOR 9 #define LUA_OPSHL 10 #define LUA_OPSHR 11 #define LUA_OPUNM 12 #define LUA_OPBNOT 13 LUA_API void (lua_arith) (lua_State *L, int op); #define LUA_OPEQ 0 #define LUA_OPLT 1 #define LUA_OPLE 2 LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op); /* ** push functions (C -> stack) */ LUA_API void (lua_pushnil) (lua_State *L); LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len); LUA_API const char *(lua_pushstring) (lua_State *L, const char *s); LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, va_list argp); LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); LUA_API void (lua_pushboolean) (lua_State *L, int b); LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); LUA_API int (lua_pushthread) (lua_State *L); /* ** get functions (Lua -> stack) */ LUA_API int (lua_getglobal) (lua_State *L, const char *name); LUA_API int (lua_gettable) (lua_State *L, int idx); LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k); LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n); LUA_API int (lua_rawget) (lua_State *L, int idx); LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n); LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p); LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec); LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz); LUA_API int (lua_getmetatable) (lua_State *L, int objindex); LUA_API int (lua_getuservalue) (lua_State *L, int idx); /* ** set functions (stack -> Lua) */ LUA_API void (lua_setglobal) (lua_State *L, const char *name); LUA_API void (lua_settable) (lua_State *L, int idx); LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawset) (lua_State *L, int idx); LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n); LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p); LUA_API int (lua_setmetatable) (lua_State *L, int objindex); LUA_API void (lua_setuservalue) (lua_State *L, int idx); /* ** 'load' and 'call' functions (load and run Lua code) */ LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k); #define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL) LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc, lua_KContext ctx, lua_KFunction k); #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, const char *chunkname, const char *mode); LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip); /* ** coroutine functions */ LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k); LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg); LUA_API int (lua_status) (lua_State *L); LUA_API int (lua_isyieldable) (lua_State *L); #define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL) /* ** garbage-collection function and options */ #define LUA_GCSTOP 0 #define LUA_GCRESTART 1 #define LUA_GCCOLLECT 2 #define LUA_GCCOUNT 3 #define LUA_GCCOUNTB 4 #define LUA_GCSTEP 5 #define LUA_GCSETPAUSE 6 #define LUA_GCSETSTEPMUL 7 #define LUA_GCISRUNNING 9 LUA_API int (lua_gc) (lua_State *L, int what, int data); /* ** miscellaneous functions */ LUA_API int (lua_error) (lua_State *L); LUA_API int (lua_next) (lua_State *L, int idx); LUA_API void (lua_concat) (lua_State *L, int n); LUA_API void (lua_len) (lua_State *L, int idx); LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); /* ** {============================================================== ** some useful macros ** =============================================================== */ #define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE)) #define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL) #define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL) #define lua_pop(L,n) lua_settop(L, -(n)-1) #define lua_newtable(L) lua_createtable(L, 0, 0) #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) #define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) #define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) #define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) #define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) #define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) #define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) #define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) #define lua_pushliteral(L, s) lua_pushstring(L, "" s) #define lua_pushglobaltable(L) \ lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS) #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) #define lua_insert(L,idx) lua_rotate(L, (idx), 1) #define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1)) #define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1)) /* }============================================================== */ /* ** {============================================================== ** compatibility macros for unsigned conversions ** =============================================================== */ #if defined(LUA_COMPAT_APIINTCASTS) #define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n)) #define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is)) #define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL) #endif /* }============================================================== */ /* ** {====================================================================== ** Debug API ** ======================================================================= */ /* ** Event codes */ #define LUA_HOOKCALL 0 #define LUA_HOOKRET 1 #define LUA_HOOKLINE 2 #define LUA_HOOKCOUNT 3 #define LUA_HOOKTAILCALL 4 /* ** Event masks */ #define LUA_MASKCALL (1 << LUA_HOOKCALL) #define LUA_MASKRET (1 << LUA_HOOKRET) #define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) typedef struct lua_Debug lua_Debug; /* activation record */ /* Functions to be called by the debugger in specific events */ typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n); LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n); LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n); LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n); LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1, int fidx2, int n2); LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count); LUA_API lua_Hook (lua_gethook) (lua_State *L); LUA_API int (lua_gethookmask) (lua_State *L); LUA_API int (lua_gethookcount) (lua_State *L); struct lua_Debug { int event; const char *name; /* (n) */ const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */ const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */ const char *source; /* (S) */ int currentline; /* (l) */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ unsigned char nups; /* (u) number of upvalues */ unsigned char nparams;/* (u) number of parameters */ char isvararg; /* (u) */ char istailcall; /* (t) */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ struct CallInfo *i_ci; /* active function */ }; /* }====================================================================== */ /****************************************************************************** * Copyright (C) 1994-2015 Lua.org, PUC-Rio. * * 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ #endif �����������������������golly-2.8-src/lua/lundump.h�������������������������������������������������������������������������0000644�0001751�0001751�00000001437�12675241401�012646� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ #ifndef lundump_h #define lundump_h #include "llimits.h" #include "lobject.h" #include "lzio.h" /* data to catch conversion errors */ #define LUAC_DATA "\x19\x93\r\n\x1a\n" #define LUAC_INT 0x5678 #define LUAC_NUM cast_num(370.5) #define MYINT(s) (s[0]-'0') #define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) #define LUAC_FORMAT 0 /* this is the official format */ /* load one chunk; from lundump.c */ LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name); /* dump one chunk; from ldump.c */ LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/ltable.c��������������������������������������������������������������������������0000644�0001751�0001751�00000046356�12675241401�012431� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ltable.c,v 2.117 2015/11/19 19:16:22 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ #define ltable_c #define LUA_CORE #include "lprefix.h" /* ** Implementation of tables (aka arrays, objects, or hash tables). ** Tables keep its elements in two parts: an array part and a hash part. ** Non-negative integer keys are all candidates to be kept in the array ** part. The actual size of the array is the largest 'n' such that ** more than half the slots between 1 and n are in use. ** Hash uses a mix of chained scatter table with Brent's variation. ** A main invariant of these tables is that, if an element is not ** in its main position (i.e. the 'original' position that its hash gives ** to it), then the colliding element is in its own main position. ** Hence even when the load factor reaches 100%, performance remains good. */ #include <math.h> #include <limits.h> #include "lua.h" #include "ldebug.h" #include "ldo.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "lvm.h" /* ** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is ** the largest integer such that MAXASIZE fits in an unsigned int. */ #define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) #define MAXASIZE (1u << MAXABITS) /* ** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest ** integer such that 2^MAXHBITS fits in a signed int. (Note that the ** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still ** fits comfortably in an unsigned int.) */ #define MAXHBITS (MAXABITS - 1) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) #define hashstr(t,str) hashpow2(t, (str)->hash) #define hashboolean(t,p) hashpow2(t, p) #define hashint(t,i) hashpow2(t, i) /* ** for some types, it is better to avoid modulus by power of 2, as ** they tend to have many 2 factors. */ #define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) #define hashpointer(t,p) hashmod(t, point2uint(p)) #define dummynode (&dummynode_) #define isdummy(n) ((n) == dummynode) static const Node dummynode_ = { {NILCONSTANT}, /* value */ {{NILCONSTANT, 0}} /* key */ }; /* ** Hash for floating-point numbers. ** The main computation should be just ** n = frexp(n, &i); return (n * INT_MAX) + i ** but there are some numerical subtleties. ** In a two-complement representation, INT_MAX does not has an exact ** representation as a float, but INT_MIN does; because the absolute ** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the ** absolute value of the product 'frexp * -INT_MIN' is smaller or equal ** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when ** adding 'i'; the use of '~u' (instead of '-u') avoids problems with ** INT_MIN. */ #if !defined(l_hashfloat) static int l_hashfloat (lua_Number n) { int i; lua_Integer ni; n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL)); return 0; } else { /* normal case */ unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u); } } #endif /* ** returns the 'main' position of an element in a table (that is, the index ** of its hash value) */ static Node *mainposition (const Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TNUMINT: return hashint(t, ivalue(key)); case LUA_TNUMFLT: return hashmod(t, l_hashfloat(fltvalue(key))); case LUA_TSHRSTR: return hashstr(t, tsvalue(key)); case LUA_TLNGSTR: return hashpow2(t, luaS_hashlongstr(tsvalue(key))); case LUA_TBOOLEAN: return hashboolean(t, bvalue(key)); case LUA_TLIGHTUSERDATA: return hashpointer(t, pvalue(key)); case LUA_TLCF: return hashpointer(t, fvalue(key)); default: lua_assert(!ttisdeadkey(key)); return hashpointer(t, gcvalue(key)); } } /* ** returns the index for 'key' if 'key' is an appropriate key to live in ** the array part of the table, 0 otherwise. */ static unsigned int arrayindex (const TValue *key) { if (ttisinteger(key)) { lua_Integer k = ivalue(key); if (0 < k && (lua_Unsigned)k <= MAXASIZE) return cast(unsigned int, k); /* 'key' is an appropriate array index */ } return 0; /* 'key' did not match some condition */ } /* ** returns the index of a 'key' for table traversals. First goes all ** elements in the array part, then elements in the hash part. The ** beginning of a traversal is signaled by 0. */ static unsigned int findindex (lua_State *L, Table *t, StkId key) { unsigned int i; if (ttisnil(key)) return 0; /* first iteration */ i = arrayindex(key); if (i != 0 && i <= t->sizearray) /* is 'key' inside array part? */ return i; /* yes; that's the index */ else { int nx; Node *n = mainposition(t, key); for (;;) { /* check whether 'key' is somewhere in the chain */ /* key may be dead already, but it is ok to use it in 'next' */ if (luaV_rawequalobj(gkey(n), key) || (ttisdeadkey(gkey(n)) && iscollectable(key) && deadvalue(gkey(n)) == gcvalue(key))) { i = cast_int(n - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ return (i + 1) + t->sizearray; } nx = gnext(n); if (nx == 0) luaG_runerror(L, "invalid key to 'next'"); /* key not found */ else n += nx; } } } int luaH_next (lua_State *L, Table *t, StkId key) { unsigned int i = findindex(L, t, key); /* find original element */ for (; i < t->sizearray; i++) { /* try first array part */ if (!ttisnil(&t->array[i])) { /* a non-nil value? */ setivalue(key, i + 1); setobj2s(L, key+1, &t->array[i]); return 1; } } for (i -= t->sizearray; cast_int(i) < sizenode(t); i++) { /* hash part */ if (!ttisnil(gval(gnode(t, i)))) { /* a non-nil value? */ setobj2s(L, key, gkey(gnode(t, i))); setobj2s(L, key+1, gval(gnode(t, i))); return 1; } } return 0; /* no more elements */ } /* ** {============================================================= ** Rehash ** ============================================================== */ /* ** Compute the optimal size for the array part of table 't'. 'nums' is a ** "count array" where 'nums[i]' is the number of integers in the table ** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of ** integer keys in the table and leaves with the number of keys that ** will go to the array part; return the optimal size. */ static unsigned int computesizes (unsigned int nums[], unsigned int *pna) { int i; unsigned int twotoi; /* 2^i (candidate for optimal size) */ unsigned int a = 0; /* number of elements smaller than 2^i */ unsigned int na = 0; /* number of elements to go to array part */ unsigned int optimal = 0; /* optimal size for array part */ /* loop while keys can fill more than half of total size */ for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) { if (nums[i] > 0) { a += nums[i]; if (a > twotoi/2) { /* more than half elements present? */ optimal = twotoi; /* optimal size (till now) */ na = a; /* all elements up to 'optimal' will go to array part */ } } } lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal); *pna = na; return optimal; } static int countint (const TValue *key, unsigned int *nums) { unsigned int k = arrayindex(key); if (k != 0) { /* is 'key' an appropriate array index? */ nums[luaO_ceillog2(k)]++; /* count as such */ return 1; } else return 0; } /* ** Count keys in array part of table 't': Fill 'nums[i]' with ** number of keys that will go into corresponding slice and return ** total number of non-nil keys. */ static unsigned int numusearray (const Table *t, unsigned int *nums) { int lg; unsigned int ttlg; /* 2^lg */ unsigned int ause = 0; /* summation of 'nums' */ unsigned int i = 1; /* count to traverse all array keys */ /* traverse each slice */ for (lg = 0, ttlg = 1; lg <= MAXABITS; lg++, ttlg *= 2) { unsigned int lc = 0; /* counter */ unsigned int lim = ttlg; if (lim > t->sizearray) { lim = t->sizearray; /* adjust upper limit */ if (i > lim) break; /* no more elements to count */ } /* count elements in range (2^(lg - 1), 2^lg] */ for (; i <= lim; i++) { if (!ttisnil(&t->array[i-1])) lc++; } nums[lg] += lc; ause += lc; } return ause; } static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { int totaluse = 0; /* total number of elements */ int ause = 0; /* elements added to 'nums' (can go to array part) */ int i = sizenode(t); while (i--) { Node *n = &t->node[i]; if (!ttisnil(gval(n))) { ause += countint(gkey(n), nums); totaluse++; } } *pna += ause; return totaluse; } static void setarrayvector (lua_State *L, Table *t, unsigned int size) { unsigned int i; luaM_reallocvector(L, t->array, t->sizearray, size, TValue); for (i=t->sizearray; i<size; i++) setnilvalue(&t->array[i]); t->sizearray = size; } static void setnodevector (lua_State *L, Table *t, unsigned int size) { int lsize; if (size == 0) { /* no elements to hash part? */ t->node = cast(Node *, dummynode); /* use common 'dummynode' */ lsize = 0; } else { int i; lsize = luaO_ceillog2(size); if (lsize > MAXHBITS) luaG_runerror(L, "table overflow"); size = twoto(lsize); t->node = luaM_newvector(L, size, Node); for (i = 0; i < (int)size; i++) { Node *n = gnode(t, i); gnext(n) = 0; setnilvalue(wgkey(n)); setnilvalue(gval(n)); } } t->lsizenode = cast_byte(lsize); t->lastfree = gnode(t, size); /* all positions are free */ } void luaH_resize (lua_State *L, Table *t, unsigned int nasize, unsigned int nhsize) { unsigned int i; int j; unsigned int oldasize = t->sizearray; int oldhsize = t->lsizenode; Node *nold = t->node; /* save old hash ... */ if (nasize > oldasize) /* array part must grow? */ setarrayvector(L, t, nasize); /* create new hash part with appropriate size */ setnodevector(L, t, nhsize); if (nasize < oldasize) { /* array part must shrink? */ t->sizearray = nasize; /* re-insert elements from vanishing slice */ for (i=nasize; i<oldasize; i++) { if (!ttisnil(&t->array[i])) luaH_setint(L, t, i + 1, &t->array[i]); } /* shrink array */ luaM_reallocvector(L, t->array, oldasize, nasize, TValue); } /* re-insert elements from hash part */ for (j = twoto(oldhsize) - 1; j >= 0; j--) { Node *old = nold + j; if (!ttisnil(gval(old))) { /* doesn't need barrier/invalidate cache, as entry was already present in the table */ setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old)); } } if (!isdummy(nold)) luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old hash */ } void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) { int nsize = isdummy(t->node) ? 0 : sizenode(t); luaH_resize(L, t, nasize, nsize); } /* ** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i */ static void rehash (lua_State *L, Table *t, const TValue *ek) { unsigned int asize; /* optimal size for array part */ unsigned int na; /* number of keys in the array part */ unsigned int nums[MAXABITS + 1]; int i; int totaluse; for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */ na = numusearray(t, nums); /* count keys in array part */ totaluse = na; /* all those keys are integer keys */ totaluse += numusehash(t, nums, &na); /* count keys in hash part */ /* count extra key */ na += countint(ek, nums); totaluse++; /* compute new size for array part */ asize = computesizes(nums, &na); /* resize the table to new computed sizes */ luaH_resize(L, t, asize, totaluse - na); } /* ** }============================================================= */ Table *luaH_new (lua_State *L) { GCObject *o = luaC_newobj(L, LUA_TTABLE, sizeof(Table)); Table *t = gco2t(o); t->metatable = NULL; t->flags = cast_byte(~0); t->array = NULL; t->sizearray = 0; setnodevector(L, t, 0); return t; } void luaH_free (lua_State *L, Table *t) { if (!isdummy(t->node)) luaM_freearray(L, t->node, cast(size_t, sizenode(t))); luaM_freearray(L, t->array, t->sizearray); luaM_free(L, t); } static Node *getfreepos (Table *t) { while (t->lastfree > t->node) { t->lastfree--; if (ttisnil(gkey(t->lastfree))) return t->lastfree; } return NULL; /* could not find a free place */ } /* ** inserts a new key into a hash table; first, check whether key's main ** position is free. If not, check whether colliding node is in its main ** position or not: if it is not, move colliding node to an empty place and ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { Node *mp; TValue aux; if (ttisnil(key)) luaG_runerror(L, "table index is nil"); else if (ttisfloat(key)) { lua_Integer k; if (luaV_tointeger(key, &k, 0)) { /* index is int? */ setivalue(&aux, k); key = &aux; /* insert it as an integer */ } else if (luai_numisnan(fltvalue(key))) luaG_runerror(L, "table index is NaN"); } mp = mainposition(t, key); if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */ Node *othern; Node *f = getfreepos(t); /* get a free place */ if (f == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ /* whatever called 'newkey' takes care of TM cache */ return luaH_set(L, t, key); /* insert key into grown table */ } lua_assert(!isdummy(f)); othern = mainposition(t, gkey(mp)); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (othern + gnext(othern) != mp) /* find previous */ othern += gnext(othern); gnext(othern) = cast_int(f - othern); /* rechain to point to 'f' */ *f = *mp; /* copy colliding node into free pos. (mp->next also goes) */ if (gnext(mp) != 0) { gnext(f) += cast_int(mp - f); /* correct 'next' */ gnext(mp) = 0; /* now 'mp' is free */ } setnilvalue(gval(mp)); } else { /* colliding node is in its own main position */ /* new node will go into free position */ if (gnext(mp) != 0) gnext(f) = cast_int((mp + gnext(mp)) - f); /* chain new position */ else lua_assert(gnext(f) == 0); gnext(mp) = cast_int(f - mp); mp = f; } } setnodekey(L, &mp->i_key, key); luaC_barrierback(L, t, key); lua_assert(ttisnil(gval(mp))); return gval(mp); } /* ** search function for integers */ const TValue *luaH_getint (Table *t, lua_Integer key) { /* (1 <= key && key <= t->sizearray) */ if (l_castS2U(key) - 1 < t->sizearray) return &t->array[key - 1]; else { Node *n = hashint(t, key); for (;;) { /* check whether 'key' is somewhere in the chain */ if (ttisinteger(gkey(n)) && ivalue(gkey(n)) == key) return gval(n); /* that's it */ else { int nx = gnext(n); if (nx == 0) break; n += nx; } } return luaO_nilobject; } } /* ** search function for short strings */ const TValue *luaH_getshortstr (Table *t, TString *key) { Node *n = hashstr(t, key); lua_assert(key->tt == LUA_TSHRSTR); for (;;) { /* check whether 'key' is somewhere in the chain */ const TValue *k = gkey(n); if (ttisshrstring(k) && eqshrstr(tsvalue(k), key)) return gval(n); /* that's it */ else { int nx = gnext(n); if (nx == 0) return luaO_nilobject; /* not found */ n += nx; } } } /* ** "Generic" get version. (Not that generic: not valid for integers, ** which may be in array part, nor for floats with integral values.) */ static const TValue *getgeneric (Table *t, const TValue *key) { Node *n = mainposition(t, key); for (;;) { /* check whether 'key' is somewhere in the chain */ if (luaV_rawequalobj(gkey(n), key)) return gval(n); /* that's it */ else { int nx = gnext(n); if (nx == 0) return luaO_nilobject; /* not found */ n += nx; } } } const TValue *luaH_getstr (Table *t, TString *key) { if (key->tt == LUA_TSHRSTR) return luaH_getshortstr(t, key); else { /* for long strings, use generic case */ TValue ko; setsvalue(cast(lua_State *, NULL), &ko, key); return getgeneric(t, &ko); } } /* ** main search function */ const TValue *luaH_get (Table *t, const TValue *key) { switch (ttype(key)) { case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key)); case LUA_TNUMINT: return luaH_getint(t, ivalue(key)); case LUA_TNIL: return luaO_nilobject; case LUA_TNUMFLT: { lua_Integer k; if (luaV_tointeger(key, &k, 0)) /* index is int? */ return luaH_getint(t, k); /* use specialized version */ /* else... */ } /* FALLTHROUGH */ default: return getgeneric(t, key); } } /* ** beware: when using this function you probably need to check a GC ** barrier and invalidate the TM cache. */ TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { const TValue *p = luaH_get(t, key); if (p != luaO_nilobject) return cast(TValue *, p); else return luaH_newkey(L, t, key); } void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { const TValue *p = luaH_getint(t, key); TValue *cell; if (p != luaO_nilobject) cell = cast(TValue *, p); else { TValue k; setivalue(&k, key); cell = luaH_newkey(L, t, &k); } setobj2t(L, cell, value); } static int unbound_search (Table *t, unsigned int j) { unsigned int i = j; /* i is zero or a present index */ j++; /* find 'i' and 'j' such that i is present and j is not */ while (!ttisnil(luaH_getint(t, j))) { i = j; if (j > cast(unsigned int, MAX_INT)/2) { /* overflow? */ /* table was built with bad purposes: resort to linear search */ i = 1; while (!ttisnil(luaH_getint(t, i))) i++; return i - 1; } j *= 2; } /* now do a binary search between them */ while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(luaH_getint(t, m))) j = m; else i = m; } return i; } /* ** Try to find a boundary in table 't'. A 'boundary' is an integer index ** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil). */ int luaH_getn (Table *t) { unsigned int j = t->sizearray; if (j > 0 && ttisnil(&t->array[j - 1])) { /* there is a boundary in the array part: (binary) search for it */ unsigned int i = 0; while (j - i > 1) { unsigned int m = (i+j)/2; if (ttisnil(&t->array[m - 1])) j = m; else i = m; } return i; } /* else must find a boundary in hash part */ else if (isdummy(t->node)) /* hash part is empty? */ return j; /* that is easy... */ else return unbound_search(t, j); } #if defined(LUA_DEBUG) Node *luaH_mainposition (const Table *t, const TValue *key) { return mainposition(t, key); } int luaH_isdummy (Node *n) { return isdummy(n); } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/ldblib.c��������������������������������������������������������������������������0000644�0001751�0001751�00000030747�12675241401�012413� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ #define ldblib_c #define LUA_LIB #include "lprefix.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** The hook table at registry[&HOOKKEY] maps threads to their current ** hook function. (We only need the unique address of 'HOOKKEY'.) */ static const int HOOKKEY = 0; /* ** If L1 != L, L1 can be in any state, and therefore there are no ** guarantees about its stack space; any push in L1 must be ** checked. */ static void checkstack (lua_State *L, lua_State *L1, int n) { if (L != L1 && !lua_checkstack(L1, n)) luaL_error(L, "stack overflow"); } static int db_getregistry (lua_State *L) { lua_pushvalue(L, LUA_REGISTRYINDEX); return 1; } static int db_getmetatable (lua_State *L) { luaL_checkany(L, 1); if (!lua_getmetatable(L, 1)) { lua_pushnil(L); /* no metatable */ } return 1; } static int db_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; /* return 1st argument */ } static int db_getuservalue (lua_State *L) { if (lua_type(L, 1) != LUA_TUSERDATA) lua_pushnil(L); else lua_getuservalue(L, 1); return 1; } static int db_setuservalue (lua_State *L) { luaL_checktype(L, 1, LUA_TUSERDATA); luaL_checkany(L, 2); lua_settop(L, 2); lua_setuservalue(L, 1); return 1; } /* ** Auxiliary function used by several library functions: check for ** an optional thread as function's first argument and set 'arg' with ** 1 if this argument is present (so that functions can skip it to ** access their other arguments) */ static lua_State *getthread (lua_State *L, int *arg) { if (lua_isthread(L, 1)) { *arg = 1; return lua_tothread(L, 1); } else { *arg = 0; return L; /* function will operate over current thread */ } } /* ** Variations of 'lua_settable', used by 'db_getinfo' to put results ** from 'lua_getinfo' into result table. Key is always a string; ** value can be a string, an int, or a boolean. */ static void settabss (lua_State *L, const char *k, const char *v) { lua_pushstring(L, v); lua_setfield(L, -2, k); } static void settabsi (lua_State *L, const char *k, int v) { lua_pushinteger(L, v); lua_setfield(L, -2, k); } static void settabsb (lua_State *L, const char *k, int v) { lua_pushboolean(L, v); lua_setfield(L, -2, k); } /* ** In function 'db_getinfo', the call to 'lua_getinfo' may push ** results on the stack; later it creates the result table to put ** these objects. Function 'treatstackoption' puts the result from ** 'lua_getinfo' on top of the result table so that it can call ** 'lua_setfield'. */ static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { if (L == L1) lua_rotate(L, -2, 1); /* exchange object and table */ else lua_xmove(L1, L, 1); /* move object to the "main" stack */ lua_setfield(L, -2, fname); /* put object into table */ } /* ** Calls 'lua_getinfo' and collects all results in a new table. ** L1 needs stack space for an optional input (function) plus ** two optional outputs (function and line table) from function ** 'lua_getinfo'. */ static int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnStu"); checkstack(L, L1, 3); if (lua_isfunction(L, arg + 1)) { /* info about a function? */ options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ lua_xmove(L, L1, 1); } else { /* stack level */ if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } if (!lua_getinfo(L1, options, &ar)) return luaL_argerror(L, arg+2, "invalid option"); lua_newtable(L); /* table to collect results */ if (strchr(options, 'S')) { settabss(L, "source", ar.source); settabss(L, "short_src", ar.short_src); settabsi(L, "linedefined", ar.linedefined); settabsi(L, "lastlinedefined", ar.lastlinedefined); settabss(L, "what", ar.what); } if (strchr(options, 'l')) settabsi(L, "currentline", ar.currentline); if (strchr(options, 'u')) { settabsi(L, "nups", ar.nups); settabsi(L, "nparams", ar.nparams); settabsb(L, "isvararg", ar.isvararg); } if (strchr(options, 'n')) { settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); } if (strchr(options, 't')) settabsb(L, "istailcall", ar.istailcall); if (strchr(options, 'L')) treatstackoption(L, L1, "activelines"); if (strchr(options, 'f')) treatstackoption(L, L1, "func"); return 1; /* return table */ } static int db_getlocal (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); lua_Debug ar; const char *name; int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ if (lua_isfunction(L, arg + 1)) { /* function argument? */ lua_pushvalue(L, arg + 1); /* push function */ lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ return 1; /* return only name (there is no value) */ } else { /* stack-level argument */ int level = (int)luaL_checkinteger(L, arg + 1); if (!lua_getstack(L1, level, &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); checkstack(L, L1, 1); name = lua_getlocal(L1, &ar, nvar); if (name) { lua_xmove(L1, L, 1); /* move local value */ lua_pushstring(L, name); /* push name */ lua_rotate(L, -2, 1); /* re-order */ return 2; } else { lua_pushnil(L); /* no name (nor value) */ return 1; } } } static int db_setlocal (lua_State *L) { int arg; const char *name; lua_State *L1 = getthread(L, &arg); lua_Debug ar; int level = (int)luaL_checkinteger(L, arg + 1); int nvar = (int)luaL_checkinteger(L, arg + 2); if (!lua_getstack(L1, level, &ar)) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); luaL_checkany(L, arg+3); lua_settop(L, arg+3); checkstack(L, L1, 1); lua_xmove(L, L1, 1); name = lua_setlocal(L1, &ar, nvar); if (name == NULL) lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ lua_pushstring(L, name); return 1; } /* ** get (if 'get' is true) or set an upvalue from a closure */ static int auxupvalue (lua_State *L, int get) { const char *name; int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); if (name == NULL) return 0; lua_pushstring(L, name); lua_insert(L, -(get+1)); /* no-op if get is false */ return get + 1; } static int db_getupvalue (lua_State *L) { return auxupvalue(L, 1); } static int db_setupvalue (lua_State *L) { luaL_checkany(L, 3); return auxupvalue(L, 0); } /* ** Check whether a given upvalue from a given closure exists and ** returns its index */ static int checkupval (lua_State *L, int argf, int argnup) { int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, "invalid upvalue index"); return nup; } static int db_upvalueid (lua_State *L) { int n = checkupval(L, 1, 2); lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); return 1; } static int db_upvaluejoin (lua_State *L) { int n1 = checkupval(L, 1, 2); int n2 = checkupval(L, 3, 4); luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); lua_upvaluejoin(L, 1, n1, 3, n2); return 0; } /* ** Call hook function registered at hook table for the current ** thread (if there is one) */ static void hookf (lua_State *L, lua_Debug *ar) { static const char *const hooknames[] = {"call", "return", "line", "count", "tail call"}; lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); lua_pushthread(L); if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ if (ar->currentline >= 0) lua_pushinteger(L, ar->currentline); /* push current line */ else lua_pushnil(L); lua_assert(lua_getinfo(L, "lS", ar)); lua_call(L, 2, 0); /* call hook function */ } } /* ** Convert a string mask (for 'sethook') into a bit mask */ static int makemask (const char *smask, int count) { int mask = 0; if (strchr(smask, 'c')) mask |= LUA_MASKCALL; if (strchr(smask, 'r')) mask |= LUA_MASKRET; if (strchr(smask, 'l')) mask |= LUA_MASKLINE; if (count > 0) mask |= LUA_MASKCOUNT; return mask; } /* ** Convert a bit mask (for 'gethook') into a string mask */ static char *unmakemask (int mask, char *smask) { int i = 0; if (mask & LUA_MASKCALL) smask[i++] = 'c'; if (mask & LUA_MASKRET) smask[i++] = 'r'; if (mask & LUA_MASKLINE) smask[i++] = 'l'; smask[i] = '\0'; return smask; } static int db_sethook (lua_State *L) { int arg, mask, count; lua_Hook func; lua_State *L1 = getthread(L, &arg); if (lua_isnoneornil(L, arg+1)) { /* no hook? */ lua_settop(L, arg+1); func = NULL; mask = 0; count = 0; /* turn off hooks */ } else { const char *smask = luaL_checkstring(L, arg+2); luaL_checktype(L, arg+1, LUA_TFUNCTION); count = (int)luaL_optinteger(L, arg + 3, 0); func = hookf; mask = makemask(smask, count); } if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) { lua_createtable(L, 0, 2); /* create a hook table */ lua_pushvalue(L, -1); lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY); /* set it in position */ lua_pushstring(L, "k"); lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ lua_pushvalue(L, -1); lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ } checkstack(L, L1, 1); lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */ lua_pushvalue(L, arg + 1); /* value (hook function) */ lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ lua_sethook(L1, func, mask, count); return 0; } static int db_gethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); char buff[5]; int mask = lua_gethookmask(L1); lua_Hook hook = lua_gethook(L1); if (hook == NULL) /* no hook? */ lua_pushnil(L); else if (hook != hookf) /* external hook? */ lua_pushliteral(L, "external hook"); else { /* hook table must exist */ lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY); checkstack(L, L1, 1); lua_pushthread(L1); lua_xmove(L1, L, 1); lua_rawget(L, -2); /* 1st result = hooktable[L1] */ lua_remove(L, -2); /* remove hook table */ } lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ return 3; } static int db_debug (lua_State *L) { for (;;) { char buffer[250]; lua_writestringerror("%s", "lua_debug> "); if (fgets(buffer, sizeof(buffer), stdin) == 0 || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || lua_pcall(L, 0, 0, 0)) lua_writestringerror("%s\n", lua_tostring(L, -1)); lua_settop(L, 0); /* remove eventual returns */ } } static int db_traceback (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); const char *msg = lua_tostring(L, arg + 1); if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ lua_pushvalue(L, arg + 1); /* return it untouched */ else { int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); luaL_traceback(L, L1, msg, level); } return 1; } static const luaL_Reg dblib[] = { {"debug", db_debug}, {"getuservalue", db_getuservalue}, {"gethook", db_gethook}, {"getinfo", db_getinfo}, {"getlocal", db_getlocal}, {"getregistry", db_getregistry}, {"getmetatable", db_getmetatable}, {"getupvalue", db_getupvalue}, {"upvaluejoin", db_upvaluejoin}, {"upvalueid", db_upvalueid}, {"setuservalue", db_setuservalue}, {"sethook", db_sethook}, {"setlocal", db_setlocal}, {"setmetatable", db_setmetatable}, {"setupvalue", db_setupvalue}, {"traceback", db_traceback}, {NULL, NULL} }; LUAMOD_API int luaopen_debug (lua_State *L) { luaL_newlib(L, dblib); return 1; } �������������������������golly-2.8-src/lua/ldo.h�����������������������������������������������������������������������������0000644�0001751�0001751�00000003770�12675241401�011742� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ldo.h,v 2.28 2015/11/23 11:29:43 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ #ifndef ldo_h #define ldo_h #include "lobject.h" #include "lstate.h" #include "lzio.h" /* ** Macro to check stack size and grow stack if needed. Parameters ** 'pre'/'pos' allow the macro to preserve a pointer into the ** stack across reallocations, doing the work only when needed. ** 'condmovestack' is used in heavy tests to force a stack reallocation ** at every check. */ #define luaD_checkstackaux(L,n,pre,pos) \ if (L->stack_last - L->top <= (n)) \ { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } /* In general, 'pre'/'pos' are empty (nothing to save) */ #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,,) #define savestack(L,p) ((char *)(p) - (char *)L->stack) #define restorestack(L,n) ((TValue *)((char *)L->stack + (n))) /* type of protected functions, to be ran by 'runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode); LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres); LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); LUAI_FUNC void luaD_growstack (lua_State *L, int n); LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC void luaD_inctop (lua_State *L); LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode); LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud); #endif ��������golly-2.8-src/lua/lopcodes.h������������������������������������������������������������������������0000644�0001751�0001751�00000021124�12675241401�012765� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lopcodes.h,v 1.148 2014/10/25 11:50:46 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ #ifndef lopcodes_h #define lopcodes_h #include "llimits.h" /*=========================================================================== We assume that instructions are unsigned numbers. All instructions have an opcode in the first 6 bits. Instructions can have the following fields: 'A' : 8 bits 'B' : 9 bits 'C' : 9 bits 'Ax' : 26 bits ('A', 'B', and 'C' together) 'Bx' : 18 bits ('B' and 'C' together) 'sBx' : signed Bx A signed argument is represented in excess K; that is, the number value is the unsigned value minus K. K is exactly the maximum value for that argument (so that -max is represented by 0, and +max is represented by 2*max), which is half the maximum for the corresponding unsigned argument. ===========================================================================*/ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */ /* ** size and position of opcode arguments. */ #define SIZE_C 9 #define SIZE_B 9 #define SIZE_Bx (SIZE_C + SIZE_B) #define SIZE_A 8 #define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A) #define SIZE_OP 6 #define POS_OP 0 #define POS_A (POS_OP + SIZE_OP) #define POS_C (POS_A + SIZE_A) #define POS_B (POS_C + SIZE_C) #define POS_Bx POS_C #define POS_Ax POS_A /* ** limits for opcode arguments. ** we use (signed) int to manipulate most arguments, ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) */ #if SIZE_Bx < LUAI_BITSINT-1 #define MAXARG_Bx ((1<<SIZE_Bx)-1) #define MAXARG_sBx (MAXARG_Bx>>1) /* 'sBx' is signed */ #else #define MAXARG_Bx MAX_INT #define MAXARG_sBx MAX_INT #endif #if SIZE_Ax < LUAI_BITSINT-1 #define MAXARG_Ax ((1<<SIZE_Ax)-1) #else #define MAXARG_Ax MAX_INT #endif #define MAXARG_A ((1<<SIZE_A)-1) #define MAXARG_B ((1<<SIZE_B)-1) #define MAXARG_C ((1<<SIZE_C)-1) /* creates a mask with 'n' 1 bits at position 'p' */ #define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p)) /* creates a mask with 'n' 0 bits at position 'p' */ #define MASK0(n,p) (~MASK1(n,p)) /* ** the following macros help to manipulate instructions */ #define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0))) #define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \ ((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP)))) #define getarg(i,pos,size) (cast(int, ((i)>>pos) & MASK1(size,0))) #define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \ ((cast(Instruction, v)<<pos)&MASK1(size,pos)))) #define GETARG_A(i) getarg(i, POS_A, SIZE_A) #define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A) #define GETARG_B(i) getarg(i, POS_B, SIZE_B) #define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B) #define GETARG_C(i) getarg(i, POS_C, SIZE_C) #define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C) #define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx) #define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx) #define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax) #define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax) #define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx) #define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx)) #define CREATE_ABC(o,a,b,c) ((cast(Instruction, o)<<POS_OP) \ | (cast(Instruction, a)<<POS_A) \ | (cast(Instruction, b)<<POS_B) \ | (cast(Instruction, c)<<POS_C)) #define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \ | (cast(Instruction, a)<<POS_A) \ | (cast(Instruction, bc)<<POS_Bx)) #define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \ | (cast(Instruction, a)<<POS_Ax)) /* ** Macros to operate RK indices */ /* this bit 1 means constant (0 means register) */ #define BITRK (1 << (SIZE_B - 1)) /* test whether value is a constant */ #define ISK(x) ((x) & BITRK) /* gets the index of the constant */ #define INDEXK(r) ((int)(r) & ~BITRK) #define MAXINDEXRK (BITRK - 1) /* code a constant index as a RK value */ #define RKASK(x) ((x) | BITRK) /* ** invalid register that fits in 8 bits */ #define NO_REG MAXARG_A /* ** R(x) - register ** Kst(x) - constant (in constant table) ** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x) */ /* ** grep "ORDER OP" if you change these enums */ typedef enum { /*---------------------------------------------------------------------- name args description ------------------------------------------------------------------------*/ OP_MOVE,/* A B R(A) := R(B) */ OP_LOADK,/* A Bx R(A) := Kst(Bx) */ OP_LOADKX,/* A R(A) := Kst(extra arg) */ OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */ OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */ OP_GETUPVAL,/* A B R(A) := UpValue[B] */ OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */ OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */ OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */ OP_SETUPVAL,/* A B UpValue[B] := R(A) */ OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */ OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */ OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */ OP_ADD,/* A B C R(A) := RK(B) + RK(C) */ OP_SUB,/* A B C R(A) := RK(B) - RK(C) */ OP_MUL,/* A B C R(A) := RK(B) * RK(C) */ OP_MOD,/* A B C R(A) := RK(B) % RK(C) */ OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */ OP_DIV,/* A B C R(A) := RK(B) / RK(C) */ OP_IDIV,/* A B C R(A) := RK(B) // RK(C) */ OP_BAND,/* A B C R(A) := RK(B) & RK(C) */ OP_BOR,/* A B C R(A) := RK(B) | RK(C) */ OP_BXOR,/* A B C R(A) := RK(B) ~ RK(C) */ OP_SHL,/* A B C R(A) := RK(B) << RK(C) */ OP_SHR,/* A B C R(A) := RK(B) >> RK(C) */ OP_UNM,/* A B R(A) := -R(B) */ OP_BNOT,/* A B R(A) := ~R(B) */ OP_NOT,/* A B R(A) := not R(B) */ OP_LEN,/* A B R(A) := length of R(B) */ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */ OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */ OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */ OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */ OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ OP_FORLOOP,/* A sBx R(A)+=R(A+2); if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/ OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */ OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */ OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/ OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */ OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */ OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ } OpCode; #define NUM_OPCODES (cast(int, OP_EXTRAARG) + 1) /*=========================================================================== Notes: (*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then 'top' is set to last_result+1, so next open instruction (OP_CALL, OP_RETURN, OP_SETLIST) may use 'top'. (*) In OP_VARARG, if (B == 0) then use actual number of varargs and set top (like in OP_CALL with C == 0). (*) In OP_RETURN, if (B == 0) then return up to 'top'. (*) In OP_SETLIST, if (B == 0) then B = 'top'; if (C == 0) then next 'instruction' is EXTRAARG(real C). (*) In OP_LOADKX, the next 'instruction' is always EXTRAARG. (*) For comparisons, A specifies what condition the test should accept (true or false). (*) All 'skips' (pc++) assume that next instruction is a jump. ===========================================================================*/ /* ** masks for instruction properties. The format is: ** bits 0-1: op mode ** bits 2-3: C arg mode ** bits 4-5: B arg mode ** bit 6: instruction set register A ** bit 7: operator is a test (next instruction must be a jump) */ enum OpArgMask { OpArgN, /* argument is not used */ OpArgU, /* argument is used */ OpArgR, /* argument is a register or a jump offset */ OpArgK /* argument is a constant or register/constant */ }; LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES]; #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3)) #define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3)) #define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3)) #define testAMode(m) (luaP_opmodes[m] & (1 << 6)) #define testTMode(m) (luaP_opmodes[m] & (1 << 7)) LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ /* number of list items to accumulate before a SETLIST instruction */ #define LFIELDS_PER_FLUSH 50 #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lcode.h���������������������������������������������������������������������������0000644�0001751�0001751�00000006165�12675241401�012253� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $ ** Code generator for Lua ** See Copyright Notice in lua.h */ #ifndef lcode_h #define lcode_h #include "llex.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" /* ** Marks the end of a patch list. It is an invalid value both as an absolute ** address, and as a list link (would link an element to itself). */ #define NO_JUMP (-1) /* ** grep "ORDER OPR" if you change these enums (ORDER OP) */ typedef enum BinOpr { OPR_ADD, OPR_SUB, OPR_MUL, OPR_MOD, OPR_POW, OPR_DIV, OPR_IDIV, OPR_BAND, OPR_BOR, OPR_BXOR, OPR_SHL, OPR_SHR, OPR_CONCAT, OPR_EQ, OPR_LT, OPR_LE, OPR_NE, OPR_GT, OPR_GE, OPR_AND, OPR_OR, OPR_NOBINOPR } BinOpr; typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; #define getcode(fs,e) ((fs)->f->code[(e)->u.info]) #define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx) #define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET) #define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t) LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C); LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); LUAI_FUNC void luaK_checkstack (FuncState *fs, int n); LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s); LUAI_FUNC int luaK_intK (FuncState *fs, lua_Integer n); LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e); LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults); LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e); LUAI_FUNC int luaK_jump (FuncState *fs); LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret); LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); LUAI_FUNC int luaK_getlabel (FuncState *fs); LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2, int line); LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/loadlib.c�������������������������������������������������������������������������0000644�0001751�0001751�00000055763�12675241401�012576� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: loadlib.c,v 1.127 2015/11/23 11:30:45 roberto Exp $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** ** This module contains an implementation of loadlib for Unix systems ** that have dlfcn, an implementation for Windows, and a stub for other ** systems. */ #define loadlib_c #define LUA_LIB #include "lprefix.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment ** variables that Lua check to set its paths. */ #if !defined(LUA_PATH_VAR) #define LUA_PATH_VAR "LUA_PATH" #endif #if !defined(LUA_CPATH_VAR) #define LUA_CPATH_VAR "LUA_CPATH" #endif #define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR #define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX #define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX /* ** LUA_PATH_SEP is the character that separates templates in a path. ** LUA_PATH_MARK is the string that marks the substitution points in a ** template. ** LUA_EXEC_DIR in a Windows path is replaced by the executable's ** directory. ** LUA_IGMARK is a mark to ignore all before it when building the ** luaopen_ function name. */ #if !defined (LUA_PATH_SEP) #define LUA_PATH_SEP ";" #endif #if !defined (LUA_PATH_MARK) #define LUA_PATH_MARK "?" #endif #if !defined (LUA_EXEC_DIR) #define LUA_EXEC_DIR "!" #endif #if !defined (LUA_IGMARK) #define LUA_IGMARK "-" #endif /* ** LUA_CSUBSEP is the character that replaces dots in submodule names ** when searching for a C loader. ** LUA_LSUBSEP is the character that replaces dots in submodule names ** when searching for a Lua loader. */ #if !defined(LUA_CSUBSEP) #define LUA_CSUBSEP LUA_DIRSEP #endif #if !defined(LUA_LSUBSEP) #define LUA_LSUBSEP LUA_DIRSEP #endif /* prefix for open functions in C libraries */ #define LUA_POF "luaopen_" /* separator for open functions in C libraries */ #define LUA_OFSEP "_" /* ** unique key for table in the registry that keeps handles ** for all loaded C libraries */ static const int CLIBS = 0; #define LIB_FAIL "open" #define setprogdir(L) ((void)0) /* ** system-dependent functions */ /* ** unload library 'lib' */ static void lsys_unloadlib (void *lib); /* ** load C library in file 'path'. If 'seeglb', load with all names in ** the library global. ** Returns the library; in case of error, returns NULL plus an ** error string in the stack. */ static void *lsys_load (lua_State *L, const char *path, int seeglb); /* ** Try to find a function named 'sym' in library 'lib'. ** Returns the function; in case of error, returns NULL plus an ** error string in the stack. */ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); #if defined(LUA_USE_DLOPEN) /* { */ /* ** {======================================================================== ** This is an implementation of loadlib based on the dlfcn interface. ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least ** as an emulation layer on top of native functions. ** ========================================================================= */ #include <dlfcn.h> /* ** Macro to convert pointer-to-void* to pointer-to-function. This cast ** is undefined according to ISO C, but POSIX assumes that it works. ** (The '__extension__' in gnu compilers is only to avoid warnings.) */ #if defined(__GNUC__) #define cast_func(p) (__extension__ (lua_CFunction)(p)) #else #define cast_func(p) ((lua_CFunction)(p)) #endif static void lsys_unloadlib (void *lib) { dlclose(lib); } static void *lsys_load (lua_State *L, const char *path, int seeglb) { void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); if (lib == NULL) lua_pushstring(L, dlerror()); return lib; } static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = cast_func(dlsym(lib, sym)); if (f == NULL) lua_pushstring(L, dlerror()); return f; } /* }====================================================== */ #elif defined(LUA_DL_DLL) /* }{ */ /* ** {====================================================================== ** This is an implementation of loadlib for Windows using native functions. ** ======================================================================= */ #include <windows.h> #undef setprogdir /* ** optional flags for LoadLibraryEx */ #if !defined(LUA_LLE_FLAGS) #define LUA_LLE_FLAGS 0 #endif static void setprogdir (lua_State *L) { char buff[MAX_PATH + 1]; char *lb; DWORD nsize = sizeof(buff)/sizeof(char); DWORD n = GetModuleFileNameA(NULL, buff, nsize); if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) luaL_error(L, "unable to get ModuleFileName"); else { *lb = '\0'; luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); lua_remove(L, -2); /* remove original string */ } } static void pusherror (lua_State *L) { int error = GetLastError(); char buffer[128]; if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) lua_pushstring(L, buffer); else lua_pushfstring(L, "system error %d\n", error); } static void lsys_unloadlib (void *lib) { FreeLibrary((HMODULE)lib); } static void *lsys_load (lua_State *L, const char *path, int seeglb) { HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); (void)(seeglb); /* not used: symbols are 'global' by default */ if (lib == NULL) pusherror(L); return lib; } static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); if (f == NULL) pusherror(L); return f; } /* }====================================================== */ #else /* }{ */ /* ** {====================================================== ** Fallback for other systems ** ======================================================= */ #undef LIB_FAIL #define LIB_FAIL "absent" #define DLMSG "dynamic libraries not enabled; check your Lua installation" static void lsys_unloadlib (void *lib) { (void)(lib); /* not used */ } static void *lsys_load (lua_State *L, const char *path, int seeglb) { (void)(path); (void)(seeglb); /* not used */ lua_pushliteral(L, DLMSG); return NULL; } static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { (void)(lib); (void)(sym); /* not used */ lua_pushliteral(L, DLMSG); return NULL; } /* }====================================================== */ #endif /* } */ /* ** return registry.CLIBS[path] */ static void *checkclib (lua_State *L, const char *path) { void *plib; lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); lua_getfield(L, -1, path); plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ lua_pop(L, 2); /* pop CLIBS table and 'plib' */ return plib; } /* ** registry.CLIBS[path] = plib -- for queries ** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries */ static void addtoclib (lua_State *L, const char *path, void *plib) { lua_rawgetp(L, LUA_REGISTRYINDEX, &CLIBS); lua_pushlightuserdata(L, plib); lua_pushvalue(L, -1); lua_setfield(L, -3, path); /* CLIBS[path] = plib */ lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ lua_pop(L, 1); /* pop CLIBS table */ } /* ** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib ** handles in list CLIBS */ static int gctm (lua_State *L) { lua_Integer n = luaL_len(L, 1); for (; n >= 1; n--) { /* for each handle, in reverse order */ lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ lsys_unloadlib(lua_touserdata(L, -1)); lua_pop(L, 1); /* pop handle */ } return 0; } /* error codes for 'lookforfunc' */ #define ERRLIB 1 #define ERRFUNC 2 /* ** Look for a C function named 'sym' in a dynamically loaded library ** 'path'. ** First, check whether the library is already loaded; if not, try ** to load it. ** Then, if 'sym' is '*', return true (as library has been loaded). ** Otherwise, look for symbol 'sym' in the library and push a ** C function with that symbol. ** Return 0 and 'true' or a function in the stack; in case of ** errors, return an error code and an error message in the stack. */ static int lookforfunc (lua_State *L, const char *path, const char *sym) { void *reg = checkclib(L, path); /* check loaded C libraries */ if (reg == NULL) { /* must load library? */ reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ if (reg == NULL) return ERRLIB; /* unable to load library */ addtoclib(L, path, reg); } if (*sym == '*') { /* loading only library (no function)? */ lua_pushboolean(L, 1); /* return 'true' */ return 0; /* no errors */ } else { lua_CFunction f = lsys_sym(L, reg, sym); if (f == NULL) return ERRFUNC; /* unable to find function */ lua_pushcfunction(L, f); /* else create new function */ return 0; /* no errors */ } } static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); int stat = lookforfunc(L, path, init); if (stat == 0) /* no errors? */ return 1; /* return the loaded function */ else { /* error; error message is on stack top */ lua_pushnil(L); lua_insert(L, -2); lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); return 3; /* return nil, error message, and where */ } } /* ** {====================================================== ** 'require' function ** ======================================================= */ static int readable (const char *filename) { FILE *f = fopen(filename, "r"); /* try to open file */ if (f == NULL) return 0; /* open failed */ fclose(f); return 1; } static const char *pushnexttemplate (lua_State *L, const char *path) { const char *l; while (*path == *LUA_PATH_SEP) path++; /* skip separators */ if (*path == '\0') return NULL; /* no more templates */ l = strchr(path, *LUA_PATH_SEP); /* find next separator */ if (l == NULL) l = path + strlen(path); lua_pushlstring(L, path, l - path); /* template */ return l; } static const char *searchpath (lua_State *L, const char *name, const char *path, const char *sep, const char *dirsep) { luaL_Buffer msg; /* to build error message */ luaL_buffinit(L, &msg); if (*sep != '\0') /* non-empty separator? */ name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ while ((path = pushnexttemplate(L, path)) != NULL) { const char *filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); lua_remove(L, -2); /* remove path template */ if (readable(filename)) /* does file exist and is readable? */ return filename; /* return that file name */ lua_pushfstring(L, "\n\tno file '%s'", filename); lua_remove(L, -2); /* remove file name */ luaL_addvalue(&msg); /* concatenate error msg. entry */ } luaL_pushresult(&msg); /* create error message */ return NULL; /* not found */ } static int ll_searchpath (lua_State *L) { const char *f = searchpath(L, luaL_checkstring(L, 1), luaL_checkstring(L, 2), luaL_optstring(L, 3, "."), luaL_optstring(L, 4, LUA_DIRSEP)); if (f != NULL) return 1; else { /* error message is on top of the stack */ lua_pushnil(L); lua_insert(L, -2); return 2; /* return nil + error message */ } } static const char *findfile (lua_State *L, const char *name, const char *pname, const char *dirsep) { const char *path; lua_getfield(L, lua_upvalueindex(1), pname); path = lua_tostring(L, -1); if (path == NULL) luaL_error(L, "'package.%s' must be a string", pname); return searchpath(L, name, path, ".", dirsep); } static int checkload (lua_State *L, int stat, const char *filename) { if (stat) { /* module loaded successfully? */ lua_pushstring(L, filename); /* will be 2nd argument to module */ return 2; /* return open function and file name */ } else return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", lua_tostring(L, 1), filename, lua_tostring(L, -1)); } static int searcher_Lua (lua_State *L) { const char *filename; const char *name = luaL_checkstring(L, 1); filename = findfile(L, name, "path", LUA_LSUBSEP); if (filename == NULL) return 1; /* module not found in this path */ return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); } /* ** Try to find a load function for module 'modname' at file 'filename'. ** First, change '.' to '_' in 'modname'; then, if 'modname' has ** the form X-Y (that is, it has an "ignore mark"), build a function ** name "luaopen_X" and look for it. (For compatibility, if that ** fails, it also tries "luaopen_Y".) If there is no ignore mark, ** look for a function named "luaopen_modname". */ static int loadfunc (lua_State *L, const char *filename, const char *modname) { const char *openfunc; const char *mark; modname = luaL_gsub(L, modname, ".", LUA_OFSEP); mark = strchr(modname, *LUA_IGMARK); if (mark) { int stat; openfunc = lua_pushlstring(L, modname, mark - modname); openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); stat = lookforfunc(L, filename, openfunc); if (stat != ERRFUNC) return stat; modname = mark + 1; /* else go ahead and try old-style name */ } openfunc = lua_pushfstring(L, LUA_POF"%s", modname); return lookforfunc(L, filename, openfunc); } static int searcher_C (lua_State *L) { const char *name = luaL_checkstring(L, 1); const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); if (filename == NULL) return 1; /* module not found in this path */ return checkload(L, (loadfunc(L, filename, name) == 0), filename); } static int searcher_Croot (lua_State *L) { const char *filename; const char *name = luaL_checkstring(L, 1); const char *p = strchr(name, '.'); int stat; if (p == NULL) return 0; /* is root */ lua_pushlstring(L, name, p - name); filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); if (filename == NULL) return 1; /* root not found */ if ((stat = loadfunc(L, filename, name)) != 0) { if (stat != ERRFUNC) return checkload(L, 0, filename); /* real error */ else { /* open function not found */ lua_pushfstring(L, "\n\tno module '%s' in file '%s'", name, filename); return 1; } } lua_pushstring(L, filename); /* will be 2nd argument to module */ return 2; } static int searcher_preload (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ lua_pushfstring(L, "\n\tno field package.preload['%s']", name); return 1; } static void findloader (lua_State *L, const char *name) { int i; luaL_Buffer msg; /* to build error message */ luaL_buffinit(L, &msg); /* push 'package.searchers' to index 3 in the stack */ if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) luaL_error(L, "'package.searchers' must be a table"); /* iterate over available searchers to find a loader */ for (i = 1; ; i++) { if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ lua_pop(L, 1); /* remove nil */ luaL_pushresult(&msg); /* create error message */ luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); } lua_pushstring(L, name); lua_call(L, 1, 2); /* call it */ if (lua_isfunction(L, -2)) /* did it find a loader? */ return; /* module loader found */ else if (lua_isstring(L, -2)) { /* searcher returned error message? */ lua_pop(L, 1); /* remove extra return */ luaL_addvalue(&msg); /* concatenate error message */ } else lua_pop(L, 2); /* remove both returns */ } } static int ll_require (lua_State *L) { const char *name = luaL_checkstring(L, 1); lua_settop(L, 1); /* _LOADED table will be at index 2 */ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); lua_getfield(L, 2, name); /* _LOADED[name] */ if (lua_toboolean(L, -1)) /* is it there? */ return 1; /* package is already loaded */ /* else must load package */ lua_pop(L, 1); /* remove 'getfield' result */ findloader(L, name); lua_pushstring(L, name); /* pass name as argument to module loader */ lua_insert(L, -2); /* name is 1st argument (before search data) */ lua_call(L, 2, 1); /* run loader to load module */ if (!lua_isnil(L, -1)) /* non-nil return? */ lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ lua_pushboolean(L, 1); /* use true as result */ lua_pushvalue(L, -1); /* extra copy to be returned */ lua_setfield(L, 2, name); /* _LOADED[name] = true */ } return 1; } /* }====================================================== */ /* ** {====================================================== ** 'module' function ** ======================================================= */ #if defined(LUA_COMPAT_MODULE) /* ** changes the environment variable of calling function */ static void set_env (lua_State *L) { lua_Debug ar; if (lua_getstack(L, 1, &ar) == 0 || lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ lua_iscfunction(L, -1)) luaL_error(L, "'module' not called from a Lua function"); lua_pushvalue(L, -2); /* copy new environment table to top */ lua_setupvalue(L, -2, 1); lua_pop(L, 1); /* remove function */ } static void dooptions (lua_State *L, int n) { int i; for (i = 2; i <= n; i++) { if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */ lua_pushvalue(L, i); /* get option (a function) */ lua_pushvalue(L, -2); /* module */ lua_call(L, 1, 0); } } } static void modinit (lua_State *L, const char *modname) { const char *dot; lua_pushvalue(L, -1); lua_setfield(L, -2, "_M"); /* module._M = module */ lua_pushstring(L, modname); lua_setfield(L, -2, "_NAME"); dot = strrchr(modname, '.'); /* look for last dot in module name */ if (dot == NULL) dot = modname; else dot++; /* set _PACKAGE as package name (full module name minus last part) */ lua_pushlstring(L, modname, dot - modname); lua_setfield(L, -2, "_PACKAGE"); } static int ll_module (lua_State *L) { const char *modname = luaL_checkstring(L, 1); int lastarg = lua_gettop(L); /* last parameter */ luaL_pushmodule(L, modname, 1); /* get/create module table */ /* check whether table already has a _NAME field */ if (lua_getfield(L, -1, "_NAME") != LUA_TNIL) lua_pop(L, 1); /* table is an initialized module */ else { /* no; initialize it */ lua_pop(L, 1); modinit(L, modname); } lua_pushvalue(L, -1); set_env(L); dooptions(L, lastarg); return 1; } static int ll_seeall (lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); if (!lua_getmetatable(L, 1)) { lua_createtable(L, 0, 1); /* create new metatable */ lua_pushvalue(L, -1); lua_setmetatable(L, 1); } lua_pushglobaltable(L); lua_setfield(L, -2, "__index"); /* mt.__index = _G */ return 0; } #endif /* }====================================================== */ /* auxiliary mark (for internal use) */ #define AUXMARK "\1" /* ** return registry.LUA_NOENV as a boolean */ static int noenv (lua_State *L) { int b; lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); b = lua_toboolean(L, -1); lua_pop(L, 1); /* remove value */ return b; } static void setpath (lua_State *L, const char *fieldname, const char *envname1, const char *envname2, const char *def) { const char *path = getenv(envname1); if (path == NULL) /* no environment variable? */ path = getenv(envname2); /* try alternative name */ if (path == NULL || noenv(L)) /* no environment variable? */ lua_pushstring(L, def); /* use default */ else { /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP, LUA_PATH_SEP AUXMARK LUA_PATH_SEP); luaL_gsub(L, path, AUXMARK, def); lua_remove(L, -2); } setprogdir(L); lua_setfield(L, -2, fieldname); } static const luaL_Reg pk_funcs[] = { {"loadlib", ll_loadlib}, {"searchpath", ll_searchpath}, #if defined(LUA_COMPAT_MODULE) {"seeall", ll_seeall}, #endif /* placeholders */ {"preload", NULL}, {"cpath", NULL}, {"path", NULL}, {"searchers", NULL}, {"loaded", NULL}, {NULL, NULL} }; static const luaL_Reg ll_funcs[] = { #if defined(LUA_COMPAT_MODULE) {"module", ll_module}, #endif {"require", ll_require}, {NULL, NULL} }; static void createsearcherstable (lua_State *L) { static const lua_CFunction searchers[] = {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; int i; /* create 'searchers' table */ lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); /* fill it with predefined searchers */ for (i=0; searchers[i] != NULL; i++) { lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ lua_pushcclosure(L, searchers[i], 1); lua_rawseti(L, -2, i+1); } #if defined(LUA_COMPAT_LOADERS) lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ lua_setfield(L, -3, "loaders"); /* put it in field 'loaders' */ #endif lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ } /* ** create table CLIBS to keep track of loaded C libraries, ** setting a finalizer to close all libraries when closing state. */ static void createclibstable (lua_State *L) { lua_newtable(L); /* create CLIBS table */ lua_createtable(L, 0, 1); /* create metatable for CLIBS */ lua_pushcfunction(L, gctm); lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ lua_setmetatable(L, -2); lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS); /* set CLIBS table in registry */ } LUAMOD_API int luaopen_package (lua_State *L) { createclibstable(L); luaL_newlib(L, pk_funcs); /* create 'package' table */ createsearcherstable(L); /* set field 'path' */ setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT); /* set field 'cpath' */ setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT); /* store config information */ lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); lua_setfield(L, -2, "config"); /* set field 'loaded' */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); lua_setfield(L, -2, "loaded"); /* set field 'preload' */ luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); lua_setfield(L, -2, "preload"); lua_pushglobaltable(L); lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ lua_pop(L, 1); /* pop global table */ return 1; /* return 'package' table */ } �������������golly-2.8-src/lua/lobject.c�������������������������������������������������������������������������0000644�0001751�0001751�00000034047�12675241401�012602� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lobject.c,v 2.108 2015/11/02 16:09:30 roberto Exp $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ #define lobject_c #define LUA_CORE #include "lprefix.h" #include <locale.h> #include <math.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "lua.h" #include "lctype.h" #include "ldebug.h" #include "ldo.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "lvm.h" LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT}; /* ** converts an integer to a "floating point byte", represented as ** (eeeeexxx), where the real value is (1xxx) * 2^(eeeee - 1) if ** eeeee != 0 and (xxx) otherwise. */ int luaO_int2fb (unsigned int x) { int e = 0; /* exponent */ if (x < 8) return x; while (x >= (8 << 4)) { /* coarse steps */ x = (x + 0xf) >> 4; /* x = ceil(x / 16) */ e += 4; } while (x >= (8 << 1)) { /* fine steps */ x = (x + 1) >> 1; /* x = ceil(x / 2) */ e++; } return ((e+1) << 3) | (cast_int(x) - 8); } /* converts back */ int luaO_fb2int (int x) { return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1); } /* ** Computes ceil(log2(x)) */ int luaO_ceillog2 (unsigned int x) { static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */ 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 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, 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,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 }; int l = 0; x--; while (x >= 256) { l += 8; x >>= 8; } return l + log_2[x]; } static lua_Integer intarith (lua_State *L, int op, lua_Integer v1, lua_Integer v2) { switch (op) { case LUA_OPADD: return intop(+, v1, v2); case LUA_OPSUB:return intop(-, v1, v2); case LUA_OPMUL:return intop(*, v1, v2); case LUA_OPMOD: return luaV_mod(L, v1, v2); case LUA_OPIDIV: return luaV_div(L, v1, v2); case LUA_OPBAND: return intop(&, v1, v2); case LUA_OPBOR: return intop(|, v1, v2); case LUA_OPBXOR: return intop(^, v1, v2); case LUA_OPSHL: return luaV_shiftl(v1, v2); case LUA_OPSHR: return luaV_shiftl(v1, -v2); case LUA_OPUNM: return intop(-, 0, v1); case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); default: lua_assert(0); return 0; } } static lua_Number numarith (lua_State *L, int op, lua_Number v1, lua_Number v2) { switch (op) { case LUA_OPADD: return luai_numadd(L, v1, v2); case LUA_OPSUB: return luai_numsub(L, v1, v2); case LUA_OPMUL: return luai_nummul(L, v1, v2); case LUA_OPDIV: return luai_numdiv(L, v1, v2); case LUA_OPPOW: return luai_numpow(L, v1, v2); case LUA_OPIDIV: return luai_numidiv(L, v1, v2); case LUA_OPUNM: return luai_numunm(L, v1); case LUA_OPMOD: { lua_Number m; luai_nummod(L, v1, v2, m); return m; } default: lua_assert(0); return 0; } } void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, TValue *res) { switch (op) { case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* operate only on integers */ lua_Integer i1; lua_Integer i2; if (tointeger(p1, &i1) && tointeger(p2, &i2)) { setivalue(res, intarith(L, op, i1, i2)); return; } else break; /* go to the end */ } case LUA_OPDIV: case LUA_OPPOW: { /* operate only on floats */ lua_Number n1; lua_Number n2; if (tonumber(p1, &n1) && tonumber(p2, &n2)) { setfltvalue(res, numarith(L, op, n1, n2)); return; } else break; /* go to the end */ } default: { /* other operations */ lua_Number n1; lua_Number n2; if (ttisinteger(p1) && ttisinteger(p2)) { setivalue(res, intarith(L, op, ivalue(p1), ivalue(p2))); return; } else if (tonumber(p1, &n1) && tonumber(p2, &n2)) { setfltvalue(res, numarith(L, op, n1, n2)); return; } else break; /* go to the end */ } } /* could not perform raw operation; try metamethod */ lua_assert(L != NULL); /* should not fail when folding (compile time) */ luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD)); } int luaO_hexavalue (int c) { if (lisdigit(c)) return c - '0'; else return (ltolower(c) - 'a') + 10; } static int isneg (const char **s) { if (**s == '-') { (*s)++; return 1; } else if (**s == '+') (*s)++; return 0; } /* ** {================================================================== ** Lua's implementation for 'lua_strx2number' ** =================================================================== */ #if !defined(lua_strx2number) /* maximum number of significant digits to read (to avoid overflows even with single floats) */ #define MAXSIGDIG 30 /* ** convert an hexadecimal numeric string to a number, following ** C99 specification for 'strtod' */ static lua_Number lua_strx2number (const char *s, char **endptr) { int dot = lua_getlocaledecpoint(); lua_Number r = 0.0; /* result (accumulator) */ int sigdig = 0; /* number of significant digits */ int nosigdig = 0; /* number of non-significant digits */ int e = 0; /* exponent correction */ int neg; /* 1 if number is negative */ int hasdot = 0; /* true after seen a dot */ *endptr = cast(char *, s); /* nothing is valid yet */ while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); /* check signal */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ return 0.0; /* invalid format (no '0x') */ for (s += 2; ; s++) { /* skip '0x' and read numeral */ if (*s == dot) { if (hasdot) break; /* second dot? stop loop */ else hasdot = 1; } else if (lisxdigit(cast_uchar(*s))) { if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ nosigdig++; else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ r = (r * cast_num(16.0)) + luaO_hexavalue(*s); else e++; /* too many digits; ignore, but still count for exponent */ if (hasdot) e--; /* decimal digit? correct exponent */ } else break; /* neither a dot nor a digit */ } if (nosigdig + sigdig == 0) /* no digits? */ return 0.0; /* invalid format */ *endptr = cast(char *, s); /* valid up to here */ e *= 4; /* each digit multiplies/divides value by 2^4 */ if (*s == 'p' || *s == 'P') { /* exponent part? */ int exp1 = 0; /* exponent value */ int neg1; /* exponent signal */ s++; /* skip 'p' */ neg1 = isneg(&s); /* signal */ if (!lisdigit(cast_uchar(*s))) return 0.0; /* invalid; must have at least one digit */ while (lisdigit(cast_uchar(*s))) /* read exponent */ exp1 = exp1 * 10 + *(s++) - '0'; if (neg1) exp1 = -exp1; e += exp1; *endptr = cast(char *, s); /* valid up to here */ } if (neg) r = -r; return l_mathop(ldexp)(r, e); } #endif /* }====================================================== */ static const char *l_str2d (const char *s, lua_Number *result) { char *endptr; if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */ return NULL; else if (strpbrk(s, "xX")) /* hex? */ *result = lua_strx2number(s, &endptr); else *result = lua_str2number(s, &endptr); if (endptr == s) return NULL; /* nothing recognized */ while (lisspace(cast_uchar(*endptr))) endptr++; return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */ } static const char *l_str2int (const char *s, lua_Integer *result) { lua_Unsigned a = 0; int empty = 1; int neg; while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { /* hex? */ s += 2; /* skip '0x' */ for (; lisxdigit(cast_uchar(*s)); s++) { a = a * 16 + luaO_hexavalue(*s); empty = 0; } } else { /* decimal */ for (; lisdigit(cast_uchar(*s)); s++) { a = a * 10 + *s - '0'; empty = 0; } } while (lisspace(cast_uchar(*s))) s++; /* skip trailing spaces */ if (empty || *s != '\0') return NULL; /* something wrong in the numeral */ else { *result = l_castU2S((neg) ? 0u - a : a); return s; } } size_t luaO_str2num (const char *s, TValue *o) { lua_Integer i; lua_Number n; const char *e; if ((e = l_str2int(s, &i)) != NULL) { /* try as an integer */ setivalue(o, i); } else if ((e = l_str2d(s, &n)) != NULL) { /* else try as a float */ setfltvalue(o, n); } else return 0; /* conversion failed */ return (e - s) + 1; /* success; return string size */ } int luaO_utf8esc (char *buff, unsigned long x) { int n = 1; /* number of bytes put in buffer (backwards) */ lua_assert(x <= 0x10FFFF); if (x < 0x80) /* ascii? */ buff[UTF8BUFFSZ - 1] = cast(char, x); else { /* need continuation bytes */ unsigned int mfb = 0x3f; /* maximum that fits in first byte */ do { /* add continuation bytes */ buff[UTF8BUFFSZ - (n++)] = cast(char, 0x80 | (x & 0x3f)); x >>= 6; /* remove added bits */ mfb >>= 1; /* now there is one less bit available in first byte */ } while (x > mfb); /* still needs continuation byte? */ buff[UTF8BUFFSZ - n] = cast(char, (~mfb << 1) | x); /* add first byte */ } return n; } /* maximum length of the conversion of a number to a string */ #define MAXNUMBER2STR 50 /* ** Convert a number object to a string */ void luaO_tostring (lua_State *L, StkId obj) { char buff[MAXNUMBER2STR]; size_t len; lua_assert(ttisnumber(obj)); if (ttisinteger(obj)) len = lua_integer2str(buff, sizeof(buff), ivalue(obj)); else { len = lua_number2str(buff, sizeof(buff), fltvalue(obj)); #if !defined(LUA_COMPAT_FLOATSTRING) if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */ buff[len++] = lua_getlocaledecpoint(); buff[len++] = '0'; /* adds '.0' to result */ } #endif } setsvalue2s(L, obj, luaS_newlstr(L, buff, len)); } static void pushstr (lua_State *L, const char *str, size_t l) { setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); luaD_inctop(L); } /* this function handles only '%d', '%c', '%f', '%p', and '%s' conventional formats, plus Lua-specific '%I' and '%U' */ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { int n = 0; for (;;) { const char *e = strchr(fmt, '%'); if (e == NULL) break; pushstr(L, fmt, e - fmt); switch (*(e+1)) { case 's': { const char *s = va_arg(argp, char *); if (s == NULL) s = "(null)"; pushstr(L, s, strlen(s)); break; } case 'c': { char buff = cast(char, va_arg(argp, int)); if (lisprint(cast_uchar(buff))) pushstr(L, &buff, 1); else /* non-printable character; print its code */ luaO_pushfstring(L, "<\\%d>", cast_uchar(buff)); break; } case 'd': { setivalue(L->top, va_arg(argp, int)); goto top2str; } case 'I': { setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt))); goto top2str; } case 'f': { setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber))); top2str: luaD_inctop(L); luaO_tostring(L, L->top - 1); break; } case 'p': { char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */ int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *)); pushstr(L, buff, l); break; } case 'U': { char buff[UTF8BUFFSZ]; int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long))); pushstr(L, buff + UTF8BUFFSZ - l, l); break; } case '%': { pushstr(L, "%", 1); break; } default: { luaG_runerror(L, "invalid option '%%%c' to 'lua_pushfstring'", *(e + 1)); } } n += 2; fmt = e+2; } luaD_checkstack(L, 1); pushstr(L, fmt, strlen(fmt)); if (n > 0) luaV_concat(L, n + 1); return svalue(L->top - 1); } const char *luaO_pushfstring (lua_State *L, const char *fmt, ...) { const char *msg; va_list argp; va_start(argp, fmt); msg = luaO_pushvfstring(L, fmt, argp); va_end(argp); return msg; } /* number of chars of a literal string without the ending \0 */ #define LL(x) (sizeof(x)/sizeof(char) - 1) #define RETS "..." #define PRE "[string \"" #define POS "\"]" #define addstr(a,b,l) ( memcpy(a,b,(l) * sizeof(char)), a += (l) ) void luaO_chunkid (char *out, const char *source, size_t bufflen) { size_t l = strlen(source); if (*source == '=') { /* 'literal' source */ if (l <= bufflen) /* small enough? */ memcpy(out, source + 1, l * sizeof(char)); else { /* truncate it */ addstr(out, source + 1, bufflen - 1); *out = '\0'; } } else if (*source == '@') { /* file name */ if (l <= bufflen) /* small enough? */ memcpy(out, source + 1, l * sizeof(char)); else { /* add '...' before rest of name */ addstr(out, RETS, LL(RETS)); bufflen -= LL(RETS); memcpy(out, source + 1 + l - bufflen, bufflen * sizeof(char)); } } else { /* string; format as [string "source"] */ const char *nl = strchr(source, '\n'); /* find first new line (if any) */ addstr(out, PRE, LL(PRE)); /* add prefix */ bufflen -= LL(PRE RETS POS) + 1; /* save space for prefix+suffix+'\0' */ if (l < bufflen && nl == NULL) { /* small one-line source? */ addstr(out, source, l); /* keep it */ } else { if (nl != NULL) l = nl - source; /* stop at first newline */ if (l > bufflen) l = bufflen; addstr(out, source, l); addstr(out, RETS, LL(RETS)); } memcpy(out, POS, (LL(POS) + 1) * sizeof(char)); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lfunc.h���������������������������������������������������������������������������0000644�0001751�0001751�00000003137�12675241401�012270� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ #ifndef lfunc_h #define lfunc_h #include "lobject.h" #define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \ cast(int, sizeof(TValue)*((n)-1))) #define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \ cast(int, sizeof(TValue *)*((n)-1))) /* test whether thread is in 'twups' list */ #define isintwups(L) (L->twups != L) /* ** maximum number of upvalues in a closure (both C and Lua). (Value ** must fit in a VM register.) */ #define MAXUPVAL 255 /* ** Upvalues for Lua closures */ struct UpVal { TValue *v; /* points to stack or to its own value */ lu_mem refcount; /* reference counter */ union { struct { /* (when open) */ UpVal *next; /* linked list */ int touched; /* mark to avoid cycles with dead threads */ } open; TValue value; /* the value (when closed) */ } u; }; #define upisopen(up) ((up)->v != &(up)->u.value) LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems); LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems); LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_close (lua_State *L, StkId level); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, int pc); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/llimits.h�������������������������������������������������������������������������0000644�0001751�0001751�00000016774�12675241401�012651� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $ ** Limits, basic types, and some other 'installation-dependent' definitions ** See Copyright Notice in lua.h */ #ifndef llimits_h #define llimits_h #include <limits.h> #include <stddef.h> #include "lua.h" /* ** 'lu_mem' and 'l_mem' are unsigned/signed integers big enough to count ** the total memory used by Lua (in bytes). Usually, 'size_t' and ** 'ptrdiff_t' should work, but we use 'long' for 16-bit machines. */ #if defined(LUAI_MEM) /* { external definitions? */ typedef LUAI_UMEM lu_mem; typedef LUAI_MEM l_mem; #elif LUAI_BITSINT >= 32 /* }{ */ typedef size_t lu_mem; typedef ptrdiff_t l_mem; #else /* 16-bit ints */ /* }{ */ typedef unsigned long lu_mem; typedef long l_mem; #endif /* } */ /* chars used as small naturals (so that 'char' is reserved for characters) */ typedef unsigned char lu_byte; /* maximum value for size_t */ #define MAX_SIZET ((size_t)(~(size_t)0)) /* maximum size visible for Lua (must be representable in a lua_Integer */ #define MAX_SIZE (sizeof(size_t) < sizeof(lua_Integer) ? MAX_SIZET \ : (size_t)(LUA_MAXINTEGER)) #define MAX_LUMEM ((lu_mem)(~(lu_mem)0)) #define MAX_LMEM ((l_mem)(MAX_LUMEM >> 1)) #define MAX_INT INT_MAX /* maximum value of an int */ /* ** conversion of pointer to unsigned integer: ** this is for hashing only; there is no problem if the integer ** cannot hold the whole pointer value */ #define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) /* type to ensure maximum alignment */ #if defined(LUAI_USER_ALIGNMENT_T) typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; #else typedef union { lua_Number n; double u; void *s; lua_Integer i; long l; } L_Umaxalign; #endif /* types of 'usual argument conversions' for lua_Number and lua_Integer */ typedef LUAI_UACNUMBER l_uacNumber; typedef LUAI_UACINT l_uacInt; /* internal assertions for in-house debugging */ #if defined(lua_assert) #define check_exp(c,e) (lua_assert(c), (e)) /* to avoid problems with conditions too long */ #define lua_longassert(c) ((c) ? (void)0 : lua_assert(0)) #else #define lua_assert(c) ((void)0) #define check_exp(c,e) (e) #define lua_longassert(c) ((void)0) #endif /* ** assertion for checking API calls */ #if !defined(luai_apicheck) #define luai_apicheck(l,e) lua_assert(e) #endif #define api_check(l,e,msg) luai_apicheck(l,(e) && msg) /* macro to avoid warnings about unused variables */ #if !defined(UNUSED) #define UNUSED(x) ((void)(x)) #endif /* type casts (a macro highlights casts in the code) */ #define cast(t, exp) ((t)(exp)) #define cast_void(i) cast(void, (i)) #define cast_byte(i) cast(lu_byte, (i)) #define cast_num(i) cast(lua_Number, (i)) #define cast_int(i) cast(int, (i)) #define cast_uchar(i) cast(unsigned char, (i)) /* cast a signed lua_Integer to lua_Unsigned */ #if !defined(l_castS2U) #define l_castS2U(i) ((lua_Unsigned)(i)) #endif /* ** cast a lua_Unsigned to a signed lua_Integer; this cast is ** not strict ISO C, but two-complement architectures should ** work fine. */ #if !defined(l_castU2S) #define l_castU2S(i) ((lua_Integer)(i)) #endif /* ** non-return type */ #if defined(__GNUC__) #define l_noret void __attribute__((noreturn)) #elif defined(_MSC_VER) && _MSC_VER >= 1200 #define l_noret void __declspec(noreturn) #else #define l_noret void #endif /* ** maximum depth for nested C calls and syntactical nested non-terminals ** in a program. (Value must fit in an unsigned short int.) */ #if !defined(LUAI_MAXCCALLS) #define LUAI_MAXCCALLS 200 #endif /* ** type for virtual-machine instructions; ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) */ #if LUAI_BITSINT >= 32 typedef unsigned int Instruction; #else typedef unsigned long Instruction; #endif /* ** Maximum length for short strings, that is, strings that are ** internalized. (Cannot be smaller than reserved words or tags for ** metamethods, as these strings must be internalized; ** #("function") = 8, #("__newindex") = 10.) */ #if !defined(LUAI_MAXSHORTLEN) #define LUAI_MAXSHORTLEN 40 #endif /* ** Initial size for the string table (must be power of 2). ** The Lua core alone registers ~50 strings (reserved words + ** metaevent keys + a few others). Libraries would typically add ** a few dozens more. */ #if !defined(MINSTRTABSIZE) #define MINSTRTABSIZE 128 #endif /* ** Size of cache for strings in the API. 'N' is the number of ** sets (better be a prime) and "M" is the size of each set (M == 1 ** makes a direct cache.) */ #if !defined(STRCACHE_N) #define STRCACHE_N 53 #define STRCACHE_M 2 #endif /* minimum size for string buffer */ #if !defined(LUA_MINBUFFER) #define LUA_MINBUFFER 32 #endif /* ** macros that are executed whenever program enters the Lua core ** ('lua_lock') and leaves the core ('lua_unlock') */ #if !defined(lua_lock) #define lua_lock(L) ((void) 0) #define lua_unlock(L) ((void) 0) #endif /* ** macro executed during Lua functions at points where the ** function can yield. */ #if !defined(luai_threadyield) #define luai_threadyield(L) {lua_unlock(L); lua_lock(L);} #endif /* ** these macros allow user-specific actions on threads when you defined ** LUAI_EXTRASPACE and need to do something extra when a thread is ** created/deleted/resumed/yielded. */ #if !defined(luai_userstateopen) #define luai_userstateopen(L) ((void)L) #endif #if !defined(luai_userstateclose) #define luai_userstateclose(L) ((void)L) #endif #if !defined(luai_userstatethread) #define luai_userstatethread(L,L1) ((void)L) #endif #if !defined(luai_userstatefree) #define luai_userstatefree(L,L1) ((void)L) #endif #if !defined(luai_userstateresume) #define luai_userstateresume(L,n) ((void)L) #endif #if !defined(luai_userstateyield) #define luai_userstateyield(L,n) ((void)L) #endif /* ** The luai_num* macros define the primitive operations over numbers. */ /* floor division (defined as 'floor(a/b)') */ #if !defined(luai_numidiv) #define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b))) #endif /* float division */ #if !defined(luai_numdiv) #define luai_numdiv(L,a,b) ((a)/(b)) #endif /* ** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when ** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of ** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b) ** ~= floor(a/b)'. That happens when the division has a non-integer ** negative result, which is equivalent to the test below. */ #if !defined(luai_nummod) #define luai_nummod(L,a,b,m) \ { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } #endif /* exponentiation */ #if !defined(luai_numpow) #define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) #endif /* the others are quite standard operations */ #if !defined(luai_numadd) #define luai_numadd(L,a,b) ((a)+(b)) #define luai_numsub(L,a,b) ((a)-(b)) #define luai_nummul(L,a,b) ((a)*(b)) #define luai_numunm(L,a) (-(a)) #define luai_numeq(a,b) ((a)==(b)) #define luai_numlt(a,b) ((a)<(b)) #define luai_numle(a,b) ((a)<=(b)) #define luai_numisnan(a) (!luai_numeq((a), (a))) #endif /* ** macro to control inclusion of some hard tests on stack reallocation */ #if !defined(HARDSTACKTESTS) #define condmovestack(L,pre,pos) ((void)0) #else /* realloc stack keeping its size */ #define condmovestack(L,pre,pos) \ { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; } #endif #if !defined(HARDMEMTESTS) #define condchangemem(L,pre,pos) ((void)0) #else #define condchangemem(L,pre,pos) \ { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } #endif #endif ����golly-2.8-src/lua/lparser.c�������������������������������������������������������������������������0000644�0001751�0001751�00000132356�12675241401�012632� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lparser.c,v 2.149 2015/11/02 16:09:30 roberto Exp $ ** Lua Parser ** See Copyright Notice in lua.h */ #define lparser_c #define LUA_CORE #include "lprefix.h" #include <string.h> #include "lua.h" #include "lcode.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "llex.h" #include "lmem.h" #include "lobject.h" #include "lopcodes.h" #include "lparser.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" /* maximum number of local variables per function (must be smaller than 250, due to the bytecode format) */ #define MAXVARS 200 #define hasmultret(k) ((k) == VCALL || (k) == VVARARG) /* because all strings are unified by the scanner, the parser can use pointer equality for string equality */ #define eqstr(a,b) ((a) == (b)) /* ** nodes for block list (list of active blocks) */ typedef struct BlockCnt { struct BlockCnt *previous; /* chain */ int firstlabel; /* index of first label in this block */ int firstgoto; /* index of first pending goto in this block */ lu_byte nactvar; /* # active locals outside the block */ lu_byte upval; /* true if some variable in the block is an upvalue */ lu_byte isloop; /* true if 'block' is a loop */ } BlockCnt; /* ** prototypes for recursive non-terminal functions */ static void statement (LexState *ls); static void expr (LexState *ls, expdesc *v); /* semantic error */ static l_noret semerror (LexState *ls, const char *msg) { ls->t.token = 0; /* remove "near <token>" from final message */ luaX_syntaxerror(ls, msg); } static l_noret error_expected (LexState *ls, int token) { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, "%s expected", luaX_token2str(ls, token))); } static l_noret errorlimit (FuncState *fs, int limit, const char *what) { lua_State *L = fs->ls->L; const char *msg; int line = fs->f->linedefined; const char *where = (line == 0) ? "main function" : luaO_pushfstring(L, "function at line %d", line); msg = luaO_pushfstring(L, "too many %s (limit is %d) in %s", what, limit, where); luaX_syntaxerror(fs->ls, msg); } static void checklimit (FuncState *fs, int v, int l, const char *what) { if (v > l) errorlimit(fs, l, what); } static int testnext (LexState *ls, int c) { if (ls->t.token == c) { luaX_next(ls); return 1; } else return 0; } static void check (LexState *ls, int c) { if (ls->t.token != c) error_expected(ls, c); } static void checknext (LexState *ls, int c) { check(ls, c); luaX_next(ls); } #define check_condition(ls,c,msg) { if (!(c)) luaX_syntaxerror(ls, msg); } static void check_match (LexState *ls, int what, int who, int where) { if (!testnext(ls, what)) { if (where == ls->linenumber) error_expected(ls, what); else { luaX_syntaxerror(ls, luaO_pushfstring(ls->L, "%s expected (to close %s at line %d)", luaX_token2str(ls, what), luaX_token2str(ls, who), where)); } } } static TString *str_checkname (LexState *ls) { TString *ts; check(ls, TK_NAME); ts = ls->t.seminfo.ts; luaX_next(ls); return ts; } static void init_exp (expdesc *e, expkind k, int i) { e->f = e->t = NO_JUMP; e->k = k; e->u.info = i; } static void codestring (LexState *ls, expdesc *e, TString *s) { init_exp(e, VK, luaK_stringK(ls->fs, s)); } static void checkname (LexState *ls, expdesc *e) { codestring(ls, e, str_checkname(ls)); } static int registerlocalvar (LexState *ls, TString *varname) { FuncState *fs = ls->fs; Proto *f = fs->f; int oldsize = f->sizelocvars; luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars, LocVar, SHRT_MAX, "local variables"); while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL; f->locvars[fs->nlocvars].varname = varname; luaC_objbarrier(ls->L, f, varname); return fs->nlocvars++; } static void new_localvar (LexState *ls, TString *name) { FuncState *fs = ls->fs; Dyndata *dyd = ls->dyd; int reg = registerlocalvar(ls, name); checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, MAXVARS, "local variables"); luaM_growvector(ls->L, dyd->actvar.arr, dyd->actvar.n + 1, dyd->actvar.size, Vardesc, MAX_INT, "local variables"); dyd->actvar.arr[dyd->actvar.n++].idx = cast(short, reg); } static void new_localvarliteral_ (LexState *ls, const char *name, size_t sz) { new_localvar(ls, luaX_newstring(ls, name, sz)); } #define new_localvarliteral(ls,v) \ new_localvarliteral_(ls, "" v, (sizeof(v)/sizeof(char))-1) static LocVar *getlocvar (FuncState *fs, int i) { int idx = fs->ls->dyd->actvar.arr[fs->firstlocal + i].idx; lua_assert(idx < fs->nlocvars); return &fs->f->locvars[idx]; } static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; fs->nactvar = cast_byte(fs->nactvar + nvars); for (; nvars; nvars--) { getlocvar(fs, fs->nactvar - nvars)->startpc = fs->pc; } } static void removevars (FuncState *fs, int tolevel) { fs->ls->dyd->actvar.n -= (fs->nactvar - tolevel); while (fs->nactvar > tolevel) getlocvar(fs, --fs->nactvar)->endpc = fs->pc; } static int searchupvalue (FuncState *fs, TString *name) { int i; Upvaldesc *up = fs->f->upvalues; for (i = 0; i < fs->nups; i++) { if (eqstr(up[i].name, name)) return i; } return -1; /* not found */ } static int newupvalue (FuncState *fs, TString *name, expdesc *v) { Proto *f = fs->f; int oldsize = f->sizeupvalues; checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues"); luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues, Upvaldesc, MAXUPVAL, "upvalues"); while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL; f->upvalues[fs->nups].instack = (v->k == VLOCAL); f->upvalues[fs->nups].idx = cast_byte(v->u.info); f->upvalues[fs->nups].name = name; luaC_objbarrier(fs->ls->L, f, name); return fs->nups++; } static int searchvar (FuncState *fs, TString *n) { int i; for (i = cast_int(fs->nactvar) - 1; i >= 0; i--) { if (eqstr(n, getlocvar(fs, i)->varname)) return i; } return -1; /* not found */ } /* Mark block where variable at given level was defined (to emit close instructions later). */ static void markupval (FuncState *fs, int level) { BlockCnt *bl = fs->bl; while (bl->nactvar > level) bl = bl->previous; bl->upval = 1; } /* Find variable with given name 'n'. If it is an upvalue, add this upvalue into all intermediate functions. */ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) { if (fs == NULL) /* no more levels? */ return VVOID; /* default is global */ else { int v = searchvar(fs, n); /* look up locals at current level */ if (v >= 0) { /* found? */ init_exp(var, VLOCAL, v); /* variable is local */ if (!base) markupval(fs, v); /* local will be used as an upval */ return VLOCAL; } else { /* not found as local at current level; try upvalues */ int idx = searchupvalue(fs, n); /* try existing upvalues */ if (idx < 0) { /* not found? */ if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */ return VVOID; /* not found; is a global */ /* else was LOCAL or UPVAL */ idx = newupvalue(fs, n, var); /* will be a new upvalue */ } init_exp(var, VUPVAL, idx); return VUPVAL; } } } static void singlevar (LexState *ls, expdesc *var) { TString *varname = str_checkname(ls); FuncState *fs = ls->fs; if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */ expdesc key; singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ lua_assert(var->k == VLOCAL || var->k == VUPVAL); codestring(ls, &key, varname); /* key is variable name */ luaK_indexed(fs, var, &key); /* env[varname] */ } } static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { FuncState *fs = ls->fs; int extra = nvars - nexps; if (hasmultret(e->k)) { extra++; /* includes call itself */ if (extra < 0) extra = 0; luaK_setreturns(fs, e, extra); /* last exp. provides the difference */ if (extra > 1) luaK_reserveregs(fs, extra-1); } else { if (e->k != VVOID) luaK_exp2nextreg(fs, e); /* close last expression */ if (extra > 0) { int reg = fs->freereg; luaK_reserveregs(fs, extra); luaK_nil(fs, reg, extra); } } } static void enterlevel (LexState *ls) { lua_State *L = ls->L; ++L->nCcalls; checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); } #define leavelevel(ls) ((ls)->L->nCcalls--) static void closegoto (LexState *ls, int g, Labeldesc *label) { int i; FuncState *fs = ls->fs; Labellist *gl = &ls->dyd->gt; Labeldesc *gt = &gl->arr[g]; lua_assert(eqstr(gt->name, label->name)); if (gt->nactvar < label->nactvar) { TString *vname = getlocvar(fs, gt->nactvar)->varname; const char *msg = luaO_pushfstring(ls->L, "<goto %s> at line %d jumps into the scope of local '%s'", getstr(gt->name), gt->line, getstr(vname)); semerror(ls, msg); } luaK_patchlist(fs, gt->pc, label->pc); /* remove goto from pending list */ for (i = g; i < gl->n - 1; i++) gl->arr[i] = gl->arr[i + 1]; gl->n--; } /* ** try to close a goto with existing labels; this solves backward jumps */ static int findlabel (LexState *ls, int g) { int i; BlockCnt *bl = ls->fs->bl; Dyndata *dyd = ls->dyd; Labeldesc *gt = &dyd->gt.arr[g]; /* check labels in current block for a match */ for (i = bl->firstlabel; i < dyd->label.n; i++) { Labeldesc *lb = &dyd->label.arr[i]; if (eqstr(lb->name, gt->name)) { /* correct label? */ if (gt->nactvar > lb->nactvar && (bl->upval || dyd->label.n > bl->firstlabel)) luaK_patchclose(ls->fs, gt->pc, lb->nactvar); closegoto(ls, g, lb); /* close it */ return 1; } } return 0; /* label not found; cannot close goto */ } static int newlabelentry (LexState *ls, Labellist *l, TString *name, int line, int pc) { int n = l->n; luaM_growvector(ls->L, l->arr, n, l->size, Labeldesc, SHRT_MAX, "labels/gotos"); l->arr[n].name = name; l->arr[n].line = line; l->arr[n].nactvar = ls->fs->nactvar; l->arr[n].pc = pc; l->n = n + 1; return n; } /* ** check whether new label 'lb' matches any pending gotos in current ** block; solves forward jumps */ static void findgotos (LexState *ls, Labeldesc *lb) { Labellist *gl = &ls->dyd->gt; int i = ls->fs->bl->firstgoto; while (i < gl->n) { if (eqstr(gl->arr[i].name, lb->name)) closegoto(ls, i, lb); else i++; } } /* ** export pending gotos to outer level, to check them against ** outer labels; if the block being exited has upvalues, and ** the goto exits the scope of any variable (which can be the ** upvalue), close those variables being exited. */ static void movegotosout (FuncState *fs, BlockCnt *bl) { int i = bl->firstgoto; Labellist *gl = &fs->ls->dyd->gt; /* correct pending gotos to current block and try to close it with visible labels */ while (i < gl->n) { Labeldesc *gt = &gl->arr[i]; if (gt->nactvar > bl->nactvar) { if (bl->upval) luaK_patchclose(fs, gt->pc, bl->nactvar); gt->nactvar = bl->nactvar; } if (!findlabel(fs->ls, i)) i++; /* move to next one */ } } static void enterblock (FuncState *fs, BlockCnt *bl, lu_byte isloop) { bl->isloop = isloop; bl->nactvar = fs->nactvar; bl->firstlabel = fs->ls->dyd->label.n; bl->firstgoto = fs->ls->dyd->gt.n; bl->upval = 0; bl->previous = fs->bl; fs->bl = bl; lua_assert(fs->freereg == fs->nactvar); } /* ** create a label named 'break' to resolve break statements */ static void breaklabel (LexState *ls) { TString *n = luaS_new(ls->L, "break"); int l = newlabelentry(ls, &ls->dyd->label, n, 0, ls->fs->pc); findgotos(ls, &ls->dyd->label.arr[l]); } /* ** generates an error for an undefined 'goto'; choose appropriate ** message when label name is a reserved word (which can only be 'break') */ static l_noret undefgoto (LexState *ls, Labeldesc *gt) { const char *msg = isreserved(gt->name) ? "<%s> at line %d not inside a loop" : "no visible label '%s' for <goto> at line %d"; msg = luaO_pushfstring(ls->L, msg, getstr(gt->name), gt->line); semerror(ls, msg); } static void leaveblock (FuncState *fs) { BlockCnt *bl = fs->bl; LexState *ls = fs->ls; if (bl->previous && bl->upval) { /* create a 'jump to here' to close upvalues */ int j = luaK_jump(fs); luaK_patchclose(fs, j, bl->nactvar); luaK_patchtohere(fs, j); } if (bl->isloop) breaklabel(ls); /* close pending breaks */ fs->bl = bl->previous; removevars(fs, bl->nactvar); lua_assert(bl->nactvar == fs->nactvar); fs->freereg = fs->nactvar; /* free registers */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */ if (bl->previous) /* inner block? */ movegotosout(fs, bl); /* update pending gotos to outer block */ else if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ } /* ** adds a new prototype into list of prototypes */ static Proto *addprototype (LexState *ls) { Proto *clp; lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; /* prototype of current function */ if (fs->np >= f->sizep) { int oldsize = f->sizep; luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions"); while (oldsize < f->sizep) f->p[oldsize++] = NULL; } f->p[fs->np++] = clp = luaF_newproto(L); luaC_objbarrier(L, f, clp); return clp; } /* ** codes instruction to create new closure in parent function. ** The OP_CLOSURE instruction must use the last available register, ** so that, if it invokes the GC, the GC knows which registers ** are in use at that time. */ static void codeclosure (LexState *ls, expdesc *v) { FuncState *fs = ls->fs->prev; init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); luaK_exp2nextreg(fs, v); /* fix it at the last register */ } static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { Proto *f; fs->prev = ls->fs; /* linked list of funcstates */ fs->ls = ls; ls->fs = fs; fs->pc = 0; fs->lasttarget = 0; fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; fs->np = 0; fs->nups = 0; fs->nlocvars = 0; fs->nactvar = 0; fs->firstlocal = ls->dyd->actvar.n; fs->bl = NULL; f = fs->f; f->source = ls->source; f->maxstacksize = 2; /* registers 0/1 are always valid */ enterblock(fs, bl, 0); } static void close_func (LexState *ls) { lua_State *L = ls->L; FuncState *fs = ls->fs; Proto *f = fs->f; luaK_ret(fs, 0, 0); /* final return */ leaveblock(fs); luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); f->sizecode = fs->pc; luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, int); f->sizelineinfo = fs->pc; luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); f->sizek = fs->nk; luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); f->sizep = fs->np; luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); f->sizelocvars = fs->nlocvars; luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); f->sizeupvalues = fs->nups; lua_assert(fs->bl == NULL); ls->fs = fs->prev; luaC_checkGC(L); } /*============================================================*/ /* GRAMMAR RULES */ /*============================================================*/ /* ** check whether current token is in the follow set of a block. ** 'until' closes syntactical blocks, but do not close scope, ** so it is handled in separate. */ static int block_follow (LexState *ls, int withuntil) { switch (ls->t.token) { case TK_ELSE: case TK_ELSEIF: case TK_END: case TK_EOS: return 1; case TK_UNTIL: return withuntil; default: return 0; } } static void statlist (LexState *ls) { /* statlist -> { stat [';'] } */ while (!block_follow(ls, 1)) { if (ls->t.token == TK_RETURN) { statement(ls); return; /* 'return' must be last statement */ } statement(ls); } } static void fieldsel (LexState *ls, expdesc *v) { /* fieldsel -> ['.' | ':'] NAME */ FuncState *fs = ls->fs; expdesc key; luaK_exp2anyregup(fs, v); luaX_next(ls); /* skip the dot or colon */ checkname(ls, &key); luaK_indexed(fs, v, &key); } static void yindex (LexState *ls, expdesc *v) { /* index -> '[' expr ']' */ luaX_next(ls); /* skip the '[' */ expr(ls, v); luaK_exp2val(ls->fs, v); checknext(ls, ']'); } /* ** {====================================================================== ** Rules for Constructors ** ======================================================================= */ struct ConsControl { expdesc v; /* last list item read */ expdesc *t; /* table descriptor */ int nh; /* total number of 'record' elements */ int na; /* total number of array elements */ int tostore; /* number of array elements pending to be stored */ }; static void recfield (LexState *ls, struct ConsControl *cc) { /* recfield -> (NAME | '['exp1']') = exp1 */ FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc key, val; int rkkey; if (ls->t.token == TK_NAME) { checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); checkname(ls, &key); } else /* ls->t.token == '[' */ yindex(ls, &key); cc->nh++; checknext(ls, '='); rkkey = luaK_exp2RK(fs, &key); expr(ls, &val); luaK_codeABC(fs, OP_SETTABLE, cc->t->u.info, rkkey, luaK_exp2RK(fs, &val)); fs->freereg = reg; /* free registers */ } static void closelistfield (FuncState *fs, struct ConsControl *cc) { if (cc->v.k == VVOID) return; /* there is no list item */ luaK_exp2nextreg(fs, &cc->v); cc->v.k = VVOID; if (cc->tostore == LFIELDS_PER_FLUSH) { luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); /* flush */ cc->tostore = 0; /* no more items pending */ } } static void lastlistfield (FuncState *fs, struct ConsControl *cc) { if (cc->tostore == 0) return; if (hasmultret(cc->v.k)) { luaK_setmultret(fs, &cc->v); luaK_setlist(fs, cc->t->u.info, cc->na, LUA_MULTRET); cc->na--; /* do not count last expression (unknown number of elements) */ } else { if (cc->v.k != VVOID) luaK_exp2nextreg(fs, &cc->v); luaK_setlist(fs, cc->t->u.info, cc->na, cc->tostore); } } static void listfield (LexState *ls, struct ConsControl *cc) { /* listfield -> exp */ expr(ls, &cc->v); checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor"); cc->na++; cc->tostore++; } static void field (LexState *ls, struct ConsControl *cc) { /* field -> listfield | recfield */ switch(ls->t.token) { case TK_NAME: { /* may be 'listfield' or 'recfield' */ if (luaX_lookahead(ls) != '=') /* expression? */ listfield(ls, cc); else recfield(ls, cc); break; } case '[': { recfield(ls, cc); break; } default: { listfield(ls, cc); break; } } } static void constructor (LexState *ls, expdesc *t) { /* constructor -> '{' [ field { sep field } [sep] ] '}' sep -> ',' | ';' */ FuncState *fs = ls->fs; int line = ls->linenumber; int pc = luaK_codeABC(fs, OP_NEWTABLE, 0, 0, 0); struct ConsControl cc; cc.na = cc.nh = cc.tostore = 0; cc.t = t; init_exp(t, VRELOCABLE, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ checknext(ls, '{'); do { lua_assert(cc.v.k == VVOID || cc.tostore > 0); if (ls->t.token == '}') break; closelistfield(fs, &cc); field(ls, &cc); } while (testnext(ls, ',') || testnext(ls, ';')); check_match(ls, '}', '{', line); lastlistfield(fs, &cc); SETARG_B(fs->f->code[pc], luaO_int2fb(cc.na)); /* set initial array size */ SETARG_C(fs->f->code[pc], luaO_int2fb(cc.nh)); /* set initial table size */ } /* }====================================================================== */ static void parlist (LexState *ls) { /* parlist -> [ param { ',' param } ] */ FuncState *fs = ls->fs; Proto *f = fs->f; int nparams = 0; f->is_vararg = 0; if (ls->t.token != ')') { /* is 'parlist' not empty? */ do { switch (ls->t.token) { case TK_NAME: { /* param -> NAME */ new_localvar(ls, str_checkname(ls)); nparams++; break; } case TK_DOTS: { /* param -> '...' */ luaX_next(ls); f->is_vararg = 2; /* declared vararg */ break; } default: luaX_syntaxerror(ls, "<name> or '...' expected"); } } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); f->numparams = cast_byte(fs->nactvar); luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } static void body (LexState *ls, expdesc *e, int ismethod, int line) { /* body -> '(' parlist ')' block END */ FuncState new_fs; BlockCnt bl; new_fs.f = addprototype(ls); new_fs.f->linedefined = line; open_func(ls, &new_fs, &bl); checknext(ls, '('); if (ismethod) { new_localvarliteral(ls, "self"); /* create 'self' parameter */ adjustlocalvars(ls, 1); } parlist(ls); checknext(ls, ')'); statlist(ls); new_fs.f->lastlinedefined = ls->linenumber; check_match(ls, TK_END, TK_FUNCTION, line); codeclosure(ls, e); close_func(ls); } static int explist (LexState *ls, expdesc *v) { /* explist -> expr { ',' expr } */ int n = 1; /* at least one expression */ expr(ls, v); while (testnext(ls, ',')) { luaK_exp2nextreg(ls->fs, v); expr(ls, v); n++; } return n; } static void funcargs (LexState *ls, expdesc *f, int line) { FuncState *fs = ls->fs; expdesc args; int base, nparams; switch (ls->t.token) { case '(': { /* funcargs -> '(' [ explist ] ')' */ luaX_next(ls); if (ls->t.token == ')') /* arg list is empty? */ args.k = VVOID; else { explist(ls, &args); luaK_setmultret(fs, &args); } check_match(ls, ')', '(', line); break; } case '{': { /* funcargs -> constructor */ constructor(ls, &args); break; } case TK_STRING: { /* funcargs -> STRING */ codestring(ls, &args, ls->t.seminfo.ts); luaX_next(ls); /* must use 'seminfo' before 'next' */ break; } default: { luaX_syntaxerror(ls, "function arguments expected"); } } lua_assert(f->k == VNONRELOC); base = f->u.info; /* base register for call */ if (hasmultret(args.k)) nparams = LUA_MULTRET; /* open call */ else { if (args.k != VVOID) luaK_exp2nextreg(fs, &args); /* close last argument */ nparams = fs->freereg - (base+1); } init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); luaK_fixline(fs, line); fs->freereg = base+1; /* call remove function and arguments and leaves (unless changed) one result */ } /* ** {====================================================================== ** Expression parsing ** ======================================================================= */ static void primaryexp (LexState *ls, expdesc *v) { /* primaryexp -> NAME | '(' expr ')' */ switch (ls->t.token) { case '(': { int line = ls->linenumber; luaX_next(ls); expr(ls, v); check_match(ls, ')', '(', line); luaK_dischargevars(ls->fs, v); return; } case TK_NAME: { singlevar(ls, v); return; } default: { luaX_syntaxerror(ls, "unexpected symbol"); } } } static void suffixedexp (LexState *ls, expdesc *v) { /* suffixedexp -> primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; int line = ls->linenumber; primaryexp(ls, v); for (;;) { switch (ls->t.token) { case '.': { /* fieldsel */ fieldsel(ls, v); break; } case '[': { /* '[' exp1 ']' */ expdesc key; luaK_exp2anyregup(fs, v); yindex(ls, &key); luaK_indexed(fs, v, &key); break; } case ':': { /* ':' NAME funcargs */ expdesc key; luaX_next(ls); checkname(ls, &key); luaK_self(fs, v, &key); funcargs(ls, v, line); break; } case '(': case TK_STRING: case '{': { /* funcargs */ luaK_exp2nextreg(fs, v); funcargs(ls, v, line); break; } default: return; } } } static void simpleexp (LexState *ls, expdesc *v) { /* simpleexp -> FLT | INT | STRING | NIL | TRUE | FALSE | ... | constructor | FUNCTION body | suffixedexp */ switch (ls->t.token) { case TK_FLT: { init_exp(v, VKFLT, 0); v->u.nval = ls->t.seminfo.r; break; } case TK_INT: { init_exp(v, VKINT, 0); v->u.ival = ls->t.seminfo.i; break; } case TK_STRING: { codestring(ls, v, ls->t.seminfo.ts); break; } case TK_NIL: { init_exp(v, VNIL, 0); break; } case TK_TRUE: { init_exp(v, VTRUE, 0); break; } case TK_FALSE: { init_exp(v, VFALSE, 0); break; } case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; check_condition(ls, fs->f->is_vararg, "cannot use '...' outside a vararg function"); fs->f->is_vararg = 1; /* function actually uses vararg */ init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0)); break; } case '{': { /* constructor */ constructor(ls, v); return; } case TK_FUNCTION: { luaX_next(ls); body(ls, v, 0, ls->linenumber); return; } default: { suffixedexp(ls, v); return; } } luaX_next(ls); } static UnOpr getunopr (int op) { switch (op) { case TK_NOT: return OPR_NOT; case '-': return OPR_MINUS; case '~': return OPR_BNOT; case '#': return OPR_LEN; default: return OPR_NOUNOPR; } } static BinOpr getbinopr (int op) { switch (op) { case '+': return OPR_ADD; case '-': return OPR_SUB; case '*': return OPR_MUL; case '%': return OPR_MOD; case '^': return OPR_POW; case '/': return OPR_DIV; case TK_IDIV: return OPR_IDIV; case '&': return OPR_BAND; case '|': return OPR_BOR; case '~': return OPR_BXOR; case TK_SHL: return OPR_SHL; case TK_SHR: return OPR_SHR; case TK_CONCAT: return OPR_CONCAT; case TK_NE: return OPR_NE; case TK_EQ: return OPR_EQ; case '<': return OPR_LT; case TK_LE: return OPR_LE; case '>': return OPR_GT; case TK_GE: return OPR_GE; case TK_AND: return OPR_AND; case TK_OR: return OPR_OR; default: return OPR_NOBINOPR; } } static const struct { lu_byte left; /* left priority for each binary operator */ lu_byte right; /* right priority */ } priority[] = { /* ORDER OPR */ {10, 10}, {10, 10}, /* '+' '-' */ {11, 11}, {11, 11}, /* '*' '%' */ {14, 13}, /* '^' (right associative) */ {11, 11}, {11, 11}, /* '/' '//' */ {6, 6}, {4, 4}, {5, 5}, /* '&' '|' '~' */ {7, 7}, {7, 7}, /* '<<' '>>' */ {9, 8}, /* '..' (right associative) */ {3, 3}, {3, 3}, {3, 3}, /* ==, <, <= */ {3, 3}, {3, 3}, {3, 3}, /* ~=, >, >= */ {2, 2}, {1, 1} /* and, or */ }; #define UNARY_PRIORITY 12 /* priority for unary operators */ /* ** subexpr -> (simpleexp | unop subexpr) { binop subexpr } ** where 'binop' is any binary operator with a priority higher than 'limit' */ static BinOpr subexpr (LexState *ls, expdesc *v, int limit) { BinOpr op; UnOpr uop; enterlevel(ls); uop = getunopr(ls->t.token); if (uop != OPR_NOUNOPR) { int line = ls->linenumber; luaX_next(ls); subexpr(ls, v, UNARY_PRIORITY); luaK_prefix(ls->fs, uop, v, line); } else simpleexp(ls, v); /* expand while operators have priorities higher than 'limit' */ op = getbinopr(ls->t.token); while (op != OPR_NOBINOPR && priority[op].left > limit) { expdesc v2; BinOpr nextop; int line = ls->linenumber; luaX_next(ls); luaK_infix(ls->fs, op, v); /* read sub-expression with higher priority */ nextop = subexpr(ls, &v2, priority[op].right); luaK_posfix(ls->fs, op, v, &v2, line); op = nextop; } leavelevel(ls); return op; /* return first untreated operator */ } static void expr (LexState *ls, expdesc *v) { subexpr(ls, v, 0); } /* }==================================================================== */ /* ** {====================================================================== ** Rules for Statements ** ======================================================================= */ static void block (LexState *ls) { /* block -> statlist */ FuncState *fs = ls->fs; BlockCnt bl; enterblock(fs, &bl, 0); statlist(ls); leaveblock(fs); } /* ** structure to chain all variables in the left-hand side of an ** assignment */ struct LHS_assign { struct LHS_assign *prev; expdesc v; /* variable (global, local, upvalue, or indexed) */ }; /* ** check whether, in an assignment to an upvalue/local variable, the ** upvalue/local variable is begin used in a previous assignment to a ** table. If so, save original upvalue/local value in a safe place and ** use this safe copy in the previous assignment. */ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { FuncState *fs = ls->fs; int extra = fs->freereg; /* eventual position to save local variable */ int conflict = 0; for (; lh; lh = lh->prev) { /* check all previous assignments */ if (lh->v.k == VINDEXED) { /* assigning to a table? */ /* table is the upvalue/local being assigned now? */ if (lh->v.u.ind.vt == v->k && lh->v.u.ind.t == v->u.info) { conflict = 1; lh->v.u.ind.vt = VLOCAL; lh->v.u.ind.t = extra; /* previous assignment will use safe copy */ } /* index is the local being assigned? (index cannot be upvalue) */ if (v->k == VLOCAL && lh->v.u.ind.idx == v->u.info) { conflict = 1; lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ } } } if (conflict) { /* copy upvalue/local value to a temporary (in position 'extra') */ OpCode op = (v->k == VLOCAL) ? OP_MOVE : OP_GETUPVAL; luaK_codeABC(fs, op, extra, v->u.info, 0); luaK_reserveregs(fs, 1); } } static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { expdesc e; check_condition(ls, vkisvar(lh->v.k), "syntax error"); if (testnext(ls, ',')) { /* assignment -> ',' suffixedexp assignment */ struct LHS_assign nv; nv.prev = lh; suffixedexp(ls, &nv.v); if (nv.v.k != VINDEXED) check_conflict(ls, lh, &nv.v); checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, "C levels"); assignment(ls, &nv, nvars+1); } else { /* assignment -> '=' explist */ int nexps; checknext(ls, '='); nexps = explist(ls, &e); if (nexps != nvars) { adjust_assign(ls, nvars, nexps, &e); if (nexps > nvars) ls->fs->freereg -= nexps - nvars; /* remove extra values */ } else { luaK_setoneret(ls->fs, &e); /* close last expression */ luaK_storevar(ls->fs, &lh->v, &e); return; /* avoid default */ } } init_exp(&e, VNONRELOC, ls->fs->freereg-1); /* default assignment */ luaK_storevar(ls->fs, &lh->v, &e); } static int cond (LexState *ls) { /* cond -> exp */ expdesc v; expr(ls, &v); /* read condition */ if (v.k == VNIL) v.k = VFALSE; /* 'falses' are all equal here */ luaK_goiftrue(ls->fs, &v); return v.f; } static void gotostat (LexState *ls, int pc) { int line = ls->linenumber; TString *label; int g; if (testnext(ls, TK_GOTO)) label = str_checkname(ls); else { luaX_next(ls); /* skip break */ label = luaS_new(ls->L, "break"); } g = newlabelentry(ls, &ls->dyd->gt, label, line, pc); findlabel(ls, g); /* close it if label already defined */ } /* check for repeated labels on the same block */ static void checkrepeated (FuncState *fs, Labellist *ll, TString *label) { int i; for (i = fs->bl->firstlabel; i < ll->n; i++) { if (eqstr(label, ll->arr[i].name)) { const char *msg = luaO_pushfstring(fs->ls->L, "label '%s' already defined on line %d", getstr(label), ll->arr[i].line); semerror(fs->ls, msg); } } } /* skip no-op statements */ static void skipnoopstat (LexState *ls) { while (ls->t.token == ';' || ls->t.token == TK_DBCOLON) statement(ls); } static void labelstat (LexState *ls, TString *label, int line) { /* label -> '::' NAME '::' */ FuncState *fs = ls->fs; Labellist *ll = &ls->dyd->label; int l; /* index of new label being created */ checkrepeated(fs, ll, label); /* check for repeated labels */ checknext(ls, TK_DBCOLON); /* skip double colon */ /* create new entry for this label */ l = newlabelentry(ls, ll, label, line, fs->pc); skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */ /* assume that locals are already out of scope */ ll->arr[l].nactvar = fs->bl->nactvar; } findgotos(ls, &ll->arr[l]); } static void whilestat (LexState *ls, int line) { /* whilestat -> WHILE cond DO block END */ FuncState *fs = ls->fs; int whileinit; int condexit; BlockCnt bl; luaX_next(ls); /* skip WHILE */ whileinit = luaK_getlabel(fs); condexit = cond(ls); enterblock(fs, &bl, 1); checknext(ls, TK_DO); block(ls); luaK_jumpto(fs, whileinit); check_match(ls, TK_END, TK_WHILE, line); leaveblock(fs); luaK_patchtohere(fs, condexit); /* false conditions finish the loop */ } static void repeatstat (LexState *ls, int line) { /* repeatstat -> REPEAT block UNTIL cond */ int condexit; FuncState *fs = ls->fs; int repeat_init = luaK_getlabel(fs); BlockCnt bl1, bl2; enterblock(fs, &bl1, 1); /* loop block */ enterblock(fs, &bl2, 0); /* scope block */ luaX_next(ls); /* skip REPEAT */ statlist(ls); check_match(ls, TK_UNTIL, TK_REPEAT, line); condexit = cond(ls); /* read condition (inside scope block) */ if (bl2.upval) /* upvalues? */ luaK_patchclose(fs, condexit, bl2.nactvar); leaveblock(fs); /* finish scope */ luaK_patchlist(fs, condexit, repeat_init); /* close the loop */ leaveblock(fs); /* finish loop */ } static int exp1 (LexState *ls) { expdesc e; int reg; expr(ls, &e); luaK_exp2nextreg(ls->fs, &e); lua_assert(e.k == VNONRELOC); reg = e.u.info; return reg; } static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; adjustlocalvars(ls, 3); /* control variables */ checknext(ls, TK_DO); prep = isnum ? luaK_codeAsBx(fs, OP_FORPREP, base, NO_JUMP) : luaK_jump(fs); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); block(ls); leaveblock(fs); /* end of scope for declared variables */ luaK_patchtohere(fs, prep); if (isnum) /* numeric for? */ endfor = luaK_codeAsBx(fs, OP_FORLOOP, base, NO_JUMP); else { /* generic for */ luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); luaK_fixline(fs, line); endfor = luaK_codeAsBx(fs, OP_TFORLOOP, base + 2, NO_JUMP); } luaK_patchlist(fs, endfor, prep + 1); luaK_fixline(fs, line); } static void fornum (LexState *ls, TString *varname, int line) { /* fornum -> NAME = exp1,exp1[,exp1] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; new_localvarliteral(ls, "(for index)"); new_localvarliteral(ls, "(for limit)"); new_localvarliteral(ls, "(for step)"); new_localvar(ls, varname); checknext(ls, '='); exp1(ls); /* initial value */ checknext(ls, ','); exp1(ls); /* limit */ if (testnext(ls, ',')) exp1(ls); /* optional step */ else { /* default step = 1 */ luaK_codek(fs, fs->freereg, luaK_intK(fs, 1)); luaK_reserveregs(fs, 1); } forbody(ls, base, line, 1, 1); } static void forlist (LexState *ls, TString *indexname) { /* forlist -> NAME {,NAME} IN explist forbody */ FuncState *fs = ls->fs; expdesc e; int nvars = 4; /* gen, state, control, plus at least one declared var */ int line; int base = fs->freereg; /* create control variables */ new_localvarliteral(ls, "(for generator)"); new_localvarliteral(ls, "(for state)"); new_localvarliteral(ls, "(for control)"); /* create declared variables */ new_localvar(ls, indexname); while (testnext(ls, ',')) { new_localvar(ls, str_checkname(ls)); nvars++; } checknext(ls, TK_IN); line = ls->linenumber; adjust_assign(ls, 3, explist(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 3, 0); } static void forstat (LexState *ls, int line) { /* forstat -> FOR (fornum | forlist) END */ FuncState *fs = ls->fs; TString *varname; BlockCnt bl; enterblock(fs, &bl, 1); /* scope for loop and control variables */ luaX_next(ls); /* skip 'for' */ varname = str_checkname(ls); /* first variable name */ switch (ls->t.token) { case '=': fornum(ls, varname, line); break; case ',': case TK_IN: forlist(ls, varname); break; default: luaX_syntaxerror(ls, "'=' or 'in' expected"); } check_match(ls, TK_END, TK_FOR, line); leaveblock(fs); /* loop scope ('break' jumps to this point) */ } static void test_then_block (LexState *ls, int *escapelist) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ BlockCnt bl; FuncState *fs = ls->fs; expdesc v; int jf; /* instruction to skip 'then' code (if condition is false) */ luaX_next(ls); /* skip IF or ELSEIF */ expr(ls, &v); /* read condition */ checknext(ls, TK_THEN); if (ls->t.token == TK_GOTO || ls->t.token == TK_BREAK) { luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ enterblock(fs, &bl, 0); /* must enter block before 'goto' */ gotostat(ls, v.t); /* handle goto/break */ skipnoopstat(ls); /* skip other no-op statements */ if (block_follow(ls, 0)) { /* 'goto' is the entire block? */ leaveblock(fs); return; /* and that is it */ } else /* must skip over 'then' part if condition is false */ jf = luaK_jump(fs); } else { /* regular case (not goto/break) */ luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ enterblock(fs, &bl, 0); jf = v.f; } statlist(ls); /* 'then' part */ leaveblock(fs); if (ls->t.token == TK_ELSE || ls->t.token == TK_ELSEIF) /* followed by 'else'/'elseif'? */ luaK_concat(fs, escapelist, luaK_jump(fs)); /* must jump over it */ luaK_patchtohere(fs, jf); } static void ifstat (LexState *ls, int line) { /* ifstat -> IF cond THEN block {ELSEIF cond THEN block} [ELSE block] END */ FuncState *fs = ls->fs; int escapelist = NO_JUMP; /* exit list for finished parts */ test_then_block(ls, &escapelist); /* IF cond THEN block */ while (ls->t.token == TK_ELSEIF) test_then_block(ls, &escapelist); /* ELSEIF cond THEN block */ if (testnext(ls, TK_ELSE)) block(ls); /* 'else' part */ check_match(ls, TK_END, TK_IF, line); luaK_patchtohere(fs, escapelist); /* patch escape list to 'if' end */ } static void localfunc (LexState *ls) { expdesc b; FuncState *fs = ls->fs; new_localvar(ls, str_checkname(ls)); /* new local variable */ adjustlocalvars(ls, 1); /* enter its scope */ body(ls, &b, 0, ls->linenumber); /* function created in next register */ /* debug information will only see the variable after this point! */ getlocvar(fs, b.u.info)->startpc = fs->pc; } static void localstat (LexState *ls) { /* stat -> LOCAL NAME {',' NAME} ['=' explist] */ int nvars = 0; int nexps; expdesc e; do { new_localvar(ls, str_checkname(ls)); nvars++; } while (testnext(ls, ',')); if (testnext(ls, '=')) nexps = explist(ls, &e); else { e.k = VVOID; nexps = 0; } adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } static int funcname (LexState *ls, expdesc *v) { /* funcname -> NAME {fieldsel} [':' NAME] */ int ismethod = 0; singlevar(ls, v); while (ls->t.token == '.') fieldsel(ls, v); if (ls->t.token == ':') { ismethod = 1; fieldsel(ls, v); } return ismethod; } static void funcstat (LexState *ls, int line) { /* funcstat -> FUNCTION funcname body */ int ismethod; expdesc v, b; luaX_next(ls); /* skip FUNCTION */ ismethod = funcname(ls, &v); body(ls, &b, ismethod, line); luaK_storevar(ls->fs, &v, &b); luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ } static void exprstat (LexState *ls) { /* stat -> func | assignment */ FuncState *fs = ls->fs; struct LHS_assign v; suffixedexp(ls, &v.v); if (ls->t.token == '=' || ls->t.token == ',') { /* stat -> assignment ? */ v.prev = NULL; assignment(ls, &v, 1); } else { /* stat -> func */ check_condition(ls, v.v.k == VCALL, "syntax error"); SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */ } } static void retstat (LexState *ls) { /* stat -> RETURN [explist] [';'] */ FuncState *fs = ls->fs; expdesc e; int first, nret; /* registers with returned values */ if (block_follow(ls, 1) || ls->t.token == ';') first = nret = 0; /* return no values */ else { nret = explist(ls, &e); /* optional return values */ if (hasmultret(e.k)) { luaK_setmultret(fs, &e); if (e.k == VCALL && nret == 1) { /* tail call? */ SET_OPCODE(getcode(fs,&e), OP_TAILCALL); lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar); } first = fs->nactvar; nret = LUA_MULTRET; /* return all values */ } else { if (nret == 1) /* only one single value? */ first = luaK_exp2anyreg(fs, &e); else { luaK_exp2nextreg(fs, &e); /* values must go to the stack */ first = fs->nactvar; /* return all active values */ lua_assert(nret == fs->freereg - first); } } } luaK_ret(fs, first, nret); testnext(ls, ';'); /* skip optional semicolon */ } static void statement (LexState *ls) { int line = ls->linenumber; /* may be needed for error messages */ enterlevel(ls); switch (ls->t.token) { case ';': { /* stat -> ';' (empty statement) */ luaX_next(ls); /* skip ';' */ break; } case TK_IF: { /* stat -> ifstat */ ifstat(ls, line); break; } case TK_WHILE: { /* stat -> whilestat */ whilestat(ls, line); break; } case TK_DO: { /* stat -> DO block END */ luaX_next(ls); /* skip DO */ block(ls); check_match(ls, TK_END, TK_DO, line); break; } case TK_FOR: { /* stat -> forstat */ forstat(ls, line); break; } case TK_REPEAT: { /* stat -> repeatstat */ repeatstat(ls, line); break; } case TK_FUNCTION: { /* stat -> funcstat */ funcstat(ls, line); break; } case TK_LOCAL: { /* stat -> localstat */ luaX_next(ls); /* skip LOCAL */ if (testnext(ls, TK_FUNCTION)) /* local function? */ localfunc(ls); else localstat(ls); break; } case TK_DBCOLON: { /* stat -> label */ luaX_next(ls); /* skip double colon */ labelstat(ls, str_checkname(ls), line); break; } case TK_RETURN: { /* stat -> retstat */ luaX_next(ls); /* skip RETURN */ retstat(ls); break; } case TK_BREAK: /* stat -> breakstat */ case TK_GOTO: { /* stat -> 'goto' NAME */ gotostat(ls, luaK_jump(ls->fs)); break; } default: { /* stat -> func | assignment */ exprstat(ls); break; } } lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg && ls->fs->freereg >= ls->fs->nactvar); ls->fs->freereg = ls->fs->nactvar; /* free registers */ leavelevel(ls); } /* }====================================================================== */ /* ** compiles the main function, which is a regular vararg function with an ** upvalue named LUA_ENV */ static void mainfunc (LexState *ls, FuncState *fs) { BlockCnt bl; expdesc v; open_func(ls, fs, &bl); fs->f->is_vararg = 2; /* main function is always declared vararg */ init_exp(&v, VLOCAL, 0); /* create and... */ newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */ luaX_next(ls); /* read first token */ statlist(ls); /* parse main body */ check(ls, TK_EOS); close_func(ls); } LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff, Dyndata *dyd, const char *name, int firstchar) { LexState lexstate; FuncState funcstate; LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */ luaD_inctop(L); lexstate.h = luaH_new(L); /* create table for scanner */ sethvalue(L, L->top, lexstate.h); /* anchor it */ luaD_inctop(L); funcstate.f = cl->p = luaF_newproto(L); funcstate.f->source = luaS_new(L, name); /* create and anchor TString */ lua_assert(iswhite(funcstate.f)); /* do not need barrier here */ lexstate.buff = buff; lexstate.dyd = dyd; dyd->actvar.n = dyd->gt.n = dyd->label.n = 0; luaX_setinput(L, &lexstate, z, funcstate.f->source, firstchar); mainfunc(&lexstate, &funcstate); lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); /* all scopes should be correctly finished */ lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); L->top--; /* remove scanner's table */ return cl; /* closure is on the stack, too */ } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/lstring.h�������������������������������������������������������������������������0000644�0001751�0001751�00000002653�12675241401�012645� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ #ifndef lstring_h #define lstring_h #include "lgc.h" #include "lobject.h" #include "lstate.h" #define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char)) #define sizeludata(l) (sizeof(union UUdata) + (l)) #define sizeudata(u) sizeludata((u)->len) #define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \ (sizeof(s)/sizeof(char))-1)) /* ** test whether a string is a reserved word */ #define isreserved(s) ((s)->tt == LUA_TSHRSTR && (s)->extra > 0) /* ** equality for short strings, which are always internalized */ #define eqshrstr(a,b) check_exp((a)->tt == LUA_TSHRSTR, (a) == (b)) LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed); LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts); LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b); LUAI_FUNC void luaS_resize (lua_State *L, int newsize); LUAI_FUNC void luaS_clearcache (global_State *g); LUAI_FUNC void luaS_init (lua_State *L); LUAI_FUNC void luaS_remove (lua_State *L, TString *ts); LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s); LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l); LUAI_FUNC TString *luaS_new (lua_State *L, const char *str); LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l); #endif �������������������������������������������������������������������������������������golly-2.8-src/lua/ltable.h��������������������������������������������������������������������������0000644�0001751�0001751�00000003525�12675241401�012425� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ltable.h,v 2.21 2015/11/03 15:47:30 roberto Exp $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ #ifndef ltable_h #define ltable_h #include "lobject.h" #define gnode(t,i) (&(t)->node[i]) #define gval(n) (&(n)->i_val) #define gnext(n) ((n)->i_key.nk.next) /* 'const' to avoid wrong writings that can mess up field 'next' */ #define gkey(n) cast(const TValue*, (&(n)->i_key.tvk)) /* ** writable version of 'gkey'; allows updates to individual fields, ** but not to the whole (which has incompatible type) */ #define wgkey(n) (&(n)->i_key.nk) #define invalidateTMcache(t) ((t)->flags = 0) /* returns the key, given the value of a table entry */ #define keyfromval(v) \ (gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val)))) LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key); LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value); LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); LUAI_FUNC Table *luaH_new (lua_State *L); LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, unsigned int nhsize); LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); LUAI_FUNC int luaH_getn (Table *t); #if defined(LUA_DEBUG) LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); LUAI_FUNC int luaH_isdummy (Node *n); #endif #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������golly-2.8-src/lua/ltablib.c�������������������������������������������������������������������������0000644�0001751�0001751�00000032704�12675241401�012567� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* ** $Id: ltablib.c,v 1.90 2015/11/25 12:48:57 roberto Exp $ ** Library for Table Manipulation ** See Copyright Notice in lua.h */ #define ltablib_c #define LUA_LIB #include "lprefix.h" #include <limits.h> #include <stddef.h> #include <string.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" /* ** Operations that an object must define to mimic a table ** (some functions only need some of them) */ #define TAB_R 1 /* read */ #define TAB_W 2 /* write */ #define TAB_L 4 /* length */ #define TAB_RW (TAB_R | TAB_W) /* read/write */ #define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n)) static int checkfield (lua_State *L, const char *key, int n) { lua_pushstring(L, key); return (lua_rawget(L, -n) != LUA_TNIL); } /* ** Check that 'arg' either is a table or can behave like one (that is, ** has a metatable with the required metamethods) */ static void checktab (lua_State *L, int arg, int what) { if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */ int n = 1; /* number of elements to pop */ if (lua_getmetatable(L, arg) && /* must have metatable */ (!(what & TAB_R) || checkfield(L, "__index", ++n)) && (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) && (!(what & TAB_L) || checkfield(L, "__len", ++n))) { lua_pop(L, n); /* pop metatable and tested metamethods */ } else luaL_argerror(L, arg, "table expected"); /* force an error */ } } #if defined(LUA_COMPAT_MAXN) static int maxn (lua_State *L) { lua_Number max = 0; luaL_checktype(L, 1, LUA_TTABLE); lua_pushnil(L); /* first key */ while (lua_next(L, 1)) { lua_pop(L, 1); /* remove value */ if (lua_type(L, -1) == LUA_TNUMBER) { lua_Number v = lua_tonumber(L, -1); if (v > max) max = v; } } lua_pushnumber(L, max); return 1; } #endif static int tinsert (lua_State *L) { lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ lua_Integer pos; /* where to insert new element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ break; } case 3: { lua_Integer i; pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */ luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds"); for (i = e; i > pos; i--) { /* move up elements */ lua_geti(L, 1, i - 1); lua_seti(L, 1, i); /* t[i] = t[i - 1] */ } break; } default: { return luaL_error(L, "wrong number of arguments to 'insert'"); } } lua_seti(L, 1, pos); /* t[pos] = v */ return 0; } static int tremove (lua_State *L) { lua_Integer size = aux_getn(L, 1, TAB_RW); lua_Integer pos = luaL_optinteger(L, 2, size); if (pos != size) /* validate 'pos' if given */ luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds"); lua_geti(L, 1, pos); /* result = t[pos] */ for ( ; pos < size; pos++) { lua_geti(L, 1, pos + 1); lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */ } lua_pushnil(L); lua_seti(L, 1, pos); /* t[pos] = nil */ return 1; } /* ** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever ** possible, copy in increasing order, which is better for rehashing. ** "possible" means destination after original range, or smaller ** than origin, or copying to another table. */ static int tmove (lua_State *L) { lua_Integer f = luaL_checkinteger(L, 2); lua_Integer e = luaL_checkinteger(L, 3); lua_Integer t = luaL_checkinteger(L, 4); int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */ checktab(L, 1, TAB_R); checktab(L, tt, TAB_W); if (e >= f) { /* otherwise, nothing to move */ lua_Integer n, i; luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3, "too many elements to move"); n = e - f + 1; /* number of elements to move */ luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4, "destination wrap around"); if (t > e || t <= f || tt != 1) { for (i = 0; i < n; i++) { lua_geti(L, 1, f + i); lua_seti(L, tt, t + i); } } else { for (i = n - 1; i >= 0; i--) { lua_geti(L, 1, f + i); lua_seti(L, tt, t + i); } } } lua_pushvalue(L, tt); /* return "to table" */ return 1; } static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { lua_geti(L, 1, i); if (!lua_isstring(L, -1)) luaL_error(L, "invalid value (%s) at index %d in table for 'concat'", luaL_typename(L, -1), i); luaL_addvalue(b); } static int tconcat (lua_State *L) { luaL_Buffer b; lua_Integer last = aux_getn(L, 1, TAB_R); size_t lsep; const char *sep = luaL_optlstring(L, 2, "", &lsep); lua_Integer i = luaL_optinteger(L, 3, 1); last = luaL_opt(L, luaL_checkinteger, 4, last); luaL_buffinit(L, &b); for (; i < last; i++) { addfield(L, &b, i); luaL_addlstring(&b, sep, lsep); } if (i == last) /* add last value (if interval was not empty) */ addfield(L, &b, i); luaL_pushresult(&b); return 1; } /* ** {====================================================== ** Pack/unpack ** ======================================================= */ static int pack (lua_State *L) { int i; int n = lua_gettop(L); /* number of elements to pack */ lua_createtable(L, n, 1); /* create result table */ lua_insert(L, 1); /* put it at index 1 */ for (i = n; i >= 1; i--) /* assign elements */ lua_seti(L, 1, i); lua_pushinteger(L, n); lua_setfield(L, 1, "n"); /* t.n = number of elements */ return 1; /* return table */ } static int unpack (lua_State *L) { lua_Unsigned n; lua_Integer i = luaL_optinteger(L, 2, 1); lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); if (i > e) return 0; /* empty range */ n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) return luaL_error(L, "too many results to unpack"); for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ lua_geti(L, 1, i); } lua_geti(L, 1, e); /* push last element */ return (int)n; } /* }====================================================== */ /* ** {====================================================== ** Quicksort ** (based on 'Algorithms in MODULA-3', Robert Sedgewick; ** Addison-Wesley, 1993.) ** ======================================================= */ /* ** Produce a "random" 'unsigned int' to randomize pivot choice. This ** macro is used only when 'sort' detects a big imbalance in the result ** of a partition. (If you don't want/need this "randomness", ~0 is a ** good choice.) */ #if !defined(l_randomizePivot) /* { */ #include <time.h> /* size of 'e' measured in number of 'unsigned int's */ #define sof(e) (sizeof(e) / sizeof(unsigned int)) /* ** Use 'time' and 'clock' as sources of "randomness". Because we don't ** know the types 'clock_t' and 'time_t', we cannot cast them to ** anything without risking overflows. A safe way to use their values ** is to copy them to an array of a known type and use the array values. */ static unsigned int l_randomizePivot (void) { clock_t c = clock(); time_t t = time(NULL); unsigned int buff[sof(c) + sof(t)]; unsigned int i, rnd = 0; memcpy(buff, &c, sof(c) * sizeof(unsigned int)); memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int)); for (i = 0; i < sof(buff); i++) rnd += buff[i]; return rnd; } #endif /* } */ /* arrays larger than 'RANLIMIT' may use randomized pivots */ #define RANLIMIT 100u static void set2 (lua_State *L, unsigned int i, unsigned int j) { lua_seti(L, 1, i); lua_seti(L, 1, j); } /* ** Return true iff value at stack index 'a' is less than the value at ** index 'b' (according to the order of the sort). */ static int sort_comp (lua_State *L, int a, int b) { if (lua_isnil(L, 2)) /* no function? */ return lua_compare(L, a, b, LUA_OPLT); /* a < b */ else { /* function */ int res; lua_pushvalue(L, 2); /* push function */ lua_pushvalue(L, a-1); /* -1 to compensate function */ lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */ lua_call(L, 2, 1); /* call function */ res = lua_toboolean(L, -1); /* get result */ lua_pop(L, 1); /* pop result */ return res; } } /* ** Does the partition: Pivot P is at the top of the stack. ** precondition: a[lo] <= P == a[up-1] <= a[up], ** so it only needs to do the partition from lo + 1 to up - 2. ** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up] ** returns 'i'. */ static unsigned int partition (lua_State *L, unsigned int lo, unsigned int up) { unsigned int i = lo; /* will be incremented before first use */ unsigned int j = up - 1; /* will be decremented before first use */ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */ for (;;) { /* next loop: repeat ++i while a[i] < P */ while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[i] */ } /* after the loop, a[i] >= P and a[lo .. i - 1] < P */ /* next loop: repeat --j while P < a[j] */ while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { if (j < i) /* j < i but a[j] > P ?? */ luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[j] */ } /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */ if (j < i) { /* no elements out of place? */ /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */ lua_pop(L, 1); /* pop a[j] */ /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */ set2(L, up - 1, i); return i; } /* otherwise, swap a[i] - a[j] to restore invariant and repeat */ set2(L, i, j); } } /* ** Choose an element in the middle (2nd-3th quarters) of [lo,up] ** "randomized" by 'rnd' */ static unsigned int choosePivot (unsigned int lo, unsigned int up, unsigned int rnd) { unsigned int r4 = (unsigned int)(up - lo) / 4u; /* range/4 */ unsigned int p = rnd % (r4 * 2) + (lo + r4); lua_assert(lo + r4 <= p && p <= up - r4); return p; } /* ** QuickSort algorithm (recursive function) */ static void auxsort (lua_State *L, unsigned int lo, unsigned int up, unsigned int rnd) { while (lo < up) { /* loop for tail recursion */ unsigned int p; /* Pivot index */ unsigned int n; /* to be used later */ /* sort elements 'lo', 'p', and 'up' */ lua_geti(L, 1, lo); lua_geti(L, 1, up); if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */ set2(L, lo, up); /* swap a[lo] - a[up] */ else lua_pop(L, 2); /* remove both values */ if (up - lo == 1) /* only 2 elements? */ return; /* already sorted */ if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */ p = (lo + up)/2; /* middle element is a good pivot */ else /* for larger intervals, it is worth a random pivot */ p = choosePivot(lo, up, rnd); lua_geti(L, 1, p); lua_geti(L, 1, lo); if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */ set2(L, p, lo); /* swap a[p] - a[lo] */ else { lua_pop(L, 1); /* remove a[lo] */ lua_geti(L, 1, up); if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */ set2(L, p, up); /* swap a[up] - a[p] */ else lua_pop(L, 2); } if (up - lo == 2) /* only 3 elements? */ return; /* already sorted */ lua_geti(L, 1, p); /* get middle element (Pivot) */ lua_pushvalue(L, -1); /* push Pivot */ lua_geti(L, 1, up - 1); /* push a[up - 1] */ set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */ p = partition(L, lo, up); /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */ if (p - lo < up - p) { /* lower interval is smaller? */ auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */ n = p - lo; /* size of smaller interval */ lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */ } else { auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */ n = up - p; /* size of smaller interval */ up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */ } if ((up - lo) / 128u > n) /* partition too imbalanced? */ rnd = l_randomizePivot(); /* try a new randomization */ } /* tail call auxsort(L, lo, up, rnd) */ } static int sort (lua_State *L) { lua_Integer n = aux_getn(L, 1, TAB_RW); if (n > 1) { /* non-trivial interval? */ luaL_argcheck(L, n < INT_MAX, 1, "array too big"); luaL_checkstack(L, 40, ""); /* assume array is smaller than 2^40 */ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */ luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */ lua_settop(L, 2); /* make sure there are two arguments */ auxsort(L, 1, (unsigned int)n, 0u); } return 0; } /* }====================================================== */ static const luaL_Reg tab_funcs[] = { {"concat", tconcat}, #if defined(LUA_COMPAT_MAXN) {"maxn", maxn}, #endif {"insert", tinsert}, {"pack", pack}, {"unpack", unpack}, {"remove", tremove}, {"move", tmove}, {"sort", sort}, {NULL, NULL} }; LUAMOD_API int luaopen_table (lua_State *L) { luaL_newlib(L, tab_funcs); #if defined(LUA_COMPAT_UNPACK) /* _G.unpack = table.unpack */ lua_getfield(L, -1, "unpack"); lua_setglobal(L, "unpack"); #endif return 1; } ������������������������������������������������������������golly-2.8-src/lua/ReadMe.html�����������������������������������������������������������������������0000644�0001751�0001751�00000001301�12675241401�013022� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Lua source code for Golly

This directory contains the source files needed to embed Lua in Golly. It's essentially the same set of files from the src directory in the full distribution of Lua 5.3.2 (available here) but with these minor changes:

  • Removed lua.c (the Lua stand-alone interpreter).
  • Removed luac.c (the Lua compiler).
  • Simplified Makefile (so it can be called from makefile-mac or makefile-gtk).
golly-2.8-src/lua/ltm.h0000644000175100017510000000332512675241401011754 00000000000000/* ** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $ ** Tag methods ** See Copyright Notice in lua.h */ #ifndef ltm_h #define ltm_h #include "lobject.h" /* * WARNING: if you change the order of this enumeration, * grep "ORDER TM" and "ORDER OP" */ typedef enum { TM_INDEX, TM_NEWINDEX, TM_GC, TM_MODE, TM_LEN, TM_EQ, /* last tag method with fast access */ TM_ADD, TM_SUB, TM_MUL, TM_MOD, TM_POW, TM_DIV, TM_IDIV, TM_BAND, TM_BOR, TM_BXOR, TM_SHL, TM_SHR, TM_UNM, TM_BNOT, TM_LT, TM_LE, TM_CONCAT, TM_CALL, TM_N /* number of elements in the enum */ } TMS; #define gfasttm(g,et,e) ((et) == NULL ? NULL : \ ((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e])) #define fasttm(l,et,e) gfasttm(G(l), et, e) #define ttypename(x) luaT_typenames_[(x) + 1] #define objtypename(x) ttypename(ttnov(x)) LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS]; LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename); LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event); LUAI_FUNC void luaT_init (lua_State *L); LUAI_FUNC void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, TValue *p3, int hasres); LUAI_FUNC int luaT_callbinTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event); LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event); LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event); #endif golly-2.8-src/lua/lapi.c0000644000175100017510000007512312675241401012105 00000000000000/* ** $Id: lapi.c,v 2.257 2015/11/02 18:48:07 roberto Exp $ ** Lua API ** See Copyright Notice in lua.h */ #define lapi_c #define LUA_CORE #include "lprefix.h" #include #include #include "lua.h" #include "lapi.h" #include "ldebug.h" #include "ldo.h" #include "lfunc.h" #include "lgc.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" #include "lstring.h" #include "ltable.h" #include "ltm.h" #include "lundump.h" #include "lvm.h" const char lua_ident[] = "$LuaVersion: " LUA_COPYRIGHT " $" "$LuaAuthors: " LUA_AUTHORS " $"; /* value at a non-valid index */ #define NONVALIDVALUE cast(TValue *, luaO_nilobject) /* corresponding test */ #define isvalid(o) ((o) != luaO_nilobject) /* test for pseudo index */ #define ispseudo(i) ((i) <= LUA_REGISTRYINDEX) /* test for upvalue */ #define isupvalue(i) ((i) < LUA_REGISTRYINDEX) /* test for valid but not pseudo index */ #define isstackindex(i, o) (isvalid(o) && !ispseudo(i)) #define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index") #define api_checkstackindex(l, i, o) \ api_check(l, isstackindex(i, o), "index not in the stack") static TValue *index2addr (lua_State *L, int idx) { CallInfo *ci = L->ci; if (idx > 0) { TValue *o = ci->func + idx; api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index"); if (o >= L->top) return NONVALIDVALUE; else return o; } else if (!ispseudo(idx)) { /* negative index */ api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); return L->top + idx; } else if (idx == LUA_REGISTRYINDEX) return &G(L)->l_registry; else { /* upvalues */ idx = LUA_REGISTRYINDEX - idx; api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); if (ttislcf(ci->func)) /* light C function? */ return NONVALIDVALUE; /* it has no upvalues */ else { CClosure *func = clCvalue(ci->func); return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : NONVALIDVALUE; } } } /* ** to be called by 'lua_checkstack' in protected mode, to grow stack ** capturing memory errors */ static void growstack (lua_State *L, void *ud) { int size = *(int *)ud; luaD_growstack(L, size); } LUA_API int lua_checkstack (lua_State *L, int n) { int res; CallInfo *ci = L->ci; lua_lock(L); api_check(L, n >= 0, "negative 'n'"); if (L->stack_last - L->top > n) /* stack large enough? */ res = 1; /* yes; check is OK */ else { /* no; need to grow stack */ int inuse = cast_int(L->top - L->stack) + EXTRA_STACK; if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ res = 0; /* no */ else /* try to grow stack */ res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); } if (res && ci->top < L->top + n) ci->top = L->top + n; /* adjust frame top */ lua_unlock(L); return res; } LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { int i; if (from == to) return; lua_lock(to); api_checknelems(from, n); api_check(from, G(from) == G(to), "moving among independent states"); api_check(from, to->ci->top - to->top >= n, "stack overflow"); from->top -= n; for (i = 0; i < n; i++) { setobj2s(to, to->top, from->top + i); to->top++; /* stack already checked by previous 'api_check' */ } lua_unlock(to); } LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { lua_CFunction old; lua_lock(L); old = G(L)->panic; G(L)->panic = panicf; lua_unlock(L); return old; } LUA_API const lua_Number *lua_version (lua_State *L) { static const lua_Number version = LUA_VERSION_NUM; if (L == NULL) return &version; else return G(L)->version; } /* ** basic stack manipulation */ /* ** convert an acceptable stack index into an absolute index */ LUA_API int lua_absindex (lua_State *L, int idx) { return (idx > 0 || ispseudo(idx)) ? idx : cast_int(L->top - L->ci->func) + idx; } LUA_API int lua_gettop (lua_State *L) { return cast_int(L->top - (L->ci->func + 1)); } LUA_API void lua_settop (lua_State *L, int idx) { StkId func = L->ci->func; lua_lock(L); if (idx >= 0) { api_check(L, idx <= L->stack_last - (func + 1), "new top too large"); while (L->top < (func + 1) + idx) setnilvalue(L->top++); L->top = (func + 1) + idx; } else { api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); L->top += idx+1; /* 'subtract' index (index is negative) */ } lua_unlock(L); } /* ** Reverse the stack segment from 'from' to 'to' ** (auxiliary to 'lua_rotate') */ static void reverse (lua_State *L, StkId from, StkId to) { for (; from < to; from++, to--) { TValue temp; setobj(L, &temp, from); setobjs2s(L, from, to); setobj2s(L, to, &temp); } } /* ** Let x = AB, where A is a prefix of length 'n'. Then, ** rotate x n == BA. But BA == (A^r . B^r)^r. */ LUA_API void lua_rotate (lua_State *L, int idx, int n) { StkId p, t, m; lua_lock(L); t = L->top - 1; /* end of stack segment being rotated */ p = index2addr(L, idx); /* start of segment */ api_checkstackindex(L, idx, p); api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ reverse(L, p, m); /* reverse the prefix with length 'n' */ reverse(L, m + 1, t); /* reverse the suffix */ reverse(L, p, t); /* reverse the entire segment */ lua_unlock(L); } LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) { TValue *fr, *to; lua_lock(L); fr = index2addr(L, fromidx); to = index2addr(L, toidx); api_checkvalidindex(L, to); setobj(L, to, fr); if (isupvalue(toidx)) /* function upvalue? */ luaC_barrier(L, clCvalue(L->ci->func), fr); /* LUA_REGISTRYINDEX does not need gc barrier (collector revisits it before finishing collection) */ lua_unlock(L); } LUA_API void lua_pushvalue (lua_State *L, int idx) { lua_lock(L); setobj2s(L, L->top, index2addr(L, idx)); api_incr_top(L); lua_unlock(L); } /* ** access functions (stack -> C) */ LUA_API int lua_type (lua_State *L, int idx) { StkId o = index2addr(L, idx); return (isvalid(o) ? ttnov(o) : LUA_TNONE); } LUA_API const char *lua_typename (lua_State *L, int t) { UNUSED(L); api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag"); return ttypename(t); } LUA_API int lua_iscfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); return (ttislcf(o) || (ttisCclosure(o))); } LUA_API int lua_isinteger (lua_State *L, int idx) { StkId o = index2addr(L, idx); return ttisinteger(o); } LUA_API int lua_isnumber (lua_State *L, int idx) { lua_Number n; const TValue *o = index2addr(L, idx); return tonumber(o, &n); } LUA_API int lua_isstring (lua_State *L, int idx) { const TValue *o = index2addr(L, idx); return (ttisstring(o) || cvt2str(o)); } LUA_API int lua_isuserdata (lua_State *L, int idx) { const TValue *o = index2addr(L, idx); return (ttisfulluserdata(o) || ttislightuserdata(o)); } LUA_API int lua_rawequal (lua_State *L, int index1, int index2) { StkId o1 = index2addr(L, index1); StkId o2 = index2addr(L, index2); return (isvalid(o1) && isvalid(o2)) ? luaV_rawequalobj(o1, o2) : 0; } LUA_API void lua_arith (lua_State *L, int op) { lua_lock(L); if (op != LUA_OPUNM && op != LUA_OPBNOT) api_checknelems(L, 2); /* all other operations expect two operands */ else { /* for unary operations, add fake 2nd operand */ api_checknelems(L, 1); setobjs2s(L, L->top, L->top - 1); api_incr_top(L); } /* first operand at top - 2, second at top - 1; result go to top - 2 */ luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2); L->top--; /* remove second operand */ lua_unlock(L); } LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) { StkId o1, o2; int i = 0; lua_lock(L); /* may call tag method */ o1 = index2addr(L, index1); o2 = index2addr(L, index2); if (isvalid(o1) && isvalid(o2)) { switch (op) { case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break; case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break; case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break; default: api_check(L, 0, "invalid option"); } } lua_unlock(L); return i; } LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { size_t sz = luaO_str2num(s, L->top); if (sz != 0) api_incr_top(L); return sz; } LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *pisnum) { lua_Number n; const TValue *o = index2addr(L, idx); int isnum = tonumber(o, &n); if (!isnum) n = 0; /* call to 'tonumber' may change 'n' even if it fails */ if (pisnum) *pisnum = isnum; return n; } LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *pisnum) { lua_Integer res; const TValue *o = index2addr(L, idx); int isnum = tointeger(o, &res); if (!isnum) res = 0; /* call to 'tointeger' may change 'n' even if it fails */ if (pisnum) *pisnum = isnum; return res; } LUA_API int lua_toboolean (lua_State *L, int idx) { const TValue *o = index2addr(L, idx); return !l_isfalse(o); } LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { StkId o = index2addr(L, idx); if (!ttisstring(o)) { if (!cvt2str(o)) { /* not convertible? */ if (len != NULL) *len = 0; return NULL; } lua_lock(L); /* 'luaO_tostring' may create a new string */ luaC_checkGC(L); o = index2addr(L, idx); /* previous call may reallocate the stack */ luaO_tostring(L, o); lua_unlock(L); } if (len != NULL) *len = vslen(o); return svalue(o); } LUA_API size_t lua_rawlen (lua_State *L, int idx) { StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TSHRSTR: return tsvalue(o)->shrlen; case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; case LUA_TUSERDATA: return uvalue(o)->len; case LUA_TTABLE: return luaH_getn(hvalue(o)); default: return 0; } } LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { StkId o = index2addr(L, idx); if (ttislcf(o)) return fvalue(o); else if (ttisCclosure(o)) return clCvalue(o)->f; else return NULL; /* not a C function */ } LUA_API void *lua_touserdata (lua_State *L, int idx) { StkId o = index2addr(L, idx); switch (ttnov(o)) { case LUA_TUSERDATA: return getudatamem(uvalue(o)); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } } LUA_API lua_State *lua_tothread (lua_State *L, int idx) { StkId o = index2addr(L, idx); return (!ttisthread(o)) ? NULL : thvalue(o); } LUA_API const void *lua_topointer (lua_State *L, int idx) { StkId o = index2addr(L, idx); switch (ttype(o)) { case LUA_TTABLE: return hvalue(o); case LUA_TLCL: return clLvalue(o); case LUA_TCCL: return clCvalue(o); case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o))); case LUA_TTHREAD: return thvalue(o); case LUA_TUSERDATA: return getudatamem(uvalue(o)); case LUA_TLIGHTUSERDATA: return pvalue(o); default: return NULL; } } /* ** push functions (C -> stack) */ LUA_API void lua_pushnil (lua_State *L) { lua_lock(L); setnilvalue(L->top); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { lua_lock(L); setfltvalue(L->top, n); api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { lua_lock(L); setivalue(L->top, n); api_incr_top(L); lua_unlock(L); } /* ** Pushes on the stack a string with given length. Avoid using 's' when ** 'len' == 0 (as 's' can be NULL in that case), due to later use of ** 'memcmp' and 'memcpy'. */ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) { TString *ts; lua_lock(L); luaC_checkGC(L); ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); setsvalue2s(L, L->top, ts); api_incr_top(L); lua_unlock(L); return getstr(ts); } LUA_API const char *lua_pushstring (lua_State *L, const char *s) { lua_lock(L); if (s == NULL) setnilvalue(L->top); else { TString *ts; luaC_checkGC(L); ts = luaS_new(L, s); setsvalue2s(L, L->top, ts); s = getstr(ts); /* internal copy's address */ } api_incr_top(L); lua_unlock(L); return s; } LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp) { const char *ret; lua_lock(L); luaC_checkGC(L); ret = luaO_pushvfstring(L, fmt, argp); lua_unlock(L); return ret; } LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) { const char *ret; va_list argp; lua_lock(L); luaC_checkGC(L); va_start(argp, fmt); ret = luaO_pushvfstring(L, fmt, argp); va_end(argp); lua_unlock(L); return ret; } LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { lua_lock(L); if (n == 0) { setfvalue(L->top, fn); } else { CClosure *cl; api_checknelems(L, n); api_check(L, n <= MAXUPVAL, "upvalue index too large"); luaC_checkGC(L); cl = luaF_newCclosure(L, n); cl->f = fn; L->top -= n; while (n--) { setobj2n(L, &cl->upvalue[n], L->top + n); /* does not need barrier because closure is white */ } setclCvalue(L, L->top, cl); } api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushboolean (lua_State *L, int b) { lua_lock(L); setbvalue(L->top, (b != 0)); /* ensure that true is 1 */ api_incr_top(L); lua_unlock(L); } LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { lua_lock(L); setpvalue(L->top, p); api_incr_top(L); lua_unlock(L); } LUA_API int lua_pushthread (lua_State *L) { lua_lock(L); setthvalue(L, L->top, L); api_incr_top(L); lua_unlock(L); return (G(L)->mainthread == L); } /* ** get functions (Lua -> stack) */ static int auxgetstr (lua_State *L, const TValue *t, const char *k) { const TValue *aux; TString *str = luaS_new(L, k); if (luaV_fastget(L, t, str, aux, luaH_getstr)) { setobj2s(L, L->top, aux); api_incr_top(L); } else { setsvalue2s(L, L->top, str); api_incr_top(L); luaV_finishget(L, t, L->top - 1, L->top - 1, aux); } lua_unlock(L); return ttnov(L->top - 1); } LUA_API int lua_getglobal (lua_State *L, const char *name) { Table *reg = hvalue(&G(L)->l_registry); lua_lock(L); return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } LUA_API int lua_gettable (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); luaV_gettable(L, t, L->top - 1, L->top - 1); lua_unlock(L); return ttnov(L->top - 1); } LUA_API int lua_getfield (lua_State *L, int idx, const char *k) { lua_lock(L); return auxgetstr(L, index2addr(L, idx), k); } LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { StkId t; const TValue *aux; lua_lock(L); t = index2addr(L, idx); if (luaV_fastget(L, t, n, aux, luaH_getint)) { setobj2s(L, L->top, aux); api_incr_top(L); } else { setivalue(L->top, n); api_incr_top(L); luaV_finishget(L, t, L->top - 1, L->top - 1, aux); } lua_unlock(L); return ttnov(L->top - 1); } LUA_API int lua_rawget (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); lua_unlock(L); return ttnov(L->top - 1); } LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) { StkId t; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setobj2s(L, L->top, luaH_getint(hvalue(t), n)); api_incr_top(L); lua_unlock(L); return ttnov(L->top - 1); } LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) { StkId t; TValue k; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); setpvalue(&k, cast(void *, p)); setobj2s(L, L->top, luaH_get(hvalue(t), &k)); api_incr_top(L); lua_unlock(L); return ttnov(L->top - 1); } LUA_API void lua_createtable (lua_State *L, int narray, int nrec) { Table *t; lua_lock(L); luaC_checkGC(L); t = luaH_new(L); sethvalue(L, L->top, t); api_incr_top(L); if (narray > 0 || nrec > 0) luaH_resize(L, t, narray, nrec); lua_unlock(L); } LUA_API int lua_getmetatable (lua_State *L, int objindex) { const TValue *obj; Table *mt; int res = 0; lua_lock(L); obj = index2addr(L, objindex); switch (ttnov(obj)) { case LUA_TTABLE: mt = hvalue(obj)->metatable; break; case LUA_TUSERDATA: mt = uvalue(obj)->metatable; break; default: mt = G(L)->mt[ttnov(obj)]; break; } if (mt != NULL) { sethvalue(L, L->top, mt); api_incr_top(L); res = 1; } lua_unlock(L); return res; } LUA_API int lua_getuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); o = index2addr(L, idx); api_check(L, ttisfulluserdata(o), "full userdata expected"); getuservalue(L, uvalue(o), L->top); api_incr_top(L); lua_unlock(L); return ttnov(L->top - 1); } /* ** set functions (stack -> Lua) */ /* ** t[k] = value at the top of the stack (where 'k' is a string) */ static void auxsetstr (lua_State *L, const TValue *t, const char *k) { const TValue *aux; TString *str = luaS_new(L, k); api_checknelems(L, 1); if (luaV_fastset(L, t, str, aux, luaH_getstr, L->top - 1)) L->top--; /* pop value */ else { setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ api_incr_top(L); luaV_finishset(L, t, L->top - 1, L->top - 2, aux); L->top -= 2; /* pop value and key */ } lua_unlock(L); /* lock done by caller */ } LUA_API void lua_setglobal (lua_State *L, const char *name) { Table *reg = hvalue(&G(L)->l_registry); lua_lock(L); /* unlock done in 'auxsetstr' */ auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); } LUA_API void lua_settable (lua_State *L, int idx) { StkId t; lua_lock(L); api_checknelems(L, 2); t = index2addr(L, idx); luaV_settable(L, t, L->top - 2, L->top - 1); L->top -= 2; /* pop index and value */ lua_unlock(L); } LUA_API void lua_setfield (lua_State *L, int idx, const char *k) { lua_lock(L); /* unlock done in 'auxsetstr' */ auxsetstr(L, index2addr(L, idx), k); } LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { StkId t; const TValue *aux; lua_lock(L); api_checknelems(L, 1); t = index2addr(L, idx); if (luaV_fastset(L, t, n, aux, luaH_getint, L->top - 1)) L->top--; /* pop value */ else { setivalue(L->top, n); api_incr_top(L); luaV_finishset(L, t, L->top - 1, L->top - 2, aux); L->top -= 2; /* pop value and key */ } lua_unlock(L); } LUA_API void lua_rawset (lua_State *L, int idx) { StkId o; TValue *slot; lua_lock(L); api_checknelems(L, 2); o = index2addr(L, idx); api_check(L, ttistable(o), "table expected"); slot = luaH_set(L, hvalue(o), L->top - 2); setobj2t(L, slot, L->top - 1); invalidateTMcache(hvalue(o)); luaC_barrierback(L, hvalue(o), L->top-1); L->top -= 2; lua_unlock(L); } LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) { StkId o; lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); api_check(L, ttistable(o), "table expected"); luaH_setint(L, hvalue(o), n, L->top - 1); luaC_barrierback(L, hvalue(o), L->top-1); L->top--; lua_unlock(L); } LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) { StkId o; TValue k, *slot; lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); api_check(L, ttistable(o), "table expected"); setpvalue(&k, cast(void *, p)); slot = luaH_set(L, hvalue(o), &k); setobj2t(L, slot, L->top - 1); luaC_barrierback(L, hvalue(o), L->top - 1); L->top--; lua_unlock(L); } LUA_API int lua_setmetatable (lua_State *L, int objindex) { TValue *obj; Table *mt; lua_lock(L); api_checknelems(L, 1); obj = index2addr(L, objindex); if (ttisnil(L->top - 1)) mt = NULL; else { api_check(L, ttistable(L->top - 1), "table expected"); mt = hvalue(L->top - 1); } switch (ttnov(obj)) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) { luaC_objbarrier(L, gcvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); } break; } case LUA_TUSERDATA: { uvalue(obj)->metatable = mt; if (mt) { luaC_objbarrier(L, uvalue(obj), mt); luaC_checkfinalizer(L, gcvalue(obj), mt); } break; } default: { G(L)->mt[ttnov(obj)] = mt; break; } } L->top--; lua_unlock(L); return 1; } LUA_API void lua_setuservalue (lua_State *L, int idx) { StkId o; lua_lock(L); api_checknelems(L, 1); o = index2addr(L, idx); api_check(L, ttisfulluserdata(o), "full userdata expected"); setuservalue(L, uvalue(o), L->top - 1); luaC_barrier(L, gcvalue(o), L->top - 1); L->top--; lua_unlock(L); } /* ** 'load' and 'call' functions (run Lua code) */ #define checkresults(L,na,nr) \ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ "results from function overflow current stack size") LUA_API void lua_callk (lua_State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k) { StkId func; lua_lock(L); api_check(L, k == NULL || !isLua(L->ci), "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); checkresults(L, nargs, nresults); func = L->top - (nargs+1); if (k != NULL && L->nny == 0) { /* need to prepare continuation? */ L->ci->u.c.k = k; /* save continuation */ L->ci->u.c.ctx = ctx; /* save context */ luaD_call(L, func, nresults); /* do the call */ } else /* no continuation or no yieldable */ luaD_callnoyield(L, func, nresults); /* just do the call */ adjustresults(L, nresults); lua_unlock(L); } /* ** Execute a protected call. */ struct CallS { /* data to 'f_call' */ StkId func; int nresults; }; static void f_call (lua_State *L, void *ud) { struct CallS *c = cast(struct CallS *, ud); luaD_callnoyield(L, c->func, c->nresults); } LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc, lua_KContext ctx, lua_KFunction k) { struct CallS c; int status; ptrdiff_t func; lua_lock(L); api_check(L, k == NULL || !isLua(L->ci), "cannot use continuations inside hooks"); api_checknelems(L, nargs+1); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); checkresults(L, nargs, nresults); if (errfunc == 0) func = 0; else { StkId o = index2addr(L, errfunc); api_checkstackindex(L, errfunc, o); func = savestack(L, o); } c.func = L->top - (nargs+1); /* function to be called */ if (k == NULL || L->nny > 0) { /* no continuation or no yieldable? */ c.nresults = nresults; /* do a 'conventional' protected call */ status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); } else { /* prepare continuation (call is already protected by 'resume') */ CallInfo *ci = L->ci; ci->u.c.k = k; /* save continuation */ ci->u.c.ctx = ctx; /* save context */ /* save information for error recovery */ ci->extra = savestack(L, c.func); ci->u.c.old_errfunc = L->errfunc; L->errfunc = func; setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */ ci->callstatus |= CIST_YPCALL; /* function can do error recovery */ luaD_call(L, c.func, nresults); /* do the call */ ci->callstatus &= ~CIST_YPCALL; L->errfunc = ci->u.c.old_errfunc; status = LUA_OK; /* if it is here, there were no errors */ } adjustresults(L, nresults); lua_unlock(L); return status; } LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname, const char *mode) { ZIO z; int status; lua_lock(L); if (!chunkname) chunkname = "?"; luaZ_init(L, &z, reader, data); status = luaD_protectedparser(L, &z, chunkname, mode); if (status == LUA_OK) { /* no errors? */ LClosure *f = clLvalue(L->top - 1); /* get newly created function */ if (f->nupvalues >= 1) { /* does it have an upvalue? */ /* get global table from registry */ Table *reg = hvalue(&G(L)->l_registry); const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ setobj(L, f->upvals[0]->v, gt); luaC_upvalbarrier(L, f->upvals[0]); } } lua_unlock(L); return status; } LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) { int status; TValue *o; lua_lock(L); api_checknelems(L, 1); o = L->top - 1; if (isLfunction(o)) status = luaU_dump(L, getproto(o), writer, data, strip); else status = 1; lua_unlock(L); return status; } LUA_API int lua_status (lua_State *L) { return L->status; } /* ** Garbage-collection function */ LUA_API int lua_gc (lua_State *L, int what, int data) { int res = 0; global_State *g; lua_lock(L); g = G(L); switch (what) { case LUA_GCSTOP: { g->gcrunning = 0; break; } case LUA_GCRESTART: { luaE_setdebt(g, 0); g->gcrunning = 1; break; } case LUA_GCCOLLECT: { luaC_fullgc(L, 0); break; } case LUA_GCCOUNT: { /* GC values are expressed in Kbytes: #bytes/2^10 */ res = cast_int(gettotalbytes(g) >> 10); break; } case LUA_GCCOUNTB: { res = cast_int(gettotalbytes(g) & 0x3ff); break; } case LUA_GCSTEP: { l_mem debt = 1; /* =1 to signal that it did an actual step */ lu_byte oldrunning = g->gcrunning; g->gcrunning = 1; /* allow GC to run */ if (data == 0) { luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */ luaC_step(L); } else { /* add 'data' to total debt */ debt = cast(l_mem, data) * 1024 + g->GCdebt; luaE_setdebt(g, debt); luaC_checkGC(L); } g->gcrunning = oldrunning; /* restore previous state */ if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ res = 1; /* signal it */ break; } case LUA_GCSETPAUSE: { res = g->gcpause; g->gcpause = data; break; } case LUA_GCSETSTEPMUL: { res = g->gcstepmul; if (data < 40) data = 40; /* avoid ridiculous low values (and 0) */ g->gcstepmul = data; break; } case LUA_GCISRUNNING: { res = g->gcrunning; break; } default: res = -1; /* invalid option */ } lua_unlock(L); return res; } /* ** miscellaneous functions */ LUA_API int lua_error (lua_State *L) { lua_lock(L); api_checknelems(L, 1); luaG_errormsg(L); /* code unreachable; will unlock when control actually leaves the kernel */ return 0; /* to avoid warnings */ } LUA_API int lua_next (lua_State *L, int idx) { StkId t; int more; lua_lock(L); t = index2addr(L, idx); api_check(L, ttistable(t), "table expected"); more = luaH_next(L, hvalue(t), L->top - 1); if (more) { api_incr_top(L); } else /* no more elements */ L->top -= 1; /* remove key */ lua_unlock(L); return more; } LUA_API void lua_concat (lua_State *L, int n) { lua_lock(L); api_checknelems(L, n); if (n >= 2) { luaC_checkGC(L); luaV_concat(L, n); } else if (n == 0) { /* push empty string */ setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); api_incr_top(L); } /* else n == 1; nothing to do */ lua_unlock(L); } LUA_API void lua_len (lua_State *L, int idx) { StkId t; lua_lock(L); t = index2addr(L, idx); luaV_objlen(L, L->top, t); api_incr_top(L); lua_unlock(L); } LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud) { lua_Alloc f; lua_lock(L); if (ud) *ud = G(L)->ud; f = G(L)->frealloc; lua_unlock(L); return f; } LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) { lua_lock(L); G(L)->ud = ud; G(L)->frealloc = f; lua_unlock(L); } LUA_API void *lua_newuserdata (lua_State *L, size_t size) { Udata *u; lua_lock(L); luaC_checkGC(L); u = luaS_newudata(L, size); setuvalue(L, L->top, u); api_incr_top(L); lua_unlock(L); return getudatamem(u); } static const char *aux_upvalue (StkId fi, int n, TValue **val, CClosure **owner, UpVal **uv) { switch (ttype(fi)) { case LUA_TCCL: { /* C closure */ CClosure *f = clCvalue(fi); if (!(1 <= n && n <= f->nupvalues)) return NULL; *val = &f->upvalue[n-1]; if (owner) *owner = f; return ""; } case LUA_TLCL: { /* Lua closure */ LClosure *f = clLvalue(fi); TString *name; Proto *p = f->p; if (!(1 <= n && n <= p->sizeupvalues)) return NULL; *val = f->upvals[n-1]->v; if (uv) *uv = f->upvals[n - 1]; name = p->upvalues[n-1].name; return (name == NULL) ? "(*no name)" : getstr(name); } default: return NULL; /* not a closure */ } } LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val = NULL; /* to avoid warnings */ lua_lock(L); name = aux_upvalue(index2addr(L, funcindex), n, &val, NULL, NULL); if (name) { setobj2s(L, L->top, val); api_incr_top(L); } lua_unlock(L); return name; } LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) { const char *name; TValue *val = NULL; /* to avoid warnings */ CClosure *owner = NULL; UpVal *uv = NULL; StkId fi; lua_lock(L); fi = index2addr(L, funcindex); api_checknelems(L, 1); name = aux_upvalue(fi, n, &val, &owner, &uv); if (name) { L->top--; setobj(L, val, L->top); if (owner) { luaC_barrier(L, owner, L->top); } else if (uv) { luaC_upvalbarrier(L, uv); } } lua_unlock(L); return name; } static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) { LClosure *f; StkId fi = index2addr(L, fidx); api_check(L, ttisLclosure(fi), "Lua function expected"); f = clLvalue(fi); api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index"); if (pf) *pf = f; return &f->upvals[n - 1]; /* get its upvalue pointer */ } LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) { StkId fi = index2addr(L, fidx); switch (ttype(fi)) { case LUA_TLCL: { /* lua closure */ return *getupvalref(L, fidx, n, NULL); } case LUA_TCCL: { /* C closure */ CClosure *f = clCvalue(fi); api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index"); return &f->upvalue[n - 1]; } default: { api_check(L, 0, "closure expected"); return NULL; } } } LUA_API void lua_upvaluejoin (lua_State *L, int fidx1, int n1, int fidx2, int n2) { LClosure *f1; UpVal **up1 = getupvalref(L, fidx1, n1, &f1); UpVal **up2 = getupvalref(L, fidx2, n2, NULL); luaC_upvdeccount(L, *up1); *up1 = *up2; (*up1)->refcount++; if (upisopen(*up1)) (*up1)->u.open.touched = 1; luaC_upvalbarrier(L, *up1); } golly-2.8-src/Help/0000755000175100017510000000000012751756120011177 500000000000000golly-2.8-src/Help/about.gif0000644000175100017510000013617112525071110012715 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 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 opening or saving 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.

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.8-src/Help/tips.html0000644000175100017510000000741612751752464013003 00000000000000 Golly Help: Hints and Tips

Some useful hints and tips

  • 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 .lua/.py files)

    If necessary, use File > Set File Folder and select the Golly folder. Now all your folders (and the supplied folders) are visible in the file panel, so with just a few clicks you can load any pattern, run any script, or switch to any .rule file. You can also 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.

  • To view a pattern file you can 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.lua 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.
golly-2.8-src/Help/python.html0000644000175100017510000015754312751752464013354 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 Files item in the File menu, open the Scripts/Python folder 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. The examples below assume you've done the import by including this line:

import golly as g

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
getview
getwidth
getxy
hash
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
setview
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 (.lua 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: g.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: g.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 = g.opendialog("Open MCell File", "MCell files (*.mcl)|*.mcl", "C:\\Temp", "sample.mcl")
Example: dirname = g.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 = g.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 = g.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: g.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 XP: C:\Documents and Settings\username\Application Data\Golly\
On Windows 7+: C:\Users\username\AppData\Roaming\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.

"files" — the directory displayed by File > Show Files.

"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")

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("download", "/path/to/my-downloads/")

 
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: g.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: g.clear(1)

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")

shrink(remove_if_empty=False)
Shrink the current selection to the smallest rectangle enclosing all of the selection's live cells. If the selection has no live cells then the optional parameter specifies whether the selection remains unchanged or is removed.
Example: if len(g.getselrect()) > 0: g.shrink(True)

randfill(percentage)
Randomly fill the current selection to a density specified by the given percentage (1 to 100).
Example: g.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 = g.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 = g.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 = g.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 = g.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: g.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 = g.getcells( g.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 = g.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 = g.hash( g.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: g.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(g.getrect()) == 0: g.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(g.getselrect()) == 0: g.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: g.setcell(0, 0, 1 - g.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 = g.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: g.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: g.setstep(0)

getstep()
Return the current step exponent.
Example: g.setstep( g.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: g.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: g.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: g.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, 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 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( g.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, 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. The following example converts the population to a floating point number.
Example: pop = float( g.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 g.empty(): g.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 = g.numstates() - 1

numalgos()
Return the number of algorithms (ie. the number of items in the Set Algorithm menu).
Example: maxalgo = g.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: g.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 = g.getalgo( g.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: g.setrule("b3/s23")

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

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

getheight()
Return the height (in cells) of the current universe (0 if unbounded).
Example: ht = g.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: g.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, 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, or just use the getposint() function defined in the glife package.
Example: x, y = g.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: g.setmag(0)

getmag()
Return the current magnification.
Example: g.setmag( g.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 g.visrect( [0,0,44,55] ): . . .

setview(wd, ht)
Set the pixel width and height of the viewport (the main window will be resized accordingly).
Example: g.setview(32*32, 32*30)

getview()
Return the pixel width and height of the viewport.
Example: wd, ht = g.getview()

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: g.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 = g.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 = g.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 = g.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: g.movelayer(1, 0)

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

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

numlayers()
Return the number of existing layers, an integer from 1 to maxlayers().
Example: if g.numlayers() > 1: g.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: g.setname("temporary")

getname(index=current)
Return the given layer's name, or the current layer's name if no index is supplied.
Example: if g.getname() == "temporary": g.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: 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

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 = g.getcolors()
Example: deadcolor = g.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)
"showfiles" 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)
"showstatusbar" 1 or 0 (True or False)
"showtoolbar" 1 or 0 (True or False)
"smartscale" 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 = g.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 g.getoption("autofit"): g.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 = g.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 = g.getcolor("select")

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

setclipstr(string)
Copy an arbitrary string (not necessarily a cell pattern) directly to the clipboard.
Example: g.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( g.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 will only be returned on a Mac and corresponds to the command key. 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()

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. Note that the cmd modifier corresponds to the command key on a Mac or the control key on Windows/Linux (this lets you write portable scripts that work on any platform).
Example: g.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 = g.getxy()

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...")

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.")

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

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")

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: g.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 g.empty(): g.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 = g.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!")
g.putcells(blinker, 1, 2)
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 supplied Python scripts 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 g.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 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.8-src/Help/view.html0000644000175100017510000001360412660172450012760 00000000000000 Golly Help: View Menu

Full Screen

Switches to full screen mode. To exit from this mode just hit the menu item's keyboard shortcut, or the escape key (if not generating a pattern), 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.

Smarter Scaling

If not ticked then Golly displays patterns at zoomed out scales by drawing all live cells using the state 1 color, regardless of the cell states. If this option is ticked then patterns will be scaled in a way that shows the correct colors, but only at scales from 2:1 to 16:1.

Note that pattern rendering is significantly slower using this scaling option, so it's probably best to only turn it on when you need to see fine details. Define a keyboard shortcut for this menu item so you can easily turn the option on or off.

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.8-src/Help/Algorithms/0000755000175100017510000000000012751756120013310 500000000000000golly-2.8-src/Help/Algorithms/HashLife.html0000644000175100017510000000120512525071110015563 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.8-src/Help/Algorithms/Generations.html0000644000175100017510000000637212525071110016370 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.8-src/Help/Algorithms/RuleLoader.html0000644000175100017510000003206312525071110016144 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.8-src/Help/Algorithms/JvN.html0000644000175100017510000000473612525071110014611 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.8-src/Help/Algorithms/hensel.png0000644000175100017510000004247512751752464015237 00000000000000‰PNG  IHDRQþª^ª. ViCCPICCProfilexœµ—PYÇ_wO¤‘Ì3’£ä8äœL 30 a† "fX*" ² ¢àªY"ŠiPÀ¼ƒ,깕käÀ½ºÛººª»Õ×ý«¯¾þÞë÷úUýÊY–@ KÂO{º0"£¢x€€,ú@“ÅN8ú‚¿Ôd?Zê®ál¯¿®û·’äÄ¥±€QŽå¤±SP>‹ò8[ L®B¹{uºe -D'ˆòöYæÎqÙ,ÇÎñ©o5¡Á®(w@ °XB.än4ÏÈdsÑäq”ù ev‹ƒr Ê))«f¹eØ?õáþSÏØ…ž,wçÞå›n¼4A2kí¹ÿY)ÉócH¡Aá'ûÏî QËÍgžÉ ù8~XÈ<ócýæ9^è¼PŸîò' ç¬Wÿ…>iî }YÞó,Ì›ç´Ì÷ïφF,Ì-Îm!Ïó`Î3/¹0VÒ*Ÿ…9ð,ÀN[3»ïÀu•`­ÇMHg8£_YœƒÉg0LM,ÿçküÿÔìùš£wôoç¢ßüžKmÀ&Mr¿çXêœ{mò{Ný-ºõ»¸ÐÍÎfÎå0³, ¡çVÈe t€!0–À8wà @(ˆ+$€ «A6Ø rA>Ø öƒPŽ‚cà$8 šÁyp\·@7è€ ƒ—`L‚i‚ð¢Ar ¤ éC¦5ä¹C¾P0Å@\ˆe@ÙÐV(*„J  ¨ú:]†n@=ÐhƒÞBŸ`¦ÀÒ°¬/†­agØ…—Ã\8΂sàp1\ Ÿ€›àËð-¸Á/á  d„ލ"†ˆ5⊠ÑH<"D6 yHR‰Ô#­H'r!¯††a` 1v/L†IÅlÀ`J0Ç0M˜Ì]Ì fóKÅ*bõ±¶X&6ËÅ®Ææb‹°ÕØFìUlv;‰Ãáè8mœÎ …KÄ­Ãàápm¸ÜnÇËáõñöø< ŸŽÏÅÄŸÀ_Â÷â‡ñd‚ Á”àAˆ&ð [E„ã„‹„^Âaš(AÔ$ÚˆâZâ.b±•x‡8Lœ&I’´Iö¤PR"i3©˜TOºJzLzG&“ÕÈ6ä 2¼‰\L>E¾N$¤HQô(®”e” ÊNJ ¥ò€òŽJ¥jQ¨ÑÔtêNj-õ õ)õƒMÌHŒ)ÆÛ(V*Ö$Ö+öZœ(®)î,¾Bõvõq  ?l:‡šDMkÍÍššSZÚZZÛ´šµFµeµ™ÚYÚuÚu¨:Ž:©:•:÷tqºÖºIº‡t»õ`= ½½R½;ú°¾¥>Oÿ~ÖÀÆ€oPi0`H1t6Ì4¬34¢ùm1j6z½Xcqôâ=‹;5¶0N6®2~d"eâm²Å¤Õä­©ž)Û´ÔôžÕÌÃl£Y‹Ùs}ó8óÃæ÷-h~Û,Ú-¾XZY -ë-Ǭ4¬b¬Ê¬¬¥­­ ¬¯Û`m\l6Úœ·ùhki›n{Úö;C»$»ãv£K´—Ä-©Z2d¯fϲ¯°90bŽ8ˆUYŽ•ŽÏœÔ8NÕN#κΉÎ'œ_»»]]¦\m]×»¶¹!nžnyn]îRîaî%îO=Ô<¸uãžžë<Û¼°^>^{¼˜JL6³–9îmå½Þ»Ã‡ââSâóÌWÏWèÛêûyûíõ{ì¯éÏ÷oÌ€½OµS •=6 Îî ¡…¬ 92êº+ôQ˜NXFX{¸xø²ðÚð©·ˆÂQäâÈõ‘·¢ä£xQ-Ñøèðèê艥îK÷/^f±,wYÿríåk–ßX!¿"yÅ…•â+Y+ÏÄ`c"bŽÇ|f°*Y±ÌزØq¶+ûû%lj³3gW7o_?ʵçîåŽ%8&%¼â¹òJxo½Ë§’’j’f’#’R)1)çøRü$~Ç*åUkVõô¹QªmêþÔq¡°: J[žÖ’.™Û:?d f:d–f~X¾úÌÉ5ü5·×ê­Ý±v$Ë#ë§u˜uìuíÙªÙ›³×;¯¯ØmˆÝоQ}cÎÆáMž›Žm&mNÚüëã-…[ÞoØÚ𣔳)gèÏêrÅr…¹Ûì¶•oÇlçmïÚa¶ãàŽ¯yœ¼›ùÆùEùŸ Ø74ù±øÇ™ñ;»vYî:¼·›¿»ãžc…’…Y…C{ýö6ícìËÛ÷~ÿÊý7ŠÌ‹Êdû·Ô8¸ûàç’„’¾R—Ò†2ŲeS‡8‡z;®/W*Ï/ÿt„wä~…gES¥VeÑQÜṆ̃ϫ«:²þ©¶Z¾:¿úK ¿Ft,øXG­UmíqÅã»êຌº±ËNtŸt;ÙRoX_Ñ@oÈ?NeœzñsÌÏý§}N·Ÿ±>SVólY#­1¯ jZÛ4ÞœÐ,j‰jé9ç}®½Õ®µñ£_jΫž/½ sa×EÒÅœ‹3—².M´ Ú^]æ^j_ÙþèJä•{A]W}®^¿æqíJ§sç¥ëö×Ïß°½qî¦õÍæ[–·šn[ÜnüÕâׯ.Ë®¦;VwZºmº[{–ô\ìuì½|×íîµ{Ì{·úüûzúÃúï,ÝçÜ}üàÍÃ̇Ó6=Æ>Î{"ñ¤è©âÓÊßtkYŠ. º Þ~òìÑ{èåïi¿ÎyN}^4¢2R;j:z~Ìc¬ûÅÒÃ//§_åþMòoe¯u^ŸýÃéÛã‘ãÃo„ofÞ¼“{WóÞü}ûDàÄÓÉ”É驼rŽ}´þØù)âÓÈôêÏøÏÅ_t¿´~õùúx&efFÀ²¾Y 8>€·5P£Pï€úS’Øœÿý&hγ#ðW<ç‘¿ 5Y5N„mÀõ(‡ÑÐD™‚Þgm`¨€ÍÌâJ‹73ëE¢ÖäÃÌÌ;%ð­|ÎÌLš™ù‚ú{äm©s¾{V8ôoä~–nh+ÿ‹ú;fÝ䯨)Ìõ pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú:`IDATxœì=o£JÇù@ßO@ÿˆÚ5ÒS¹»¢s‘D4{‘m‰Ý\![¢²-Y¯HlYÖjÙëиqAÃSPPÐPPø9ƒ7 ‰bÃ9šHÑ 3?ÍÀ^1‡ù ­IÆÀß ­vrr²ÕüI}­â "qŽ{Òügu¥ô‹K/0¡~t Ôü»V™æŸ!-x~ ʧ.v‘Ûl ¨vÁ±b× ¡Å³Ì,bG®@ó‰Å¡·Ô’=‹¶á–гeB‘ ÇuFÉâE¦Ú)ü¨¸£ÓÑæBÍ¿c•kÞ•XV¥\]ï[Ç#qeïr0seàûKfÁ’ãùTKì=ÎØ€ÅDgN•‡çÀbŒS6³‰`« ŽjÓ·híB˜ØKíö+jþ=«Vó¡*pÊvÈ#š)é>·Ï†™)åpA‡‹–"˰ì‹Ífª~mŸÚ-ARùšgåÍm m¹"Í,úƒ]Ôü;¶ÙÃsè7g ži0/õåÒq[}Eq?iq¡kÖf%({ìQåZ“´*æö¾mèÛ3²»F;o¢®o>ž}øÛTG­ÅÓƒ‰½ Ø5DÍ¿e¾­‹¸Ã]_ÏîïO³³Ü_ÿn¾äà ’òÒO¯wXJÔ÷šæcG'~v9þÚÏ—&ƒÄتÈrÏ2lKñˆdc[kCŒyÉ&Ÿú,M8¡#*ÿùo›‡üB+qŒÊ¶~š"SnqÆHú2•EAÿÈÄ·š»¦7ª˜yÂ@”ó˜öûÿ쳇‡¸ÃÁ£¼Xœç¨âÏŒ{YU(}HÊ[xŸï(šáò5ïŽÚp¤y¸&nÃA{šWsè ¶~ùT·_2qË8ö —mÄ%«„›Ëˆ+^g›Ç›VÞî·Eĵ+cÀèÙ½uÙÙüƒ[?GæØŽ½Åµ:ª¢È²¬(ªí¿Ì²å>ù¥²CxL÷¸ú‰°b\¾æ“!šéX9s‰_ï³ÁÈPz|?tÝÿõnFþ­;göAóœ½ÅÃÿЛ’Ÿ4ÏA¦Ç©Dìºþ‹,‰%} jq5aŸü¹ýƒOÑö£peȺó˜'ÍÛí´¹L.“tÛ÷WJâA=q{ÊmÜf–´õÎ; óÑÆMhì$ã<Éé¬LJžw U­UzZ‹m›Þ‹,‰YííB€ÖaÛ qˆ«ß¦ZŸWöðbO¹‡{!Î_øcöAÊ’µñ†ûtY{´¨#ƒ8WæeEbÞX…P”Ö&ÓVè8Al)-†l j¶¥%9“LV™[ê<•%)v%$ëü5½½z¼dÙ³·Ïê*ÆÕ÷$²‚Ó¬4îÖÈf?^Ü[guaàûAŽËðd¡.=ºÀÎz6Žßu=Ê“µ˜ø~% «ÉÊO{Ï^{LÇãqöÓ,眊qõ~ã¨ü·VRµƒ+³Ù¡Ì#Å|Ï5$NÔ ¬® ˜£‰¬¨çô=»ÕŽƒÁ ×+áÝÛŠqõ~³¸ü·Sw©” %#®øûö¡ç•¼{ë¹Þ>ªm'Ü`N›ß÷76ãêý ¢ò…²Kí L(ùqÅ5,v"DÍ?Ç¡æ?‡š¯D„¨ùç8Ôü§âPó•ˆ5ÿ‡šÿT\s5Ÿ{¤< ºÝ¾Y1®Þ_ø,ÿ+‘»ÔÊ„’×PÍ¿öEáñxl%|ëºb\½¿ä]þ× w©”IÒ×PÍ¿á9 ,Ÿãêí±£d¯;ÖJ>FÜÿÿÿì=›HÇùD|†ãðhÚÍî"KW¸ZÑ$È^‰D'Ë+Q¹ —µQr$:¹ˆs7n¬ \AA±÷`{ý² ¶˜ÙYæyšµg~‹í?3ÌÛ_RÍ#qÒâPóˆCœ\8Ô<â'58ÄÉ…;hþMsƒó"q"ã”í+ ⤞ojp¾@Ä!NpÜAó/uãaœ/qˆ‡šGâ䡿‡8¹p¨yÄ!N.œ¤š§ž³ý™Õ|{Ä•ÁqžÞß,œ¤š§^›õ̓¬ò+ÏW#Žó2¾Æá$Õüß´k°ö «ü sÄÕˆã¼\¿q8y5Cµ×ÊÃ-dåËßTÛ'qepœ·åi5ßDU4×8rơ曨Šfã'BÎ8Ô|UÑl\ãDÈWAóI‘ÓÔ¡ÄzMa`uù|¥¢ègJç…òЇ¬|ùŠ>6ˆ+ƒãl›Ó8\IÍÇ‹¦uÎxFF¥*tN²SÛ4íÕ¿qM/°È@n2)tƒ¬*~u´kœq•/'ÇÙ×6 ê÷«ƒsŽk•Ñ|Ř_ª•ýÌ=šNÃ#C1Ýåår4Qô3%ÅŽ'…îŸUÚ¹µ„•*g\æmš+'¹ÖJ•#޳ .-Ž©/m-¸³šO“„P“']1Üð¸ØóR›fúÂÖN4Ÿ&ÏýkóÇFîÞܾ® RÄ2ÚÅùîhqâ˜Eš}Ë„¶9DË™ËrSÉ«þÎ’6bš–ÉwÜÅ6iæ´Õ0MÚöšµÓüÜm«šIz«ÓíZÓÌu’pìããÚRsttC©TÝNÐXÊîùßÍííœ^àÓx¸!|‘?î²zï¥qY¤ï›+¦äN¡öާ qsUäùc·çŸYˆ¾FÃ[~7¨ùq¨ùŠ8¢æc[Û^—nêÙã¨kmnëŠjoÜàcrÍ®cÛ–eÙ¶3[ý)š=ß–õnÛö›¦2Xfu;TãÝYL:6}:¿¦¨VÎö"ünPó5âPóqDͯ·šï«Ç\„4Ý­æ5Ewö]niþ úJÛß¾Ÿ[ûçùÄkÃùôn·¥·œ›|þØksOAÍ£æEùî$ÑüãÔÚÔïj{±ŽáQÜtæû¬daï»Ù¦]¸7¨N°Œãh`ªm?Ê«¨îî «ìÆÑ­ÓLÑUs‚E†ûn¼ü±Ûô M7Âw1DèÂ>¼q؇WWЇ—F¶©î.࣓¼UgßH–]}WÊt6BMBËØ¼W5MUT½åÎWéÂ8þ´4+"›ÅÒ8z¶¯%¨Æê.Œ÷°<{q\3ÆêÆãñ—O$ܧOccu…8–cuµàÎÕÅëq"]2‡ª¾óÔîOãõúÙ º$>IˆüŽÖöâ]ÉÕÀ4žºýŸ›utNýVª99¾_<¯Ã¯’Ìdâ'/ƒDÈzísr&Añ§ þ99gpã¿êŸ“ç¬ Wr^èu´–{ÝSwîŠaMË0\nW7lB?<ÉZjË©þ+‚jºèp8ì÷I3û}¢C{ÅÙ©ÍÆqž{ûa:|øNÂ}ï 9´Wœ ûzqåçÛÇQ¸¾® ž®æVËÐ tÓr§EªŽÂ¨Î6ýSPuÌ@] Mè|:$Þ1èj6Žó¨Ü MKRÅ-dÕ¾èåõâÊkþµ„Ȫh65/&5/‘QóbŠ35/‘QóbŠ3N^Í]‡Ãa¯GÚi°×#örUãm6Žó˜ï§ÃŸ3nÖ{Oê媸)åëÅIªù¢í™ïïï=´£°çAV>½ânÐÍÆqÞëúÏà>ÙÎã¾zUûæÓ¯'©æÏØ0:°q}h6޳§Åç/$ÜV&¯'©æ‡8iq¨yÄ!N.jqˆ“ ‡šGâäÂ4ÿ¦¹Áù‡8‘qÊö† qRÏ758_ â'8î ù—ºñ°Îˆ8Ä ŽCÍ#qráPóˆCœ\8Ô<â'5Ïwf5« ð‚ã*ÎH§šÞ_}[WÌs§šÚ¦iÏ® „š/ò<ó¿’íñªÈqÇ-Ö&?.2ÿûZÁ@ŽÞ¯’__»¸PÏ's+Ó¼n 0FŠbdŽÔÉL»Ró ú Xži;¬}•tª…kOŸœñF†bºËç%Άš/ð6-²ÁeäÜÊwÞJµÐu·¬Q,µ n5_ZÎ8vq©mŸ9Ïf•r–“®n¸yy^óiòLãéIf|œ½9Õ,ó«OöÉiäTþ‘ ·¢9M_Íñ2ò0猣µL¯hßl»Øãþÿÿ쿎«HÆy¢zž€ &&u6"#º"CÝ-1«ê+9YfºÛšÛhtå`õ8! aï)ÀÆnÀÓÔ–íó%ã[Tù+<ý£þRç$ó’•$þB !Ú²i]ËFžÔñ¤w ¦«”U}¾MCËYË'Ç2¤Œ†ž³‰dÔ¡ægADY&‚¤jºn@)ø*(¥jªP—Ðs‡vø"Jö¦â>…ˆ²Œ.¸Õ ?ך‚Ž.mfÛšOÐKì+~|ȳ“yÈáÒ¡€¤ëª¤ZuÜù¼O2/!ó\ÙÝ6„÷Â|X´š²“&«rL.ì†ÓåÕÙL¤4»~^¬èòžä%ubÙÎÓž„Vës…%îÖêŠH#¢åm¢(j¦ñrzôÞ¾Njæ3úøpã4ÚDU.o±ëö¼ÕQ?ÐÅâaR çð®×n>f¾ž9£i_-Õà{Ó ª™kÀw;šLó-œ°zLÔ^ì™J™hûž]>2äU\¬m~&ŠçÛb#þ¢o[KIn9ÃE™e±Ü”Ö!t¢áÃy.˜§‹g®ûÔÒŒku]v¯o=ËKÓ×êF­fýþÔ¤]=¨óÐÅ3ÆKƒýv·³VwV9íükÉ¥öñJn¶-²4ÍòÄVäÕ‰ÎúÁÒ}~ÍëÏÚ!N˜yyùÞÒj5Ï&™;øÎ¾m$¯¯“ìFïZy[µ«uæq PÝëûmíÉ¢ÈÕDÕ>®>P|A6Ö›0ŠBÏÑ%Ùòøl•¨Î í?âù¾ý›ÏÏÏ3l†»]ôã.]ã­¾=vÿZ?üçvöÞUGéˆ^v£" UA’b8ÃvñAï Š/pã„ùÎI5hÜ OÛNŸúÒËØ×B>žàÒÕØ1~¥§Çšzèáw1ïØÜ’yd™ß"óŒíyd™g'd™Gæ·ÈZ»Çîwï…®ÛãY׊æOÄE˜+ÈĨ0 ^›ã=vþÀ˜\ŠæÑíø±CæÑíîË™G;´»/;díÐî¾ìæ¹]1¾A´C;ží„ê …ºµó·*Æ7ˆvhǹ]ÃüÿëÁ3·ß Ú¡çvÈ<Ú¡Ý}Ù!óh‡v÷e‡Ì£ÚÝ—2ÏÂnôžíÙv¤sa7mGú%//\Ý|Bæ™Ú~7kž7Ïx±›öæÙè—'¾WÇÖn>!óLíF¿ƒ=Ïæ¼ØM{ÃüçØÃ&¾?ÏÖn>!óLíFŸµ2ÏI2¼ØM;IæçØC‡&ž“ÃÖn>!óLíx‡™çÆn>!óLíx‡™çÆn>!óLíx‡™çÆn>}óy–ŸË‘¦u–"K“ô\ö ê« 'Ì‹…2O¤^ì¦Ezù96(ÐÄ86líæÓ0ŸmlQÔND‹Œ=ƒM Y_‡Dyj¸Ö¦¢˜~;æß¼¿üõÒŽaöæ1èv*ÄÚ4»±w5iWê<(€ÜØà¯4€Ü»Îh|ð‹½¾}½Ý|šÊ|/AÎ5Û+7ºæ0 ×^_RÙ“Ú8æz4o) Š~ÊÀóïïî¿Ýv¬RøûøñëÈ­_nwÁÝÑ0¸­êA§DÝ=ä÷R»ÓQw¿Ün> b¾Èó&"ì‘r[d'Úÿ›vÛ³ãœeW{cŠ{æ?©£H‘g­”.û&µˆ]A›xw±#Ò§'Ì÷­ñö„¿®écïnb¸{Ævc̉vóéóÙÆP$Q’DèœËÚ:9¨läI=:u‰Hª*5!â·¾¥B1E‘ -O™Ï¢µ©)D2Óþ"D”%"Å,#Qæ+CE‡^shßÖ%Z¥ M/.C¨Rî(à Q²7÷©!Ê2:¬-'ÌwÎAW¶ mŸž~›Çþ¶>>¾uü™þý6³_m7öî P“®i…o™gi7öÇœh7ŸÎ0˜”,;¦-5%l7&¯”®5A0*ä3:L—i—=€:$&\]”øÌ$5óÛ"u5Ú̺ŠÄ®*H}®¤ØY›õaÀÔÙþŠÎ¶K{ KEÐ,£- ,è\»ñ¶¡G‰-¹XU9ƒ.æÛEèmÿúAEÿ…§€dígãŠ(JJ¼ÃO·g˜—yd™oë4óe3 iw8*|Ëô »œÓ=UFô¸È=`ÓÃ,/SˆCØ "ìÊî™oYÔOsü$ MY4ýt­Ó™Ë ³,¶²XÁ"(Ûyê £b”¡Œ>Ü86QU7oѬ~ºÕÙ~Ì#áÞÙ»Ã9¼vóéÜx¾ESÚ•úƒî.³%0d×¼d[.ÂW5>u™ç‘Q"¢oIušsÏ|G‘ml©be´X–Í;ç«ÿ_*eØ3Zfaûž]f•Wq]…E]ªš årðßy«óýšgíÆ./A"\š´V7fyi¢Ý…‹g­êA‡®Õ1\¼`áóZ×êò,ËÊ5±[%ªÓÞçÇó£÷o>>vÆŸºö¶íoõek7Ÿ¾f¿}GiÿÞÛ ÏT !ÒÂN.ð¬8Š;ë óãÞÓxzú>Ã¤ÚØ1~¥‡­Ý|úæ¯BÈü­Ù!ó ™gjwã"óÈ!óLí.‰‹01ÈÄmÛ1¡ÁÐn>!óh‡vwj‡Ì£ÚÝ—2vhw_vÈ<Ú¡Ý}Ù5Ìÿr»b|ƒh‡v<Û Õ' u:jçoUŒoíÐŽs»ÿÿÿì¿nK‡óD¼Ã>Á¾õ­ÝÞ.r—ÊJ“¬l$œD´n ,F1²ÒÄÁnhRÜ&Í-R¸qAÁ=kG× ;ãõÎì9œÙù¹@ÄÇ,|,ìüù=9¿«îî pÀ)ÇÁyà€‹ ç..œ¸¸pp^÷ÌŒô‹ Ӝ틖ÌH·Î·÷Äé˜ÞÏÑ;¾‚ó¢8Ûʳñ8Ø ¶´6k1¢¦ÐWžå‹|tfZWw6¢&wœŽe|L½ã+8/Š»²¬0?>ÜܘÖ`ßRSè+Ì߇ïLëçßR“;NÇr}¦ÞñœÅ]Yv’ùøq¸\šöZYö¨©|ÿƒ v’^{™iŸœ¬GMî8Ûò0õޝà¼(ÎÃy8/WpÎÃù œÆÁy8¯ßùõÏÕí+ƒ£(%Γ^>|,—¦,”å5•ïVÒËàzpôÞ”cóþˆšÜq:bs˜zÇWÎßqt¯¶B- ÎÛÝÎÏ­™gÔä W?ÑšÊ÷§ñIt£Çœóê¦Î=@®fŸ<ždïøªÂùõÏQ‡œïž´àD¯Äycr+½mÙ¦Ôä[+¹u2¡¦òýéA^ƒkOnµæÒúÅÖIÝõŒÁî_Uÿž_ßýjðÎÛ†”™òç…q ííÆñÕóÎߟîw“4MM1¯Á•ç—è«`qf(KØë}b–aÂÑ[y¹<0Xq=,¾D”­ÈzÔdºŠqðB [Œã«ªßóßÞ¯y’á÷|#88®„Ñ8ÿx /ÉpžoçÕ0:çqžoçÕ0çïWýâ5Oû8Ï7‚Ã5¼?¬ê¢Z4×ðö’‡½s² þâ½çw0VgÂåÓé|b^¢R“3NÕà™ñ`ú F2VךRâ¼èœ n6›å¦i$ôOjòÁi˜$3[&5¹OŠdNN›JƒóÒso…g§ê˜ ÛŽ™Å|çEqÒkl„W¡èXôÒŽD|çEqp¾Iœw*8/ŠƒóMâà¼SÁyQœoç ΋â¤÷ÀÞ%RǦ”íØá“¯à¼(Nz¯káÝ ul>ÝŽ¼ù ΋âvi!œú #d¢‰|ç.Rœ¸¸pp8àâÂÁyà€‹ ÷äüëö–pN3îÕã- Cýqžok w8à”ãžœßÕw w8à”ãà1ËØptv¢/¥¦_Â/t^²wô”è‰$¼§Ù]ã<&_Uœçïo³‡ÃÒ9]ýsúwB·Þ|ý%óÌ/8_‰ƒó âBuþîÑù´¿ÞlVY—n¾ýçÝqp~‡Âù-ܳÎ'ý”¿…óÞ88¿C áüÎòÝ~Õ/ŽJš=çoCýA¯Äy\Ãkªw¸†çVU×ðö’‡Ã’ôOOþê<ÞÜÿ±–yn —ç‹Ñ¬Ñ¨<\T1Vç:šU÷{x©4µXxÕ1Dƒg—£ò`˜uðÌh°Îï`òÆçEqôÞÊó¼<-d6³ÏɹôšµR 7=/f­”§ŒÇ,S€üg¿äåI/Ó9Ï ú8êŸóÁä«ÿqÿÿÿì1Nã@†s"îä‚6ÚŽjE%‘XEF¢¢rä$be¶ ah¶¡ ¡Ù‚‚†‚"k“•0ëŒÉdòöÌ÷KHhˆøl>lìyóp^gZ¿EÑ` °Ö§¼ÔW'µÔ×ç¶ÔW.8¯Š3=åÊ.nÙ=myܵèŧ\Ò#ƒ“*é±Å¹•ôÈçUq8ó8¯œÇyœ_à¼2çqçõRçW¾ÁŽ¢¨ßؔҧ¼å¦ NjËM[œÛ–›rÁyUœi¿ä$IâX`ói[œòÖÚ28©­µmqn[kËçUq}¤šLØâ”[hÈà¤ZhXáÜZhÈçÁ ‡óàÀ……ÃypàÂÂá<8paáÞœß÷7Ê'\q­åw„òî:ïk”O¸šãÞœÿ¬?<ÒQ>ApàjŽÃypàÂÂá<8paáp¸°p8ï!n“ð2+Ò•« ..¹^‡ó⬠ÝËø”q†ªÁñ8ym&Ù¼B7eÎ{ˆ³.hw,×WÆv8:ŠnnYЮŒÃyqÖ×8nË£Œ3ìtrr:Ÿ7rãeÎ{ˆÃyœ¯Àἇ8œÇù Î{ˆÃyœ¯Àἇ8ëÆ2Žms”q†.=ÇÇÑ|ÞÈÆ2Ê8œ÷·I9—öx–¸É$o Wî7N×íÆ7'å†pÙI4´œ2ç=ÄmØ(Ö¥ ® î_çÖR§×Ÿ—kunÍÅæïáÿoüÚÜF±Ê8œ÷gzƒíG»{ÿÂ+ãV:ÿ|Þí´;ì«7»M{{;;³»g#Ûz™Èâ é)Wv__fË·ß]ËXâ²kov˽êï¯k:Ÿ}r…ó¿Nó«ú¶qr©•ó‹ÅŸY;Ÿµöìqñr{Øþ’®ü-H YÄyœ¯ÀïíÓƒÜúÝ^<ÚÛ=xÑ9,‰2‘ÅAœÇù œùÿù‡óåÔuFM½­M YÄyœ¯ÀU<Ã{>ÛÍgîðêQ瘄ÈDy†·Eœ\jèüâé¶×jíÝë‘X™Èâ`þò,އ¥L¦Æ·YÙÊŸÏ~‰à»ºM_žåïê.ãò«¾å»º­¿”K½œ¿KÏF³û§ßßv®uH.Ldq0“0I’ÓR¦S㪕ìGåÏg¿d-çm×äLsÜÆ‹d2Ü8MÊKz¦él"°H.µrþñ ¿5k·w:³fß×ç d"‹ƒÊ«S­×Þ+ûÏKáÜ–úÊ¥VÎ/îÓQ·Û]=èh™Èâ rŠuÍpxêòÈP·¤G.õrÞ§2‘ÅAœÇù Î{ˆÃyœ¯Àἇ8œÇù Î{ˆSÞ%ÒzÌ~å3<)œÛ–›rÁy©2‘ÅAåÝ ­÷ºŽã$QĹm­-œ—J YTîú°IO eœC ¹à¼T™HpàÖÄá<8paáp¸°p8\X¸7ç÷ýò ‚Wg\kù!$„¼»Îû宿¸7ç?ët”O¸šãp¸°p8\X8œ.,Î{ˆ«X‘~ñCu½½ÎPMÀzûup8ï!ÎTy6N“|ÇX­º:)œ¡j0I’8¦®îcÎ{ˆ3U˜]E7×zõóR8ÃîQõûÔÏŒû ÿÿì1oÚ@ÇùD|>¿@fæ¬l›§ˆ KNZUXêÔ¥Kt`€ŠfÉ’¥K† YÒç¤jl_@ðöÝÿ)RÑ#ÊïèË/˜»ó=8o ®è$™ÏÓ`1“;'‡ Wp Pž‡sr>ÆÁyqpÎkppÞ@œ‡óœ7çá¼ç Äuz¹žö3¹>6\¸‚.=ý~¿×C›qpÞ@\Q¹Ñ„«_]n¹x̃ƒ(ÛîŽ~fœ¯ÎÃy .ßùå÷ó´gþêeýý×öÃaoÃyÌámâ æðÖüf]­œ¯.]« ÃìbXÇãaÎj%é©ìÚ^øƒeñì¸=—ÓµºÌðhÌX«ÛŽç§Çç——û¯ÍWçŸeFvô°¤j’̉¢(»é%I’-»k…’Ém’ÝÃýÜi×ʾ›dÅí¿ˆ€ÙáјwùÃetþ5_?Î×ÚáRfdGK ©&…w§Jãd·úòEI_†ÝóVÛuÛ­V÷a%3¶#‡%…T“Âw¡Hãdoéá‹’:o@XRH5 çá¼ç ÄÁy8¯ÁÁyqpÎkppÞ@œð)‘Ò8Ù#7ùÎs…%…T“§AKãdÖæ 8Ï–RM w}8N°…_Ày®°¤À·#Μ]88pváàIF'{,_Ày®°¤jÎÃy Έƒóp^ƒƒóâà<œ×àŠ_=ÞÍï«Ú°J K ©&…;½HãdÛæðEÙœ_'­´Gå™/3 ¾°¤jr|3Ž~FÙ†p£ KG7iœl{<¾(›óÿÚλ“G™ñ…%…T“i_Úa¶ñ+©v3<~çVaœp\¾(ó/i_Újv¨Û K ©&‹V°‹úÏØ¡]'Üîž/Êåüj6Žã4ÚßdÄ–RMÍrÑ….½ïåHØõè’;ïƒ÷ÅŽÎKâè{è;sœÿ¤Yç=F’ÞŽS†|Q.ç)îºý¿4:s™ñ…%…T“pÎkpçÓÏóœ¯ ÎÃy Έƒóp^ƒƒóâ0‡·á<æð6q8ÏóUÄ¥‹gaèe"Šãñ0g5ëkuy¸x”.ž±¬Õ݆‹™·õõ¶V—ƒc¬Õi_%îY³›Lý&9ß ÿÈ ˆ/,)¤š¤_å(Š‚L$IBÚgw­œ£ÑA›drqô3™¶ &Ñçi°õ q£ öäèœöµZ½å·éŸÚ·åZf@|aI!ÕäÞ»S{½~ÞÕï›a¯¯û‹E ¶úÎzôöÞê®íWË©ï¶ÝŽ?}x’ kXRH5¹÷](ž0ËU„£·nºbÏs^ö–ž™GOá›öá™–RMÂy8¯ÁÁyqpÎkppÞ@œ‡óœ7·÷)‘——¹sxJyuÕÿý»GnÎ/¯òæðp&œ7·÷iÐaHOýðéÁ z½éõÔGk߆ôκþû ÿÿì¿Râ@Çy¢{ž€°¾ÚÖα³rl<2srW„Ö†H†?GaˆÖ÷WX\Caám¤M6övv?¿±`ô³™õc0ûç‹óâI}Ð21V BcD¦Å΃ççÁs ‡óàÀ¹…ÃypàÜÂmœ?·· _ 8pUÆÕÖ¯(Šr¡>Üçm-Ã\ÅqçËúã» _ 8pÇá<8pnáp8·p8œ[8œ·WxFºá ð긢« ˜oóvã ¯<3¼ÐMWtÕ`/§¬«Ãy«q…W˜^Юˆ+º;ÀMËdý<Î[+¼“ŒákqEwjzÝûäà¼Õ8œÇùÎ[ˆÃyœÏÁá¼…8œÇùÎ[ˆ+œôb8XFW4¥ç[Û_cƒóVãÆ£q8 Ó mñDžèÒsa¨+@N)¯n<ïL»¸„(ÎJã‹’¼ºtóD›É«³³éÈíƒIPl/H'±ŠßþQ?;(VØ’– ‚½’[ ŪçÒ&Ûé~þö5Nšº›jžhó>8}U]ç_WÇSéHGn”`ËáÚ‹ÂΟWÄé«J9¿º»8©7¯×g Ñ÷gw¿Í4KG9Ò‘ÛeO¹ÄÝä¾—vÞó~*äØs–Ë« Ý䮞–°é‰SYÿç_íé¼Iœ¾ª”óoo_Þ{ýôú²^«5šÏfš¥£éÈíƒ8ó98‰ó«ù‰èózs%^¿òÙþÈp8ó9¸\çÍ¿fš£³éÈíƒ8ó98‰ó/“úû}çÇ3¼ÿˆÓW•r~uwºþw¾Ö¸VfZ¤­éÈíƒÉX]¤ÇÞ¢X:x¦:VwÀà™ÊX|h±º8Æç-Ä QÃ0Lϱ‰c=srŠN’‰Üásr$S€âÉ Š˜“³‡óâd³S;¹¬ÀdØv;3î^qª¯¿ðÛߘ{»‡óâdÏðĽT|„ÎrÞì¢Ïë*<2”-éé.º^“56»q8o!çq>‡óâpçsp8o!çq>‡óâdãó··þÓS6¥lµ2Ÿá)n¹é?ú­öÀÜÃy q²Ý ïïÃ÷ô²7Ÿqêpœdkíp=öºÞÃy q9©Ãa5B&ôDhi±çÁs ‡óàÀ¹…ÃypàÜÂá<8pná6ΟÛ[†/¸*ãjëWE¹Pîó¶–á ®â¸óeýáÑ]†/¸Šãp8·p8œ[8œÎ-΃SÅåL€޲¦÷˜_&çÁ©âd Ýî'a²Amz߯@œb¡Îë*G:²DœlAûíƒÿ4ÏZ®?o‰S,hÇy]åHG–ˆ“m\óã¡»œemË3óÄ)6®Áy]åHG–ˆÃùãÂá<8UÎçÁ©âpþ¸p8N' –é<øËYVlάÝÉz†çl°Œa\Žó/“`~ì•oÎtd‰¸ñhNÃî¢ûé+žÈãñ&ƒôûÅq3@Î0Nêüó÷F­vùb¦9:Ë‘Ž,—Äàö¯é}úŠ¢hÔÏŠÁí÷Å©ôûÅÙ'£ÒðÕÙ‡ûÿÿì¿n£J‡óDy?_ µë´éVé\ËÍ^ËFÊ?E ¹Š„‚&6EÖ*ÉâmÒ¤H³Í.ܸp‘=Ø‘¢Ë ¾º30žßÑèèËŒg‡ïüêý&ý2x½‹~¸ÿÄI.w/ùéöÇu~qVûLÃaýôUqï5Id‰¸¼:6W¶–g7Í+:6’Ÿnÿpü~~>í¤I¨uþȹ"C“D–ˆƒójáøÎ/~u7cû…œÛ)24Id‰88¯Î'Šƒójá¶;ß nºƒ_j‹¯I"KÄaO-\ÎZÝêõx“‡Zç÷JÎ-š$²D\ºVçº&þÈŸ ykuÃ;:ÄžOÁZÜ–wrV‹ùBqßÓÐ$‘%âHTÏól&F£üwrF{>]ÎKÀáÝ[àDq4 7 ƒ«_\XIÂ{÷6éÓ!ö|ºÆöpp8Q\ÞÞå¥$¼ÿ±IL:„9<8_Th’Èqp^-œNçÕÂÁyàDqp^-œN—·>~nÍf¼o`Îztˆ=ëórpp8Q\EŽã´™½8æ}ë:vé{>]„.Uµ§Û?œN—Ö´ˆ¢G&Â0y5-Æt$dϧ‹ ¦…œ8½pp8àôÂÁyà€Ó çN/Ü—óßö7$? pÀUw°ÙB :Ä¿úù} ÉpÇ}9_Öž¢Cò\Åqp8àôÂÁyà€Ó çN/œN—¾o?Žï3-œ„ã Þ·¯Î'Š#áØi'íLF^ü€ÿ««Î'Š£.½5k±õäϧÖìÿ?_9œNGÎS¯Î:9µ“'|'§r88œ(Ϋ…ƒóÀ‰âà¼Z88œ(Ϋ…ƒóÀ‰âÈy#1Xç/¦Vò„:6•ÃÁyàDqá$ôbÏ~±3måÖ«óý€ºúLQ¯NÎ'ŠKëÒÞºf×Ì42{rǯKKÚÓ?ÓâØLà|á88œ(îÿÖŸïýøiñÖí[÷÷ÛŽã:¿×kuŠ“›àº±Þ:î nº'‡‡GîûRÎ-î*4Id‰¸¼:6W¶ý`šç»&ðy¿óÛp^ŽßÏ/ß®×Y;ùóñá6Ö[Á|ùܬwžåÜßC“D–ˆƒójáòÆö‹³zš¶¦œ¬ówØhž5¢¹œÛÛeh’Èqp^-\îïùyÔÜdîx4k›-WÎÍí64Id‰88¯nËÞûº‡o¼}|¼žÑÖõ›b¿ä7¡I"KÄaO-ܶyû×nýàtJ«÷ ó×§¡I"KÄ¥ku®k2áù~xwG]}¦}®Õ=™™?`­NnëZÝj¹\}n-+9w¶óÐ$‘%âÈyÏól&‚ íi„Ÿi¾ï¢àrjgÚ0òB8_<ëóÀ‰âhlo;¶·,«ßï³ûûÿô­‹}W×HŒGŒí‹ÇÁyàDqysxÔÕÓŸÝovMûÅfo'm8/çÅÁyµpp8QœW çÅÁyµpp8Q\Þú¼eY½^ÝßûÞ³~ræðZ³œ—€ƒóÀ‰â¢(r‡ývµçy®ë²ûÝ[׋=öÛØNìDc|ëºpœN—Ö´ˆ"¶FEòkW¤{'![ƒ„GM 88pzáàûþ¡Ú¼è¼ëò]èû,ç‹÷7ƒÇ§-ûpÌ…UlõU%aH"kÄÁùfáäÎ??í÷O?nŽ™x{ûKÏ1U†$²Fœoîìó|Øk¯ñƒÝþy³Ùé9¬*ÂDÖˆƒóÍÂÉß®Ç,tæ¿÷›Ûn«Çä?Ó„0$‘5âЇ×,œÔùÝ'ë% –Õ៛ü@oH"kÄÆêÂP{‹“8‹dcu³YÇâØ^x‡±:8ŒÕ§Šã¢BÄ96Ir~N›‹sxHNhç+ÇÁyàTqü†Üqñ^}2™–¥lîír4)$õçÒAýy 88œ*î\žçùe){Çféz…/:ß/ûp^Î§ŠƒóÍÂÁyàTqp¾Y88œ*Î7 çSÅŸ§ëµl ÌÕp,ëó×6œ×€ƒóÀ©âcAˆkWGÉsÙZ׋0bD\;È–b­ëÊqp8UÜ¡¦cb JišÊjZd”fT¬Á…GM 88pfáàAà€»d\ëï7aB¼8ÿ@ÿÿSÆë½£©°BIEND®B`‚golly-2.8-src/Help/Algorithms/QuickLife.html0000644000175100017510000002007212751752464016002 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/S [Seeds]
Every living cell dies every generation, but most patterns still explode.

B234/S [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. 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. 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.

 
Non-totalistic rules

All of the above rules are classified as "totalistic" because the outcome depends only on the total number of neighbors. Golly also supports non-totalistic rules — such rules depend on the configuration of the neighbors, not just their counts.

The syntax used to specify a non-totalistic rule is based on a notation developed by Alan Hensel. It's very similar to the above "B.../S..." notation but uses various lowercase letters to represent unique neighborhoods. One or more of these letters can appear after an appropriate digit (which must be from 1 to 7, depending on the letters). The usual counts of 0 and 8 can still be used without letters since there is no way to constrain 0 or 8 neighbors. B0 is not allowed.

For example, B3/2a34 means birth on 3 neighbors and survival on 2 adjacent neighbors (a corner and an edge), or 3 or 4 neighbors.

Letter strings can get quite long, so it's possible to specify their inverse using a "-" between the digit and the letters. For example, B2cekin/S12 is equivalent to B2-a/S12 and means birth on 2 non-adjacent neighbors, and survival on 1 or 2 neighbors. (This is David Bell's "Just Friends" rule.)

The following table shows which letters correspond to which neighborhoods. The central cell in each neighborhood is colored red, corner neighbors are green, edge neighbors are yellow and ignored neighbors are black:

The table makes it clear which digits are allowed before which letters. For example, B1a/S and B5z/S are both invalid rules.

Golly uses the following steps to convert a given non-totalistic rule into its canonical version:

  1. An underscore can be used instead of a slash, but the canonical version always uses a slash.
  2. The lowercase letters are listed in alphabetical order. For example, B2nic/S will become B2cin/S.
  3. A given rule is converted to its shortest equivalent version. For example, B2ceikn/S will become B2-a/S. If equivalent rules have the same length then the version without the minus sign is preferred. For example, B4-qjrtwz/S will become B4aceikny/S.
  4. It's possible for a non-totalistic rule to be converted to a totalistic rule. If you supply all the letters for a specific neighbor count then the canonical version removes the letters. For example, B2aceikn3/S will become B23/S. (Note that B2-3/S is equivalent to B2aceikn3/S so will also become B23/S.)
  5. If you supply a minus sign and all the letters for a specific neighbor count then the letters and the neighbor count are removed. For example, B2-aceikn3/S will become B3/S.

 
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.8-src/Help/lua.html0000644000175100017510000016122312751752464012602 00000000000000 Golly Help: Lua Scripting

Golly uses a statically embedded Lua interpreter (version 5.3.2) to execute .lua scripts. This lets you extend Golly's capabilities in lots of interesting ways.

Example scripts
Golly's scripting commands
Cell arrays
Rectangle arrays
Using the gplus package
Potential problems
Lua copyright notice

 
Example scripts

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

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

To run one of these scripts, tick the Show Files item in the File menu, open the Scripts/Lua folder 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.lua 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 g.* commands that can be used in a script after including this line:

local g = golly()

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
continue
copy
cut
dellayer
doevent
duplicate
empty
error
evolve
exit
fit
fitsel
flip
getalgo
getbase
getcell
getcells
getclip
getclipstr
getcolor
getcolors
getcursor
getdir
getevent
getfiles
getgen
getheight
getlayer
getmag
getname
getoption
getpop
getpos
getrect
getrule
getselrect
getstep
getstring
getview
getwidth
getxy
hash
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
setview
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 (.lua 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: g.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: g.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: local fname = g.opendialog("Open MCell File", "MCell files (*.mcl)|*.mcl", "C:\\Temp", "sample.mcl")
Example: local dirname = g.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: local fname = g.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 array.
Example: local blinker = g.load("blinker.rle")

store(cell_array, filename)
Write the given cell array 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: g.store(cells, "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 XP: C:\Documents and Settings\username\Application Data\Golly\
On Windows 7+: C:\Users\username\AppData\Roaming\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.

"files" — the directory displayed by File > Show Files.

"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 ("/" on Mac and Linux, "\" on Windows).
Example: g.open(g.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: g.setdir("download", "/path/to/my-downloads/")

getfiles(dirpath)
Return the contents of the given directory as an array of strings. A non-absolute directory path is relative to the location of the script. File names are returned first, then subdirectory names. The latter names end with the platform-specific path separator ("/" on Mac and Linux, "\" on Windows). See slide-show.lua for an example.

 
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: g.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: g.clear(1)

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")

shrink(remove_if_empty=false)
Shrink the current selection to the smallest rectangle enclosing all of the selection's live cells. If the selection has no live cells then the optional parameter specifies whether the selection remains unchanged or is removed.
Example: if #g.getselrect() > 0 then g.shrink(true) end

randfill(percentage)
Randomly fill the current selection to a density specified by the given percentage (1 to 100).
Example: g.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_array, numgens)
Advance the pattern in the given cell array by the specified number of generations and return the resulting cell array.
Example: local newpatt = g.evolve(currpatt, 100)

join(cell_array1, cell_array2)
Join the given cell arrays and return 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) rather than {0}. See below for a description of one-state and multi-state cell arrays.
Example: local result = g.join(part1, part2)

transform(cell_array, x0, y0, axx=1, axy=0, ayx=0, ayy=1)
Apply an affine transformation to the given cell array and return the resulting 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: local rot_blinker = g.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 array.
Example: local blinker = g.parse("3o!")

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

getcells(rect_array)
Return any live cells in the specified rectangle as a cell array. The given 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: local cells = g.getcells( g.getrect() )

getclip()
Parse the pattern data in the clipboard and return the pattern's width, height, and a cell array. The width and height are not necessarily the minimal bounding box because the pattern might have empty borders, or it might even be empty.
Example: local wd, ht, cells = g.getclip()

hash(rect_array)
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: local h = g.hash( g.getrect() )

select(rect_array)
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 {}.
Example: g.select( {-10,-10,20,20} )

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: if #g.getrect() == 0 then g.show("No pattern.") end

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: if #g.getselrect() == 0 then g.show("No selection.") end

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: g.setcell(0, 0, 1 - g.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: local oldcurs = g.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: g.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: g.setstep(0)

getstep()
Return the current step exponent.
Example: g.setstep( g.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: g.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: g.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: g.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, 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 because then it's easy to convert the string to a number.
Example: local gen = tonumber( g.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, 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. The following example converts the population to a number.
Example: local pop = tonumber( g.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 g.empty() then g.show("All cells are dead.") end

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: local maxstate = g.numstates() - 1

numalgos()
Return the number of algorithms (ie. the number of items in the Set Algorithm menu).
Example: local maxalgo = g.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: g.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: local lastalgo = g.getalgo( g.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: g.setrule("b3/s23")

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

getwidth()
Return the width (in cells) of the current universe (0 if unbounded).
Example: local wd = g.getwidth()

getheight()
Return the height (in cells) of the current universe (0 if unbounded).
Example: local ht = g.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: g.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 two strings. The optional parameter (default = '\0') 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, or just use the getposint() function defined in the gplus package.
Example: local x, y = g.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: g.setmag(0)

getmag()
Return the current magnification.
Example: g.setmag( g.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_array)
Return true if the given rectangle is completely visible in the viewport. The rectangle must be an array of the form {x,y,width,height}.
Example: if not g.visrect({0,0,1,1}) then g.setpos("0","0") end

setview(wd, ht)
Set the pixel width and height of the viewport (the main window will be resized accordingly).
Example: g.setview(32*32, 32*30)

getview()
Return the pixel width and height of the viewport.
Example: local wd, ht = g.getview()

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 scripts.
Example: g.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: local newindex = g.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: local cloneindex = g.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: local dupeindex = g.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: g.movelayer(1, 0)

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

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

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

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: g.setname("temporary")

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

setcolors(color_array)
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

getcolors(state=-1)
Return the color of a given state in the current layer as 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 numstates() - 1. Note that the array returned by getcolors can be passed into setcolors; this makes it easy to save and restore colors.
Example: local allcolors = g.getcolors()
Example: local deadcolor = g.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
"boldspacing" 2 to 1000 (cells)
"drawingstate" 0 to 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
"showfiles" 1 or 0
"showgrid" 1 or 0
"showhashinfo" 1 or 0
"showicons" 1 or 0
"showlayerbar" 1 or 0
"showstatusbar" 1 or 0
"showtoolbar" 1 or 0
"smartscale" 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: local oldgrid = g.setoption("showgrid", 1)

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

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 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: local oldr, oldg, oldb = g.setcolor("HashLife", 255, 255, 255)

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

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

setclipstr(string)
Copy an arbitrary string (not necessarily a cell pattern) directly to the clipboard.
Example: g.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: local n = tonumber( g.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.lua 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 will only be returned on a Mac and corresponds to the command key. 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: local evt = g.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. Note that the cmd modifier corresponds to the command key on a Mac or the control key on Windows/Linux (this lets you write portable scripts that work on any platform).
Example: g.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.lua for a good example of how to use this command.
Example: local mousepos = g.getxy()

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...")

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.")

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

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")

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: g.check(false)

continue(message)
This function can be used to continue execution after pcall has detected some sort of error or the user has aborted the script. It's typically used to ensure some finalization code is executed. If not empty, the given message will be displayed in the status bar after the script has finished. See the end of envelope.lua for an example.

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 g.empty() then g.exit("There is no pattern.") end

 
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.lua 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.

 
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.

 
Using the gplus package

The gplus package supplied with Golly provides a high-level interface to many of Golly's built-in scripting commands. The package consists of a set of .lua files stored in the Scripts/Lua/gplus directory. The best way to learn how to use gplus is to look at some of the scripts supplied with Golly:

  • See bricklayer.lua for how to use the pattern function to contruct a complicated pattern by combining simpler sub-patterns.
  • See invert.lua for how to use the rect function to make it easier to manipulate rectangles.
  • See pop-plot.lua for how to draw lines and text.
  • See shift.lua for how to use the split and validint functions to parse user input.

Here's a summary of the functions available after a script calls local gp = require "gplus" (see init.lua for all the implementation details):

gp.int(x) — return integer part of given floating point number
gp.min(a) — return minimum value in given array
gp.max(a) — return maximum value in given array
gp.drawline(x1,y1,x2,y2,z) — draw a line of state z cells from x1,y1 to x2,y2
gp.getedges(r) — return left, top, right, bottom edges of given rectangle array
gp.getminbox(p) — return minimal bounding box of given cell array or pattern
gp.validint(s) — return true if given string is a valid integer
gp.getposint() — return viewport position as 2 integers
gp.setposint(x,y) — use given integers to set viewport position
gp.split(s,sep) — split given string into 1 or more substrings
gp.equal(a1,a2) — return true if given arrays have the same values
gp.compose(S,T) — return the composition of two transformations S and T
gp.rect(r) — return a table for manipulating a rectangle
gp.pattern(p) — return a table for manipulating a pattern

Most of the supplied Lua scripts use gplus, but it isn't compulsory. You might prefer to create your own package for use in the scripts you write. If a script calls require "foo" then Golly will look for foo.lua in the same directory as the script, then it looks for foo/init.lua. If a script calls require "foo.bar" then Golly looks for foo/bar.lua. (If none of those files exist in the script's directory then Golly will look in the supplied Scripts/Lua directory, so scripts can always use the gplus package no matter where they are located.)

 
Potential problems

1. There are some important points to remember about Lua, especially when converting an existing Perl/Python script to Lua:

  • Cell arrays and rectangle arrays start with index 1, not 0. This is necessary to be able to use Lua's length operator (#) and standard library functions like table.unpack.
  • Lua's true and false are not equivalent to 1 and 0. In particular, "if 0" is true.
  • Avoid calls like local x, y, wd, ht = g.getrect(). Only x will get a non-nil value (a rectangle array). You need to do local x, y, wd, ht = table.unpack(g.getrect()).
  • When writing a complicated script it's a good idea to add the line require "gplus.strict" near the top. This will catch any undeclared global variables. When the script is working just remove or comment out that line.

More tips can be found at Lua Gotchas.

2. The escape key check to abort a running script is not done by Lua but by each g.* function. This means that very long Lua computations should call an occasional "no-op" 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 call (or, less useful, a g.open call that loads a pattern) otherwise the script might create lots of temporary files or use lots of memory. From Golly'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 calls 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 or g.step calls) are stored in temporary files; all other changes are stored in memory.

 
Lua copyright notice

Copyright © 1994–2015 Lua.org, PUC-Rio.

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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. golly-2.8-src/Help/about.html0000644000175100017510000000117712751752464013134 00000000000000


This is Golly version 2.8

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



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

http://golly.sourceforge.net/
golly-2.8-src/Help/formats.html0000644000175100017510000011740312751752464013475 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+1 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 (.lua or .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.8-src/Help/help.html0000644000175100017510000000633712751752464012755 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 (.lua 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.8-src/Help/control.html0000644000175100017510000002317512525071110013461 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.8-src/Help/index.html0000644000175100017510000000263312751752464013127 00000000000000 Golly Help: Contents

 

Table of Contents

Introduction
Hints and Tips
Algorithms
Life Lexicon
Online Archives

Lua 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.8-src/Help/mouse.html0000644000175100017510000000215512660172450013135 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/rule file in the left panel to open the file in a text editor. Use Preferences > File to select your preferred text editor.
golly-2.8-src/Help/Lexicon/0000755000175100017510000000000012751756120012600 500000000000000golly-2.8-src/Help/Lexicon/lex_m.htm0000644000175100017510000004720012525071110014325 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.8-src/Help/Lexicon/lex_w.htm0000644000175100017510000002603412525071110014341 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.8-src/Help/Lexicon/lex_a.htm0000644000175100017510000003122512525071110014311 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.8-src/Help/Lexicon/lex_u.htm0000644000175100017510000002322712525071110014340 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.8-src/Help/Lexicon/lex_f.htm0000644000175100017510000004356012525071110014323 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.8-src/Help/Lexicon/lex_c.htm0000644000175100017510000011225212525071110014313 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.8-src/Help/Lexicon/lex_r.htm0000644000175100017510000004216012525071110014332 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.8-src/Help/Lexicon/lex_l.htm0000644000175100017510000004524012525071110014326 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.8-src/Help/Lexicon/lex.htm0000644000175100017510000001726512525071110014021 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.8-src/Help/Lexicon/lex_n.htm0000644000175100017510000001671712525071110014337 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.8-src/Help/Lexicon/lex_x.htm0000644000175100017510000000652712525071110014347 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.8-src/Help/Lexicon/lex_t.htm0000644000175100017510000011322612525071110014336 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.8-src/Help/Lexicon/lex_q.htm0000644000175100017510000001716012525071110014333 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.8-src/Help/Lexicon/lex_1.htm0000644000175100017510000001063412525071110014232 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.8-src/Help/Lexicon/lex_y.htm0000644000175100017510000000462112525071110014341 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.8-src/Help/Lexicon/lex_b.htm0000644000175100017510000010634712525071110014322 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.8-src/Help/Lexicon/lex_o.htm0000644000175100017510000002324112525071110014326 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.8-src/Help/Lexicon/lex_s.htm0000644000175100017510000015226512525071110014343 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.8-src/Help/Lexicon/lex_h.htm0000644000175100017510000007505312525071110014327 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.8-src/Help/Lexicon/lex_v.htm0000644000175100017510000001135112525071110014334 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.8-src/Help/Lexicon/lex_k.htm0000644000175100017510000001237212525071110014325 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.8-src/Help/Lexicon/lex_p.htm0000644000175100017510000012613412525071110014334 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.8-src/Help/Lexicon/lex_bib.htm0000644000175100017510000001025012525071110014620 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.8-src/Help/Lexicon/lex_j.htm0000644000175100017510000001370512525071110014325 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.8-src/Help/Lexicon/lex_d.htm0000644000175100017510000004100612525071110014312 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.8-src/Help/Lexicon/lex_z.htm0000644000175100017510000000602012525071110014335 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.8-src/Help/Lexicon/lex_e.htm0000644000175100017510000004626012525071110014322 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.8-src/Help/Lexicon/lex_i.htm0000644000175100017510000002654312525071110014330 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.8-src/Help/Lexicon/lex_g.htm0000644000175100017510000006371112525071110014324 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.8-src/Help/Lexicon/modify.pl0000755000175100017510000000273112525071110014336 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.8-src/Help/changes.html0000644000175100017510000012421312751752464013427 00000000000000 Golly Help: Changes

Changes in version 2.8 (released August 2016)

  • Golly no longer supports Perl scripting. In its place we've added support for Lua using a statically linked interpreter, so no need to download an installer or set a path to a shared library. See Lua Scripting for all the details.
  • QuickLife and HashLife now support non-totalistic rules. A number of interesting examples can be found in the new Patterns/Non-Totalistic folder.
  • OpenGL is used for rendering patterns.
  • Timers are used to control pattern generation and timeline recording/playback.
  • The File menu items Show Patterns and Show Scripts have been replaced by a single Show Files item for consistency with the recommended way to organize your Golly folder.
  • The shrink command has an optional flag that can remove the selection if it has no live cells (the default is to leave the selection unchanged).
  • Two new scripting commands, setview and getview, can be used to set/get the pixel dimensions of the viewport.
  • The View menu has a new Smarter Scaling option for displaying correctly colored patterns when zoomed out at scales from 2:1 to 16:1.
  • The Buffered item has been removed from the View menu.
  • Paste patterns are covered with a translucent rectangle instead of being enclosed by thin border lines.
  • Correct colors/icons are now displayed when pasting a pattern with a rule different to the current layer's rule.
  • Better reporting of errors in a .rule file.
  • Fixed a bug that could result in a spurious error message when loading a .rule file without any TABLE or TREE section.
  • Fixed a crash on Linux when typing in the Keyboard preferences.
  • Fixed some bugs that could cause Reset/Undo to restore an incorrect pattern.
  • Fixed a timeline bug that could show incorrect population for a bounded grid.
  • bgolly now supports rules that specify bounded grids.
  • Fixed a bug in bgolly that prevented use of the RuleLoader algorithm.
  • bgolly has a new -s option (or --search) for specifying the folder in which the RuleLoader algorithm will look for .rule files before looking in the supplied Rules folder. For example, assuming SlowLife.rule is in a folder called My-rules, you could type a command like this:

    bgolly -a RuleLoader -s My-rules/ -r SlowLife My-patterns/foo.rle

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.lua, 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 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. Lua 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.
  • 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.8-src/Help/edit.html0000644000175100017510000001375212525071110012726 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.8-src/Help/problems.html0000644000175100017510000000202712660172450013626 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.

Windows problems

  • None.

Mac problems

  • Dragging the sash (the thin vertical bar separating the file panel and the viewport) can result in ugly flashing.

Linux problems

  • Scroll bars are not updated correctly while resizing the window.
  • Buttons in the edit/layer bar can become temporarily blank after resizing the window.
golly-2.8-src/Help/credits.html0000644000175100017510000000503012751752464013447 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 are thanks to the generosity and efforts of Eugene Langvagen (author of PLife), Guido van Rossum (creator of Python), and Roberto Ierusalimschy and all the other Lua developers.

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 Chris Rowett.

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, Adam P. Goucher and David Bell.

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.8-src/Help/intro.html0000644000175100017510000000354412525071110013132 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.8-src/Help/refs.html0000644000175100017510000000745112675241401012747 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.8-src/Help/algos.html0000644000175100017510000000107212525071110013076 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.8-src/Help/archives.html0000644000175100017510000000365412660172450013616 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 Files 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.8-src/Help/bounded.html0000644000175100017510000005565012525071110013424 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.8-src/Help/file.html0000644000175100017510000001446612751752464012746 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.

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 Lua 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 Lua Scripting and Python Scripting help topics.

Run Clipboard

Runs the Lua or Python code 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 Files

If ticked then a scrollable folder is displayed in a panel to the left of the viewport. The initial location is the folder containing the Golly application and all the supplied patterns, scripts and rules. Clicking on a pattern file will display it in the viewport, clicking on a .lua/.py script will run it, and clicking on a .rule file will switch to that rule. See Hints and Tips for a good way to organize the Golly folder so you can quickly access your own patterns/rules/scripts and make it easy to upgrade to a newer version of Golly.

Set File Folder...

Lets you change the folder displayed by Show Files (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 XP: C:\Documents and Settings\username\Application Data\Golly\
On Windows 7+: C:\Users\username\AppData\Roaming\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 paste in "~/Library/Application Support/Golly". golly-2.8-src/gollybase/0000755000175100017510000000000012751756121012271 500000000000000golly-2.8-src/gollybase/qlifealgo.h0000644000175100017510000003153312525071110014315 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.8-src/gollybase/ghashbase.cpp0000644000175100017510000014610212751752464014654 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) ; } 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 == 32) 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 >= 32) { if (depth == 32) 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 if (poller->isCalculating()) { // AKT: avoid calling poller->bailIfCalculating 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] == '#') { char *p, *pp ; const char *err ; switch (line[1]) { 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 = 8 ; // 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::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 ; 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 32 bytes of pixel data (8 * RGBA) 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; pixbuf[j++] = livea; } else { pixbuf[j++] = deadr; pixbuf[j++] = deadg; pixbuf[j++] = deadb; pixbuf[j++] = deada; } } } } renderer->pixblit(rx, ry, rw, rh, 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) { // don't do anything } 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 and alpha values for dead and live pixels unsigned char *r, *g, *b; renderer->getcolors(&r, &g, &b, &deada, &livea); 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) { 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) { 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)) { // no live cells } else { drawpixel(0, 0) ; renderbm(-llx, -lly) ; } } else { z = zeronode(d) ; maxd = 1 << (d - mag + 2) ; 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.8-src/gollybase/viewport.h0000644000175100017510000000560712660172450014245 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. */ 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 devices with // high-resolution screens will probably want a bigger cell size) #endif golly-2.8-src/gollybase/util.h0000644000175100017510000000441412525071110013325 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.8-src/gollybase/ruletable_algo.h0000644000175100017510000000540712525071110015334 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.8-src/gollybase/hlifealgo.h0000644000175100017510000003204112525071110014277 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.8-src/gollybase/liferules.h0000755000175100017510000001111212751752464014361 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 ; const int ALL3X3 = 512 ; 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 // rowett: support for hensel2 enum neighborhood_masks { MOORE = 0x1ff, // all 8 neighbors HEXAGONAL = 0x0fe, // ignore NE and SW neighbors VON_NEUMANN = 0x0ba // 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: // canonical version of valid rule passed into setrule char canonrule[MAXRULESIZE] ; neighborhood_masks neighbormask ; bool totalistic ; // is rule totalistic? int neighbors ; // number of neighbors int rulebits ; // bitmask of neighbor counts used (9 birth, 9 survival) int letter_bits[18] ; // bitmask for non-totalistic letters used int neg_letter_bits[18] ; // bitmask for non-totalistic negative letters used int wolfram ; // >= 0 if Wn rule (n is even and <= 254) int survival_offset ; // bit offset in rulebits for survival int max_letters[18] ; // maximum number of letters per neighbor count const int *order_letters[18] ; // letter order per neighbor count void initRule() ; void setTotalistic(int value, bool survival) ; int flipBits(int x) ; int rotateBits90Clockwise(int x) ; void setSymmetrical512(int x, int b) ; void setSymmetrical(int value, bool survival, int lindex, int normal) ; void setTotalisticRuleFromString(const char *rule, bool survival) ; void setRuleFromString(const char *rule, bool survival) ; void createWolframMap() ; void createRuleMap(const char *birth, const char *survival) ; void createB0SmaxRuleMap(const char *birth, const char *survival) ; void createB0EvenRuleMap(const char *birth, const char *survival) ; void createB0OddRuleMap(const char *birth, const char *survival) ; void convertTo4x4Map(char *which) ; void createCanonicalName(lifealgo *algo) ; void removeChar(char *string, char skip) ; bool lettersValid(const char *part) ; int addLetters(int count, int p) ; const char *valid_rule_letters ; const char *rule_letters[4] ; const int *rule_neighborhoods[4] ; char rule3x3[ALL3X3] ; // all 3x3 cell mappings 012345678->4' } ; #endif golly-2.8-src/gollybase/lifepoll.cpp0000755000175100017510000000336112751752464014537 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: nicer 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: nicer not to call lifefatal // lifefatal("recursive poll called.") ; lifewarning("Illegal operation while calculating.") ; interrupted = 1 ; } } void lifepoll::updatePop() {} lifepoll default_poller ; golly-2.8-src/gollybase/util.cpp0000644000175100017510000000766512525071110013673 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.8-src/gollybase/jvnalgo.cpp0000644000175100017510000021172112525071110014344 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.8-src/gollybase/liferules.cpp0000755000175100017510000007252112751752464014727 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() { int i ; valid_rule_letters = "012345678ceaiknjqrytwz-" ; rule_letters[0] = "ce" ; rule_letters[1] = "ceaikn" ; rule_letters[2] = "ceaiknjqry" ; rule_letters[3] = "ceaiknjqrytwz" ; static int entry0[2] = { 1, 2 } ; static int entry1[6] = { 5, 10, 3, 40, 33, 68 } ; static int entry2[10] = { 69, 42, 11, 7, 98, 13, 14, 70, 41, 97 } ; static int entry3[13] = { 325, 170, 15, 45, 99, 71, 106, 102, 43, 101, 105, 78, 108 } ; rule_neighborhoods[0] = entry0 ; rule_neighborhoods[1] = entry1 ; rule_neighborhoods[2] = entry2 ; rule_neighborhoods[3] = entry3 ; survival_offset = 9 ; max_letters[0] = 0 ; max_letters[1] = (int) strlen(rule_letters[0]) ; max_letters[2] = (int) strlen(rule_letters[1]) ; max_letters[3] = (int) strlen(rule_letters[2]) ; max_letters[4] = (int) strlen(rule_letters[3]) ; max_letters[5] = max_letters[3] ; max_letters[6] = max_letters[2] ; max_letters[7] = max_letters[1] ; max_letters[8] = max_letters[0] ; for (i = 0; i < survival_offset; i++) { max_letters[i + survival_offset] = max_letters[i] ; } static int order0[1] = { 0 } ; static int order1[2] = { 0, 1 } ; static int order2[6] = { 2, 0, 1, 3, 4, 5 } ; static int order3[10] = { 2, 0, 1, 3, 6, 4, 5, 7, 8, 9 } ; static int order4[13] = { 2, 0, 1, 3, 6, 4, 5, 7, 8, 10, 11, 9, 12 } ; order_letters[0] = order0 ; order_letters[1] = order1 ; order_letters[2] = order2 ; order_letters[3] = order3 ; order_letters[4] = order4 ; order_letters[5] = order3 ; order_letters[6] = order2 ; order_letters[7] = order1 ; order_letters[8] = order0 ; for (i = 0; i < survival_offset; i++) { order_letters[i + survival_offset] = order_letters[i] ; } // initialize initRule() ; } 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 void liferules::initRule() { neighbormask = MOORE ; neighbors = 8 ; wolfram = -1 ; totalistic = true ; rulebits = 0 ; memset(letter_bits, 0, sizeof(letter_bits)); memset(neg_letter_bits, 0, sizeof(letter_bits)); memset(rule0, 0, sizeof(rule0)) ; memset(rule1, 0, sizeof(rule1)) ; memset(rule3x3, 0, sizeof(rule3x3)) ; memset(canonrule, 0, sizeof(canonrule)) ; } // set 3x3 grid based on totalistic value void liferules::setTotalistic(int value, bool survival) { int mask = 0 ; int nbrs = 0 ; int nhood = 0 ; int i = 0 ; int j = 0 ; int offset = 0 ; // update the rulebits if (survival) { offset = survival_offset ; } rulebits |= 1 << (value + offset) ; // update the mask if survival if (survival) { mask = 0x10 ; } // fill the array based on totalistic value for (i = 0; i < ALL3X3; i += 32) { for (j = 0; j < 16; j++) { nbrs = 0 ; nhood = (i+j) & neighbormask ; while (nhood > 0) { nbrs += (nhood & 1) ; nhood >>= 1 ; } if (value == nbrs) { rule3x3[i+j+mask] = 1 ; } } } } // flip bits int liferules::flipBits(int x) { return ((x & 0x07) << 6) | ((x & 0x1c0) >> 6) | (x & 0x38) ; } // rotate 90 int liferules::rotateBits90Clockwise(int x) { return ((x & 0x4) << 6) | ((x & 0x20) << 2) | ((x & 0x100) >> 2) | ((x & 0x2) << 4) | (x & 0x10) | ((x & 0x80) >> 4) | ((x & 0x1) << 2) | ((x & 0x8) >> 2) | ((x & 0x40) >> 6) ; } // set symmetrical neighborhood into 3x3 map void liferules::setSymmetrical512(int x, int b) { int y = x ; int i = 0 ; // process each of the 4 rotations for (i=0; i<4; i++) { rule3x3[y] = (char) b ; y = rotateBits90Clockwise(y) ; } // flip y = flipBits(y) ; // process each of the 4 rotations for (i=0; i<4; i++) { rule3x3[y] = (char) b ; y = rotateBits90Clockwise(y) ; } } // set symmetrical neighborhood void liferules::setSymmetrical(int value, bool survival, int lindex, int normal) { int xorbit = 0 ; int nindex = value - 1 ; int x = 0 ; int offset = 0 ; // check for homogeneous bits if (value == 0 || value == 8) { setTotalistic(value, survival) ; } else { // update the rulebits if (survival) { offset = survival_offset ; } rulebits |= 1 << (value + offset) ; // reflect the index if in second half if (nindex > 3) { nindex = 6 - nindex ; xorbit = 0x1ef ; } // update the letterbits if (normal) { letter_bits[value + offset] |= 1 << lindex ; } else { neg_letter_bits[value + offset] |= 1 << lindex ; } // lookup the neighborhood x = rule_neighborhoods[nindex][lindex] ^ xorbit ; if (survival) { x |= 0x10 ; } setSymmetrical512(x, normal) ; } } // set totalistic birth or survival rule from a string void liferules::setTotalisticRuleFromString(const char *rule, bool survival) { char current ; // process each character in the rule string while ( *rule ) { current = *rule ; rule++ ; // convert the digit to an integer current -= '0' ; // set totalistic setTotalistic(current, survival) ; } } // set rule from birth or survival string void liferules::setRuleFromString(const char *rule, bool survival) { // current and next character char current ; char next ; // whether character normal or inverted int normal = 1 ; // letter index char *letterindex = 0 ; int lindex = 0 ; int nindex = 0 ; // process each character while ( *rule ) { current = *rule ; rule++ ; // find the index in the valid character list letterindex = strchr((char*) valid_rule_letters, current) ; lindex = letterindex ? int(letterindex - valid_rule_letters) : -1 ; // check if it is a digit if ((lindex > 0 && lindex <= 8) || (lindex == 0 && survival)) { // determine what follows the digit next = *rule ; nindex = -1 ; if (next) { letterindex = strchr((char*) rule_letters[3], next) ; if (letterindex) { nindex = int(letterindex - rule_letters[3]) ; } } // is the next character a digit or minus? if (nindex == -1) { setTotalistic(lindex, survival) ; } // check for inversion normal = 1 ; if (next == '-') { rule++ ; next = *rule ; // invert following character meanings normal = 0 ; } // process non-totalistic characters if (next) { letterindex = strchr((char*) rule_letters[3], next) ; nindex = -1 ; if (letterindex) { nindex = int(letterindex - rule_letters[3]) ; } while (nindex >= 0) { // set symmetrical setSymmetrical(lindex, survival, nindex, normal) ; // get next character rule++ ; next = *rule ; nindex = -1 ; if (next) { letterindex = strchr((char*) rule_letters[3], next) ; if (letterindex) { nindex = int(letterindex - rule_letters[3]) ; } } } } } } } // create the rule map from Wolfram number void liferules::createWolframMap() { int i = 0 ; // clear the rule array memset(rule3x3, 0, ALL3X3) ; // set in the 3x3 map for (i = 0; i < ALL3X3; i+= 1) { if ((wolfram & (1 << (i & 7))) || (i & 16)) { rule3x3[i] = 1 ; } } } // create the rule map from birth and survival strings void liferules::createRuleMap(const char *birth, const char *survival) { // clear the rule array memset(rule3x3, 0, ALL3X3) ; // check for totalistic rule if (totalistic) { // set the totalistic birth rule setTotalisticRuleFromString(birth, false) ; // set the totalistic surivival rule setTotalisticRuleFromString(survival, true) ; } else { // set the non-totalistic birth rule setRuleFromString(birth, false) ; // set the non-totalistic survival rule setRuleFromString(survival, true) ; } } // add canonical letter representation int liferules::addLetters(int count, int p) { int bits ; // bitmask of letters defined at this count int negative = 0 ; // whether negative int setbits ; // how many bits are defined int maxbits ; // maximum number of letters at this count int letter = 0 ; int j ; // check if letters are defined for this neighbor count if (letter_bits[count] || neg_letter_bits[count]) { // check whether normal or negative letters defined if (letter_bits[count]) { bits = letter_bits[count] ; } else { bits = neg_letter_bits[count] ; negative = 1 ; } // compute the number of bits set setbits = bitcount(bits) ; // get the maximum number of allowed letters at this neighbor count maxbits = max_letters[count] ; // do not invert if not negative and seven letters if (!(!negative && setbits == 7 && maxbits == 13)) { // if maximum letters minus number used is greater than number used then invert if (setbits + negative > (maxbits >> 1)) { // invert maximum letters for this count bits = ~bits & ((1 << maxbits) - 1) ; if (bits) { negative = !negative ; } } } // if negative and no letters then remove neighborhood count if (negative && !bits) { canonrule[p] = 0 ; p-- ; } else { // check whether to output minus if (negative) { canonrule[p++] = '-' ; } // add defined letters for (j=0; j= 0) { sprintf(canonrule, "W%d", wolfram) ; while (canonrule[p]) p++ ; } else { // output birth part canonrule[p++] = 'B' ; for (i=0; i<=neighbors; i++) { if (rulebits & (1 << i)) { canonrule[p++] = '0' + (char)i ; // check for non-totalistic if (!totalistic) { // add any defined letters p = addLetters(i, p) ; } } } // add slash canonrule[p++] = '/' ; // output survival part canonrule[p++] = 'S' ; for (i=0; i<=neighbors; i++) { if (rulebits & (1 << (survival_offset+i))) { canonrule[p++] = '0' + (char)i ; // check for non-totalistic if (!totalistic) { // add any defined letters p = addLetters(survival_offset + i, p) ; } } } // add neighborhood if (neighbormask == HEXAGONAL) canonrule[p++] = 'H' ; if (neighbormask == VON_NEUMANN) canonrule[p++] = 'V' ; } // check for bounded grid 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++] ; } // null terminate canonrule[p] = 0 ; } // convert the 3x3 map to the 4x4 map void liferules::convertTo4x4Map(char *which) { int i = 0 ; int v = 0 ; // create every possible cell combination for 4x4 for (i = 0; i < 65536; i += 1) { // perform 4 lookups in the 3x3 map to create the 4x4 entry // 15 14 13 x 7 6 5 // 11 10 9 x -> 11 10 9 -> 10' x 0 0 x x // 7 6 5 x 15 14 13 // x x x x v = rule3x3[((i & 57344) >> 13) | ((i & 3584) >> 6) | ((i & 224) << 1)] << 5 ; // x 14 13 12 6 5 4 // x 10 9 8 -> 10 9 8 -> x 9' 0 0 x x // x 6 5 4 14 13 12 // x x x x v |= rule3x3[((i & 28672) >> 12) | ((i & 1792) >> 5) | ((i & 112) << 2)] << 4 ; // x x x x // 11 10 9 x -> 3 2 1 -> x x 0 0 6' x // 7 6 5 x 7 6 5 // 3 2 1 x 11 10 9 v |= rule3x3[((i & 3584) >> 9) | ((i & 224) >> 2) | ((i & 14) << 5)] << 1 ; // x x x x // x 10 9 8 -> 2 1 0 -> x x 0 0 x 5' // x 6 5 4 6 5 4 // x 2 1 0 10 9 8 v |= rule3x3[((i & 1792) >> 8) | ((i & 112) >> 1) | ((i & 7) << 6)] ; // save the entry which[i] = (char) v ; } } /* Following routines emulate B0 rules using David Eppstein's idea to change the current rule depending on generation 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). */ // create the B0 (no Smax) even generation rule map void liferules::createB0SmaxRuleMap(const char *birth, const char *survival) { int b = 0 ; int s = 0 ; int i = 0 ; char newbirth[10] ; char newsurvival[10] ; // invert neighbor counts and Bx->S(max-x) and Sx->B(max-x) for (i = 0 ; i <= neighbors; i++) { // check if the digit is in the birth part if (strchr(birth, '0' + i) == 0) { // compute Smax-x and add to survival part newsurvival[s++] = '0' + (char) (neighbors - i) ; } // check if the digit is in the survival part if (strchr(survival, '0' + i) == 0) { // compute Smax-x and add to birth part newbirth[b++] = '0' + (char) (neighbors - i) ; } } // terminate strings newbirth[b] = 0 ; newsurvival[s] = 0 ; // create the rule map createRuleMap(newbirth, newsurvival) ; } // create the B0 (no Smax) odd generation rule map void liferules::createB0OddRuleMap(const char *birth, const char *survival) { int b = 0 ; int s = 0 ; int i = 0 ; char newbirth[10] ; char newsurvival[10] ; // Bx->S(max-x) and Sx->B(max-x) for (i = 0 ; i <= neighbors; i++) { // check if the digit is in the birth part if (strchr(birth, '0' + i) != 0) { // Sx->B(max-x) newsurvival[s++] = '0' + (char) (neighbors - i) ; } // check if the digit is in the survival part if (strchr(survival, '0' + i) != 0) { // Bx->S(max-x) newbirth[b++] = '0' + (char) (neighbors - i) ; } } // terminate strings newbirth[b] = 0 ; newsurvival[s] = 0 ; // create the rule map createRuleMap(newbirth, newsurvival) ; } // create the B0 Smax rule map void liferules::createB0EvenRuleMap(const char *birth, const char *survival) { int b = 0 ; int s = 0 ; int i = 0 ; char newbirth[10] ; char newsurvival[10] ; // invert neighbor counts for (i = 0 ; i <= neighbors; i++) { // check if the digit is in the birth part if (strchr(birth, '0' + i) == 0) { // add to birth part newbirth[b++] = '0' + (char) i ; } // check if the digit is in the survival part if (strchr(survival, '0' + i) == 0) { // add to survival part newsurvival[s++] = '0' + (char) i ; } } // terminate strings newbirth[b] = 0 ; newsurvival[s] = 0 ; // create the rule map createRuleMap(newbirth, newsurvival) ; } // remove character from a string in place void liferules::removeChar(char *string, char skip) { int src = 0 ; int dst = 0 ; char c = string[src++] ; // copy characters other than skip while ( c ) { if (c != skip) { string[dst++] = c ; } c = string[src++] ; } // ensure null terminated string[dst] = 0 ; } // check whether non-totalistic letters are valid for defined neighbor counts bool liferules::lettersValid(const char *part) { char c ; int nindex = 0 ; int currentCount = -1 ; // get next character while ( *part ) { c = *part ; if (c >= '0' && c <= '8') { currentCount = c - '0' ; nindex = currentCount - 1; if (nindex > 3) { nindex = 6 - nindex ; } } else { // ignore minus if (c != '-') { // not valid if 0 or 8 if (currentCount == 0 || currentCount == 8) { return false ; } // check against valid rule letters for this neighbor count if (strchr((char*) rule_letters[nindex], c) == 0) { return false ; } } } part++ ; } return true ; } // set rule const char *liferules::setrule(const char *rulestring, lifealgo *algo) { char *r = (char *)rulestring ; char tidystring[MAXRULESIZE] ; // tidy version of rule string char *t = (char *)tidystring ; char *end = r + strlen(r) ; // end of rule string char c ; char *charpos = 0 ; int digit ; int maxdigit = 0 ; // maximum digit value found char *colonpos = 0 ; // position of colon char *slashpos = 0 ; // position of slash char *underscorepos = 0 ; // position of underscore char *bpos = 0 ; // position of b char *spos = 0 ; // position of s // initialize rule type initRule() ; // we might need to emulate B0 rule by using two different rules for odd/even gens alternate_rules = false ; // check for colon colonpos = strchr(r, ':') ; if (colonpos) { // only process up to the colon end = colonpos ; } // create lower case version of rule name without spaces while (r < end) { // get the next character and convert to lowercase c = (char) tolower(*r) ; // process the character switch (c) { // birth case 'b': if (bpos) { // multiple b found return "Only one B allowed." ; } bpos = t ; *t = c ; t++ ; break ; // survival case 's': if (spos) { // multiple s found return "Only one S allowed." ; } spos = t ; *t = c ; t++ ; break ; // slash case '/': if (slashpos) { // multiple slashes found return "Only one slash allowed." ; } slashpos = t ; *t = c ; t++ ; break ; // underscore case '_': if (underscorepos) { // multiple underscores found return "Only one underscore allowed." ; } underscorepos = t ; *t = c ; t++ ; break ; // hex case 'h': if (neighbormask != MOORE || wolfram != -1) { // multiple neighborhoods specified return "Only one neighborhood allowed." ; } neighbormask = HEXAGONAL ; neighbors = 6 ; *t = c ; t++ ; break ; // von neumann case 'v': if (neighbormask != MOORE || wolfram != -1) { // multiple neighborhoods specified return "Only one neighborhood allowed." ; } neighbormask = VON_NEUMANN ; neighbors = 4 ; *t = c ; t++ ; break ; // wolfram case 'w': // check if at beginning of string if (t == tidystring) { if (neighbormask != MOORE || wolfram != -1) { // multiple neighborhoods specified return "Only one neighborhood allowed." ; } wolfram = 0 ; } else { // copy character *t = c ; t++ ; totalistic = false ; } break ; // minus case '-': // check if previous character is a digit if (t == tidystring || *(t-1) < '0' || *(t-1) > '8') { // minus can only follow a digit return "Minus can only follow a digit." ; } *t = c ; t++ ; break ; // other characters default: // ignore space if (c != ' ') { // check character is valid charpos = strchr((char*) valid_rule_letters, c) ; if (charpos) { // copy character *t = c ; t++ ; // check if totalistic (i.e. found a valid non-digit) digit = int(charpos - valid_rule_letters) ; if (digit > 8) { totalistic = false ; } else { // update maximum digit found if (digit > maxdigit) { maxdigit = digit ; } } } else { return "Bad character found." ; } } break ; } // next character r++ ; } // ensure null terminated *t = 0 ; // don't allow empty rule string t = tidystring ; if (*t == 0) { return "Rule cannot be empty string." ; } // can't have slash and underscore if (underscorepos && slashpos) { return "Can't have slash and underscore." ; } // underscore only valid for non-totalistic rules if (underscorepos && totalistic) { return "Underscore not valid for totalistic rules, use slash." ; } // if underscore defined then set the slash position if (underscorepos) { slashpos = underscorepos ; } // check for Wolfram if (wolfram == 0) { // parse Wolfram 1D rule while (*t >= '0' && *t <= '9') { wolfram = 10 * wolfram + *t - '0' ; t++ ; } if (wolfram < 0 || wolfram > 254 || wolfram & 1) { return "Wolfram rule must be an even number from 0 to 254." ; } if (*t) { return "Bad character in Wolfram rule." ; } } else { // if neighborhood specified then must be last character if (neighbormask != MOORE) { size_t len = strlen(t) ; if (len) { c = t[len - 1] ; if (!((c == 'h') || (c == 'v'))) { return "Neighborhood must be at end of rule." ; } // remove character t[len - 1] = 0 ; } } // at least one of slash, b or s must be present if (!(slashpos || bpos || spos)) { return "Rule must contain a slash or B or S." ; } // digits can not be greater than the number of neighbors for the defined neighborhood if (maxdigit > neighbors) { return "Digit greater than neighborhood allows." ; } // if slash present and both b and s then one must be each side of the slash if (slashpos && bpos && spos) { if ((bpos < slashpos && spos < slashpos) || (bpos > slashpos && spos > slashpos)) { return "B and S must be either side of slash." ; } } // check if there was a slash to divide birth from survival if (!slashpos) { // check if both b and s exist if (bpos && spos) { // determine whether b or s is first if (bpos < spos) { // skip b and cut the string using s bpos++ ; *spos = 0 ; spos++ ; } else { // skip s and cut the string using b spos++ ; *bpos = 0 ; bpos++ ; } } else { // just bpos if (bpos) { bpos = t ; removeChar(bpos, 'b') ; spos = bpos + strlen(bpos) ; } else { // just spos spos = t; removeChar(spos, 's') ; bpos = spos + strlen(spos) ; } } } else { // slash exists so set determine which part is b and which is s *slashpos = 0 ; // check if b or s are defined if (bpos || spos) { // check for birth first if ((bpos && bpos < slashpos) || (spos && spos > slashpos)) { // birth then survival bpos = t ; spos = slashpos + 1 ; } else { // survival then birth bpos = slashpos + 1 ; spos = t ; } // remove b or s from rule parts removeChar(bpos, 'b') ; removeChar(spos, 's') ; } else { // no b or s so survival first spos = t ; bpos = slashpos + 1 ; } } // if not totalistic and a part exists it must start with a digit if (!totalistic) { // check birth c = *bpos ; if (c && (c < '0' || c > '8')) { return "Non-totalistic birth must start with a digit." ; } // check survival c = *spos ; if (c && (c < '0' || c > '8')) { return "Non-totalistic survival must start with a digit." ; } } // if not totalistic then neighborhood must be Moore if (!totalistic && neighbormask != MOORE) { return "Non-totalistic only supported with Moore neighborhood." ; } // validate letters used against each specified neighbor count if (!lettersValid(bpos)) { return "Letter not valid for birth neighbor count." ; } if (!lettersValid(spos)) { return "Letter not valid for survival neighbor count." ; } // non-totalistic does not support B0 rules if (!totalistic && strchr(bpos, '0')) { return "Non-totalistic rules do not support B0." ; } } // AKT: check for rule suffix like ":T200,100" to specify a bounded universe if (colonpos) { const char* err = algo->setgridsize(colonpos) ; if (err) return err ; } else { // universe is unbounded algo->gridwd = 0 ; algo->gridht = 0 ; } // create the rule map if (wolfram >= 0) { // create the 3x3 map createWolframMap() ; // save the canonical rule name createCanonicalName(algo) ; // convert to the 4x4 map convertTo4x4Map(rule0) ; } else { // generate the 3x3 map (which also creates the data for the canonical format) createRuleMap(bpos, spos) ; // save the canonical rule name createCanonicalName(algo) ; // check for B0 rules if (totalistic && strchr(bpos, '0')) { // check for Smax if (strchr(spos, '0' + neighbors)) { // B0 Smax createB0SmaxRuleMap(bpos, spos) ; // convert to the even 4x4 map convertTo4x4Map(rule0) ; } else { // set alternate rules needed alternate_rules = true ; // B0 without Smax even generation createB0EvenRuleMap(bpos, spos) ; // convert to the even 4x4 map convertTo4x4Map(rule0) ; // B0 without Smax odd generation createB0OddRuleMap(bpos, spos) ; // convert to the odd 4x4 map convertTo4x4Map(rule1) ; } } else { // non-B0 rule so convert 3x3 to 4x4 map convertTo4x4Map(rule0) ; } } // exit with success return 0 ; } const char* liferules::getrule() { return canonrule ; } // B3/S23 -> (1 << 3) + (1 << (9 + 2)) + (1 << (9 + 3)) = 0x1808 bool liferules::isRegularLife() { return (neighbormask == MOORE && totalistic && rulebits == 0x1808 && wolfram < 0) ; } golly-2.8-src/gollybase/readpattern.cpp0000644000175100017510000007343512525071110015225 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.8-src/gollybase/bigint.h0000644000175100017510000001552012660172450013635 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 ; // editing limits static const bigint min_coord, max_coord ; // 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.8-src/gollybase/ghashbase.h0000644000175100017510000002010112525071110014264 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.8-src/gollybase/ruleloaderalgo.cpp0000644000175100017510000002030012751752464015717 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(); // 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.8-src/gollybase/jvnalgo.h0000644000175100017510000000302312525071110014003 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.8-src/gollybase/liferender.h0000644000175100017510000000525612660172450014505 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 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() ; // pixblit is used to draw a pixel map by passing data in two formats: // If pmscale == 1 then pm data contains 4*w*h bytes where each // byte quadruplet contains the RGBA 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, unsigned char* pm, int pmscale) = 0; // the drawing code needs access to the current layer's colors, // and to the transparency values for dead pixels and live pixels virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b, unsigned char* dead_alpha, unsigned char* live_alpha) = 0; } ; #endif golly-2.8-src/gollybase/qlifedraw.cpp0000644000175100017510000007751612660172450014707 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 ; 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 32 bytes of pixel data (8 * RGBA) 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; pixbuf[j++] = livea; } else { pixbuf[j++] = deadr; pixbuf[j++] = deadg; pixbuf[j++] = deadb; pixbuf[j++] = deada; } } } } renderer->pixblit(rx, ry, rw, rh, pixbuf, pmag); memset(bigbuf, 0, sizeof(ibigbuf)) ; } 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]) { 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) { 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]) { 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 and alpha values for dead and live pixels unsigned char *r, *g, *b; renderer->getcolors(&r, &g, &b, &deada, &livea); 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]) { 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) { 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) { 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) { renderer = 0 ; view = 0 ; return ; } 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.8-src/gollybase/generationsalgo.cpp0000644000175100017510000001106712525071110016066 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.8-src/gollybase/viewport.cpp0000644000175100017510000001447312525071110014570 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.8-src/gollybase/platform.h0000644000175100017510000000443612525071110014200 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.8-src/gollybase/qlifealgo.cpp0000644000175100017510000011627512525071110014657 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.8-src/gollybase/ruletable_algo.cpp0000644000175100017510000010044012525071110015660 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.8-src/gollybase/ruleloaderalgo.h0000644000175100017510000000370312660172450015362 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); }; extern const char* noTABLEorTREE; #endif golly-2.8-src/gollybase/lifealgo.h0000644000175100017510000002155612660172450014151 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" bool CreateBorderCells() ; bool DeleteBorderCells() ; // the above routines can be called around step() to create the // illusion of a bounded universe (note that increment must be 1); // they return false if the pattern exceeds the editing limits 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 ; private: // following are called by CreateBorderCells() to join edges in various ways void JoinTwistedEdges() ; void JoinTwistedAndShiftedEdges() ; void JoinShiftedEdges(int hshift, int vshift) ; void JoinAdjacentEdges(int pt, int pl, int pb, int pr) ; void JoinEdges(int pt, int pl, int pb, int pr) ; // following is called by DeleteBorderCells() void ClearRect(int top, int left, int bottom, int right) ; } ; /** * 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.8-src/gollybase/ruletreealgo.h0000644000175100017510000000347012525071110015043 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.8-src/gollybase/readpattern.h0000644000175100017510000000341112525071110014655 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.8-src/gollybase/writepattern.h0000644000175100017510000000317312525071110015101 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.8-src/gollybase/ruletreealgo.cpp0000644000175100017510000002244512660172450015412 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 ; vector nodelev ; 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())) ; nodelev.push_back(lev) ; 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" ; } if (nodelev[v] != lev - 1) { return "Bad node pointer does not point to one level down" ; } 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.8-src/gollybase/hlifealgo.cpp0000644000175100017510000016531112751752464014664 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) ; } 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 >= 32) { if (depth == 32) 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 >= 32) { if (depth == 32) 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 if (poller->isCalculating()) { // AKT: avoid calling poller->bailIfCalculating 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] == '#') { char *p, *pp ; const char *err ; switch (line[1]) { 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.8-src/gollybase/liferender.cpp0000644000175100017510000000176412525071110015027 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.8-src/gollybase/generationsalgo.h0000644000175100017510000000320112525071110015522 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.8-src/gollybase/ghashdraw.cpp0000644000175100017510000006037312660172450014672 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 ; // AKT: a 256x256 pixmap is good for OpenGL and matches the size // used in qlifedraw.cpp and hlifedraw.cpp; // note that logpmsize *must* be 8 in iOS 9.x to avoid drawing problems // in my iPad (probably due to a bug in the OpenGL ES 2 driver) const int logpmsize = 8; // 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 RGBA 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] ; pixbuf[i+3] = livea; } i += bpp ; if (se) { pixbuf[i] = cellred[se] ; pixbuf[i+1] = cellgreen[se] ; pixbuf[i+2] = cellblue[se] ; pixbuf[i+3] = livea; } i -= rowoff ; if (ne) { pixbuf[i] = cellred[ne] ; pixbuf[i+1] = cellgreen[ne] ; pixbuf[i+2] = cellblue[ne] ; pixbuf[i+3] = livea; } i -= bpp ; if (nw) { pixbuf[i] = cellred[nw] ; pixbuf[i+1] = cellgreen[nw] ; pixbuf[i+2] = cellblue[nw] ; pixbuf[i+3] = livea; } } } void ghashbase::draw4x4_1(ghnode *n, ghnode *z, int llx, int lly) { // AKT: draw all live cells using state 1 color // pmag == 1, so store RGBA 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]; pixbuf[i+3] = livea; } i += bpp; if (n->se != z) { pixbuf[i] = cellred[1]; pixbuf[i+1] = cellgreen[1]; pixbuf[i+2] = cellblue[1]; pixbuf[i+3] = livea; } i -= rowoff; if (n->ne != z) { pixbuf[i] = cellred[1] ; pixbuf[i+1] = cellgreen[1] ; pixbuf[i+2] = cellblue[1] ; pixbuf[i+3] = livea; } i -= bpp; if (n->nw != z) { pixbuf[i] = cellred[1] ; pixbuf[i+1] = cellgreen[1] ; pixbuf[i+2] = cellblue[1] ; pixbuf[i+3] = livea; } } // 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 4 bytes (RGBA) for each pixel if (deada == 0) { // dead cells are 100% transparent so we can use fast method // (RGB values are irrelevant if alpha is 0) memset(pixbuf, 0, sizeof(ipixbuf)); } else { // use slower method pixbuf[0] = cellred[0]; pixbuf[1] = cellgreen[0]; pixbuf[2] = cellblue[0]; pixbuf[3] = deada; // copy 1st pixel to remaining pixels in 1st row for (int i = bpp; i < rowoff; i += bpp) { memcpy(&pixbuf[i], pixbuf, bpp); } // copy 1st row to remaining rows for (int i = rowoff; i < ibufsize; i += rowoff) { memcpy(&pixbuf[i], pixbuf, rowoff); } } } } 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, 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) { // don't do anything } 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: get cell colors and alpha values for dead and live pixels renderer->getcolors(&cellred, &cellgreen, &cellblue, &deada, &livea); 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) { 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) { 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)) { // no live cells } else { drawpixel(0, 0) ; renderbm(-llx, -lly) ; } } else { z = zeroghnode(d) ; maxd = 1 << (d - mag + 2) ; 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.8-src/gollybase/lifealgo.cpp0000644000175100017510000007370712660172450014511 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 "util.h" // for lifestatus #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 following 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; } } void lifealgo::JoinTwistedEdges() { // set grid edges int gl = gridleft.toint(); int gt = gridtop.toint(); int gr = gridright.toint(); int gb = 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 (htwist && 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 = getcell(twistedx, gt); if (state > 0) setcell(x, bb, state); state = getcell(twistedx, gb); if (state > 0) setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { int twistedy = gb - y + gt; int state = getcell(gl, twistedy); if (state > 0) setcell(br, y, state); state = getcell(gr, twistedy); if (state > 0) setcell(bl, y, state); } // copy grid's corner cells to SAME corners in border // (these cells are topologically different to non-corner cells) setcell(bl, bt, getcell(gl, gt)); setcell(br, bt, getcell(gr, gt)); setcell(br, bb, getcell(gr, gb)); setcell(bl, bb, getcell(gl, gb)); } else if (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 = getcell(twistedx, gt); if (state > 0) setcell(x, bb, state); state = getcell(twistedx, gb); if (state > 0) setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no twist int state = getcell(gl, y); if (state > 0) setcell(br, y, state); state = getcell(gr, y); if (state > 0) setcell(bl, y, state); } // do corner cells setcell(bl, bt, getcell(gl, gb)); setcell(br, bt, getcell(gr, gb)); setcell(bl, bb, getcell(gl, gt)); setcell(br, bb, getcell(gr, gt)); } else { // 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 = getcell(x, gt); if (state > 0) setcell(x, bb, state); state = getcell(x, gb); if (state > 0) setcell(x, bt, state); } for (int y = gt; y <= gb; y++) { int twistedy = gb - y + gt; int state = getcell(gl, twistedy); if (state > 0) setcell(br, y, state); state = getcell(gr, twistedy); if (state > 0) setcell(bl, y, state); } // do corner cells setcell(bl, bt, getcell(gr, gt)); setcell(br, bt, getcell(gl, gt)); setcell(bl, bb, getcell(gr, gb)); setcell(br, bb, getcell(gl, gb)); } } void lifealgo::JoinTwistedAndShiftedEdges() { // set grid edges int gl = gridleft.toint(); int gt = gridtop.toint(); int gr = gridright.toint(); int gb = 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) { // 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 = getcell(shiftedx, gb); if (state > 0) setcell(x, bt, state); state = getcell(shiftedx, gt); if (state > 0) setcell(x, bb, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no twist or shift state = getcell(gl, y); if (state > 0) setcell(br, y, state); state = getcell(gr, y); if (state > 0) setcell(bl, y, state); } // do corner cells shiftedx = gl - 1; if (shiftedx < gl) shiftedx = gr; setcell(bl, bt, getcell(shiftedx, gb)); setcell(bl, bb, getcell(shiftedx, gt)); shiftedx = gr - 1; if (shiftedx < gl) shiftedx = gr; setcell(br, bt, getcell(shiftedx, gb)); setcell(br, bb, getcell(shiftedx, gt)); } else { // 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 = getcell(x, gt); if (state > 0) setcell(x, bb, state); state = getcell(x, gb); if (state > 0) 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 = getcell(gr, shiftedy); if (state > 0) setcell(bl, y, state); state = getcell(gl, shiftedy); if (state > 0) setcell(br, y, state); } // do corner cells shiftedy = gt - 1; if (shiftedy < gt) shiftedy = gb; setcell(bl, bt, getcell(gr, shiftedy)); setcell(br, bt, getcell(gl, shiftedy)); shiftedy = gb - 1; if (shiftedy < gt) shiftedy = gb; setcell(bl, bb, getcell(gr, shiftedy)); setcell(br, bb, getcell(gl, shiftedy)); } } void lifealgo::JoinShiftedEdges(int hshift, int vshift) // horizontal and vertical shifts { // set grid edges int gl = gridleft.toint(); int gt = gridtop.toint(); int gr = gridright.toint(); int gb = 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 += gridwd; else if (shiftedx > gr) shiftedx -= gridwd; state = getcell(shiftedx, gb); if (state > 0) setcell(x, bt, state); shiftedx = x + hshift; if (shiftedx < gl) shiftedx += gridwd; else if (shiftedx > gr) shiftedx -= gridwd; state = getcell(shiftedx, gt); if (state > 0) setcell(x, bb, state); } for (int y = gt; y <= gb; y++) { // join left and right edges with no shift state = getcell(gl, y); if (state > 0) setcell(br, y, state); state = getcell(gr, y); if (state > 0) setcell(bl, y, state); } // do corner cells shiftedx = gr - hshift; if (shiftedx < gl) shiftedx += gridwd; else if (shiftedx > gr) shiftedx -= gridwd; setcell(bl, bt, getcell(shiftedx, gb)); shiftedx = gl - hshift; if (shiftedx < gl) shiftedx += gridwd; else if (shiftedx > gr) shiftedx -= gridwd; setcell(br, bt, getcell(shiftedx, gb)); shiftedx = gr + hshift; if (shiftedx < gl) shiftedx += gridwd; else if (shiftedx > gr) shiftedx -= gridwd; setcell(bl, bb, getcell(shiftedx, gt)); shiftedx = gl + hshift; if (shiftedx < gl) shiftedx += gridwd; else if (shiftedx > gr) shiftedx -= gridwd; setcell(br, bb, 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 = getcell(x, gt); if (state > 0) setcell(x, bb, state); state = getcell(x, gb); if (state > 0) 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 += gridht; else if (shiftedy > gb) shiftedy -= gridht; state = getcell(gr, shiftedy); if (state > 0) setcell(bl, y, state); shiftedy = y + vshift; if (shiftedy < gt) shiftedy += gridht; else if (shiftedy > gb) shiftedy -= gridht; state = getcell(gl, shiftedy); if (state > 0) setcell(br, y, state); } // do corner cells shiftedy = gb - vshift; if (shiftedy < gt) shiftedy += gridht; else if (shiftedy > gb) shiftedy -= gridht; setcell(bl, bt, getcell(gr, shiftedy)); shiftedy = gb + vshift; if (shiftedy < gt) shiftedy += gridht; else if (shiftedy > gb) shiftedy -= gridht; setcell(br, bt, getcell(gl, shiftedy)); shiftedy = gt - vshift; if (shiftedy < gt) shiftedy += gridht; else if (shiftedy > gb) shiftedy -= gridht; setcell(bl, bb, getcell(gr, shiftedy)); shiftedy = gt + vshift; if (shiftedy < gt) shiftedy += gridht; else if (shiftedy > gb) shiftedy -= gridht; setcell(br, bb, getcell(gl, shiftedy)); } } void lifealgo::JoinAdjacentEdges(int pt, int pl, int pb, int pr) // pattern edges { // set grid edges int gl = gridleft.toint(); int gt = gridtop.toint(); int gr = gridright.toint(); int gb = 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 = nextcell(x, gt, state); if (skip < 0) break; x += skip; if (state > 0) 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 = getcell(gl, y); if (state > 0) 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 = nextcell(x, gb, state); if (skip < 0) break; x += skip; if (state > 0) 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 = getcell(gr, y); if (state > 0) setcell(gl + (y - gt), bb, state); } // copy grid's corner cells to SAME corners in border setcell(bl, bt, getcell(gl, gt)); setcell(br, bt, getcell(gr, gt)); setcell(br, bb, getcell(gr, gb)); setcell(bl, bb, getcell(gl, gb)); } void lifealgo::JoinEdges(int pt, int pl, int pb, int pr) // pattern edges { // set grid edges int gl = gridleft.toint(); int gt = gridtop.toint(); int gr = gridright.toint(); int gb = 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 (gridht > 0) { // copy live cells in top edge to bottom border for (int x = pl; x <= pr; x++) { int state; int skip = nextcell(x, gt, state); if (skip < 0) break; x += skip; if (state > 0) setcell(x, bb, state); } // copy live cells in bottom edge to top border for (int x = pl; x <= pr; x++) { int state; int skip = nextcell(x, gb, state); if (skip < 0) break; x += skip; if (state > 0) setcell(x, bt, state); } } if (gridwd > 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 = getcell(gl, y); if (state > 0) 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 = getcell(gr, y); if (state > 0) setcell(bl, y, state); } } if (gridwd > 0 && gridht > 0) { // copy grid's corner cells to opposite corners in border setcell(bl, bt, getcell(gr, gb)); setcell(br, bt, getcell(gl, gb)); setcell(br, bb, getcell(gl, gt)); setcell(bl, bb, getcell(gr, gt)); } } bool lifealgo::CreateBorderCells() { // no need to do anything if there is no pattern or if the grid is a bounded plane if (isEmpty() || boundedplane) return true; bigint top, left, bottom, right; findedges(&top, &left, &bottom, &right); // no need to do anything if pattern is completely inside grid edges if ( (gridwd == 0 || (gridleft < left && gridright > right)) && (gridht == 0 || (gridtop < top && gridbottom > bottom)) ) { return true; } // if grid has infinite width or height then pattern might be too big to use setcell/getcell if ( (gridwd == 0 || gridht == 0) && (top < bigint::min_coord || left < bigint::min_coord || bottom > bigint::max_coord || right > bigint::max_coord) ) { lifestatus("Pattern is beyond editing limit!"); // return false so caller can exit step() loop return false; } if (sphere) { // to get a sphere we join top edge with left edge, and right edge with bottom edge; // note that grid must be square (gridwd == gridht) int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); JoinAdjacentEdges(pt, pl, pb, pr); } else if (htwist || vtwist) { // Klein bottle or cross-surface if ( (htwist && hshift != 0 && (gridwd & 1) == 0) || (vtwist && vshift != 0 && (gridht & 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(); } else { JoinTwistedEdges(); } } else if (hshift != 0 || vshift != 0) { // torus with horizontal or vertical shift JoinShiftedEdges(hshift, vshift); } else { // unshifted torus or infinite tube int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); JoinEdges(pt, pl, pb, pr); } endofpattern(); return true; } void lifealgo::ClearRect(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 = 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; setcell(cx, cy, 0); } else { cx = right + 1; // done this row } } } } bool lifealgo::DeleteBorderCells() { // no need to do anything if there is no pattern if (isEmpty()) return true; // 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; findedges(&top, &left, &bottom, &right); // no need to do anything if grid encloses entire pattern if ( (gridwd == 0 || (gridleft <= left && gridright >= right)) && (gridht == 0 || (gridtop <= top && gridbottom >= bottom)) ) { return true; } // set pattern edges int pl = left.toint(); int pt = top.toint(); int pr = right.toint(); int pb = bottom.toint(); // set grid edges int gl = gridleft.toint(); int gt = gridtop.toint(); int gr = gridright.toint(); int gb = gridbottom.toint(); if (gridht > 0 && pt < gt) { // delete live cells above grid ClearRect(pt, pl, gt-1, pr); pt = gt; // reduce size of rect below } if (gridht > 0 && pb > gb) { // delete live cells below grid ClearRect(gb+1, pl, pb, pr); pb = gb; // reduce size of rect below } if (gridwd > 0 && pl < gl) { // delete live cells left of grid ClearRect(pt, pl, pb, gl-1); } if (gridwd > 0 && pr > gr) { // delete live cells right of grid ClearRect(pt, gr+1, pb, pr); } endofpattern(); // do this test AFTER clearing border if ( top < bigint::min_coord || left < bigint::min_coord || bottom > bigint::max_coord || right > bigint::max_coord ) { lifestatus("Pattern exceeded editing limit!"); // return false so caller can exit step() loop return false; } return true; } // ----------------------------------------------------------------------------- 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.8-src/gollybase/bigint.cpp0000644000175100017510000004435512751752464014212 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 = (2 * ((1 << 30) % a) % 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) ; // most editing operations are limited to absolute coordinates <= 10^9, // partly because getcell and setcell only take int parameters, but mostly // to avoid ridiculously long cut/copy/paste/rotate/etc operations const bigint bigint::min_coord(-1000000000) ; const bigint bigint::max_coord(+1000000000) ; golly-2.8-src/gollybase/writepattern.cpp0000644000175100017510000002666312525071110015445 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.8-src/Scripts/0000755000175100017510000000000012751756120011736 500000000000000golly-2.8-src/Scripts/Lua/0000755000175100017510000000000012751756120012457 500000000000000golly-2.8-src/Scripts/Lua/make-torus.lua0000755000175100017510000000135312751752464015205 00000000000000-- Use the current selection to create a toroidal universe. -- Author: Andrew Trevorrow (andrewtrevorrow.com), Apr 2016. local g = golly() local selrect = g.getselrect() if #selrect == 0 then g.exit("There is no selection.") end local x, y, wd, ht = table.unpack(selrect) local selcells = g.getcells(selrect) if not g.empty() then g.clear(0) g.clear(1) end -- get current rule, remove any existing suffix, then add new suffix local rule = g.getrule() rule = rule:match("^(.+):") or rule g.setrule(string.format("%s:T%d,%d", rule, wd, ht)) local newx = -math.floor(wd/2) local newy = -math.floor(ht/2) selrect[1] = newx selrect[2] = newy g.select(selrect) if #selcells > 0 then g.putcells(selcells, newx - x, newy - y) end g.fitsel() golly-2.8-src/Scripts/Lua/density.lua0000755000175100017510000000061412751752464014574 00000000000000-- Calculates the density of live cells in the current pattern. -- Author: Andrew Trevorrow (andrew@trevorrow.com), March 2016. local g = golly() local bbox = g.getrect() if #bbox == 0 then g.exit("The pattern is empty.") end local d = g.getpop() / (bbox[3] * bbox[4]) if d < 0.000001 then g.show(string.format("Density = %.1e", d)) else g.show(string.format("Density = %.6f", d)) end golly-2.8-src/Scripts/Lua/move-object.lua0000644000175100017510000002703512751752464015332 00000000000000-- Allow user to move a connected group of live cells. -- Author: Andrew Trevorrow (andrew@trevorrow.com), Jan 2011. local g = golly() local gp = require "gplus" local int = gp.int local split = gp.split local rect = gp.rect local getminbox = gp.getminbox -- set edges of bounded grid for later use local gridl, gridr, gridt, gridb if g.getwidth() > 0 then gridl = -int(g.getwidth()/2) gridr = gridl + g.getwidth() - 1 end if g.getheight() > 0 then gridt = -int(g.getheight()/2) gridb = gridt + g.getheight() - 1 end local helpmsg = " (hit 'h' for help)" local ncells = {} -- list of neighboring live cells local oldcells = {} -- cells under moved object local object = {} -- cells in moving object local object1 = {} -- cells in initial object -------------------------------------------------------------------------------- local function 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).]]) end -------------------------------------------------------------------------------- local function 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]]) end -------------------------------------------------------------------------------- local function getstate(x, y) -- first check if x,y is outside bounded grid if g.getwidth() > 0 and (x < gridl or x > gridr) then return 0 end if g.getheight() > 0 and (y < gridt or y > gridb) then return 0 end return g.getcell(x, y) end -------------------------------------------------------------------------------- local function findlivecell(x, y) if g.getcell(x, y) > 0 then return {x, y} end -- spiral outwards from x,y looking for a nearby live cell; -- the smaller the scale the smaller the area searched local maxd = 10 local mag = g.getmag() if mag > 0 then -- mag can be 1..5 (ie. scales 1:2 to 1:32) maxd = 2 * (6 - mag) -- 10, 8, 6, 4, 2 end local d = 1 while d <= maxd do x = x - 1 y = y - 1 for i = 1, 2*d do x = x + 1 -- move east if getstate(x, y) > 0 then return {x, y} end end for i = 1, 2*d do y = y + 1 -- move south if getstate(x, y) > 0 then return {x, y} end end for i = 1, 2*d do x = x - 1 -- move west if getstate(x, y) > 0 then return {x, y} end end for i = 1, 2*d do y = y - 1 -- move north if getstate(x, y) > 0 then return {x, y} end end d = d + 1 end return {} -- failed to find a live cell end -------------------------------------------------------------------------------- local function checkneighbor(x, y) -- first check if x,y is outside bounded grid if g.getwidth() > 0 and (x < gridl or x > gridr) then return end if g.getheight() > 0 and (y < gridt or y > gridb) then return end if g.getcell(x, y) == 0 then return end ncells[#ncells + 1] = {x, y, g.getcell(x,y)} g.setcell(x, y, 0) end -------------------------------------------------------------------------------- local function getobject(x, y) local object = {} ncells[#ncells + 1] = {x, y, g.getcell(x,y)} g.setcell(x, y, 0) while #ncells > 0 do -- remove cell from end of ncells and append to object local x, y, s = table.unpack( table.remove(ncells) ) object[#object + 1] = x object[#object + 1] = y object[#object + 1] = 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) end -- append padding int if necessary if #object > 0 and (#object & 1) == 0 then object[#object + 1] = 0 end g.putcells(object) return object end -------------------------------------------------------------------------------- local function underneath(object) -- return array of live cells underneath given object (a multi-state array) local cells = {} local objlen = #object if objlen % 3 == 1 then objlen = objlen - 1 end -- ignore padding int local i = 1 while i <= objlen do local x = object[i] local y = object[i+1] local s = g.getcell(x, y) if s > 0 then cells[#cells + 1] = x cells[#cells + 1] = y cells[#cells + 1] = s end i = i + 3 end -- append padding int if necessary if #cells > 0 and (#cells & 1) == 0 then cells[#cells + 1] = 0 end return cells end -------------------------------------------------------------------------------- local function rectingrid(r) -- return true if all of given rectangle is inside grid if g.getwidth() > 0 and (r[1] < gridl or r[1] + r[3] - 1 > gridr) then return false end if g.getheight() > 0 and (r[2] < gridt or r[2] + r[4] - 1 > gridb) then return false end return true end -------------------------------------------------------------------------------- local function lookforkeys(event) -- look for keys used to flip/rotate object if event == "key x none" or event == "key y none" then -- flip floating object left-right or top-bottom g.putcells(object, 0, 0, 1, 0, 0, 1, "xor") -- erase object if #oldcells > 0 then g.putcells(oldcells) end local obox = getminbox(object) if event == "key x none" then -- translate object so that bounding box doesn't change local xshift = 2 * (obox.left + int(obox.wd/2)) if obox.wd % 2 == 0 then xshift = xshift - 1 end object = g.transform(object, xshift, 0, -1, 0, 0, 1) else -- translate object so that bounding box doesn't change local yshift = 2 * (obox.top + int(obox.ht/2)) if obox.ht % 2 == 0 then yshift = yshift - 1 end object = g.transform(object, 0, yshift, 1, 0, 0, -1) end oldcells = underneath(object) g.putcells(object) g.update() return end if event == "key > none" or event == "key < none" then -- rotate floating object clockwise or anticlockwise -- about the center of the object's bounding box local obox = getminbox(object) local midx = obox.left + int(obox.wd/2) local midy = obox.top + int(obox.ht/2) local newleft = midx + obox.top - midy local newtop = midy + obox.left - midx local rotrect = { newleft, newtop, obox.ht, obox.wd } if not rectingrid(rotrect) then g.warn("Rotation is not allowed if object would be outside grid.") return end g.putcells(object, 0, 0, 1, 0, 0, 1, "xor") -- erase object if #oldcells > 0 then g.putcells(oldcells) end if event == "key > none" then -- 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) end -- 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 end if event == "key h none" then showhelp2() return end g.doevent(event) end -------------------------------------------------------------------------------- local function moveobject() local oldmouse, mousepos, prevx, prevy -- wait for 1st click in live cell while true do local event = g.getevent() if event:find("click") == 1 then -- event is a string like "click 10 20 left none" local evt, xstr, ystr, butt, mods = split(event) local result = findlivecell(tonumber(xstr), tonumber(ystr)) if #result > 0 then prevx = tonumber(xstr) prevy = tonumber(ystr) oldmouse = xstr .. ' ' .. ystr g.show("Extracting object...") local x, y = table.unpack(result) object = getobject(x, y) object1 = g.join({},object) -- save in case user aborts script if mods == "alt" then -- don't delete object oldcells = g.join({},object) end break else g.warn("Click on or near a live cell belonging to the desired object.") end elseif event == "key h none" then showhelp1() else g.doevent(event) end end -- wait for 2nd click while moving object g.show("Move mouse and click again..." .. helpmsg) local gotclick = false while not gotclick do local event = g.getevent() if event:find("click") == 1 then local evt, x, y, butt, mods = split(event) mousepos = x..' '..y gotclick = true else if #event > 0 then lookforkeys(event) end mousepos = g.getxy() end if #mousepos > 0 and mousepos ~= oldmouse then -- mouse has moved, so move object g.putcells(object, 0, 0, 1, 0, 0, 1, "xor") -- erase object if #oldcells > 0 then g.putcells(oldcells) end local xstr, ystr = split(mousepos) local x = tonumber(xstr) local y = tonumber(ystr) if g.getwidth() > 0 then -- ensure object doesn't move beyond left/right edge of grid local obox = getminbox( g.transform(object, x - prevx, y - prevy) ) if obox.left < gridl then x = x + gridl - obox.left elseif obox.right > gridr then x = x - obox.right - gridr end end if g.getheight() > 0 then -- ensure object doesn't move beyond top/bottom edge of grid local obox = getminbox( g.transform(object, x - prevx, y - prevy) ) if obox.top < gridt then y = y + gridt - obox.top elseif obox.bottom > gridb then y = y - obox.bottom - gridb end end object = g.transform(object, x - prevx, y - prevy) oldcells = underneath(object) g.putcells(object) prevx = x prevy = y oldmouse = mousepos g.update() end end end -------------------------------------------------------------------------------- if #g.getrect() == 0 then g.exit("There are no objects.") end g.show("Click on or near live cell in object, move mouse and click again..."..helpmsg) local oldcursor = g.getcursor() g.setcursor("Move") local aborted = true local status, err = pcall(function () moveobject() aborted = false end) if err then g.continue(err) end g.setcursor(oldcursor) if aborted then -- erase object if it moved if #object > 0 then g.putcells(object, 0, 0, 1, 0, 0, 1, "xor") end if #oldcells > 0 then g.putcells(oldcells) end if #object1 > 0 then g.putcells(object1) end else g.show(" ") end golly-2.8-src/Scripts/Lua/draw-lines.lua0000644000175100017510000001074112751752464015161 00000000000000-- Allow user to draw one or more straight lines by clicking end points. -- Author: Andrew Trevorrow (andrew@trevorrow.com), Apr 2016. local g = golly() local gp = require "gplus" local oldline = {} local firstcell = {} -- pos and state of the 1st cell clicked local drawstate = g.getoption("drawingstate") -------------------------------------------------------------------------------- local function 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 local oldcells = {} -- note that x1,y1 has already been drawn if x1 == x2 and y1 == y2 then g.update() return oldcells end local dx = x2 - x1 local ax = math.abs(dx) * 2 local sx = 1 if dx < 0 then sx = -1 end local dy = y2 - y1 local ay = math.abs(dy) * 2 local sy = 1 if dy < 0 then sy = -1 end if ax > ay then local d = ay - (ax / 2) while x1 ~= x2 do oldcells[#oldcells+1] = {x1, y1, g.getcell(x1, y1)} g.setcell(x1, y1, drawstate) if d >= 0 then y1 = y1 + sy d = d - ax end x1 = x1 + sx d = d + ay end else local d = ax - (ay / 2) while y1 ~= y2 do oldcells[#oldcells+1] = {x1, y1, g.getcell(x1, y1)} g.setcell(x1, y1, drawstate) if d >= 0 then x1 = x1 + sx d = d - ay end y1 = y1 + sy d = d + ax end end oldcells[#oldcells+1] = {x2, y2, g.getcell(x2, y2)} g.setcell(x2, y2, drawstate) g.update() return oldcells end -------------------------------------------------------------------------------- local function eraseline(oldcells) for _, t in ipairs(oldcells) do g.setcell( table.unpack(t) ) end end -------------------------------------------------------------------------------- local function drawlines() local started = false local oldmouse = "" local startx, starty, endx, endy while true do local event = g.getevent() if event:find("click") == 1 then -- event is a string like "click 10 20 left altctrlshift" local evt, x, y, butt, mods = gp.split(event) oldmouse = x .. ' ' .. y if started then -- draw permanent line from start pos to end pos endx = tonumber(x) endy = tonumber(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 = tonumber(x) starty = tonumber(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)...") end else -- event might be "" or "key m none" if #event > 0 then g.doevent(event) end local mousepos = g.getxy() if started and #mousepos == 0 then -- erase old line if mouse is not over grid if #oldline > 0 then eraseline(oldline) oldline = {} g.update() end elseif started and #mousepos > 0 and mousepos ~= oldmouse then -- mouse has moved, so erase old line (if any) and draw new line if #oldline > 0 then eraseline(oldline) end local x, y = gp.split(mousepos) oldline = drawline(startx, starty, tonumber(x), tonumber(y)) oldmouse = mousepos end end end end -------------------------------------------------------------------------------- g.show("Click where to start line...") local oldcursor = g.getcursor() g.setcursor("Draw") local status, err = pcall(function () drawlines() end) if err then g.continue(err) end -- the following code is executed even if error occurred or user aborted script g.setcursor(oldcursor) if #oldline > 0 then eraseline(oldline) end if #firstcell > 0 then local x, y, s = table.unpack(firstcell) g.setcell(x, y, s) endgolly-2.8-src/Scripts/Lua/pd-glider.lua0000755000175100017510000000120312751752464014757 00000000000000-- Creates a large set of pentadecathlon + glider collisions. -- Based on pd_glider.py from PLife (http://plife.sourceforge.net/). local g = golly() local gp = require "gplus" local gpo = require "gplus.objects" g.new("pd-glider") -- best to create empty universe before setting rule -- to avoid converting an existing pattern (slow if large) g.setrule("B3/S23") local function collision(i, j) return gpo.pentadecathlon + gpo.glider[i + 11].t(-8 + j, -10, gp.flip) end local all = gp.pattern() for i = -7, 7 do for j = -9, 9 do all = all + collision(i, j).t(100 * i, 100 * j) end end all.display("") -- don't change name golly-2.8-src/Scripts/Lua/pop-plot.lua0000755000175100017510000001105412751752464014667 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 (andrewtrevorrow.com), Apr 2016. local g = golly() local gp = require "gplus" local int = gp.int local min = gp.min local max = gp.max local drawline = gp.drawline local gpt = require "gplus.text" -- size of plot local xlen = 500 -- length of x axis local ylen = 500 -- length of y axis -------------------------------------------------------------------------------- local function monotext(s) -- convert given string to a pattern in a mono-spaced font and return -- its cell array and its minimal width and height local p = gpt.maketext(s, "mono") local r = gp.getminbox(p) return p.array, r.wd, r.ht end -------------------------------------------------------------------------------- local function fit_if_not_visible() -- fit pattern in viewport if not empty and not completely visible local r = g.getrect() if #r > 0 and not g.visrect(r) then g.fit() end end -------------------------------------------------------------------------------- if g.empty() then g.exit("There is no pattern.") end -- check that a layer is available for population plot local layername = "population plot" local poplayer = -1 for i = 0, g.numlayers()-1 do if g.getname(i) == layername then poplayer = i break end end if poplayer == -1 and g.numlayers() == g.maxlayers() then g.exit("You need to delete a layer.") end -- prompt user for number of steps local s = g.getstring("Enter the number of steps:", xlen, "Population plotter") if string.len(s) == 0 then g.exit() end local numsteps = tonumber(s) if numsteps <= 0 then g.exit() end -- generate pattern for given number of steps local pops = { tonumber(g.getpop()) } local gens = { tonumber(g.getgen()) } local oldsecs = os.clock() for i = 1, numsteps do g.step() pops[#pops+1] = tonumber(g.getpop()) gens[#gens+1] = tonumber(g.getgen()) local newsecs = os.clock() if newsecs - oldsecs >= 1.0 then -- show pattern every second oldsecs = newsecs fit_if_not_visible() g.update() g.show(string.format("Step %d of %d", i, numsteps)) end end fit_if_not_visible() -- save some info before we switch layers local stepsize = string.format("%d^%d", g.getbase(), g.getstep()) local pattname = g.getname() -- create population plot in separate layer g.setoption("stacklayers", 0) g.setoption("tilelayers", 0) g.setoption("showlayerbar", 1) if poplayer == -1 then poplayer = g.addlayer() else g.setlayer(poplayer) end g.new(layername) -- use same rule but without any suffix (we don't want a bounded grid) local rule = g.getrule() rule = rule:match("^(.+):") or rule g.setrule(rule) local deadr, deadg, deadb = g.getcolor("deadcells") if (deadr + deadg + deadb) / 3 > 128 then -- use black if light background g.setcolors({1,0,0,0}) else -- use white if dark background g.setcolors({1,255,255,255}) end local minpop = min(pops) local maxpop = max(pops) if minpop == maxpop then -- avoid division by zero minpop = minpop - 1 end local popscale = (maxpop - minpop) / ylen local mingen = min(gens) local maxgen = max(gens) local genscale = (maxgen - mingen) / xlen -- draw axes with origin at 0,0 drawline(0, 0, xlen, 0) drawline(0, 0, 0, -ylen) -- add annotation using mono-spaced ASCII font local t, wd, ht = monotext(string.upper(pattname)) g.putcells(t, int((xlen - wd) / 2), -ylen - 10 - ht) t, wd, ht = monotext("POPULATION") g.putcells(t, -10 - ht, int(-(ylen - wd) / 2), 0, 1, -1, 0) t, wd, ht = monotext(""..minpop) g.putcells(t, -wd - 10, int(-ht / 2)) t, wd, ht = monotext(""..maxpop) g.putcells(t, -wd - 10, -ylen - int(ht / 2)) t, wd, ht = monotext("GENERATION (step="..stepsize..")") g.putcells(t, int((xlen - wd) / 2), 10) t, wd, ht = monotext(""..mingen) g.putcells(t, int(-wd / 2), 10) t, wd, ht = monotext(""..maxgen) g.putcells(t, xlen - int(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) local x = int((gens[1] - mingen) / genscale) local y = int((pops[1] - minpop) / popscale) oldsecs = os.clock() for i = 1, numsteps do local newx = int((gens[i+1] - mingen) / genscale) local newy = int((pops[i+1] - minpop) / popscale) drawline(x, -y, newx, -newy) x = newx y = newy local newsecs = os.clock() if newsecs - oldsecs >= 1.0 then -- show pattern every second oldsecs = newsecs g.update() end end golly-2.8-src/Scripts/Lua/move-selection.lua0000644000175100017510000002017412751752464016046 00000000000000-- Allow user to move the current selection. -- Author: Andrew Trevorrow (andrew@trevorrow.com), Apr 2011. local g = golly() local gp = require "gplus" local split = gp.split -- set edges of bounded grid for later use local gridl, gridr, gridt, gridb if g.getwidth() > 0 then gridl = -gp.int(g.getwidth() / 2) gridr = gridl + g.getwidth() - 1 end if g.getheight() > 0 then gridt = -gp.int(g.getheight() / 2) gridb = gridt + g.getheight() - 1 end local helpmsg = " (hit 'h' for help)" local selrect = g.getselrect() if #selrect == 0 then g.exit("There is no selection.") end local selpatt = g.getcells(selrect) local oldcells = {} -------------------------------------------------------------------------------- local function 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).]]) end -------------------------------------------------------------------------------- local function 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]]) end -------------------------------------------------------------------------------- local function cellinrect(x, y, r) -- return true if given cell position is inside given rectangle if x < r[1] or x >= r[1] + r[3] then return false end if y < r[2] or y >= r[2] + r[4] then return false end return true end -------------------------------------------------------------------------------- local function rectingrid(r) -- return true if all of given rectangle is inside grid if g.getwidth() > 0 and (r[1] < gridl or r[1] + r[3] - 1 > gridr) then return false end if g.getheight() > 0 and (r[2] < gridt or r[2] + r[4] - 1 > gridb) then return false end return true end -------------------------------------------------------------------------------- local function lookforkeys(event, deltax, deltay) -- look for keys used to flip/rotate selection if event == "key x none" or event == "key y none" then -- flip floating selection left-right or top-bottom if #oldcells > 0 then g.clear(0) g.putcells(selpatt, deltax, deltay) end if event == "key x none" then g.flip(0) else g.flip(1) end selpatt = g.transform(g.getcells(selrect), -deltax, -deltay) if #oldcells > 0 then g.clear(0) g.putcells(oldcells) g.putcells(selpatt, deltax, deltay) end g.update() return end if event == "key > none" or event == "key < none" then -- 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 local midx = selrect[1] + gp.int((selrect[3]-1) / 2) local midy = selrect[2] + gp.int((selrect[4]-1) / 2) local newleft = midx + selrect[2] - midy local newtop = midy + selrect[1] - midx local rotrect = { newleft, newtop, selrect[4], selrect[3] } if not rectingrid(rotrect) then g.warn("Rotation is not allowed if selection would be outside grid.") return end g.clear(0) if #oldcells > 0 then g.putcells(oldcells) end 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 event == "key > none" then g.rotate(0) else g.rotate(1) end selrect = g.getselrect() if not gp.equal(selrect,rotrect) then g.warn("Bug: selrect ~= rotrect") end selpatt = g.transform(g.getcells(selrect), -deltax, -deltay) if #oldcells > 0 then g.clear(0) g.putcells(oldcells) g.putcells(selpatt, deltax, deltay) end g.update() return end if event == "key h none" then showhelp2() return end g.doevent(event) end -------------------------------------------------------------------------------- local function moveselection() local x, y, firstx, firsty, xoffset, yoffset, oldmouse -- wait for 1st click in selection while true do local event = g.getevent() if event:find("click") == 1 then -- event is a string like "click 10 20 left none" local evt, xstr, ystr, butt, mods = split(event) x = tonumber(xstr) y = tonumber(ystr) if cellinrect(x, y, selrect) then oldmouse = xstr .. ' ' .. ystr firstx = x firsty = y xoffset = firstx - selrect[1] yoffset = firsty - selrect[2] if mods == "alt" then -- don't delete pattern in selection oldcells = g.getcells(selrect) end break end elseif event == "key h none" then showhelp1() else g.doevent(event) end end -- wait for 2nd click while moving selection g.show("Move mouse and click again..."..helpmsg) local gotclick = false local mousepos while not gotclick do local event = g.getevent() if event:find("click") == 1 then local evt, x, y, butt, mods = split(event) mousepos = x..' '..y gotclick = true else if #event > 0 then lookforkeys(event, x - firstx, y - firsty) -- update xoffset,yoffset in case selection was rotated xoffset = x - selrect[1] yoffset = y - selrect[2] end mousepos = g.getxy() end if #mousepos > 0 and mousepos ~= oldmouse then -- mouse has moved, so move selection rect and pattern g.clear(0) if #oldcells > 0 then g.putcells(oldcells) end local xstr, ystr = split(mousepos) x = tonumber(xstr) y = tonumber(ystr) selrect[1] = x - xoffset selrect[2] = y - yoffset if g.getwidth() > 0 then -- ensure selrect doesn't move beyond left/right edge of grid if selrect[1] < gridl then selrect[1] = gridl x = selrect[1] + xoffset elseif selrect[1] + selrect[3] - 1 > gridr then selrect[1] = gridr + 1 - selrect[3] x = selrect[1] + xoffset end end if g.getheight() > 0 then -- ensure selrect doesn't move beyond top/bottom edge of grid if selrect[2] < gridt then selrect[2] = gridt y = selrect[2] + yoffset elseif selrect[2] + selrect[4] - 1 > gridb then selrect[2] = gridb + 1 - selrect[4] y = selrect[2] + yoffset end end g.select(selrect) oldcells = g.getcells(selrect) g.putcells(selpatt, x - firstx, y - firsty) oldmouse = mousepos g.update() end end end -------------------------------------------------------------------------------- -- remember initial selection in case user aborts script local firstrect = g.getselrect() local firstpatt = g.getcells(selrect) g.show("Click anywhere in selection, move mouse and click again..."..helpmsg) local oldcursor = g.getcursor() g.setcursor("Move") local aborted = true local status, err = pcall(function () moveselection() aborted = false end) if err then g.continue(err) end g.setcursor(oldcursor) if aborted then g.clear(0) if #oldcells > 0 then g.putcells(oldcells) end g.putcells(firstpatt) g.select(firstrect) else g.show(" ") end golly-2.8-src/Scripts/Lua/bricklayer.lua0000755000175100017510000000177012751752464015250 00000000000000-- Based on bricklayer.py from PLife (http://plife.sourceforge.net/). local g = golly() local gp = require "gplus" local pattern = gp.pattern g.new("bricklayer") -- best to create empty universe before setting rule -- to avoid converting an existing pattern (slow if large) g.setrule("B3/S23") local p22_half = pattern("2o$bo$bobo$2b2o3bo$6bob2o$5bo4bo$6bo3bo$7b3o!") local p22 = p22_half + p22_half.t(26, 9, gp.flip) local gun22 = p22 + p22[1].t(-18, 11) local gun154 = gun22[27] + gun22[5].t(49, 12, gp.rcw) + gun22.t(5, 53, gp.flip_y) local p7_reflector = pattern([[ 2b2o5b2o$2b2o5bo$7bobo$7b2o$3b2o$3bobo$4bo3$13bo$10bo2b3o3b2o$3b5o 2b3o3bo2bo$b3obob3o4b2obobo$o4bo4b4obobo2b2o$2ob2ob4o3bobob2obo$ 4bobobobobo2bo2bobo$4bobobo2bo2bob3ob2o$3b2obob4o6bobo$7bo4b6o2b o$9bo2bo2bo4b2o$8b2o!]]) local pre_lom = pattern("2bo$2ob2o$2ob2o2$b2ob2o$b2ob2o$3bo!") local all = gun154[210].t(-52, -38) + gun154[254].t(52, -38, gp.flip_x) + p7_reflector.t(8, 23) + pre_lom.t(-3, 30) all.display("") -- don't change name golly-2.8-src/Scripts/Lua/gplus/0000755000175100017510000000000012751756120013611 500000000000000golly-2.8-src/Scripts/Lua/gplus/guns.lua0000755000175100017510000000431412751752464015224 00000000000000-- This module is loaded if a script calls require "gplus.guns". local g = golly() local gp = require "gplus" local pattern = gp.pattern local flip = gp.flip local flip_x = gp.flip_x local flip_y = gp.flip_y local rccw = gp.rccw local gpo = require "gplus.objects" local block = gpo.block local eater = gpo.eater local queenbee = gpo.queenbee local bheptomino = gpo.bheptomino local m = {} -- better to assume that caller has set Life rule to evolve phases -- gp.setrule("B3/S23") -------------------------------------------------------------------------------- -- an aligned gun shooting SE: m.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) -------------------------------------------------------------------------------- local lgun30 = queenbee + block.t(12, 2) + (queenbee[5] + block.t(12, 2)).t(-9, 2, flip_x) local lgun30_asym = queenbee + eater.t(10, 1, rccw) + (queenbee[5] + block.t(12, 2)).t(-9, 2, flip_x) m.gun30 = lgun30.t(1, -7) -- aligned gun shooting SE m.gun30_a = lgun30_asym.t(1, -7) -- aligned gun shooting SE m.gun60 = m.gun30 + m.gun30_a[26].t(-4, 11, flip_y) -------------------------------------------------------------------------------- local lhalf = bheptomino.t(0, 2, flip_x) + bheptomino.t(0, -2, flip) + block.t(16, -4) + block.t(16, 3) m.gun46_double = lhalf.t(7, -2) + lhalf.t(-8, 2, flip_x) m.gun46 = lhalf[1].t(1, -7) + lhalf.t(-13, -4, flip_x) -- aligned version shooting SE -------------------------------------------------------------------------------- return m golly-2.8-src/Scripts/Lua/gplus/text.lua0000755000175100017510000002021012751752464015225 00000000000000-- This module is loaded if a script calls require "gplus.text". local g = golly() local gp = require "gplus" local m = {} -------------------------------------------------------------------------------- -- Eric Angelini integer font local eafont = {} eafont['0'] = g.parse("3o$obo$obo$obo$3o!", 0, -5) eafont['0'].width = 4 eafont['1'] = g.parse("o$o$o$o$o!", 0, -5) eafont['1'].width = 2 eafont['2'] = g.parse("3o$2bo$3o$o$3o!", 0, -5) eafont['2'].width = 4 eafont['3'] = g.parse("3o$2bo$3o$2bo$3o!", 0, -5) eafont['3'].width = 4 eafont['4'] = g.parse("obo$obo$3o$2bo$2bo!", 0, -5) eafont['4'].width = 4 eafont['5'] = g.parse("3o$o$3o$2bo$3o!", 0, -5) eafont['5'].width = 4 eafont['6'] = g.parse("3o$o$3o$obo$3o!", 0, -5) eafont['6'].width = 4 eafont['7'] = g.parse("3o$2bo$2bo$2bo$2bo!", 0, -5) eafont['7'].width = 4 eafont['8'] = g.parse("3o$obo$3o$obo$3o!", 0, -5) eafont['8'].width = 4 eafont['9'] = g.parse("3o$obo$3o$2bo$3o!", 0, -5) eafont['9'].width = 4 eafont[' '] = g.parse("", 0, 0) eafont[' '].width = 2 eafont['-'] = g.parse("", 0, 0) eafont['-'].width = 0 -------------------------------------------------------------------------------- -- Snakial font (all chars are stable Life patterns) local sfont = {} sfont['0'] = g.parse("2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$o5bo$bo5bo$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!", 0, -14) sfont['0'].width = 10 sfont['1'] = g.parse("2o$bo$o$2o2$2o$bo$o$2o2$2o$bo$o$2o!", 1, -14) sfont['1'].width = 6 sfont['2'] = g.parse("2b2obo$2bob2o$6b2o$6bo$7bo$6b2o$2b2obo$2bob2o$2o$o$bo$2o$2b2obo$2bob2o!", 0, -14) sfont['2'].width = 10 sfont['3'] = g.parse("2obo$ob2o$4b2o$4bo$5bo$4b2o$2obo$ob2o$4b2o$4bo$5bo$4b2o$2obo$ob2o!", 0, -14) sfont['3'].width = 8 sfont['4'] = g.parse("2o3b2o$2o3b2o2$2o3b2o$obobobo$2bobo$b2obo$5b2o$6bo$5bo$5b2o$6bo$5bo$5b2o!", 0, -14) sfont['4'].width = 9 sfont['5'] = g.parse("2b2obo$2bob2o$2o$o$bo$2o$2b2obo$2bob2o$6b2o$6bo$7bo$6b2o$2b2obo$2bob2o!", 0, -14) sfont['5'].width = 10 sfont['6'] = g.parse("2b2obo$2bob2o$2o$o$bo$2o$2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!", 0, -14) sfont['6'].width = 10 sfont['7'] = g.parse("ob2o$2obo$4b2o$5bo$4bo$4b2o$2b2o$3bo$2bo$2b2o$2o$bo$o$2o!", 0, -14) sfont['7'].width = 8 sfont['8'] = g.parse("2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o!", 0, -14) sfont['8'].width = 10 sfont['9'] = g.parse("2b2obo$2bob2o$2o4b2o$o5bo$bo5bo$2o4b2o$2b2obo$2bob2o$6b2o$6bo$7bo$6b2o$2b2obo$2bob2o!", 0, -14) sfont['9'].width = 10 sfont['-'] = g.parse("2obo$ob2o!", 0, -8) sfont['-'].width = 6 -------------------------------------------------------------------------------- -- mono-spaced ASCII font local 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!") for key, _ in pairs(mfont) do mfont[key].width = 6 end -------------------------------------------------------------------------------- -- convert given string to a pattern using one of the above fonts function m.maketext(s, font) font = font or "Snakial" local p = gp.pattern() local x = 0 local f, unknown if string.lower(font) == "mono" then f = mfont unknown = '?' elseif string.lower(font:sub(1,2)) == "ea" then f = eafont unknown = '-' else f = sfont unknown = '-' end for ch in string.gmatch(s, ".[\128-\191]*") do if f[ch] == nil then ch = unknown end p = p + gp.pattern(g.transform(f[ch], x, 0)) x = x + f[ch].width end return p end -------------------------------------------------------------------------------- return m golly-2.8-src/Scripts/Lua/gplus/objects.lua0000644000175100017510000001472612751752464015706 00000000000000-- This module is loaded if a script calls require "gplus.objects". local g = golly() local gp = require "gplus" local pattern = gp.pattern local m = {} m.block = pattern([[ ** ** ]]) m.blinker = pattern("***", -1, 0) m.glider = pattern([[ .** **. ..* ]]) m.lwss = pattern([[ ****. *...* *.... .*..* ]]) m.mwss = pattern([[ *****. *....* *..... .*...* ...*.. ]]) m.hwss = pattern([[ ******. *.....* *...... .*....* ...**.. ]]) m.eater = pattern([[ ** * .*** ...* ]]) m.hook = m.eater m.queenbee = pattern([[ **.. ..*. ...* ...* ...* ..*. **.. ]]) m.herschel = pattern([[ ***. .*.. .*** ]]) m.bheptomino = pattern([[ **. .** **. *.. ]]) m.tub = pattern([[ .*. *.* .*. ]], -1, -1) m.boat = pattern([[ **. *.* .*. ]]) m.long_boat = pattern([[ **. *.* .*.* ..* ]]) m.ship = pattern([[ **. *.* .** ]], -1, -1) m.beehive = pattern([[ .**. *..* .**. ]], 0, -1) m.loaf = pattern([[ .**. *..* *.*. .*.. ]]) m.snake = pattern([[ *.** **.* ]]) m.aircraft_carrier = pattern([[ **.. *..* ..** ]]) m.honeyfarm = pattern([[ ......*...... .....*.*..... .....*.*..... ......*...... ............. .**.......**. *..*.....*..* .**.......**. ............. ......*...... .....*.*..... .....*.*..... ......*...... ]], -6, -6) m.beacon = pattern([[ **.. *... ...* ..** ]]) m.blocker = pattern([[ ......*.*. .....*.... **..*....* **.*..*.** ....**.... ]]) m.clock = pattern([[ ..*. **.. ..** .*.. ]]) m.dart = pattern([[ ........*. .......*.* ......**.. .........* .....*...* ..*..*.... .*.*..**** *..*...... .*.*..**** ..*..*.... .....*...* .........* ......**.. .......*.* ........*. ]], 0, -7) m.big_beacon = pattern([[ ***... ***... ***... ...*** ...*** ...*** ]]) m.middleweight_volcano = pattern([[ ...*******... .***.***.***. *....***....* .****.*.***.* ...........*. *.**.*.*.*... **.*.*.*.**.. ....*..*.*... .....**..*... .........**.. ]], -6, 0) m.heavyweight_volcano = pattern([[ .........*.......................... ........*.*......................... ......***.*......................... .....*....**.*...................... .....*.**...**......**.............. ....**.*.**.........*.*............. .........*.*****......*..*.**....... ..*.**.**.*.....*....**.*.**.*...... .....**.....****........*....*...... *...*.*..*...*.*....**.*.****.**.... *...*.*..**.*.**.**....*.*....*.*... .....**...***.**.*.***.*..***...*... ..*.**.**.**.............*.*..*.*.** ...........*......*.*.*.*..**.*.*.*. ....**.*.*.**......**.*.*.*...*.*.*. .....*.**.*..*.......*.**..****.**.. .....*....*.*........*...**......... ....**....**........**...*..*....... ...........................**....... ]]) m.galaxy = pattern([[ ******.** ******.** .......** **.....** **.....** **.....** **....... **.****** **.****** ]], -4, -4) m.orion = pattern([[ ...**......... ...*.*........ ...*.......... **.*.......... *....*........ *.**......***. .....***....** ......***.*.*. .............* ......*.*..... .....**.*..... ......*....... ....**.*...... .......*...... .....**....... ]]) m.pentadecathlon = pattern([[ ..*....*.. **.****.** ..*....*.. ]], 0, -1) m.pi = pattern([[ *** *.* *.* ]]) m.pond = pattern([[ .**. *..* *..* .**. ]]) m.pulsar = pattern([[ ..***...***.. ............. *....*.*....* *....*.*....* *....*.*....* ..***...***.. ............. ..***...***.. *....*.*....* *....*.*....* *....*.*....* ............. ..***...***.. ]], -6, -6) m.rpentomino = pattern([[ .** ** .* ]]) m.rabbits = pattern([[ *...*** ***..*. .*..... ]]) m.spider = pattern([[ .........*.......*......... ...**.*.*.**...**.*.*.**... ***.*.***.........***.*.*** *...*.*.....*.*.....*.*...* ....**......*.*......**.... .**.........*.*.........**. .**.**...............**.**. .....*...............*..... ]], -13, 0) m.lightweight_volcano = pattern([[ ...**..**... .***.**.***. *..........* .****..****. ....*..*.... .**......**. .*..*..*..*. ..***..***.. ............ ****.**.**** *..**..**..* ]]) m.unix = pattern([[ ..**.... ....*.** *..*..** *.*..... .*...... ........ .**..... .**..... ]]) m.biblocker = pattern([[ ..................*........... .................*.**......... .................*.**......... ..................**.......... .............................. .......**............**....... .......**............**....... .............................. .............................. ......*.*..................... .....*..................**.... **..*....*..........**.*..*.** **.*..*.**..........**..*....* ....**...................*.... ..........................*.*. ]]) -------------------------------------------------------------------------------- -- this section emulates glife's herschel.py m.herschel_ghost = pattern([[ *** . .*.* ]]) -- A Herschel conduit is represented by its pattern and -- the transformation it applies to the Herschel. -- Hence the additional .transform field. local block = m.block local eater = m.eater local snake = m.snake m.hc64 = block.t(14, -8) + block.t(9, -13) + block.t(13, -15) + block.t(7, -19) m.hc64.transform = {-9, -9, gp.rccw} m.hc77 = block.t(9, -13) + eater.t(10, 0, gp.swap_xy) + eater.t(-7, -12, gp.swap_xy_flip) m.hc77.transform = {10, -25, gp.flip_x} m.hc112 = block.t(16, -10) + block.t(-3, -11) + m.aircraft_carrier.t(13, -3, gp.swap_xy) + eater.t(10, 1) + eater.t(-3, -14, gp.flip) + eater.t(9, -16, gp.flip_y) m.hc112.transform = {35, -12, gp.rcw} m.hc117 = eater.t(10, 1) + eater.t(13, -9, gp.swap_xy) + eater.t(0, -12, gp.swap_xy_flip) + block.t(8, -22) + snake.t(15, -19) m.hc117.transform = {6, -40, gp.identity} m.hc119 = block.t(-14, -3) + block.t(-13, -8) + block.t(-19, -9) + eater.t(-17, -2, gp.rcw) m.hc119.transform = {-12, -20, gp.flip_x} m.hc156 = eater.t(10, 0, gp.swap_xy) + eater.t(12, -9, gp.swap_xy) + eater.t(0, -12, gp.swap_xy_flip) + eater.t(17, -21, gp.flip_y) + snake.t(21, -5, gp.rccw) + block.t(24, -15) + m.tub.t(11, -24) m.hc156.transform = {43, -17, gp.rcw} m.hc158 = eater.t(-2, -13, gp.flip) + eater.t(-3, -8, gp.rcw) + eater.t(20, -19, gp.rccw) + pattern([[ .....** .....*.* .......* .......*.*.** ..**.*.*.**.* ..**.**.* ........* ..**.*** ...*.* ...*.* **.** *.* ..* ..** ]], 14, -12) m.hc158.transform = {7, -27, gp.flip_x} m.hc190 = eater.t(-3, -8, gp.rcw) + eater.t(-10, -12, gp.swap_xy) + eater.t(-3, -12, gp.swap_xy_flip) + eater.t(-8, -17) + eater.t(11, -27, gp.flip_y) + block.t(2, -25) + snake.t(5, -31, gp.rccw) + pattern([[ ..**.* ..**.*** ........* ..**.*** ...*.* ...*.* **.** *.* ..* ..** ]], 14, -8) m.hc190.transform = {-16, -22, gp.rccw} -------------------------------------------------------------------------------- return m golly-2.8-src/Scripts/Lua/gplus/init.lua0000755000175100017510000002340012751752464015210 00000000000000-- This module is loaded if a script calls require "gplus". local g = golly() local m = {} -------------------------------------------------------------------------------- function m.int(x) -- return integer part of given floating point number return x < 0 and math.ceil(x) or math.floor(x) end -------------------------------------------------------------------------------- function m.min(a) -- return minimum value in given array if #a == 0 then return nil end local n = a[1] for i = 2, #a do if a[i] < n then n = a[i] end end return n end -------------------------------------------------------------------------------- function m.max(a) -- return maximum value in given array if #a == 0 then return nil end local n = a[1] for i = 2, #a do if a[i] > n then n = a[i] end end return n end -------------------------------------------------------------------------------- function m.drawline(x1, y1, x2, y2, state) -- draw a line of cells from x1,y1 to x2,y2 using Bresenham's algorithm state = state or 1 g.setcell(x1, y1, state) if x1 == x2 and y1 == y2 then return end local dx = x2 - x1 local ax = math.abs(dx) * 2 local sx = 1 if dx < 0 then sx = -1 end local dy = y2 - y1 local ay = math.abs(dy) * 2 local sy = 1 if dy < 0 then sy = -1 end if ax > ay then local d = ay - (ax / 2) while x1 ~= x2 do g.setcell(x1, y1, state) if d >= 0 then y1 = y1 + sy d = d - ax end x1 = x1 + sx d = d + ay end else local d = ax - (ay / 2) while y1 ~= y2 do g.setcell(x1, y1, state) if d >= 0 then x1 = x1 + sx d = d - ay end y1 = y1 + sy d = d + ax end end g.setcell(x2, y2, state) end -------------------------------------------------------------------------------- function m.getedges(r) -- return left, top, right, bottom edges of given rect array return r[1], r[2], r[1]+r[3]-1, r[2]+r[4]-1 end -------------------------------------------------------------------------------- function m.getminbox(cells) -- return a rect with the minimal bounding box of given cell array or pattern if cells.array then -- arg is a pattern so get its cell array cells = cells.array end local len = #cells if len < 2 then return m.rect( {} ) end local minx = cells[1] local miny = cells[2] local maxx = minx local maxy = miny -- determine if cell array is one-state or multi-state local inc = 2 if (len & 1) == 1 then inc = 3 end -- ignore padding int if present if (inc == 3) and (len % 3 == 1) then len = len - 1 end for x = 1, len, inc do if cells[x] < minx then minx = cells[x] end if cells[x] > maxx then maxx = cells[x] end end for y = 2, len, inc do if cells[y] < miny then miny = cells[y] end if cells[y] > maxy then maxy = cells[y] end end return m.rect( {minx, miny, maxx - minx + 1, maxy - miny + 1} ) end -------------------------------------------------------------------------------- function m.validint(s) -- return true if given string represents a valid integer if #s == 0 then return false end s = s:gsub(",","") return s:match("^[+-]?%d+$") ~= nil end -------------------------------------------------------------------------------- function m.getposint() -- return current viewport position as integer coords local x, y = g.getpos() return tonumber(x), tonumber(y) end -------------------------------------------------------------------------------- function m.setposint(x,y) -- convert integer coords to strings and set viewport position g.setpos(tostring(x), tostring(y)) end -------------------------------------------------------------------------------- function m.split(s, sep) -- split given string into substrings that are separated by given sep -- (emulates Python's split function) sep = sep or " " local t = {} local start = 1 while true do local i = s:find(sep, start) if i == nil then if start <= #s then t[#t+1] = s:sub(start, -1) end break end if i > start then t[#t+1] = s:sub(start, i-1) end start = i + #sep end if #t == 0 then -- sep does not exist in s so return s return s else return table.unpack(t) end end -------------------------------------------------------------------------------- function m.equal(a1, a2) -- return true if given arrays have the same values if #a1 ~= #a2 then -- arrays are not the same length return false else -- both arrays are the same length (possibly 0) for i = 1, #a1 do if a1[i] ~= a2[i] then return false end end return true end end -------------------------------------------------------------------------------- function m.rect(a) -- return a table that makes it easier to manipulate rectangles -- (emulates glife's rect class) local r = {} if #a == 0 then r.empty = true elseif #a == 4 then r.empty = false r.x = a[1] r.y = a[2] r.wd = a[3] r.ht = a[4] r.left = r.x r.top = r.y r.width = r.wd r.height = r.ht if r.wd <= 0 then error("rect width must be > 0", 2) end if r.ht <= 0 then error("rect height must be > 0", 2) end r.right = r.left + r.wd - 1 r.bottom = r.top + r.ht - 1 r.visible = function () return g.visrect( {r.x, r.y, r.wd, r.ht} ) end else error("rect arg must be {} or {x,y,wd,ht}", 2) end return r end -------------------------------------------------------------------------------- -- create some useful synonyms: -- for g.clear and g.advance m.inside = 0 m.outside = 1 -- for g.flip m.left_right = 0 m.top_bottom = 1 m.up_down = 1 -- for g.rotate m.clockwise = 0 m.anticlockwise = 1 -- for g.setcursor (must match strings in Cursor Mode submenu) m.draw = "Draw" m.pick = "Pick" m.select = "Select" m.move = "Move" m.zoomin = "Zoom In" m.zoomout = "Zoom Out" -- transformation matrices m.identity = { 1, 0, 0, 1} m.flip = {-1, 0, 0, -1} m.flip_x = {-1, 0, 0, 1} m.flip_y = { 1, 0, 0, -1} m.swap_xy = { 0, 1, 1, 0} m.swap_xy_flip = { 0, -1, -1, 0} m.rcw = { 0, -1, 1, 0} m.rccw = { 0, 1, -1, 0} -------------------------------------------------------------------------------- function m.compose(S, T) -- Return the composition of two transformations S and T. -- A transformation is an array of the form {x, y, A}, which denotes -- multiplying by matrix A and then translating by vector (x, y). local x, y, A = table.unpack(S) local s, t, B = table.unpack(T) return { x * B[1] + y * B[2] + s, x * B[3] + y * B[4] + t, { A[1] * B[1] + A[3] * B[2], A[2] * B[1] + A[4] * B[2], A[1] * B[3] + A[3] * B[4], A[2] * B[3] + A[4] * B[4] } } end -------------------------------------------------------------------------------- -- create a metatable for all pattern tables local mtp = {} -------------------------------------------------------------------------------- function m.pattern(arg, x0, y0, A) -- return a table that makes it easier to manipulate patterns -- (emulates glife's pattern class) local p = {} setmetatable(p, mtp) arg = arg or {} x0 = x0 or 0 y0 = y0 or 0 A = A or m.identity if type(arg) == "table" then p.array = {} if getmetatable(arg) == mtp then -- arg is a pattern if #arg.array > 0 then p.array = g.join({},arg.array) end else -- assume arg is a cell array if #arg > 0 then p.array = g.join({},arg) end end elseif type(arg) == "string" then p.array = g.parse(arg, x0, y0, table.unpack(A)) else error("1st arg of pattern must be a cell array, a pattern, or a string", 2) end p.t = function (x, y, A) -- allow scripts to call patt.t(x,y,A) or patt.t({x,y,A}) if type(x) == "table" then x, y, A = table.unpack(x) end A = A or m.identity local newp = m.pattern() newp.array = g.transform(p.array, x, y, table.unpack(A)) return newp end -- there's no need to implement p.translate and p.apply as they -- are just trivial variants of p.t p.put = function (x, y, A) -- paste pattern into current universe x = x or 0 y = y or 0 A = A or m.identity g.putcells(p.array, x, y, table.unpack(A)) end p.display = function (title, x, y, A) -- paste pattern into new universe and display it all title = title or "untitled" x = x or 0 y = y or 0 A = A or m.identity g.new(title) g.putcells(p.array, x, y, table.unpack(A)) g.fit() g.setcursor(m.zoomin) end p.save = function (filepath) -- save the pattern to given file in RLE format g.store(p.array, filepath) end p.add = function (p1, p2) local newp = m.pattern() newp.array = g.join(p1.array, p2.array) return newp -- note that above code is about 15% faster than doing -- return m.pattern( g.join(p1.array, p2.array) ) -- because it avoids calling g.join again end p.evolve = function (p1, n) local newp = m.pattern() newp.array = g.evolve(p1.array, n) return newp end -- set metamethod so scripts can do pattern1 + pattern2 mtp.__add = p.add -- set metamethod so scripts can do pattern[10] to get evolved pattern mtp.__index = p.evolve return p end -------------------------------------------------------------------------------- return m golly-2.8-src/Scripts/Lua/gplus/strict.lua0000644000175100017510000000173712751752464015563 00000000000000-- strict.lua -- checks uses of undeclared global variables -- All global variables must be 'declared' through a regular assignment -- (even assigning nil will do) in a main chunk before being used -- anywhere or assigned to inside a function. -- distributed under the Lua license: http://www.lua.org/license.html local getinfo, error, rawset, rawget = debug.getinfo, error, rawset, rawget local mt = getmetatable(_G) if mt == nil then mt = {} setmetatable(_G, mt) end mt.__declared = {} local function what () local d = getinfo(3, "S") return d and d.what or "C" end mt.__newindex = function (t, n, v) if not mt.__declared[n] then local w = what() if w ~= "main" and w ~= "C" then error("assign to undeclared variable '"..n.."'", 2) end mt.__declared[n] = true end rawset(t, n, v) end mt.__index = function (t, n) if not mt.__declared[n] and what() ~= "C" then error("variable '"..n.."' is not declared", 2) end return rawget(t, n) end golly-2.8-src/Scripts/Lua/goto.lua0000755000175100017510000001076312751752464014073 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, Apr 2016. local g = golly() local gp = require "gplus" local validint = gp.validint ---------------------------------------------------------------------- local function intbase(n, b) -- convert integer n >= 0 to a base b digit array (thanks to PM 2Ring) digits = {} while n > 0 do digits[#digits + 1] = n % b n = math.floor(n / b) end if #digits == 0 then digits = {0} end return digits end ---------------------------------------------------------------------- local function go_to(gen) local currgen = tonumber(g.getgen()) local newgen if gen:sub(1,1) == '+' then newgen = currgen + tonumber(gen:sub(2,-1)) elseif gen:sub(1,1) == '-' then local n = tonumber(gen:sub(2,-1)) if currgen > n then newgen = currgen - n else newgen = 0 end else newgen = tonumber(gen) end if newgen < currgen then -- 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 local midx, midy = g.getpos() local 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 = tonumber(g.getgen()) if newgen < currgen then g.error("Can't go back any further; pattern was saved ".. "at generation "..currgen..".") return end end if newgen == currgen then return end g.show("Hit escape to abort...") local oldsecs = os.clock() -- 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 = currgen + 1 -- use fast stepping (thanks to PM 2Ring) for i, d in ipairs(intbase(newgen - currgen, g.getbase())) do if d > 0 then g.setstep(i-1) for j = 1, d do if g.empty() then g.show("Pattern is empty.") return end g.step() local newsecs = os.clock() if newsecs - oldsecs >= 1.0 then -- do an update every sec oldsecs = newsecs g.update() end end end end g.show("") end ---------------------------------------------------------------------- local function savegen(filename, gen) local f = io.open(filename, "w") if f then f:write(gen) f:close() else g.warn("Can't save gen in filename:\n"..filename) end end ---------------------------------------------------------------------- -- use same file name as in goto.py local GotoINIFileName = g.getdir("data").."goto.ini" local previousgen = "" local f = io.open(GotoINIFileName, "r") if f then previousgen = f:read("*l") or "" f:close() end local gen = g.getstring("Enter the desired generation number,\n".. "or -n/+n to go back/forwards by n:", previousgen, "Go to generation") if gen == "" then g.exit() elseif gen == '+' or gen == '-' then -- clear the default savegen(GotoINIFileName, "") elseif not validint(gen) then 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) local oldstep = g.getstep() go_to(gen:gsub(",","")) g.setstep(oldstep) end golly-2.8-src/Scripts/Lua/tile.lua0000755000175100017510000001107112751752464014051 00000000000000-- Tile current selection with pattern inside selection. -- Author: Andrew Trevorrow (andrewtrevorrow.com), Mar 2016. local g = golly() local gp = require "gplus" local selrect = g.getselrect() if #selrect == 0 then g.exit("There is no selection.") end local selpatt = g.getcells(selrect) if #selpatt == 0 then g.exit("No pattern in selection.") end -- determine if selpatt is one-state or multi-state local inc = 2 if (#selpatt & 1) == 1 then inc = 3 end -------------------------------------------------------------------------------- local function clip_left(cells, left) local len = #cells local x = 1 if inc == 3 then -- ignore padding int if present if len % 3 == 1 then len = len - 1 end while x <= len do if cells[x] >= left then g.setcell(cells[x], cells[x+1], cells[x+2]) end x = x + 3 end else while x <= len do if cells[x] >= left then g.setcell(cells[x], cells[x+1], 1) end x = x + 2 end end end -------------------------------------------------------------------------------- local function clip_right(cells, right) local len = #cells local x = 1 if inc == 3 then -- ignore padding int if present if len % 3 == 1 then len = len - 1 end while x <= len do if cells[x] <= right then g.setcell(cells[x], cells[x+1], cells[x+2]) end x = x + 3 end else while x <= len do if cells[x] <= right then g.setcell(cells[x], cells[x+1], 1) end x = x + 2 end end end -------------------------------------------------------------------------------- local function clip_top(cells, top) local len = #cells local y = 2 if inc == 3 then -- ignore padding int if present if len % 3 == 1 then len = len - 1 end while y <= len do if cells[y] >= top then g.setcell(cells[y-1], cells[y], cells[y+1]) end y = y + 3 end else while y <= len do if cells[y] >= top then g.setcell(cells[y-1], cells[y], 1) end y = y + 2 end end end -------------------------------------------------------------------------------- local function clip_bottom(cells, bottom) local len = #cells local y = 2 if inc == 3 then -- ignore padding int if present if len % 3 == 1 then len = len - 1 end while y <= len do if cells[y] <= bottom then g.setcell(cells[y-1], cells[y], cells[y+1]) end y = y + 3 end else while y <= len do if cells[y] <= bottom then g.setcell(cells[y-1], cells[y], 1) end y = y + 2 end end end -------------------------------------------------------------------------------- -- get selection edges local selleft, seltop, selright, selbottom = gp.getedges(selrect) -- find selpatt's minimal bounding box local bbox = gp.getminbox(selpatt) local i -- first tile selpatt horizontally, clipping where necessary local left = bbox.x local right = left + bbox.wd - 1 i = 0 while left > selleft do left = left - bbox.wd i = i + 1 if left >= selleft then g.putcells(selpatt, -bbox.wd * i, 0) else local tempcells = g.transform(selpatt, -bbox.wd * i, 0) clip_left(tempcells, selleft) end end i = 0 while right < selright do right = right + bbox.wd i = i + 1 if right <= selright then g.putcells(selpatt, bbox.wd * i, 0) else local tempcells = g.transform(selpatt, bbox.wd * i, 0) clip_right(tempcells, selright) end end -- get new selection pattern and tile vertically, clipping where necessary selpatt = g.getcells(selrect) bbox = gp.getminbox(selpatt) local top = bbox.y local bottom = top + bbox.ht - 1 i = 0 while top > seltop do top = top - bbox.ht i = i + 1 if top >= seltop then g.putcells(selpatt, 0, -bbox.ht * i) else local tempcells = g.transform(selpatt, 0, -bbox.ht * i) clip_top(tempcells, seltop) end end i = 0 while bottom < selbottom do bottom = bottom + bbox.ht i = i + 1 if bottom <= selbottom then g.putcells(selpatt, 0, bbox.ht * i) else local tempcells = g.transform(selpatt, 0, bbox.ht * i) clip_bottom(tempcells, selbottom) end end if not g.visrect(selrect) then g.fitsel() end golly-2.8-src/Scripts/Lua/gun-demo.lua0000644000175100017510000000325012751752464014624 00000000000000-- Based on gun_demo.py from PLife (http://plife.sourceforge.net/). local g = golly() local gp = require "gplus" local gpo = require "gplus.objects" local gpg = require "gplus.guns" local gun24 = gpg.gun24 local gun30 = gpg.gun30 local gun46 = gpg.gun46 g.new("gun-demo") -- best to create empty universe before setting rule -- to avoid converting an existing pattern (slow if large) g.setrule("B3/S23") -------------------------------------------------------------------------------- local function mirror_gun(glider_gun) -- mirror an 'aligned' glider gun and preserve its timing return glider_gun[2].t(-1, 0, gp.swap_xy) end -------------------------------------------------------------------------------- local function compose_lwss_gun(glider_gun, A, B, C) -- construct an lwss gun using 3 copies of an 'aligned' glider gun -- where A, B and C are distances from the glider collision point to -- NE, NW and SW guns respectively local m = gp.min({A, B, C}) local a = A - m local b = B - m local c = C - m return glider_gun[4 * a].t( A, -A - 3, gp.flip_x) + glider_gun[4 * b].t(-B + 2, -B + 1) + glider_gun[4 * c + 1].t(-C + 6, C, gp.flip_y) end -------------------------------------------------------------------------------- local lwss_eater = gpo.eater.t(4, 2, gp.swap_xy) local all = compose_lwss_gun(mirror_gun(gun24), 12, 11, 12).t(0, -100) + lwss_eater.t(100, -100) + compose_lwss_gun(gun24, 11, 13, 4) + lwss_eater.t(100, 0) + compose_lwss_gun(gun30, 13, 11, 4).t(0, 70) + lwss_eater.t(100, 70) + compose_lwss_gun(gun46, 22, 13, 3).t(0, 130) + lwss_eater.t(100, 130) all.display("") -- don't change name golly-2.8-src/Scripts/Lua/giffer.lua0000644000175100017510000001556212751752464014364 00000000000000-- Run the current selection for a given number of steps and -- create an animated GIF file using the current layer's colors. -- Based on giffer.pl by Tony Smith. -- Conversion to Lua by Andrew Trevorrow and Scorbie. local g = golly() local gp = require "gplus" local getcell = g.getcell local int = gp.int local chr = string.char local lshift = bit32.lshift local rshift = bit32.rshift local r = g.getselrect() if #r == 0 then g.exit("There is no selection.") end local x, y, width, height = table.unpack(r) if width >= 65536 or height >= 65536 then g.exit("The width and height of the selection must be less than 65536.") end -- get the parameters given last time local inifilename = g.getdir("data").."giffer.ini" local oldparams = "100 1" local f = io.open(inifilename, "r") if f then oldparams = f:read("*l") or "" f:close() end local prompt = [[ Enter the number of frames, and the pause time between each frame (in centisecs): ]] local answer = g.getstring(prompt, oldparams, "Create animated GIF") local frames, pause = gp.split(answer) -- validate given parameters frames = frames or 100 pause = pause or 1 if not gp.validint(frames) then g.exit("Bad frames value: "..frames) end if not gp.validint(pause) then g.exit("Bad pause value: "..pause) end frames = tonumber(frames) pause = tonumber(pause) -- given parameters are valid so save them for next run f = io.open(inifilename, "w") if f then f:write(answer) f:close() end local depth = g.numstates() local bitdepth = 0 while depth > 2^(bitdepth+1) do bitdepth = bitdepth + 1 end local codesize = 2 if bitdepth > 0 then codesize = bitdepth + 1 end -------------------------------------------------------------------------------- local function getframedata() local data = {} for row = y, y+height-1 do for col = x, x+width-1 do data[#data+1] = chr( getcell(col, row) ) end end return data end -------------------------------------------------------------------------------- local function compress(data) local t = {} for i = 0, depth-1 do t[chr(i)] = i end local curr = 2^codesize local cc = 2^codesize local used = cc + 1 local bits = codesize + 1 local size = codesize + 1 local mask = 2^size - 1 local output = "" local code = "" for _, nextch in ipairs(data) do if t[code .. nextch] then code = code .. nextch else used = used + 1 t[code .. nextch] = used curr = curr + lshift(t[code], bits) bits = bits + size while bits >= 8 do output = output .. chr(curr & 255) curr = rshift(curr, 8) bits = bits - 8 end if used > mask then if size < 12 then size = size + 1 mask = mask*2 + 1 else curr = curr + lshift(cc, bits) bits = bits + size while bits >= 8 do output = output .. chr(curr & 255) curr = rshift(curr, 8) bits = bits - 8 end -- reset t t = {} for j = 0, depth-1 do t[chr(j)] = j end used = cc + 1 size = codesize + 1 mask = 2^size - 1 end end code = nextch end end curr = curr + lshift(t[code], bits) bits = bits + size while bits >= 8 do output = output .. chr(curr & 255) curr = rshift(curr, 8) bits = bits - 8 end output = output .. chr(curr) local subbed = "" while #output > 255 do subbed = subbed .. chr(255) .. output:sub(1,255) output = output:sub(256) end return subbed .. chr(#output) .. output .. chr(0) end -------------------------------------------------------------------------------- -- This function packs a list of +ve integers into a binary string using -- little-endian ordering. The format parameter is a string composed of -- ASCII digits which specify the size in bytes of the corresponding value. -- Based on code at http://lua-users.org/wiki/ReadWriteFormat. local function mypack(format, ...) local result = "" local values = {...} for i = 1, #format do local size = tonumber(format:sub(i,i)) local value = values[i] local str = "" for j = 1, size do str = str .. chr(value % 256) value = math.floor(value / 256) end result = result .. str end return result end -------------------------------------------------------------------------------- -- For information on GIF format: -- http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp local function savegiffile(gifpath) local header = "GIF89a" local screendesc = mypack("22111", width, height, 0xF0 + bitdepth, 0, 0) local colortable = "" for state = 0, depth-1 do local s, r, g, b = table.unpack(g.getcolors(state)) colortable = colortable .. mypack("111", r, g, b) end local fullength = 6 * 2^bitdepth while #colortable < fullength do colortable = colortable .. mypack("111", 0, 0, 0) end -- this application extension allows looping local applicext = "\x21\xFF\x0BNETSCAPE2.0" .. mypack("1121", 3, 1, 0, 0) local controlext = "\x21\xF9" .. mypack("11211", 4, 0, pause, 0, 0) local imagedesc = "," .. mypack("222211", 0, 0, width, height, 0, codesize) local gif = io.open(gifpath,"wb") if not gif then g.exit("Unable to create GIF file: "..gifpath) end gif:write(header) gif:write(screendesc) gif:write(colortable) gif:write(applicext) for f = 1, frames do -- write the data for this frame gif:write(controlext) gif:write(imagedesc) gif:write(compress(getframedata())) g.show("Frame: "..f.."/".. frames) g.step() g.update() end gif:write("\x3B") gif:close() g.show("GIF animation saved in "..gifpath) end -------------------------------------------------------------------------------- -- set initial directory for the save dialog local initdir = g.getdir("app") local savedirfile = g.getdir("data").."gifdir.ini" local f = io.open(savedirfile, "r") if f then initdir = f:read("*l") or "" f:close() end -- remove any existing extension from layer name and append .gif local initfile = gp.split(g.getname(),"%.")..".gif" -- prompt for file name and location local gifpath = g.savedialog("Save as GIF file", "GIF (*.gif)|*.gif", initdir, initfile) if #gifpath == 0 then g.exit() end -- save directory for next time f = io.open(savedirfile, "w") if f then local pathsep = g.getdir("app"):sub(-1) f:write(gifpath:gsub("[^"..pathsep.."]+$","")) f:close() end savegiffile(gifpath) golly-2.8-src/Scripts/Lua/heisenburp.lua0000755000175100017510000006112312751752464015263 00000000000000-- Stable pseudo-Heisenburp device. -- Show several views of a multi-stage signal-processing circuit. -- Author: Dave Greene, 27 February 2007. Lua version 1 April 2016. local g = golly() local gp = require "gplus" local split = gp.split local clock = os.clock local ticks=0 local tickstep=5 local last_signal=-99999 local viewport_speed=16 local sel_speed=0 local delta_sel=0 local delay=-1 local run_flag=0 local ch="" local selx=600 local sely=365 local place_signal=3 local 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.]] local instr="Press H for help. " ------------------------------------------------------- local function sleep(n) -- n is seconds (with precision in hundredths of a second) local t0 = clock() while clock() - t0 <= n do g.doevent("") -- no-op, but allows user to abort script here end end ------------------------------------------------------- local function show_status_text(s, d, t) if d==-1 then if t==1 then g.show(s.."Speed is "..t.." tick per step.") else g.show(s.."Speed is "..t.." ticks per step.") end else g.show(s.."Delay between ticks is "..d.." seconds.") end end ------------------------------------------------------- local function prepare_burp() while g.numlayers()>1 do g.dellayer() end local highway_robber=g.parse([[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!]]) local connecting_neck=g.parse([[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!]]) local transmitter2c3=g.parse([[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!]]) local head2c3=g.parse("8b2o$3bo2bo2bo$3b6o2$3b6o$2bo6bo$2bo2b5o$obobo$2o2bo$4bo$3b2o!") local body2c3=g.parse("6bo$b6o$o$o2b6o$obo6bo$obo2b5o$b2obo$4bo$4bo$3b2o!") local tail2c3=g.parse("5b2o$5b2o2$b6o$o5bo$o2b3o$obo$o2bo$b2o!") local wire2c3=g.join(g.transform(head2c3,625,388), g.transform(tail2c3,2143,1905)) -- 251 body segments, first one at (631, 395) for i=631,2142,6 do wire2c3=g.join(wire2c3,g.transform(body2c3,i,i-236)) end local receiver2c3=g.parse([[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!]]) local inserter2c3=g.parse([[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!]]) local all = g.join(g.transform(highway_robber,86,0), g.join(g.transform(connecting_neck,195,262), g.join(g.transform(transmitter2c3,347,219), g.join(wire2c3, g.join(g.transform(receiver2c3,2103,1763), g.transform(inserter2c3,2024,2042)))))) g.new("Stable Pseudo-Heisenburp Device") -- ??? g.setalgo("HashLife") g.setrule("B3/S23") g.putcells(all) g.setmag(0) g.setpos("120","200") g.setname("Highway Robber") g.clone() g.setname("2c/3 Transmitter") g.setpos("500","400") g.clone() g.setname("2c/3 Receiver") g.setpos("2175","2000") g.clone() g.setname("Stable Pseudo-Heisenburp Device") g.clone() g.setname("Glider Fleet") g.setpos("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. -- Could instead select each key rectangle, use g.fitsel(), then unselect. g.setlayer(0) while not g.visrect( {100,100,150,175} ) do g.setmag(g.getmag()-1) end g.setlayer(1) while not g.visrect( {350,225,400,350} ) do g.setmag(g.getmag()-1) end g.setlayer(2) while not g.visrect( {2100,1750,225,300} ) do g.setmag(g.getmag()-1) end g.setlayer(3) g.fit() g.setlayer(4) while not g.visrect( {0,200,300,400} ) do g.setmag(g.getmag()-1) end g.update() end ------------------------------------------------------- local function burp() local test_signal=g.parse([[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() g.show(instr..tickstep) g.select( {selx,sely,50,50} ) -- keyboard handling local ch = "" while ch~="q" do if place_signal>0 then if ticks-last_signal>1846 then g.putcells(test_signal,-150,60) last_signal=ticks place_signal=place_signal-1 end end local status_text=instr if place_signal>0 and run_flag==1 then status_text="Next signal placement in "..(1847 - ticks + last_signal).." ticks. " local plural="s" if place_signal==2 then plural="" end if place_signal>1 then status_text=status_text..(place_signal-1).." more signal"..plural.." requested after that. " end status_text=status_text..instr end show_status_text(status_text,delay,tickstep) local event = g.getevent() if event:find("key") == 1 then _, ch, _ = split(event) else ch = "" end if ch=="r" then prepare_burp() ticks=0 last_signal=-99999 viewport_speed=16 sel_speed=0 run_flag=0 selx=600.0 sely=365.0 place_signal=3 g.select({selx,sely,50,50}) elseif ch=="h" then g.note(helpstring) elseif ch=="t" then g.setoption("tilelayers",1-g.getoption("tilelayers")) elseif ch=="=" or ch=="+" then if delay>.01 then delay=delay/2 elseif delay==.01 then delay=-1 else if tickstep==1 then tickstep=3 elseif tickstep<250 then tickstep=(tickstep-1)*2+1 end end elseif ch=="-" or ch=="_" then if delay==-1 then if tickstep==1 then delay=.01 else if tickstep==3 then tickstep=1 else tickstep=math.floor((tickstep-1)/2)+1 end end else if delay<1 then delay=delay*2 end end elseif ch=="space" then run_flag=0 elseif ch=="return" then run_flag=1-run_flag elseif ch=="s" then place_signal=place_signal+1 if run_flag==0 then run_flag=1 end else g.doevent(event) end -- generation and selection speed handling if ch=="space" or run_flag==1 then g.run(tickstep) currlayer = g.getlayer() if currlayer ~= 4 then -- user has switched layer so temporarily change it back -- so we only change location of bottom right layer g.check(0) g.setlayer(4) end x, y = g.getpos() x, y = tonumber(x), tonumber(y) oldticks=ticks ticks=ticks+tickstep delta_view=math.floor(ticks/viewport_speed) - math.floor(oldticks/viewport_speed) if delta_view ~= 0 then g.setpos(tostring(x + delta_view), tostring(y + delta_view)) end sel = g.getselrect() if #sel ~= 0 then x, y, w, h = table.unpack(sel) if math.floor(selx)~=x then selx,sely=x,y else selx=selx+sel_speed*tickstep sely=sely+sel_speed*tickstep g.select( {math.floor(selx), math.floor(sely), w, h} ) end else g.select({math.floor(selx), math.floor(sely), 50, 50}) end if currlayer ~= 4 then g.setlayer(currlayer) g.check(1) end -- change viewport speed at appropriate times to follow the action if oldticks<4570 and ticks>=4570 then sel_speed=.666667 -- one-time correction to catch up with the signal at high sim speeds g.select( {math.floor(600+(ticks-4570)*1.5), math.floor(365+(ticks-4570)*1.5), w, h} ) end if selx>2125 then sel_speed=0 g.select( {2125, math.floor(sely+2125-selx), w, h} ) end if oldticks<4750 and ticks>=4750 then viewport_speed=1.5 end if oldticks<6125 and ticks>=6125 then viewport_speed=16 end if oldticks>=11995 then viewport_speed=99999.9 end -- stop automatically after the last signal passes through the device if oldticks-last_signal<8705 and ticks-last_signal>=8705 then run_flag=0 end if run_flag==1 and delay>0 then sleep(delay) end g.update() end end end ------------------------------------------------------- -- if there's more than one existing layer, the layout won't work correctly if g.numlayers() > 1 then local answer = g.getstring("All existing layers will be removed. OK?") if string.lower(string.sub(answer,1,1)) == "n" then g.exit() end end local oldswitch = g.setoption("switchlayers", 1) -- allow user to switch layers local oldtile = g.setoption("tilelayers", 1) local status, err = pcall(function () burp() end) if err then g.continue(err) end -- the following code is executed even if error occurred or user aborted script -- remove the cloned layers added by the script while g.numlayers() > 1 do g.dellayer() end g.setname("Stable Pseudo-Heisenburp Device") g.setoption("tilelayers", oldtile) g.setoption("switchlayers", oldswitch) g.show("") golly-2.8-src/Scripts/Lua/metafier.lua0000644000175100017510000012652312751752464014716 00000000000000-- metafier.lua: -- 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). -- -- converted from Python to Lua by Dave Greene, 23 April 2016 local g = golly() local gp = require "gplus" local split = gp.split local pattern = gp.pattern local selrect = g.getselrect() if #selrect == 0 then g.exit("There is no selection.") end -- check that a layer is available for the metafied pattern; -- if metafied layer already exists then we'll use that local layername = "metafied" local metalayer = -1 local i for i= 0,g.numlayers()-1 do if g.getname(i) == layername then metalayer = i break end end if metalayer < 0 and g.numlayers() == g.maxlayers() then g.exit("Delete a layer.") end -- note that getrule returns canonical rule string rulestr, _ = split(g.getrule(),":") if string.sub(rulestr,1,1)~="B" or string.find(rulestr,"/S") == nil then g.exit("This script only works with B*/S* rules.") end -- get the current selection local slist = g.getcells(selrect) local selwidth = selrect[3] local selheight = selrect[4] -- create a sparse table of 0s and 1s representing entire selection livecell = {} for i=1, #slist, 2 do livecell[(slist[i] - selrect[1])..","..(slist[i+1] - selrect[2])] = 1 end local r1, r2 = split(rulestr,"/") -- build a patch pattern based on the current rule -- that fixes the appropriate broken eaters in the rules table if string.sub(r1,1,1) == "B" then Bvalues = string.sub(r1,2) Svalues = string.sub(r2,2) elseif string.sub(r1,1,1) == "S" then Svalues = string.sub(r1,2) Bvalues = string.sub(r2,2) else Svalues, Bvalues = r1, r2 end -- create metafied pattern in separate layer if metalayer >= 0 then g.setlayer(metalayer) -- switch to existing layer else metalayer = g.addlayer() -- create new layer end g.new(layername) -- clear any existing pattern g.setrule("Life") g.setalgo("QuickLife") -- qlife's setcell is faster local Brle = "b10$b10$b26$b10$b10$b26$b10$b10$b!" local Srle = Brle for i = 1, #Bvalues do ind=225-Bvalues:byte(i)*4 -- because B and S values are highest at the top! Brle=string.sub(Brle,1,ind-1).."o"..string.sub(Brle,ind+1) end for i = 1, #Svalues do ind=225-Svalues:byte(i)*4 -- ASCII byte value of '0' is 48, '8' is 56 Srle=string.sub(Srle,1,ind-1).."o"..string.sub(Srle,ind+1) end local RuleBits = pattern(Brle, 148, 1404) + pattern(Srle, 162, 1406) -- load or generate the OFFcell tile: local OFFcellFileName = g.getdir("data").."metapixel-OFF.rle" local ONcellFileName = g.getdir("data").."metapixel-ON.rle" local fOFF = io.open(OFFcellFileName, "r") local fON = io.open(OFFcellFileName, "r") local OFFcell, ONcell if fON and fOFF then 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)) fON:close() fOFF:close() else g.show("Building OFF metacell definition...") -- slide #21: programmables -------------------- local LWSS = pattern("b4o$o3bo$4bo$o2bo!", 8, 0) local DiagProximityFuse = pattern([[ bo$obo$bo2$4b2o$4b2o$59b2o$59b2o3$58b2o2b2o$9b2o3bo5bo5bo5bo5bo5bo5bo 7b2o2b2o$9bo3bobo3bobo3bobo3bobo3bobo3bobo3bobo$10bo2bo2bo2bo2bo2bo2bo 2bo2bo2bo2bo2bo2bo2bo2bo$11bobo3bobo3bobo3bobo3bobo3bobo3bobo3bo5b2o$ 12bo5bo5bo5bo5bo5bo5bo5bo3bobo$55bo2bo$56bobo$57bo!]], -5, -5) local OrthoProximityFuse = pattern("2o41b2o$2o41bo$41bobo$41b2o!", 1001, 0) local ProximityFuses = LWSS + DiagProximityFuse + OrthoProximityFuse local AllFuses = pattern() -- place four sets of fuses around cell perimeter for i=0,3 do AllFuses = AllFuses.t(2047, 0, gp.rcw) + ProximityFuses end local temp = pattern("o$3o$3bo$2bo!") -- broken eater temp = temp + temp.t(0, 10) + temp.t(0, 20) temp = temp + temp.t(0, 46) + temp.t(0, 92) local TableEaters = temp.t(145, 1401) + temp.t(165, 1521, gp.flip) -- 18 eaters in all local 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) local HoneyBitsS = HoneyBitsB.t(57, 34) -- silly composition of letter labels out of subpatterns temp = pattern("2bobo2$obobo2$obo2$obo2$2bobo4$obo2$obobo2$2bobo!") local S = temp + temp.t(10, 16, gp.flip) local B = S + pattern("o6$8bobo2$o2$obo6$o!") temp = pattern("2bobo2$obobo2$obo2$obo2$obo2$obo2$obo2$obobo2$2bobo!") local O = temp + temp.t(10, 16, gp.flip) temp = pattern("obo2$obo2$obobo2$obobo2$obo2bo2$obo2$obo2$obo2$obo!") local N = temp + temp.t(10, 16, gp.flip) temp = pattern("obobobobo2$obobobobo2$obo2$obo2$obo2$obo!") local F = temp + temp.t(0,6) -- overlap, just to try it out... local Eatr = pattern("4bobo2$4bobo2$obo2$obo2$4bobobobobobo2$4bobobobobobo2$12bobo2$12bobo2$") local Eater = Eatr + pattern("obo2$obo2$") local 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!]]) local VLine = pattern(string.rep("o2$", 25)) local VLine2 = pattern(string.rep("o2$", 71)) local HLine = pattern(string.rep("ob", 38)) local TableLabels = VLine.t(18, 1440) + VLine.t(96, 1440) + Eater.t(77, 1446) + HLine.t(20, 1440) + HLine.t(20, 1488) + O.t(39, 1444) + N.t(55, 1444) + O.t(23, 1468) + F.t(39, 1468) + F.t(55, 1468) + Eatr.t(77, 1470) TableLabels = TableLabels + pattern(string.rep("ob",29).."8bobobo", 120, 1533) + HLine.t(118, 1391) + VLine2.t(118, 1393) + VLine2.t(192, 1393) + B.t(123, 1410) + B.t(123, 1456) + B.t(123, 1502) + S.t(177, 1398) + S.t(177, 1444) + S.t(177, 1490) + LabelDigits.t(138, 1396) + LabelDigits.t(168, 1401) local 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(string.rep("3bo$b3o$o$2o5$", 36)..Gap ..string.rep("3bo$b3o$o$2o5$",10).."24$"..string.rep("3bo$b3o$o$2o5$",17) ..Gap..string.rep("3bo$b3o$o$2o5$",42)..Gap.."3bo$b3o$o$2o5$3bo7bo$b3o5b3o$o7bo$2o6b2o13$" ..string.rep("3bo$b3o$o$2o5$",30).."8$"..string.rep("3bo$b3o$o$2o5$",2)..Gap.."16$" ..string.rep("3bo$b3o$o$2o5$",11).."8$"..string.rep("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 = all + LinearClockGun[1840] + LinearClockEaters + LinearClockCap -- slide 23: MWSS track -------------------- local MWSS = pattern("b5o$o4bo$5bo$o3bo$2bo!", 521, 1973) local P46Osc = pattern([[ 40bo$31b2o5b3o$10b3o14b2o3bo4bo$10bo3bo12b2o3bobo3bo$3bo6bo4bo17bobo3b o$b3o7bo3bo18bo3b2o$o$b3o7bo3bo7b3o$3bo6bo4bo5b2obob2o$10bo3bo5bo5b2o$ 10b3o8b2obob2o$23b3o!]]) local P46Gun = pattern([[ 31b2o$30b2o$31b5o9bo$16b3o13b4o9b3o$14bo3bo29bo$3bo9bo4bo13b4o9b3o$b3o 9bo3bo13b5o9bo$o29b2o$b3o9bo3bo13b2o$3bo9bo4bo$14bo3bo$16b3o!]]) local GliderToMWSS = P46Osc.t(449, 1963) + P46Gun.t(474, 1981) -- exact match would be P46Gun[46](474, 1981), but that glider is absorbed local StateBit = pattern("b2o$obo$bo!", 569, 1970) local Snake = pattern("2o$o$bo$2o!", 570, 1965) local BitKeeper = pattern([[ 15bobo2b2o19b2o$14bo3bob3o19bo$15bo6b2o15b3o$3bo12b5obo16bo$b3o15b3o$o $b3o15b3o$3bo12b5obo$15bo6b2o3b2o$14bo3bob3o4b2o$15bobo2b2o!]], 524, 1982) local GliderFromTheBlue = pattern([[ 23b2o$23bo2bobo$25b2ob3o$31bo$25b2ob3o$12bo3bo8b2obo$11bo5bo$17bo$3bo 8bo3b2o$b3o9b3o$o$b3o9b3o19bo$3bo8bo3b2o7bo7b3o$17bo4bo2bob2o3bo$11bo 5bo10bo4bo$12bo3bo10bo4b2o2$23b5o$24b4o$26bo!]]) local 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 local ReflectLWSS = pattern([[ b2o$b2o8$b3o3b3o$o2bo3bo2bo$2obo3bob2o14$3b2ob2o$4bobo$4bobo$5bo!]], 589, 1940) local ReflectLWSS2 = pattern([[ 15b2o3bo$15b3obob2o4b2o$15b3o4bo4b2o$3bo14bo3bo$b3o15b3o$o$b3o15b3o$3b o14bo3bo$15b3o4bo$15b3obob2o$15b2o3bo!]], 573, 1884) -- P46Osc really local LWSStoBoat = pattern([[ 2o14b2o9b2o$2o15b2o8b2o$13b5o$13b4o2$3b2o8b4o$2bobob2o5b5o$b2o3b2o9b2o 8b2o$2bobob2o8b2o9b2o$3b2o!]], 821, 1883) -- P46Osc really local 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!]]) local HoneyBit = pattern("b2o$o2bo$b2o!") local 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 = CornerSignalSystem + pattern("5b2o$5b2o3$2o2b2o$2o2b2o!", 86, 1) + pattern([[ 11b2o$11b2o12$4b3o3b3o$4b3o3b3o$3bob2o3b2obo$3bob2o3b2obo$4b2o5b2o$5bo 5bo6$2o13b2o$2o2b2o5b2o2b2o$4b2o5b2o!]], 159, 0) -- P46OscAlt1 really local SignalSystem = pattern() for i=0,2 do -- place three sets of mechanisms to signal neighbors SignalSystem = SignalSystem[32].t(2047, 0, gp.rcw) + HoneyBit.t(42, 111, gp.rcw) + ReflectMWSS.t(38, 46) + GliderFromTheBlue.t(73, 52) + CornerSignalSystem + HoneyBit.t(964, 40) + GliderFromTheBlue[12].t(953, 52) end -- 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 = SignalSystem + HoneyBit.t(48, 1086, gp.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 = 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 = 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 = 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 = all + SignalSystem + GliderToMWSS + MWSS + Snake + BitKeeper all = all + GliderFromTheBlue.t(607, 1953) + GliderToLWSS + ReflectLWSS + ReflectLWSS2 + LWSStoBoat -- StateBit will be added later on, when defining OFFcell and ONcell -- slide 24: LWSS track -------------------- -- [phase adjusters and a bunch of honeybits] local PhaseAdjuster = P46Gun.t(2, 11, gp.flip_y) + P46Gun[12].t(0, 32) + pattern("o$3o$3bo$2b2o!", 0, 13) + pattern("2b2o$bobo$bo$2o!", 2, 26) -- eaters really all = all + PhaseAdjuster[43].t(1772,10) + PhaseAdjuster[26].t(2037, 1772, gp.rcw) all = all + PhaseAdjuster[43].t(269, 2037, gp.flip) + PhaseAdjuster[9].t(58, 1203, gp.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 local 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 = 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 local P46OscAlt1 = pattern([[ b2o$b2o2$6bo3b2o$2o2b2obob3o13b2o$2o2bo4b3o13b2o$4bo3bo$5b3o$19b2o3b2o $5b3o10b3o3b3o$4bo3bo7b3o7b3o$2o2bo4b3o4b3o7b3o$2o2b2obob3o4b3o7b3o$6b o3b2o6b3o3b3o$19b2o3b2o$b2o$b2o!]]) all = all + P46OscAlt1.t(4, 24) + P46OscAlt1[12].t(224, 67, gp.swap_xy_flip) local P46OscAlt2 = pattern([[ 2o8b3o14b2o$2o8bo3bo12b2o$10bo4bo$11bo3bo2$11bo3bo7b3o$10bo4bo5b2obob 2o$2o8bo3bo5bo5b2o$2o8b3o8b2obob2o$23b3o!]]) all = all + P46OscAlt2.t(179, 19) + P46OscAlt1[29].t(2023, 4, gp.rcw) -- got impatient here, started throwing in placeholders instead of true definitions -- -- NE corner along E edge: all = 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 = 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 = 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 = 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 = 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 = 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 = 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 = all + pattern([[ b2o5b2o$b2o5b2o7$2bo5bo$b3o3b3o$o2b2ob2o2bo$3o5b3o9$b3o$o3bo$2ob2o$bob o2$bobo$2ob2o$o3bo3b2o$b3o4b2o!]], 150, 958) -- P46OscAlt3 really all = all + pattern([[ 10b2o$2o6b2ob2o14b2o$2o6bo2bo15b2o$8bo2bo$9b2o2$9b2o$8bo2bo$8bo2bo15b 2o$8b2ob2o14b2o$10b2o!]], 155, 998) -- P46OscAlt3 really all = all + pattern([[ 15bobo2b2o$2o12bo3bob3o4b2o$2o13bo6b2o3b2o$16b5obo$19b3o2$19b3o$16b5ob o$2o13bo6b2o$2o12bo3bob3o$15bobo2b2o!]], 114, 1008) -- P46OscAlt3 really all = 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 = 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 = all + pattern([[ 24bo2bo$14b3o7bo$13bo4bo9bo$12bo5bo8b2o$3bo9bo8bo$b3o10b2o8b2o$o$b3o 10b2o8b2o$3bo9bo8bo3bo$12bo5bo4bo2bo$13bo4bo4bo2bo$14b3o7b2o! ]], 33, 1332) -- P46Osc really all = 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 = all + pattern([[ b2o$b2o2$13bobo2b2o$2o10bo3bob3o$2o11bo6b2o$14b5obo$17b3o2$17b3o$14b5o bo$2o11bo6b2o3b2o$2o10bo3bob3o4b2o$13bobo2b2o2$b2o$b2o! ]], 24, 1661) -- P46OscAlt1 really all = all + pattern([[ b2o$b2o12$b3o3b3o$b3o3b3o$ob2o3b2obo$ob2o3b2obo$b2o5b2o$2bo5bo3$3b2ob 2o$4bobo$4bobo$4bobo$3b2ob2o$4bobo$4bobo$5bo!]], 49, 1679) -- P46Osc really all = all + pattern([[ b2o$o2bo$o7bo$o2bo3bobo$2ob2ob2ob2o$4bobo$3b2ob2o5$b3o3b3o$o9bo$o3bobo 3bo$b3o3b3o$2bo5bo10$3b2ob2o$4bobo$4bobo$5bo!]], 140, 1546) -- P46Osc really all = 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 = 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 = 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 = 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 = 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 = all + pattern([[ b2o5b2o$b2o5b2o14$3o5b3o$3o5b3o$b2o5b2o$3bo3bo$bo2bobo2bo$o3bobo3bo$bo 2bobo2bo$b3o3b3o5$8b2o$8b2o!]], 514, 1887) -- P46OscAlt3 really all = all + pattern([[ 4bo7b2o$3b2o6bo2bo$2bo8bo2b2o$3b2obo4bo2bo10bo$4b3o6bo11b3o$28bo$4b3o 6bo11b3o$bob2obo4bo2bo10bo$o10bo2b2o$o3bo6bo2bo$b4o7b2o! ]], 791, 1929) -- P46Osc really all = all + pattern([[ 8bo$9bo3bo$2o2b2o8bo$2o2bo5b2o2bo$4bobo5b2o11bo$5b2o3b3o12b3o$28bo$5b 2o3b3o12b3o$4bobo5b2o11bo$4bo5b2o2bo$4b2o8bo$9bo3bo$8bo! ]], 845, 1905) -- P46Osc really all = all + pattern([[ 10b2o$2o6b2ob2o14b2o$2o6bo2bo15b2o$8bo2bo$9b2o2$9b2o10b3ob3o$8bo2bo8bo b2ob2obo$2o6bo2bo7b2o7b2o$2o6b2ob2o7bob2ob2obo$10b2o9b3ob3o! ]], 1050, 1903) -- P46OscAlt2 really all = all + pattern([[ 9b2o$9b2o11$2b3o3b3o$bo3bobo3bo$o3b2ob2o3bo$ob2o5b2obo$2bo7bo11$2b2o5b 2o$2b2o5b2o!]], 1088, 1920) -- P46OscAlt2 really all = 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 = 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 = all + pattern("2o$obo$2bo$2b2o!", 1281, 1873) -- eater all = 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 local 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 = 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 = 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 = 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 -------------------- local 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 local 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 local RowOfLWSSFTB = pattern("o$3o$3bo$2b2o!", 1737, 24) for i=0,42 do RowOfLWSSFTB =RowOfLWSSFTB + LWSSFromTheBlue[(i*12) % 46].t(40*i, 0) end local HWSSHalfControl = HWSSGun.t(106, 87) + RowOfLWSSFTB.t(188, 79) local CellCenter = HWSSHalfControl + HWSSHalfControl.t(2047, 2047, gp.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 not fOFF then OFFcell.save(OFFcellFileName) end -- slide 31: display on -------------------- g.show("Building ON metacell definition...") -- switch on the HWSS guns: CellCenter = 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 not fON then ONcell.save(ONcellFileName) end -- g.store(ONcell,ONcellFileName) -- doesn't work; would need to be ONcell.array end OFFcell = OFFcell + RuleBits ONcell = ONcell + RuleBits for j=0,selheight-1 do for i=0,selwidth-1 do g.show("Placing ("..(i+1)..","..(j+1)..") tile".. " in a "..selwidth.." by "..selheight.." rectangle.") if livecell[i..","..j]~=nil then ONcell.put(2048 * i - 5, 2048 * j - 5) else OFFcell.put(2048 * i - 5, 2048 * j - 5) end g.fit() g.update() end end g.show("") g.setalgo("HashLife") -- no point running a metapattern without hashing g.setoption("hyperspeed", 0) -- 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.8-src/Scripts/Lua/envelope.lua0000755000175100017510000001021112751752464014724 00000000000000-- Use multiple layers to create a history of the current pattern. -- The "envelope" layer remembers all live cells. -- Author: Andrew Trevorrow (andrewtrevorrow.com), Apr 2016. local g = golly() if g.empty() then g.exit("There is no pattern.") end local currindex = g.getlayer() local startindex local envindex local startname = "starting pattern" local envname = "envelope" if currindex > 1 and g.getname(currindex - 1) == startname and g.getname(currindex - 2) == envname then -- continue from where we left off startindex = currindex - 1 envindex = currindex - 2 elseif (currindex + 2) < g.numlayers() and g.getname(currindex + 1) == startname and g.getname(currindex) == envname then -- switch from envelope layer to current layer and continue currindex = currindex + 2 g.setlayer(currindex) startindex = currindex - 1 envindex = currindex - 2 elseif (currindex + 1) < g.numlayers() and g.getname(currindex) == startname and g.getname(currindex - 1) == envname then -- switch from starting layer to current layer and continue currindex = 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() then g.exit("You need to delete a couple of layers.") end if g.numlayers() + 2 > g.maxlayers() then g.exit("You need to delete a layer.") end -- get current layer's starting pattern local startpatt = g.getcells(g.getrect()) envindex = g.addlayer() -- create layer for remembering all live cells g.setcolors({-1,100,100,100}) -- set all live 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 live 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) end -------------------------------------------------------------------------------- local function envelope() -- draw stacked layers using same location and scale g.setoption("stacklayers", 1) g.show("Hit escape key to stop script...") while true do g.run(1) if g.empty() then g.show("Pattern died out.") return end -- copy current pattern to envelope layer -- we temporarily disable event checking so thumb scrolling -- and other mouse events won't cause confusing changes local currpatt = g.getcells(g.getrect()) g.check(0) g.setlayer(envindex) g.putcells(currpatt) g.setlayer(currindex) g.check(1) local step = 1 local expo = g.getstep() if expo > 0 then step = g.getbase()^expo end if g.getgen() % step == 0 then -- display all 3 layers (envelope, start, current) g.update() end end end -------------------------------------------------------------------------------- -- show status bar but hide layer & edit bars (faster, and avoids flashing) local oldstatus = g.setoption("showstatusbar", 1) local oldlayerbar = g.setoption("showlayerbar", 0) local oldeditbar = g.setoption("showeditbar", 0) local status, err = pcall(function () envelope() end) if err then g.continue(err) end -- the following code is executed even if error occurred or user aborted script -- restore original state of status/layer/edit bars g.setoption("showstatusbar", oldstatus) g.setoption("showlayerbar", oldlayerbar) g.setoption("showeditbar", oldeditbar) golly-2.8-src/Scripts/Lua/slide-show.lua0000644000175100017510000000513012751752464015166 00000000000000-- Display all patterns in Golly's Patterns folder. -- Author: Andrew Trevorrow (andrew@trevorrow.com), Apr 2016. local g = golly() local pathsep = g.getdir("app"):sub(-1) local message = "Hit space to continue or escape to exit the slide show..." -------------------------------------------------------------------------------- local function walk(dir) local files = g.getfiles(dir) for _, name in ipairs(files) do if name:sub(1,1) == "." then -- ignore hidden files (like .DS_Store on Mac) elseif name:sub(-1) == pathsep then -- name is a subdirectory walk(dir..name) else g.new("") g.setalgo("QuickLife") -- nicer to start from this algo local fullname = dir..name g.open(fullname, false) -- don't add file to Open/Run Recent submenu g.update() if name:sub(-4) == ".lua" or name:sub(-3) == ".py" then -- reshow message in case it was changed by script g.show(message) end while true do local event = g.getevent() if event == "key space none" then break end g.doevent(event) -- allow keyboard/mouse interaction end end end end -------------------------------------------------------------------------------- local function slideshow() local oldalgo = g.getalgo() local oldrule = g.getrule() g.show(message) walk(g.getdir("app").."Patterns"..pathsep) -- 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) end -------------------------------------------------------------------------------- -- show status bar but hide other info to maximize viewport local oldstatus = g.setoption("showstatusbar", 1) local oldtoolbar = g.setoption("showtoolbar", 0) local oldlayerbar = g.setoption("showlayerbar", 0) local oldeditbar = g.setoption("showeditbar", 0) local oldfiles = g.setoption("showfiles", 0) local status, err = pcall(function () slideshow() end) if err then g.continue(err) end -- 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("showfiles", oldfiles) golly-2.8-src/Scripts/Lua/life-integer-gun30.lua0000644000175100017510000000326112751752464016417 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. local g = golly() local gpt = require "gplus.text" g.new("Eric Angelini integer glider gun") g.setrule("B3/S23") local all = gpt.maketext([[ 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("") golly-2.8-src/Scripts/Lua/tile-with-clip.lua0000755000175100017510000000400612751752464015747 00000000000000-- Tile current selection with clipboard pattern. -- Author: Andrew Trevorrow (andrewtrevorrow.com), Mar 2016. local g = golly() local gp = require "gplus" -- assume one-state cell array (may change below) local multistate = false -------------------------------------------------------------------------------- local function clip_rb(cells, right, bottom) -- set given cells except those outside given right and bottom edges local len = #cells local x = 1 local y = 2 if multistate then -- ignore padding int if present if len % 3 == 1 then len = len - 1 end while x <= len do if (cells[x] <= right) and (cells[y] <= bottom) then g.setcell(cells[x], cells[y], cells[x+2]) end x = x + 3 y = y + 3 end else while x <= len do if (cells[x] <= right) and (cells[y] <= bottom) then g.setcell(cells[x], cells[y], 1) end x = x + 2 y = y + 2 end end end -------------------------------------------------------------------------------- local selrect = g.getselrect() if #selrect == 0 then g.exit("There is no selection.") end -- get selection edges local selleft, seltop, selright, selbottom = gp.getedges(selrect) local pwidth, pheight, p = g.getclip() if #p & 1 == 1 then multistate = true end g.clear(0) if #p > 0 then -- tile selrect with p, clipping right & bottom edges if necessary local y = seltop while y <= selbottom do local bottom = y + pheight - 1 local x = selleft while x <= selright do local right = x + pwidth - 1 if (right <= selright) and (bottom <= selbottom) then g.putcells(p, x, y) else local tempcells = g.transform(p, x, y) clip_rb(tempcells, selright, selbottom) end x = x + pwidth end y = y + pheight end end if not g.visrect(selrect) then g.fitsel() end golly-2.8-src/Scripts/Lua/p1100-MWSS-gun.lua0000644000175100017510000001122012751752464015224 00000000000000-- Bill Gosper's pure-period p1100 double MWSS gun, circa 1984. local g = golly() local gp = require "gplus" local pattern = gp.pattern local flip = gp.flip local flip_x = gp.flip_x local flip_y = gp.flip_y local rccw = gp.rccw local rcw = gp.rcw local swap_xy_flip = gp.swap_xy_flip 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() local glider = pattern("bo$bbo$3o!") local block = pattern("oo$oo!") local eater = pattern("oo$bo$bobo$bboo!") local bhept = pattern("bbo$boo$oo$boo!") local twobits = eater + bhept.t(8,3) local half = twobits + twobits[1].t(51,0,flip_x) local centinal = half + half.t(0,16,flip_y) local passthrough = centinal[1].t(16,3,rcw) + centinal[19].t(52,0,rcw) + centinal[81].t(55,51,rccw) + centinal[99].t(91,54,rccw) -- build the source signal -- the most compact set of gliders -- from which all other gliders and spaceships can be generated local MWSSrecipes = glider.t(5759,738,rccw) + glider.t(6325,667,flip_x) + glider[3].t(5824,896,flip_x) + glider[2].t(5912,1264) + glider[2].t(6135,1261,flip_x) + glider[1].t(5912,1490,flip_y) + glider.t(6229,4717,flip_x) + glider[1].t(6229,5029,flip) + glider[1].t(5920,5032,flip_y) + glider.t(6230,5188,flip) + glider[3].t(6230,5306,flip) + glider[3].t(5959,5309,flip_y) -- suppress output MWSSes as long as gliders are being added MWSSrecipes = MWSSrecipes + pattern("o!",6095,-65) + pattern("o!",6075,228) -- add the first four centinals to guide the recipe gliders local all = centinal[44].t(6185,5096,flip_x) + centinal[73].t(5897,1066) all = all + centinal[42].t(5782,690) + centinal[25].t(5793,897,rcw) -- generate the MWSSes for the glider-fanout ladder for i = 1, 7 do g.show("Building rung " .. i .. " of ladder...") all = (all + MWSSrecipes)[1100] end -- add the actual glider-fanout ladder -- six rungs for i = 0, 5 do all = all + glider.t(6030,1706+550*i,swap_xy_flip) + centinal[15].t(6102,1585+550*i) + block.t(6029,1721+550*i) + centinal[34].t(5996,1725+550*i,rccw) + block.t(6087,1747+550*i) + centinal[87].t(6122,1745+550*i,rcw) end -- add the rest of the centinals to guide the ladder's output gliders g.show("Adding centinal reflectors...") all = all + centinal[88].t(5704,0) + centinal[29].t(6423,295,flip_x) + centinal[74].t(5616,298) + centinal[40].t(6361,613,rcw) + centinal[23].t(6502,620,flip_x) + centinal[36].t(5636,986) + centinal[38].t(6370,1008,rcw) + centinal[19].t(5747,1347,rcw) + centinal[67].t(5851,1516) + centinal.t(4061,2605,rccw) + centinal[10].t(5376,3908,rccw) + centinal[77].t(8191,4407,flip_x) + centinal[6].t(4988,4606) + centinal[34].t(6357,4608,flip_x) + centinal[27].t(8129,4621,flip_x) + centinal[92].t(5159,5051) + centinal[53].t(7991,5201,flip_x) + centinal[94].t(7038,5370,rccw) + centinal[13].t(5591,5379,rccw) + centinal[3].t(5858,5428,rccw) + centinal[87].t(7805,5511,flip_x) + centinal[98].t(401,5557,rccw) + centinal[14].t(955,5561,rccw) + centinal[8].t(6592,5584,rccw) + centinal[39].t(6933,5698,flip_x) + centinal[32].t(6230,5881) + centinal[47].t(11676,5854,rccw) + centinal[68].t(0,5748,rccw) + centinal[89].t(6871,5912,flip_x) + centinal[45].t(12095,6027,rccw) + centinal[86].t(6209,6134) + centinal[55].t(6868,6357,flip_x) + centinal[95].t(9939,6491,rccw) + centinal[23].t(8782,6548,rccw) + centinal[58].t(3066,6572,rccw) + centinal[21].t(9326,6596,rccw) + centinal[80].t(3628,6626,rccw) + centinal[45].t(6821,6528,flip_x) + centinal[33].t(10373,6649,rccw) + centinal[16].t(2587,6685,rccw) -- to change behavior at center, comment out one of the lines below all = all + eater.t(6018,5924,rccw) + eater.t(6037,5943,rccw) -- true p1100 gun -- all = all + block.t(6018,6787) -- synch center to recreate original p1100x5 local center = block.t(1081,6791) + block.t(2731,6791) + block.t(3831,6791) + block.t(9108,6791) + block.t(10208,6791) + block.t(11308,6791) + passthrough.t(8475,6737) + passthrough[39].t(3365,6737,flip_x) + passthrough.t(9575,6737) + passthrough[39].t(2265,6737,flip_x) + passthrough.t(10675,6737) + passthrough[39].t(1715,6737,flip_x) -- add asymmetric Equator to mirror-symmetric North and South MWSSrecipes = MWSSrecipes + MWSSrecipes.t(0,13583,flip_y) all = all + all.t(0,13583,flip_y) + center all.put() g.fit() -- Different glider paths are different lengths, so incomplete -- glider recipes must be overwritten for a while to prevent disaster. for i = 0, 45 do g.show("Filling glider tracks -- " .. (49500 - i*1100) .. " ticks left.") g.update() MWSSrecipes.put() g.run(1100) end g.show("") -- reset gen count to 0 g.setgen("0") golly-2.8-src/Scripts/Lua/shift.lua0000755000175100017510000000471212751752464014235 00000000000000-- Shift current selection by given x y amounts using optional mode. -- Author: Andrew Trevorrow (andrewtrevorrow.com), Mar 2016. local g = golly() local gp = require "gplus" local selrect = g.getselrect() if #selrect == 0 then g.exit("There is no selection.") end -- use same file name as in shift.py local inifilename = g.getdir("data").."shift.ini" local oldparams = "0 0 or" local f = io.open(inifilename, "r") if f then -- get the parameters given last time oldparams = f:read("*l") or "" f:close() end local 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") local x, y, mode = gp.split(s) -- check x and y if y == nil then g.exit("Enter x and y amounts separated by a space.") end if not gp.validint(x) then g.exit("Bad x value: "..x) end if not gp.validint(y) then g.exit("Bad y value: "..y) end x = tonumber(x) y = tonumber(y) -- check optional mode if mode == nil then mode = "or" else mode = string.lower(mode) if mode == "c" then mode = "copy" end if mode == "o" then mode = "or" end if mode == "x" then mode = "xor" end if not (mode == "copy" or mode == "or" or mode == "xor") then g.exit("Unknown mode: "..mode.." (must be copy/or/xor)") end end -- given parameters are valid so save them for next run f = io.open(inifilename, "w") if f then f:write(s) f:close() end -- abort shift if the new selection would be outside a bounded grid if g.getwidth() > 0 then local gridl = -g.getwidth()/2 local gridr = gridl + g.getwidth() - 1 local newl = selrect[1] + x local newr = newl + selrect[3] - 1 if newl < gridl or newr > gridr then g.exit("New selection would be outside grid.") end end if g.getheight() > 0 then local gridt = -g.getheight()/2 local gridb = gridt + g.getheight() - 1 local newt = selrect[2] + y local newb = newt + selrect[4] - 1 if newt < gridt or newb > gridb then g.exit("New selection would be outside grid.") end end -- do the shift by cutting the current selection and pasting it into -- the new position without changing the current clipboard pattern local selcells = g.getcells(selrect) g.clear(0) selrect[1] = selrect[1] + x selrect[2] = selrect[2] + y g.select(selrect) if mode == "copy" then g.clear(0) end g.putcells(selcells, x, y, 1, 0, 0, 1, mode) if not g.visrect(selrect) then g.fitsel() end golly-2.8-src/Scripts/Lua/invert.lua0000755000175100017510000000151112751752464014421 00000000000000-- Invert all cell states in the current selection. -- Author: Andrew Trevorrow (andrew@trevorrow.com), Mar 2016. local g = golly() local gp = require "gplus" -- re-assigning inner loop functions results in a 10% speed up local setcell = g.setcell local getcell = g.getcell local r = gp.rect(g.getselrect()) if r.empty then g.exit("There is no selection.") end -- local t1 = os.clock() local oldsecs = os.clock() local maxstate = g.numstates() - 1 for row = r.top, r.bottom do -- if large selection then give some indication of progress local newsecs = os.clock() if newsecs - oldsecs >= 1.0 then oldsecs = newsecs g.update() end for col = r.left, r.right do setcell(col, row, maxstate - getcell(col, row)) end end if not r.visible() then g.fitsel() end -- g.show(""..(os.clock()-t1)) golly-2.8-src/Scripts/Lua/flood-fill.lua0000644000175100017510000001243212751752464015142 00000000000000-- Fill clicked region with current drawing state. -- Author: Andrew Trevorrow (andrew@trevorrow.com), Apr 2016. local g = golly() local gp = require "gplus" -- avoid an unbounded fill local minx, miny, maxx, maxy if g.empty() then if g.getwidth() == 0 or g.getheight() == 0 then g.exit("You cannot fill an empty universe that is unbounded!") end else -- set fill limits to the pattern's bounding box -- (these will be extended below if the grid is bounded) minx, miny, maxx, maxy = gp.getedges(g.getrect()) end -- allow filling to extend to the edges of bounded grid if g.getwidth() > 0 then minx = -gp.int(g.getwidth() / 2) maxx = minx + g.getwidth() - 1 end if g.getheight() > 0 then miny = -gp.int(g.getheight() / 2) maxy = miny + g.getheight() - 1 end -------------------------------------------------------------------------------- local function checkneighbor(x, y, oldstate) -- first check if x,y is outside fill limits if x < minx or x > maxx then return false end if y < miny or y > maxy then return false end return g.getcell(x, y) == oldstate end -------------------------------------------------------------------------------- local function floodfill() local newstate = g.getoption("drawingstate") local oldstate = newstate local x, y -- wait for user to click a cell g.show("Click the region you wish to fill... (hit escape to abort)") while oldstate == newstate do local event = g.getevent() if event:find("click") == 1 then -- event is a string like "click 10 20 left none" local evt, xstr, ystr, butt, mods = gp.split(event) x = tonumber(xstr) y = tonumber(ystr) if x < minx or x > maxx or y < miny or y > maxy then -- 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 then g.warn("The clicked cell must have a different state\n".. "to the current drawing state.") end end else g.doevent(event) end end -- 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)") local clist = {} clist[1] = {x, y} g.setcell(x, y, newstate) local oldsecs = os.clock() while #clist > 0 do -- remove cell from end of clist (much faster than removing from start) x, y = table.unpack( table.remove(clist) ) local newsecs = os.clock() if newsecs - oldsecs >= 0.5 then -- show changed pattern every half second oldsecs = newsecs g.update() end -- check if any orthogonal neighboring cells are in oldstate if checkneighbor( x, y-1, oldstate) then g.setcell( x, y-1, newstate) clist[#clist+1] = {x, y-1} end if checkneighbor( x, y+1, oldstate) then g.setcell( x, y+1, newstate) clist[#clist+1] = {x, y+1} end if checkneighbor (x+1, y, oldstate) then g.setcell( x+1, y, newstate) clist[#clist+1] = {x+1, y} end if checkneighbor( x-1, y, oldstate) then g.setcell( x-1, y, newstate) clist[#clist+1] = {x-1, y} end -- check if any diagonal neighboring cells are in oldstate -- (note that 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) then g.setcell( x+1, y+1, newstate) clist[#clist+1] = {x+1, y+1} end if checkneighbor( x+1, y-1, oldstate) and (g.getcell(x, y-1) == 0 or g.getcell(x+1, y) == 0) then g.setcell( x+1, y-1, newstate) clist[#clist+1] = {x+1, y-1} end if checkneighbor( x-1, y+1, oldstate) and (g.getcell(x, y+1) == 0 or g.getcell(x-1, y) == 0) then g.setcell( x-1, y+1, newstate) clist[#clist+1] = {x-1, y+1} end if checkneighbor( x-1, y-1, oldstate) and (g.getcell(x, y-1) == 0 or g.getcell(x-1, y) == 0) then g.setcell( x-1, y-1, newstate) clist[#clist+1] = {x-1, y-1} end end end -------------------------------------------------------------------------------- oldcursor = g.getcursor() g.setcursor("Draw") local status, err = pcall(function () floodfill() end) if err then g.continue(err) end -- the following code is executed even if error occurred or user aborted script g.setcursor(oldcursor) g.show(" ") golly-2.8-src/Scripts/Lua/oscar.lua0000755000175100017510000001367412751752464014236 00000000000000-- Oscar is an OSCillation AnalyzeR for use with Golly. -- Author: Andrew Trevorrow (andrewtrevorrow.com), Mar 2016. -- -- 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). local g = golly() -- initialize lists local hashlist = {} -- for pattern hash values local genlist = {} -- corresponding generation counts local poplist = {} -- corresponding population counts local boxlist = {} -- corresponding bounding boxes -- check if outer-totalistic rule has B0 but not S8 local r = g.getrule() r = string.match(r, "^(.+):") or r local hasB0notS8 = r:find("B0") == 1 and r:find("/") > 1 and r:sub(-1,-1) ~= "8" ---------------------------------------------------------------------- local function show_spaceship_speed(period, deltax, deltay) -- we found a moving oscillator if period == 1 then g.show("Spaceship detected (speed = c)") elseif deltax == deltay or deltax == 0 or deltay == 0 then local speed = "" if deltax == 0 or deltay == 0 then -- orthogonal spaceship if deltax > 1 or deltay > 1 then speed = speed..(deltax + deltay) end else -- diagonal spaceship (deltax == deltay) if deltax > 1 then speed = speed..deltax end end g.show("Spaceship detected (speed = "..speed.."c/"..period..")") else -- deltax != deltay and both > 0 local speed = deltay..","..deltax g.show("Knightship detected (speed = "..speed.."c/"..period..")") end end ---------------------------------------------------------------------- local function oscillating() -- return true if the pattern is empty, stable or oscillating -- first get current pattern's bounding box local pbox = g.getrect() if #pbox == 0 then g.show("The pattern is empty.") return true end local h = g.hash(pbox) -- determine where to insert h into hashlist local pos = 1 local listlen = #hashlist while pos <= listlen do if h > hashlist[pos] then pos = pos + 1 elseif h < hashlist[pos] then -- shorten lists and append info below for i = 1, listlen - pos + 1 do table.remove(hashlist) table.remove(genlist) table.remove(poplist) table.remove(boxlist) end 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 local rect = boxlist[pos] if tonumber(g.getpop()) == poplist[pos] and pbox[3] == rect[3] and pbox[4] == rect[4] then local period = tonumber(g.getgen()) - genlist[pos] if hasB0notS8 and (period % 2) > 0 and pbox[1] == rect[1] and pbox[2] == rect[2] and pbox[3] == rect[3] and pbox[4] == rect[4] then -- 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 end if period == 1 then if pbox[1] == rect[1] and pbox[2] == rect[2] and pbox[3] == rect[3] and pbox[4] == rect[4] then g.show("The pattern is stable.") else show_spaceship_speed(1, 0, 0) end elseif pbox[1] == rect[1] and pbox[2] == rect[2] and pbox[3] == rect[3] and pbox[4] == rect[4] then g.show("Oscillator detected (period = "..period..")") else local deltax = math.abs(rect[1] - pbox[1]) local deltay = math.abs(rect[2] - pbox[2]) show_spaceship_speed(period, deltax, deltay) end return true else -- look at next matching hash value or insert if no more pos = pos + 1 end end end -- store hash/gen/pop/box info at same position in various lists table.insert(hashlist, pos, h) table.insert(genlist, pos, tonumber(g.getgen())) table.insert(poplist, pos, tonumber(g.getpop())) table.insert(boxlist, pos, pbox) return false end ---------------------------------------------------------------------- local function fit_if_not_visible() -- fit pattern in viewport if not empty and not completely visible local r = g.getrect() if #r > 0 and not g.visrect(r) then g.fit() end end ---------------------------------------------------------------------- g.show("Checking for oscillation... (hit escape to abort)") local oldsecs = os.clock() while not oscillating() do g.run(1) local newsecs = os.clock() if newsecs - oldsecs >= 1.0 then -- show pattern every second oldsecs = newsecs fit_if_not_visible() g.update() end end fit_if_not_visible() golly-2.8-src/Scripts/Python/0000755000175100017510000000000012751756121013220 500000000000000golly-2.8-src/Scripts/Python/tile.py0000644000175100017510000000757712525071110014452 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.8-src/Scripts/Python/make-torus.py0000644000175100017510000000132612525071110015566 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.8-src/Scripts/Python/oscar.py0000644000175100017510000001332012525071110014603 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.8-src/Scripts/Python/flood-fill.py0000644000175100017510000001116312751752464015551 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): g.setcell( x, y-1, newstate) clist.append( (x, y-1) ) if checkneighbor( x, y+1, oldstate): g.setcell( x, y+1, newstate) clist.append( (x, y+1) ) if checkneighbor( x+1, y, oldstate): g.setcell( x+1, y, newstate) clist.append( (x+1, y) ) if checkneighbor( x-1, y, oldstate): g.setcell( x-1, y, newstate) clist.append( (x-1, y) ) # 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): g.setcell( x+1, y+1, newstate) clist.append( (x+1, y+1) ) if checkneighbor( x+1, y-1, oldstate) and (g.getcell(x, y-1) == 0 or g.getcell(x+1, y) == 0): g.setcell( x+1, y-1, newstate) clist.append( (x+1, y-1) ) if checkneighbor( x-1, y+1, oldstate) and (g.getcell(x, y+1) == 0 or g.getcell(x-1, y) == 0): g.setcell( x-1, y+1, newstate) clist.append( (x-1, y+1) ) if checkneighbor( x-1, y-1, oldstate) and (g.getcell(x, y-1) == 0 or g.getcell(x-1, y) == 0): g.setcell( x-1, y-1, newstate) clist.append( (x-1, y-1) ) # ------------------------------------------------------------------------------ oldcursor = g.getcursor() g.setcursor("Draw") try: floodfill() finally: g.setcursor(oldcursor) g.show(" ") golly-2.8-src/Scripts/Python/draw-lines.py0000644000175100017510000000764712525071110015560 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.8-src/Scripts/Python/make-Codd-constructor.py0000644000175100017510000000437012525071110017650 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.8-src/Scripts/Python/pop-plot.py0000644000175100017510000001167712525071110015263 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.8-src/Scripts/Python/Rule-Generators/0000755000175100017510000000000012751756121016236 500000000000000golly-2.8-src/Scripts/Python/Rule-Generators/TriTurmite-gen.py0000644000175100017510000006105512525071110021401 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.8-src/Scripts/Python/Rule-Generators/RuleTableToTree.py0000644000175100017510000000316012525071110021515 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.8-src/Scripts/Python/Rule-Generators/make-ruletree.py0000644000175100017510000000414412525071110021260 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.8-src/Scripts/Python/Rule-Generators/AbsoluteHexTurmite-gen.py0000644000175100017510000003077212525071110023070 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.8-src/Scripts/Python/Rule-Generators/icon-importer.py0000644000175100017510000004635412525071110021316 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.8-src/Scripts/Python/Rule-Generators/Turmite-gen.py0000644000175100017510000006706012525071110020724 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.8-src/Scripts/Python/Rule-Generators/icon-exporter.py0000644000175100017510000002752712525071110021326 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.8-src/Scripts/Python/Rule-Generators/HexTurmite-gen.py0000644000175100017510000007504712525071110021375 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.8-src/Scripts/Python/Rule-Generators/FredkinModN-gen.py0000644000175100017510000000466612525071110021436 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.8-src/Scripts/Python/Rule-Generators/Langtons-Ant-gen.py0000644000175100017510000002563312525071110021600 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.8-src/Scripts/Python/Rule-Generators/AbsoluteTurmite-gen.py0000644000175100017510000003266112525071110022422 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.8-src/Scripts/Python/make-Devore-tape.py0000644000175100017510000004301712525071110016570 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.8-src/Scripts/Python/move-selection.py0000644000175100017510000001642512525071110016436 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.8-src/Scripts/Python/metafier.py0000644000175100017510000012357012751752464015324 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.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.update() 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.8-src/Scripts/Python/p1100-MWSS-gun.py0000644000175100017510000001037312525071110015620 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.8-src/Scripts/Python/goto.py0000644000175100017510000001040712751752464014472 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. 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) 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.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.lua 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.8-src/Scripts/Python/goto_expression.py0000644000175100017510000003212012751752464016745 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.lua 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.8-src/Scripts/Python/slide-show.py0000644000175100017510000000452012751752464015577 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: g.new("") g.setalgo("QuickLife") # nicer to start from this algo fullname = join(root, name) g.open(fullname, False) # don't add file to Open/Run Recent submenu g.update() if name.endswith(".lua") 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) oldfiles = g.setoption("showfiles", 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("showfiles", oldfiles) golly-2.8-src/Scripts/Python/envelope.py0000644000175100017510000000767312525071110015327 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.8-src/Scripts/Python/make-Banks-IV-constructor.py0000644000175100017510000001117012525071110020345 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.8-src/Scripts/Python/tile-with-clip.py0000644000175100017510000000362412525071110016335 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.8-src/Scripts/Python/bricklayer.py0000644000175100017510000000145712525071110015633 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.8-src/Scripts/Python/glife/0000755000175100017510000000000012751756120014305 500000000000000golly-2.8-src/Scripts/Python/glife/EmulateHexagonal.py0000644000175100017510000001171012525071110020006 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.8-src/Scripts/Python/glife/gun24.py0000644000175100017510000000140312525071110015520 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.8-src/Scripts/Python/glife/EmulateTriangular.py0000644000175100017510000004602312525071110020215 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.8-src/Scripts/Python/glife/EmulateOneDimensional.py0000644000175100017510000000117012525071110021003 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.8-src/Scripts/Python/glife/herschel.py0000644000175100017510000000324112525071110016360 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.8-src/Scripts/Python/glife/BuiltinIcons.py0000644000175100017510000002523512525071110017174 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.8-src/Scripts/Python/glife/__init__.py0000644000175100017510000002045512525071110016330 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.8-src/Scripts/Python/glife/gun46.py0000644000175100017510000000046012525071110015526 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.8-src/Scripts/Python/glife/base.py0000644000175100017510000001041712525071110015500 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.8-src/Scripts/Python/glife/gun256.py0000644000175100017510000000042112525071110015606 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.8-src/Scripts/Python/glife/WriteBMP.py0000644000175100017510000000603612525071110016221 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.8-src/Scripts/Python/glife/ReadRuleTable.py0000644000175100017510000002532412525071110017244 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.8-src/Scripts/Python/glife/EmulateMargolus.py0000644000175100017510000001671312525071110017701 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.8-src/Scripts/Python/glife/RuleTree.py0000644000175100017510000004276712525071110016332 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.8-src/Scripts/Python/density.py0000644000175100017510000000066412525071110015162 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.8-src/Scripts/Python/Margolus/0000755000175100017510000000000012751756120015010 500000000000000golly-2.8-src/Scripts/Python/Margolus/import.py0000644000175100017510000000077412525071110016610 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.8-src/Scripts/Python/Margolus/export.py0000644000175100017510000000053212525071110016607 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.8-src/Scripts/Python/Margolus/convert-MCell-string.py0000644000175100017510000000537312525071110021254 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.8-src/Scripts/Python/pd-glider.py0000644000175100017510000000063112525071110015344 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.8-src/Scripts/Python/life-integer-gun30.py0000644000175100017510000000315212525071110017002 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.8-src/Scripts/Python/gun-demo.py0000644000175100017510000000252312525071110015212 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.8-src/Scripts/Python/heisenburp.py0000644000175100017510000005720212660172450015660 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 import golly as g from glife import * from time import sleep import os 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.8-src/Scripts/Python/shift.py0000644000175100017510000000477012751752464014645 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.lua 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.8-src/Scripts/Python/move-object.py0000644000175100017510000002454312525071110015717 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.8-src/gui-ios/0000755000175100017510000000000012751756120011663 500000000000000golly-2.8-src/gui-ios/Golly.xcodeproj/0000755000175100017510000000000012751756121014746 500000000000000golly-2.8-src/gui-ios/Golly.xcodeproj/project.pbxproj0000644000175100017510000016441712660172450017753 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 */; }; 0D2AA2F21C1C4B0B00484BB6 /* Patterns in Resources */ = {isa = PBXBuildFile; fileRef = 0D2AA2F11C1C4B0B00484BB6 /* Patterns */; }; 0D2AA2F41C1C4B2400484BB6 /* Rules in Resources */ = {isa = PBXBuildFile; fileRef = 0D2AA2F31C1C4B2400484BB6 /* Rules */; }; 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 */; }; 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 */; }; 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 */; }; 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"; }; }; 0DB7062E1C1C163D008A57C8 /* Help in Resources */ = {isa = PBXBuildFile; fileRef = 0DB7062D1C1C163D008A57C8 /* Help */; }; 0DBD205B1C131D9E007A70EF /* PatternViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0DBD205A1C131D9E007A70EF /* PatternViewController.xib */; }; 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 = ""; }; 0D2AA2F11C1C4B0B00484BB6 /* Patterns */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Patterns; path = ../Patterns; sourceTree = ""; }; 0D2AA2F31C1C4B2400484BB6 /* Rules */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Rules; path = ../Rules; 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 = ""; }; 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 = ""; }; 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 = ""; }; 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 = ""; }; 0DB7062D1C1C163D008A57C8 /* Help */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Help; path = "../gui-common/Help"; sourceTree = ""; }; 0DBD205A1C131D9E007A70EF /* PatternViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PatternViewController.xib; 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 = ( 0D2AA2F31C1C4B2400484BB6 /* Rules */, 0D2AA2F11C1C4B0B00484BB6 /* Patterns */, 0DB7062D1C1C163D008A57C8 /* Help */, 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 */, 0DBD205A1C131D9E007A70EF /* 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 = ( 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 = 0720; TargetAttributes = { 0D078722156881080051973C = { DevelopmentTeam = UQZQF2G54F; }; }; }; 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 = ( 0D2AA2F41C1C4B2400484BB6 /* Rules in Resources */, 0D2AA2F21C1C4B0B00484BB6 /* Patterns in Resources */, 0DB7062E1C1C163D008A57C8 /* Help in Resources */, 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 */, 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 */, 0D1E9E6D17420EE2002C1270 /* triangle-right.png in Resources */, 0D1E9E6E17420EE2002C1270 /* triangle-down.png in Resources */, 0DBD205B1C131D9E007A70EF /* PatternViewController.xib 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}/../gui-common/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; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; 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_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 2; }; name = Debug; }; 0D07874E156881080051973C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.0; OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = 2; VALIDATE_PRODUCT = YES; }; name = Release; }; 0D078750156881080051973C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 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 = 7.0; PRODUCT_BUNDLE_IDENTIFIER = "com.trevorrow.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; TARGETED_DEVICE_FAMILY = 2; WRAPPER_EXTENSION = app; }; name = Debug; }; 0D078751156881080051973C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 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 = 7.0; PRODUCT_BUNDLE_IDENTIFIER = "com.trevorrow.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; TARGETED_DEVICE_FAMILY = 2; VALIDATE_PRODUCT = NO; WRAPPER_EXTENSION = app; }; name = Release; }; 0DBF0CFD15DA801A004A5509 /* AppStore */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; COPY_PHASE_STRIP = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 7.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 = { CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 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 = 7.0; PRODUCT_BUNDLE_IDENTIFIER = "com.trevorrow.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; 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.8-src/gui-ios/Golly.xcodeproj/project.xcworkspace/0000755000175100017510000000000012751756121020744 500000000000000golly-2.8-src/gui-ios/Golly.xcodeproj/project.xcworkspace/contents.xcworkspacedata0000644000175100017510000000022612525071110025611 00000000000000 golly-2.8-src/gui-ios/Golly/0000755000175100017510000000000012751756121012752 500000000000000golly-2.8-src/gui-ios/Golly/settings@2x.png0000644000175100017510000000170712525071110015602 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.8-src/gui-ios/Golly/help@2x.png0000644000175100017510000000207512525071110014671 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.8-src/gui-ios/Golly/Icon@2x.png0000644000175100017510000000515712525071110014635 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.8-src/gui-ios/Golly/open@2x.png0000644000175100017510000000177312525071110014706 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.8-src/gui-ios/Golly/iTunesArtwork@2x0000644000175100017510000033150512525071110016002 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.8-src/gui-ios/Golly/StatePickerController.m0000644000175100017510000000527612525071110017327 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.8-src/gui-ios/Golly/main.m0000644000175100017510000000217512525071110013764 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.8-src/gui-ios/Golly/StatePickerView.h0000644000175100017510000000175412525071110016106 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.8-src/gui-ios/Golly/triangle-right.png0000644000175100017510000000027112525071110016303 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.8-src/gui-ios/Golly/PatternViewController.h0000644000175100017510000000627512525071110017354 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.8-src/gui-ios/Golly/Default-Portrait~ipad.png0000644000175100017510000014430212660172450017622 00000000000000‰PNG  IHDRV&> AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs  šœ@IDATxì|ÕöÇ϶„z¯¡7El€l b{ÁÞõé³—ç³ëßg{Å *‚" ‚ôzï-eËÿüf3ÙɲI6ÉîβùÏ'ÙÙ™;·|göÎ9çž{Ç‘ @… ଭd#I€H€H€H€H€ 4x# @"@ ]l6•H€H€H€H€hð     D€@ºØl* Ðà=@$@$@$@$@ˆ€»µ•M%¤&°n—Èmc<2{£S6ìñë½,ÒË…z“úº¬•s¨ûÇé©_M¤y€|78W2ÒÖÖTìz¯µô;Ã_±™°õ©E€ýU쯧ƒïˆ=TæH¥%°;W¤áÓér__Ÿ\r¨OZÔ ˆêfµT}<]ö>œsP·¡¨Ê§RÛVîyj²[>šå’Å·çH“êEµšû“‘@*öÑrN¥ßa´m¶¦«ˆíge½Ê·Í€òñãÙ$g|š&—v÷Ƀ½½1É™@´ZÔ:Ð+M«ävqA^´§2]`ß‘UHöW±CÍ9±cÉœH ÌVïtÈ}½}e>Ÿ'’@y \ÚÕo„Ÿ•7žŸXì;Ë›¥%öWå¿4ÊÏ9@¹ lÚŒÃ.wFÌ€ÊHagõ>¤\Øw\׋µ öWåçH ü ™ ”›&üì1ÿå†À l'àãÄQÛ¯Ai+À¾£´Ä˜>U°¿*ß•¤P>~<›bB @Å+&™Iùð>,?;Îæ5³ƒ:ËL¼÷Ëwl3rrrdéÒ¥Q×^W+’%K–Dž I€H€H€H€H€$ðU€º°ù¦M›dݺuâó•<éÑï÷ˆ Œ?lÇ[6îZ+K·Ì—jé5¤Cƒ.’î®ï"™œäê‚:K¶9dÓ^‡4ÉH«Zq»âTXœ³Ý™-2j¡SÖïqHcmËü’‘,4GÛùk–Sú·‰ÿï#–Í\°ÙaÔ{¿.:Ó¥A@Nlå‡ÍqP»”óÖýi©÷J,dìRgÄ×8ôná—JžX”À£‘íÛ·Ëš5k£ñ–Í{6È¿&Ÿ'Kݳġ¿¿þKŸSIέu›ÜØëa1çmyiãmÅVã¾&oË€NÉÒÍó势{JF^msÚªÎ0º¥l÷l*´¿²·ªtr%ƒZ]#Ç·(½ÎŸ£h…®Gà$y¹ÿw…òˆõ—ó>÷ÈèENyû¬<¹èÐëòïŸÝòÚŸ.Ùý`l¯Ïz}©Í}Öñ-ý’VÆ;ôå?\òü·lµÜjÍt’ã“'yåìN¡¶Ä¢¬XsÏoº>LÏü,MŽiî—Uòñl—Üó³C~¹"W:Ô ÈÖ}"ƒ>õTkî?ù«K^Ÿî–í|²/Ï¡×Ê)]úõeTy‚‡Ñn½¥Î×ûßËz„sŒæû'¹e›o›¥0}摎zjT*\z÷F¹e6ìbS¸ü‰ÀE#<2rAÑë#.Ì(“—|é‘·æHs]‚29Ë!uªˆtªRÀ‚Gb÷¿¤~$v%‰Ü;Ö#7÷ôÊ9ý2j±K¦®rʧçÅæ7U\=KêWŠ;·¸cñècKÓ×L[íS?N“m÷ÅæY‹gãd½&­óÙzOÎÝä ñÉÐ3ô‹ŠõÇæ`:vÕ7ùü§Õ< ãôùIðûlùé²s¿È“ý¼rÛQ>ùf¾ó€ßl¤s±ïfxª¿WníU¼ƒ;<]7Ò¤Gc¿¼yfQùÇrÕ«ÒUž~xü7nÜÕ‰÷Y½zµìܹ3ªô±HtçäA²%°V^îø³Öôh™¹ú7y{Þ“òéîg¥Ý’CåøV¥qµE=¿ðVñHšÜÖáù‚}t7¶?™÷²ÔÌ­/;Ò6É„%£äø¶ Ò˜í|=äšv™_eéö¹òí†7å‘åë‹x¦È3m¿Õ7ÁÕ1YŸÊßòd«/Äí¾ª³AF“‚sã½q÷OõÎæo wYÈÒJ§à‡ºìŽ©´òê4—ܧÆÉMGúär][¿²ÞåÕCþÖL—\ö•GêVɓޙA¶å-«´u+Kú~qË Gøä¡¾¡ŽaÀÇyh¼û \³}³eÿýÕ-Ó¯Ï-Px`ˆu~-]¾ÒŽöÂ.~ÉÓ¾s’^3LpL„<¡õÁ(ÊÔ•¬ËaÆR^8÷[ì’h6±dQò‚ÁúÚ€ÈÊn×~Y¾Ý!Ç`Èòô½ñ{ôÑ>éÕ¡ßx¬Y¥Z?Î'š~%ü;¾—¦¯ùApŸþã’—èHb캣Ùg´÷ÉÿN ÝoóÕ8bhšÜ}ŒOÚÔ ÈçJÚA:b^Òuý}•C–it@ëÚBý^™Cù·JÝ*~³Öãë¶¥ ŠO¶mÛfxñss#[[ÖRâ³~ýzÃPHD¸YvŽ7[VºæÊywÊ?ö÷hv¬´¨õžœ3¥­Œ]9BNj{–Ô­ÖÏK€§ ÑåØx[}<`Ÿ=9Ô¹µªí“cÕƒ~˜ZÙoÎpå(&a§îÎuÈÎìÂÕëª`,ÙÙÓ¸x‹Cîã–ëœR_G ®éá3¼^Õk{¿›&Cõ\ ÇoQEüÄ÷ÓäÅS½Fø "ìŽÓãžgtŒ_ÌuÊSêߨ!TPN^9-OêV™§ЇÔ(gäqn¹çX¯’-=ÚÂLi¤oŸ}I®á)ÿg£CàI…ô|3Mž81˜ÿÒ­¹mt°]ùxôx¯1J„tƒ5=ŒºOæ¸d¡†¢!E/œœ'‡5.Ì i#IŸ>9²‰_¾¨ ¦¡¡ñHicµ+XÜ7Ö-Ãçº4DBŒ‘‚aóŒa~»WØÏôá¿_oãžZ··ÎÈ“9¥cSÞk«¶V¤| 4 Ž0bj2hR# ?gF6Ì4ñø,©BtËn9W½öÏþæ’\ŸCþsBžäùòôd—lב±+Õ¡ò´z7!YjÈÜô½[þXã4B÷NmëÜ¿U‚>ª"›PT¿òS]RYöð¶ø·KÝV²Î`-¤¤~i÷i–ÿÒßÕ:*O/êü?í×NYÜïÑZ¶‹ë‹ÂÓ†/®¯Á(Í5ßyä }_{ ÇAHÎÝ|r²†w¢ï‹§˜iµ´`Ÿ £t°¾•¡¥àvçnùq©Kªzrßq^yåO·L»6xæjŸã³7Gr´÷Ëf}nüGûnHQ×ÜŽþ©:1ÊŒ{챂õ³rý@÷Ñ4 ¸¦§;~³fùñúŒ¬AÄ 4„í`ÒîòåË%åá>sçÎ5 €D*ÿhj®7GãtunBöÚB-¯[­ÜÛü-9¾é Bû‹ûòÓ¢¯dŸg§œÛqˆWû ù'0IvgG7’ѥцê‘îJžy5+©"¥L k­ÞÙ’CÙ'à‘†Ï¦Ë‘ª¼=¬^jx,!P0¯TÏ~=nUþÛxÌÛiòÁ,—¡ø=2!ØÑá —¦"Ì!ºÿˆ7ÅÃ.\Йˆ9«c°BÈ»¨²—¬Ë«iÒä¹t#eŠz‡MùI=2¨3¼&ç ÷H³çÓ¥ýËéFûb½–úÝG{ £å¸wTžè2<Õ´CÌ|¸ìÕþ¸ÿ‡iÒS;°Å·åÈ;¾õªvÔý@§‡·½þ¤qé©«ƒs ~Îÿ>K¯Ã–}A¯ÈÄNCÉoPž,¸%Ç8ïÂÁ';ØÀ¸xT¯Óm½¼†a^â¾#¾þ¼CürÊGÁë;tzPiïÕ,`(ÁmÕ+ó®ÖòɹyÒW{<€NÓ!ð tt`Ùí9r¯PúWî^“•ú"µ§'»å©“òd©?³ƒONÕü·«'gŽš#]¤?óÞDßOtm"x„ŠkK4Ç~^æ26xàà÷;šït^ǸËseã=9r¸ÿ>ó[ðÞÿFo?,vÊôërdåÊ¿†èˆGJ˦¼×*šö1Méà·…¾cƒ:uÆ- n¯Òû÷»…ê¸ÐýØ)©B$WžWú†Q£}ݘKóäÇKsåu ùDŒ=äFUþ›ª1³HC™æÜ˜#3×9Œ{¶¸ºׯlÖ¾}Á¢-NA9P1+._+©_A8²V¨áòëU¹2åš\A¿q¿:1 ÅýùÿŠë‹ÊÛ×À9¼I@G­ƒJx[õÄ£_Bøg¬e‘:ŠÌ> ¡Sƒ5,í>Þ‚Qw°A¸!ä¦<†#hê59òý%y2l¦[àh‚ Í'ë3笎~Y¢Ïœ;öÉãÝÆ|5/îšÛÑ?9µÚ—¨agt«¬QUmür§\¦F—U¬¿Ys? Õ!ß¹¥ÃËiRû©tÁ¨<~;ámºðóJÒAÂÓ—å{ÌMJxÀꃟhy ÷Ù±cGYê“s2*ÕÎce¼w¸¬ýq©Sg€×âiW¿‹œÖñ‚R•ñíÊ·¥™¯£4®Ù\Î=dˆ|6õY>ç ÒóßÅæãèpÜŠ3à’[Gop›iŒ"$cÄ<¿Ü®gŸÌ#V5RÖˆ“»ìk\ÚÕ'בg ±½0ÕmxdáÑpêsívUá…¾KÊÞÖ8kÜäW¨Q€ŽÞ†\ýݹNY­ ¼xÙGie*øoêƒäÔ=ríá>é«s jåÛTuò¬)'èþHeyµ'}fx¢îÒάzºê‰¨ †E?¸UË¿õ¥ùÀHZ·Û!ÿ÷»[âéòçµ9R[czc!ˆ£íÙ$G¾œTþ_žæ4¬áB˜P CàÁÞ^Áœ°À°¯1‡à8Ÿü¦û[4Lj´>à!¿hÇ7Pcò!xÐ_¯aG™ÊCÏÿVO§WÒõáìà0·b´>ài/‹¼¯£ CÔ ú^=qŸjG|·zðàû`P®Ž¼I"…“e‡kÜ&ŒÔ#G7SB½wŸÌvÊý}‚u¾åH5FZës»ŽN|9Ïeü5S%ÆA$¡Ñ*J¿µ¬ßÕÐZ²5Ä)Ý0¼ü½šú囋ü†—†ëîŸ=r*™ÏŸòÞ¥ŠÚɪLÿ¦Ê”3„žà…ïŒöN«Þ.¬FðÝà\ÃC=Dχ câ&DV–9Ïé5¨aêsÉ—ÁÞÿ~­ýrÕa>câ,ê_TYoª·a$³Õ«Ï+žçSÔ xL=?^ê Okë“׆Ú{šv~=4Žò¥?Üòx„áÅ`nÑÿGG°E= Ít²àjŒà«=7Å%—«±Õ[ 2« SÇÃÙúíTÏ/Y;‚?õÓÚéP²rðbMQårø¹¹òáìtÙ¡JÉxõLÞß;؉#`ü ·†„ºxNV«W£B•µŸ+«òNJü1z?Ó"Ès.û&Mní‘Q‡øšm[®õ™¡JSG5B¬’Ñ9¤,uÐklp\çSÚjƒm’GúFžPGãJÿ£÷”|ŒÎà¾7÷êôþyV'ë]ùÃ0ä`Ô5¯zX™iKbSžke–ÁÏè àþƨa¸ÜªÎ{Õð¶ îÑŽõ‚F9”éðãÖ´åÙŽ¶©¢&”ˆ+_ Ǫc¦˜ûðÝã ÈUß=ê 4TMIR\¿‚sT£ØÚw•”ŸõxIý ž pf´S¯º)0l ãFw÷{4Ó㳸ßÛ)ú<°³¯±Ö³¤m8جsð\Aèpuv¡Ï4e𔛜°?Ó²JúX¬°g•–j,×ýâ®yyŸ%Ö2K³¶ L£>¦€{ã#50ýqq‚ÅOÖè³pªŽ”™«[aTû¡_D^Ôg³)Ѧ3Ó›Ÿ¥ÑAÌsÊòzº—åìçdffJ•*UdíÚµQ)ö;w6V²sÍð¸ÒŒÕ~n”‡ÕºÛ%¿­øI~\5\~ÈyG–ÿGÞ>e|„ÖÞõéì×ÅëôÉê½ËÔ p‡qСVðZÏY°áo騰[Á uýÍä„:ç|ßš½AÆï.¯Î»_ÞmökÁþdÙh¢Šð3ÚÞ4Ê-çuv bü¬‚6¨‡!K(ûV©©Þ÷o¸Ô*{7¨§ÊæÕúð€"ŠÕ!LŒõ¼²nc©OÄö=¨Ã™Ó4ŽoŠ®v€¡m /Ãñ_] ñëE Bbà‰AÇ–e˜ê®ÆËË¿»Œ‘ó\õì;å³…¯:­‘;Sn8ò¡‚¿û¼&—èÈÁ"× Y¶yA¡´Éòå í$û¨r{‹*.ð[+[@îÔɧðø[ÿá1VAì8”ÿZzCaއÀŠÇ¨¼jˆ[\¨±ª¢½_'^bmê¢mÁ½µ ؆ò±®ŸÉpÁ>36½¨2¢ÝŽ ž Œ¼@)„ÀSñ¾z.ªéÏëç[åt áÁCè+²…lÓsžS/òê0åLÕ|R'÷WŠ5é{Ž9®üá< ;zC &³LÄ%CµzÍüJû‰©ùZGc1€À{÷¹N†…11ë±70žµ?×:Åœ‡{ ¡dˆ6«?™ó/†Þ—€•„àôgžkÇ'êÞµ¡.7¬^´ÃÏ`å tμrèèÏîä_þ¥. ›`®üŸéÚMܬ¡uá˜ãb—”¶)©ž˜à‰{Ó4j0™Nó-ê|;û,`€Éfˆ~sˆÿß©Ÿâ~ÁÁÿÅõEåíkJõ?}Î`E£x ú<ƒñ‡9y˜ãÅ3üyŒþÏýÿ¨Ã ×ÏëÈ0ž9pŽÔùL(Òæ6¾Çóš#ÿ² Âg1aÏȇ³Ý†BÍÈ6B¥`,… "êlJ´éÌôægitóœ²|ÝMe9³„sLÅž}¬ý_ÒDà54_ÌÀJ@ÑÌ(¡ Qöúód¢o„L_u¥ѼO¡óêUj"¢„¹$g¡ƒ–/s×Ï”õžårWÃWåì.WZŽˆ\ûcùcÿš‡O=–Á›­P‚ü/Ç꼃w4ôhÅŽEÒº^ÇHIlß÷††» Ä+)ÔQåÔs˜x¬®­ Oy¸XGL6Ã|‚ó˜rx^» Áž:g¤*üá“d¿xçÑ^¹Xcgéj-jåk[a£-"®#‘xÓK‚I³5+n/öÕË÷šD:¿´û>:'OWçðH+ @¬áNÕ„G¤†M!&\,ÆB¦Po¬àp߸`ÇŽxL¬Ôc âüÿ¥!Xwl?VϹY'ô=bYfôbCqÿXÃÞ³WNϋɋÔ0|üÅùyƪ˜,Óz5¯þ’†šAPæÑj¼µ|1]×¥Î3VUyOcc&„{É¡WvóZåáf=ßL7b‘á¡|CW$1—yë\?4’ar°ûó¦#t$J0´`ÔaÙZ¼[“á¯ÖPµ êej®íÇ»ŸûZ/þ¢e3cmÈ@²»½,ß^%ö#¥¨úG(P‡¾žnôu-´_Âh–÷=WÕ¢Äî~1ÿWêÈ3m€ƒÏüÖ Åýûµµ ïâú¢òô5Ëwh¦:¨0ÚËgH¤ëñþ_:«¦4U- 1W$\ÀíÚ‘iúBº1¢ˆçÉüÍAõÏUãf˜•Â(@FF†1)oÆ$á¢Ä©¦S£F¤N: ::³ŸÔ_Ô\ž{©Ü´çé×nZ†é2iÙùzËkÒÒÑE—mPTµýü*•½UäŒÎ—n@³Ëä™u×ÉèŸë‹ÂpÜÜѸF csÓžµæ®¤û„w±Éˆáïlñ>à e^ £›‡:Kx2.ø"͘D ‚¥#±ÃLŒ…uøoéVåÏi(yåmða‚eÀ›n oİC¬q ÆË?xêÞÒù˜UÝò'Äöaõ¬LcÊõ´ß—7}ð*a2е•àƒIÔÙG¡¦† $ËtÀ{ÎwcéΓ4~+}M­?tVÁ0®5=”dëw¤…—ù)«k½K³¶NhÆdÝåúކòÈ úàuC®±Ê6Un1©.üeYcuu«œªL—µ ¶«®z¥`XÌ_;ÝkŒ€IøqkÚ¢¶ƒ1Ø¡û·¨tÑîßóPÑœ.éæWÏ~Žá}CJBvàEúæ¢<㌄v!´Í”hÙÄâZ™eòóà&PR?‚—mÐÕ¨LÁ=Þ/üssè7ù±öƒXJý‹ùÛÅ*2ðO¸2”Î A¾Åõ+xIcy¥¤~ëÛOÖÐC(j˜ïcÚ”’~V%õEfžÅ}Fêk°Ü²µó|ôÑÛï]sY??T§Ò‡ç¶õ"”ðS½Þ`†~#0ú =ÈÐ¥CçÝ’kŒ²âøµº:Ž9g ¸knwÿ„pŸ~ï»ä]­#"hü4‚¹*ˆX¥#6æËüpÞWºP‡U¢Mg=Û¥ÑAÂÏ-Íwý‰Ç_\.—4kÖL:tè U«–<™Ö=@XP¥J ,NUMwW’—þAš9;ÈÓk‡È‰êJïqòÐò $ÓÕY^íûC±%ó?-gŒæé'n§þBÂ+ Á8ønÕ;aG EèQš/]þØ<¶ð$û†ÕazéJ8ó,K^းú§tµ abäIº$è]Ókœ›Ê8:Ž74ôÊ%<ÁÆP ƒÛtFÄ\1SW…iy%°À|ƒûõ!ô…®s±.k†:¬ÕØÅ%Z„ˆ`ÙÏã´“5߸©,¬&ƒ¡ìAÃÓËš"öý]õ”`0–µ*–¯1Û‹ºž=Üc¬lô/‹Ç½„*G}ÆHg}H[•ÿâNƪáÊqé#CgnUþ#¥)ë>p„â‹6™ D4y¡]Ök`=õŸ¢Ž[Ó&Ã6ÖL7•Ô÷¯u\0¬ŒvE#ű‰æ|¦±‡ú¡¿uTË cyÐxJiû‘âê‚°ëo7Ú¸d»ûüÎ¬Ê¿ÙÆ’~f:ó³¢üÞ^×¥¤¯Ó%a±Ãh]9kþcA SÎù\Cdu¥¹9ªà9‹%má̰J<¯¹µœÒl­z V¦£°XõÊ\-°¤<ÂŒwV` ~Ð]0¯íA}?ŽU¢Mg=Û¥ÑAÂÏ-Í÷µ-Í™eH åFÀæÍ›£š$Œ° Œ$",¨Y­Vòæ)?ëà¶ËâMÿ­kWÿ©Q¹vÄ–~vêÌ‚ýë{ꆂïá0 ƺ¹`÷÷§­(Øߘpʶð]rS¯Gå&yô€ýví€r5TÃ+Ž–Vú`¹É4]FÀýjÃ`DŠ?^`/<ÒFDÈÉ}9•)x©U]aËþ¢^_Ä#<èA)€‘0ç¦7É<§¸O¬dS[;x,AúíüЬ2tî˜øcõ4E* 1¬ºbY/ Zar/–½;ßK: îëúìh/É]/«{PGà|0ïå<×–TÑàe}PÎÖy6ïi8dx?SÑx°½ÉEàM}†#Tñ¥ßÝ:BÇô%Œf¨ @Ë–?¦ŽÁh&ÿšíá‡6^­Î34ä‚ùŒ³;ó“8Útf¾ægitóœ²|:²³Ã^1Z–\Êpæ`n&G#x_ÒcT€’ü04†!gsI9;jŒX¼5ºŒ±t¥Xª V{i¤°J@¸×ýS]±eˆÆ’fÝ•£ññbxÐ1Â#V©úxzġ߲ä•,ç¤b›L¶©Ú¶Tm—yÝRñ³"_³ŠÜvÜËl¿ýÏM„æ" Ê\!©¨>&Útá祃„§+Ë÷„ŽX+h†ùX÷·‚¨üG(¹ŽYãâìªB)P¼¤¤¬‚Qü'¡÷¹8BØ_•Ÿ+C€ÊÏ9@¹ ¼|jž´{)]—-uo†"ÆhŒrceQÀÈŒÏôE6þ»·FQ4“Ä€ûŽ@d öW±»T¶½ vM`N$öè;ðfA¼·`ã¿N ÀKȌɩÑD¶"‰`–ÊÅû:àE†"ÙDßÌL9øì¶ô›Ì¾C߃B!T!Àþ*öW’@ì™2G    HZ :NÚKÊ‘ @ì Ј=SæH$@$@$@$@IK€@Ò^VŒH€H€H€H€bO€@ì™2G    HZ4’öÒ°b$@$@$@$@${4bÏ”9’ @Òpÿþû7I[9VŒH€H€H€H€H ¶À_xÕ…H€H€H€H€H `P¸Èl" ˜h˜$øI$@$@$@$@€ € p‘ÙD    0 Ð0Ið“H€H€H€H€*à"³‰$@$@$@$@$` `’à' T4*ÀEfI€H€H€H€HÀ$@À$ÁO    ¨hT€‹Ì&’ €I€€I‚Ÿ$@$@$@$@$PШ™M$    “ “?I€H€H€H€H  P.2›H$@$@$@$@&& ~’ @ @ \d6‘H€H€H€H€L4Lü$    @€@¸Èl" ˜h˜$øI$@$@$@$@€ € p‘ÙD ’JJPÄñhÏ‹6µ˜âÎ)î˜5¢¶ÍóÃ?Íôæ~|ǶùÝüŒ”ÎÜé3ü¼Hi¢ÙgæƒOs;šó¦´é£Í—éH€Hàà#à>øªÌ“ @Y ¨¨¬.Í€ aY)¦ÞyGnðOt›B$@)N€@Š_`6H (TôŠ"Sñöó^¨xל-&ŠM€!@ûú³õ$@$@$@$@ŒG*ØgsI€Â8þ¡„%yXYW¿?¬–¯Î|¿N¢ÚcÖIL’Ö-€?K¢Ù4ó1Ï-ø~\—hÚÇ4$@$Dh$ÑÅ`UH€IŠެœ·LV¬Ù!u:t’¶MjH%LH:A]÷Ëš%+eùºö–œ9àùñïµ’­B‰bÔ{·Ìýû¹xÀ2uåfÉöï“sþÁú}Êò ²'ÖÖ3e  â°W-Ž‘ ¤6 —ñ¨—:'w³*´ê)wX=ê–¦CI…2[èÏT®-ÇâЮÕH«Ÿf2„æüYò2Ï ž™ŸÆrÜ™ŸêªÞü5’.éénIséP…YäÐ?GiÙ¬¥N2êamW>Ô[¹4f(7°_Ä|Áïyø®FŒ«àÜà9ÆUŠÄ¸P%ù…H€H (ÚSH€H â0õàHz®AE•ÝÀö2æ›qòõ/Ëe¿*¬õ›·”S/>MŽíÐXªd/×cSeÜL¿\xû)Ò½e#É^>C¾ÿq’ÌØÛNn¸äiÝ( Ó¾Ÿ –8¤g»tYøÏBù}Ör©Þéh¹öêþÒ¹©†ê RÇ©žðñ“äóoþ”¬Ùâ©Þ\μb œxhs©–Ž:¥»cLÿñG™3bŸ,Õ ô¶ÇÊ× ›ÔVûEUã<Ÿøò4¥Ž¤kÚ¿~œ(?Ï÷Êáí«Êòù dòôe’Ñ¡—\£åÚ¢Ž†Öè9Þ-Z¿qòáð¿dKFtbSÉݱYì¨/—_p”thQ3ÎÅ;{¥ÌZ²XFŒZ-»®¹YFÝÑOº¶®¥…zä¦u¤nöSòø»_ËÒ«{HÛÖu¥Š†&-š2U>úx¼,Ø’-Þ<—ô<ç¹êônÒ¨vð1„Ö¹ ¬%ƒ¼¸•¥r%¯,˜6Ef)¿-Ž—Á'*-T“ sgÊØï’EµŽ’+ôÐp§*ZÇ" ¸`vüO$@$O€o (мà{–ʇ}'o Ÿ%{¶í‘m>4[³ZF½·JÞz³ôª¶GV¯X(/½¾\z]ÑGÑp•½6È’?§Ê‹ã½ráÙ‡kîY»vüôÉt™TÇ!ë×´ÊRcùrCvMùøæc¥U‘ÉŸ’w^U¥67G¶ìòK­ºeúyó$ç«dPJâV§µÕdÊSeÛÆ=úJƒÊR}ñ'r­£º¼ݱҦqž¬]¿F†¾8NÚžÛW÷¹eÃúõòãSdRC·l\·S²ÝéRsÅ—rsN yÿæ>Ò®™W~ýú'yí…Ÿeu W¶í^-ë–T—*®ý2nMWpzWñKÍ‚)¾âp‰wÓfÙ¾nµ,ðÕ“÷.Yäè.wŸÜ^Ök$5ë×–Ìf5Ä¡¡EN3–I«àÊרƒ~Y.­ä¦ÓÚJÃúe§–[§Š(W •ýªPïÚ¼PüÞ%ÙNZ5¯'uì*Kþ™)#ßR)lh”‘†ÚäùÔſͭfÅ$ÝýÛdÕÒ©òÀËëä¸NUdí¯´=³Ô×ðŸ]›–ˆ¿ß9rÊ¡-¤aê"‡u–ž}z‰|ñ«lÙŸ+Z›Ðƒ¡nû½^©Ô ™4kÑIŽ—á2KWlê¦s¶¯œ-þ“N’¶õjK†9Š—B$@$%Q‚b2 Ô%57]z'ÔP‹"-ä,ýM¾üø{þK–d¹È=kJ]_®ž‘ÄQpªÇãO„¨¯æoƹ§W«"•ª×Y§Ùht¬@yªÅvÒ˜ùô4#ïŒÚu%£v­W».Šwg`¯¾®J·†ÍøÁ•6usQó—‘‘Wl´Š|z•Ê’^³¾–«™åjtâmZ½ \¬•Ve¾R•4I¯ª^õˆ:õ«K½Ìvõ­ÌÛ>@:éääZ5[IÿÁ÷ÈüÈèQcäîIËŒæçÔü¥YMI«T)˜cåJREëQ“’õv¿ø5¤]‹ÆÒÿ¼ö2rÒ_Ò¤N¶¬œöÜpÙMR§¡2D.¸nƵÓF™sÌ}ïDÐ4ÆPÚlÄ&r' ¤8Â.ªo,›G$@‘¤©^¸}çNõ†ï”}»vËÎâ²m‡*ž~Y¶p£,þcœLîq‘ü2ü yåÑ äÄn UÌ“<Õ!±bs;dož[½ïy²zÝYµl‡ÜP¹ ‹¹GÍ…|…U«¢ðëÌ]Oeq¾÷›¬Ø»WwúeÚ×ßÈ®g˽_-m{üâq¡Ë@o/VÂú®e9 E9˜E–Cåzâ}]CvVl’\8¼lùj™3}U¨~ÖÒ>q7h$udJ'¤ûäÓ#eòŒ’“^Kµ¨!y;·Éò9+õÜ ä×ð¨@z†8?™!+¶íÒE~Ò%wŽ¢,^¢iªë ?ú‘Ÿ¡zZÊôiëµn"-9NfŒŸ,?M™)ïþ~‚ôëXWÖF9:‚²i½Ìýãoù{ÁFÙ…å\^Ù´z•ü9u®dmÐrÕˆòïß.Y çÊ´™KeÓ6]a(rÜ‘¥dn’ @jà@j^W¶ŠH JªvKZû2ïóOäÎïÓ4,&8!uÿúµÒëÑ'¥Ï~¯Ô¨ÓLê,#?}¿G>_¶T~Ÿ¶XuÎtIs¤RýºR­fméÞ¨†|ðÂ0™ÞÀ/›Wo’µûuUÕM}u=M·1vòz«¢ªžè s©ß!Sê´?TªÕúG^|æC[3[6­Z+-È’aõ*K•Ê=/ È#OÏ1•e8²!S Fýf–Sè;Ò矓­+ÕÓr›tê¢Êð4ùôùWdÌ0·ìÛ¡áHû´þ--FŠ™;^,–ÖTŽ=¢“\råòŸseØ«åëÆÕÄ¡!JÛ×l’;0sÀ/û5ÿ&]ZJf·^Rÿ­Éò¿Ç†Ê”öjdm•y³æJ`Ð¥Ò¹N]5 àå7píȯžâÓ¶"'¿!Ôj"Í·‘³·þ&Ëtð ï‚þÒ¢fÑM•€,ÿk®¼sϳòÍI7ËÈ›O”n­så{pÍEßÊ£ãþ#g7l Þå‹dôÛ¯Ë-#»É¸/Ï•ºuZ踈Yš‘ÿ‘ @… @ B\f6’H 2Uÿròô-´kdç¶Ý’fÑ7o^,í÷äJ‡cSoõ"©ýÈoòòâiÒæ¤Ã¤jÍ*’é/oY&=÷’þ}º«B;Ož>]Æ{›Ë77‘lï6qÌ7½í~ñê„ÛMm¢ÑA4Òe÷U¹ÍÙ¤[ªPûTÁ­Ö^.8«Ÿl^»Iykª¬ní’ WÊ}½-§uk®o(Þ"9ûÕ(lfÌCÿÜš‡/ý¢[ޤј ÍžuoNŽ~ߤó Ìs´\œ£ž|Ö õdÊà+ΓšU«ÊsÏü ëv”›ª'{2öˤÑ9âUå†Ê+­¨Ó½ ¹³ª¸‡~*÷¼ºH'êV‘Êéˆ;ï•ëšï‘®yã%WÙæ¥7‘Ó,ÏnÞ)÷<ü›¬^®£›VÊúËO/]Úëò¡²I—Í‘²Z ëÃóé÷ ú= –AÐ$«*t2ð±6‘Ï_/÷ÞÓZêªÑe¼8@ÿ;Ù²céjY}´¦ÇR¥*þ¼ý²Ê?W´†`®EÞ.e¾y˜w€th…H€*]6ú/Ë#¯b5ž­%¨h´» ¨Ï85$  ´*¸ðj[ÂbŒ#êZwºt¢¯Î¨ äí“Í[wI¶O'ÐÖª*é30ò]âqâ«íÙ#;öêJ@•ªJF·¡|£suëq„¹ „¹<eÐ’UÓõjÌ¿_Sº=:#Z¦?{lÔUvvïÍ“ õŽ×®©/ôRíJ°W=ì>Ÿæ¡yºõE`¿7˜‡*÷åJã0&{#£ùytB°ìX#Óç,–yËrå°Þ‡É!mɪ cäž’§Þ ÿÜßO:·R%]_˜.`à÷î—m[vÊÎÝ9â®VCùdˆN!PE^q]È¥Çû üþÙŠt;÷‹#­šÔ©]]ªgxò'/«Â¯õÕ³p½<•$gõ_òÉ{ïÉgÒdÔ¯×J¿#Zé‹Ü0Áåá|X:¹YËĻìy"XAæeŽë¢û Q€ŽýÃø Ì& ¤6ޤöõeëH€Š% ÊwZÉÝ #­ªÔo¨!1*Öøù`ÖPóõ¥[Õu¥ÝVC"’ ‰r¬%94&Ý“n"Áœ·«r†4jRMªÒìPeÖQ0»Wë Å¿ =!Âitr1 ¢ÎÁäâÀ.Y8sª<ùÉr9düLɬã—Ý[6ʼiëä°›k‹Û˜¸‹6(X–Ô•VE=ñ•u2®Ñô>¡2õ $ (ÿ‡K—ûR‹ÅÞ‡sR«AÚšª§ Û•Ü—uå‘§&»¥áÓé²øöiãG; €ä¾þ¬ ”HÀTþ½^/€i1 |?üp1ÿzôèq@fΜ)3fÌ(ø; A‚v<4Þ“rÊ‚б8€@‹š"Cz¥iõ€Ü>Æ##.È; MyvÐ(=žK6عs§deeI›6mdáÂ…Æç²eˤeË– °ùÚ°xˆ믿^®»îºb³‚Q€?¤6l˜ :´Øôñ:øÛ*®+/¶Ì·â¸´«_>œ{u¿ÖŠ{O±å9SùoݺµT«¦Á‚*øÄ÷+VF($@'xügÍšU¢òÞ:8ç'ZÖ±ËI4r–W´¨{bßP±gÊI îî³zõjÃão*ÿf¡øŽŒ ø8ÏÄÂO8h¼ýöÛòÖ[o•«¾8ù$Rüœð›HÜ,«ðùcßX±gÊI îÜn·têÔIªV­±,ì?äCÄårE<Î$@ÉIJ{¤8ÿ²Ôù$Ú(K=y @ñ4ŠÄ£$P‘8ÅÛï%¯H¬ØV8 l'VÊ¿Ù^ägG8Y>?I€’“@ìg$g;Y+  Hjå û)ªqÈ·{÷îE¶mçiX-`”ïUçÊYµÓ!þ8x;íj䨥N ¶0XƒÖµ‚?SVnÙ‘í®BûÌcÖÏhÓYωÕö‚Íù5Ë)ûuš.zÍNl凮S_’äxÅ8¯›ä½ s7:d¾¯¢w ¿TònÚ;y¥S—ß HçúÅ_ŸÂgßbb,^¼Xrrr¤K—.[½råJÙ¼y³áÙpDs×DÌ%´Ë5kÖL4hÚí¥K—ÊŽºk˜ œ¢råÊÒ¨Q#©Q£FØÑ²}w[ÊV+žUwŽq˰é.¹¬»OÞÐ%»Â¥ÇiÒ£±_Þ<Ó+ßÌwÊ%_zdÁ­9Ò\—øŠVpŸ%‘¼{¥M_TÞðÈÈ…Gðn¢·ÿ‰-}òø ^©9 ©¨,KÜÕ©"Ò);ÜÏ}ûöÉ_ý%Û·o—:uêH·nݤJ½)’HðÌËÎÎŽÙ³«ýÄS¿]«Õ®»ñÊqªx-Ûæ0^|„ÉŽnínüÅ#ŸÎ.Üï•G²ïô™G:Ö HJ">Õ!çlpH»º60OmQ‹]2UWOúô¼â—xŒ6]¬y<ù«K^Ÿî–í|²/Ï!ÏOqJ׆~}9UžxJˆ0ݪïƒô©§Üï½Ø)Ó×:å‘ã|¾–²µe@IDAT·½ÿûÃmÜkoŸ•'ZØPùjžS®é‘Kºùdر/»¼u/ïù11Ê[‰d<á-Z´(T5<”ð@‚Ю];ÉÈÈ(tœ_*lí³?ûÇ%Mõm}#æ¹ä¹þ^©–‘ý¢J**mq†AQy¥i/ñÚ€ÐÃiÝ.‡Œ_á”f»dÞf§L¸"WJˆF**ëˆûoüÞ#}2ýòê€Ôëp#6˜; À2¶Ï>û¬ìß¿_ÒÒÒ ç&¶ßu×]Æäv$~ÿý÷¯Î=÷ÜBçFú²eË#}ÿþýåÐC”¤Ôû0 ÿå—_6&âã³¼‚ßkIK}–· äßYú€ò–]Üù#ºNSŽÕßþççÉ–}ùyIj/œ’'½3ƒä<(}éWyýO— U¥òÚ>¹ú°äœ=½y¯ÈuËôës 2ëu¥§Î¯¥ËWê̺°Ka…Ù¼†±þ„‡~¶Nñ<¿ñ< 7°ÇRURãׇ«ƒ‘ xž¬uÀëÓ€à¡B!¯Õ;¾[_ùáÙy²?Wä 5RMÒ´IƒÕ3bþÝ}¬OF_š'çâ—k2s]ü:æTcÉö”L`øðájP:åÅ_4VÂyàΗwÞy§àd¼ó†B4OýìÙ³eëÖ­Ñ$/6_cS^zé%¹ãŽ;dΜ9Ŧ-ÍÁ¢ öÒäMÚD•M]ŠJ󛆚 ›¡FÁÑAÀ­GùdÈ>ùwoŸÌ¿U;Y•3:úeæ¹²ýY¢oH½VCz·ô˘ËBΊóUAýýÚƒâè꨹0tÜ8)Áÿà5?ACh¦­ ª_#ÔËüðøôÁ,—t=Mj?•.}ßM“kì_U‘;Ôhò[`PÄKöäËÞ™*¡‘¾vô%¹: RŒ¿˜ë4êÜø¹tÁ¨ñ5"ÉÒ­9ý#4x&]úhÛ&¨#É”ù›ÒÿÔÕ·Þ¶ÿ_š ÕQuÈ S\ò„!“4§ëki§[¬åôv~50œ²Úøp48¸Nm[ØÈþSš&õ´žÇ¿—&¬2B¨êo•ƹ Úzßý£[2_L—N¯¤©ae¿®ºë¬µŽóö’%K¤víÚ†"Ð £VªTIš4iRèåEæR‡{ö쑼¼<ÃãŽ4‘kžoذÁxPàáUPš6m*éé±uÇ"ù[C™ðPX»v­`]vÔÞª† ¬ÍŽú&c["qä¾Òxo–[Nlí—#›äXÊ~÷/—\•¤ÞœÒµ¬äÔ'·ñÉð9ÚiêˆÀåŠ^[þ¹vkt_%í]Žiî—ÿSïW‹ZÁü0üý>ìþXíÄüb(üΣ¼ržã–éï·üzgi‡ü˜ùž¤|! ƒ`öFÓP“5®ô¡>Þ‡¡ƒ%óÿÁBΕÜÜ\£ÏD?Û¡C¹á†ŒÑW8_þûßÿʦM› …ÆÁ#ÉÔíà gÅ)ú}Ñ–jKÑqß\¢JðÇêYÐ>دm×øÿµÚ_BÆh{øÅ-Ÿœ›']êûå•in9çó4Yv›z™òó#®å–Õ:WâK}3lIa8æyeùl©ìÐ7ŸòQšq 02ÛWÿzéóΔ‰ªÄ?¤uÆ5@zôÑŽH“q:2l•}úõ´ÓäAí³‘ ý`5þP­níÏ?L“ÛzAGèT}>\¦÷‹ÿÊé^IƒÖŠ<Ïéä“Oæ¸ Cõþèo§œ×Ù'p€íÏŒþY•üÛF{äc½ÿz5óËpý?UÙüsSŽ­Ïº¿4¼÷ïõé¦ó9°lç»äçË‚þõ³Û˜ë1ãºãóR½kW¹¡g-8눰2¿"Œ×®½{÷3”t¤Pê±^9<:æºåø\°`ñ2£úõëá8èœÑÁ‡ <;æ~xé£áãùóçŸáéËóJ>~3ü¤E‹ ÌI@ù8ŽúìÞ½Û(*YÛR¶1ù ‚¹xx`òÜëŽt®vÖoª—ðbíp)©E OŸ>†pï½÷ÊSO=%£F2Þl}ê©§Ê=ŽÃÉ'ÒI'd,uûúë¯ËòåËeðàÁr饗ʼyóäË/¿4ÒôêÕËÔ±cÇ‚‰°~ø¡üúë¯Ò·o_8p Lœ8Q>úè##<û“&M:à¡3pþ\|ñÅÆ_­ZùVm ðÇz埢ª”¨rŠ*?ÚýûÔ[®è]© Ó„åN#ŽþL+ÿVû8²U9ƒ’VScì¡d«|’zØ!PTáIÆO&¯ŽZì·Œ úwþiÒìùtiôlºùfš4×>ó ý —·ÕtÃ^#†Î½½òÔIy{L‰9W§sÈÔ3üx…›Zëõ¾öåðøgjŸü©*Èð~cd“’!eº^G`p#ÿ>Î+ÿèÄÚpCkä"§4Õþý:œ?G«}Šz×?ѹß-t†F—k©R £î[m ƒz:Ǭ¡F[WÕçFjßÇE.íꓵ}´ÛØgŒLݨ {?u>e¨oyÈá>ÃñEõ;KG¦¾YÌoÅÆó sÙàý_ ÔGúz9.h׿tþËÛ3/ZÛ[Êš}ÑÛðècrt¨Äz"¶JsÍš5 C·XëÜœü…pœ5kÖž~3g(ÛØW½zu#.ßÜÎyîܹÆ1„í”V Ø#_SPêƒúÁ`ÁÃOŒ ´m€ ž0Ö¯_o Hcg[ŒJñ_Ì À㔡ùžœ³:úä6–}W÷ÿ¯Qêįçigýµ>lM·j¬zëñ =¬I@º«·æOê·Š¿)XÑã }@@0Ä»K‡’oêé5‡°ìàéY²-xnÇzÚ «w¬›N2»÷¸`çk þì‘ë´³}þ”PÞGéääÒä75ÂŽm¡ ¤³Î:KZµje(àèÃáÈ·¾_¿~rÙe—ÉqÇ'?üðƒ ?þøã6Ã8¨[·®dffÏ<3à`B?}ä‘GÊ7ß|#íÛ·7æ œÊ?Î9ýôÓó·mÛfä BŒÂŽ¥ƒÅƒ^÷ƒí;äU‚aŠ.ƒï;÷‹¢JÕ#}s gÁÂ0>”I(–èðöÔ1K\r¿*Ò诱âП¶˜hyQGA{j_ i¤N(‹‘$KG-w õení:ziʪDcÒô|]•#mê„Òšibù¹G ¬£ýë1-‚}/æ\öMšÜ¬žðQç¸Ç¯p˳¿…ÔI§"Fý:éägS–ëDïê ëøJᨌŒÎúüÐDðö[£ ‰”#š' OUg”×ï*ê[ÂÈÑçsCµÀõ¹ðÂFAgmcVþ½:¸‹ê£ÝòØ "ßjxðEú²RY¨ )ǽSøÂW¶Ùºb¡6&d »©ü£@xt æm„ñ˜Ê¿qPÿa4¡>¦ 3‡1Ѽyss—ñ‰%AÇC ,…aEVÁ°4ꌼÍ Œ , >þLA½QO„þØÝ³NüŒxž ¨R¥«Vxõ{eý5 Сj >u’Wªþ­Ç®ð産ދKÃ<íuÔ+sŽzúáÊ·áeÑmÁ¡NToÍN‘¿uw”>Œa@@3ZS½;wýè‘åÛ‚¡=ÝtßH}ˆ'sÕpØ ?Ŷú°ƒ²oä˱ù'ë1n|Š~ 0Ü|óÍÆh*”qxìÇŽk(ÿ-[¶< aè›ñ«uëÖJ?ÂF‹’7ùˆÀŸUpìî»ï6Ž[÷cÛìóÃ÷ó{ì ÖQÕ‰:À̳2å\ IAØÄ‰ï§ýÞuxv§PŒLþWû_x‘'i35†þÐ~ÁR”£Õ€³"ÑÏw4Êzõ oÜêãFòâT— É-8ªyÀ˜u£†B]?Ê#c/Ï›GŒ0§ žëIW‡úv̸²»WÔ^kÛníå“Ëu1š‰¿yj„{ÿQf­Â[­²V'(cô‚öíó:Œp5܇¯ Þ—ò—º]¬¡\9€ ¬iãžÂy$îL €’:FxÓ!ÖtP¢‹(ÓP¬Ã^vk>¦Ò)Öû Èãá`zçÃó+ê;–üÄèC¸`˜ËšÂ`Aý7ZŠ$0NìnK¤zq_ùŒROÌVèô¡vŽø ¬pi·|Í7üàAö½ªvX«î =`Ñace pùK½;OëÄvæê³ ½zt0Œ½"bΙrM®çÿ’.½öŸ‰bI0¢ðÀÆPo$Y®^ˆu¥k:¬AI p–<ôÐC†gÿª«®2.è‡{÷î-Ÿ}ö™Ñ׆·NÄùŸ|òÉÆ|Ì'ƒ_”˜K8_rÉ%#pö`…7ÌÃ$dôñႆk¯½6|7¿—“¼ÜéªKâWÜL=ÿ÷ë5B=.¡“Ñ4€ƒNÂO pÄ@Ð/c´Jé}cÝF,ö?:osÔXõdÌ @hãêeF|8æ”A‘ü—†Æ@ê©àPPO÷óJ÷7Òå oBHJ¼ä5¢îÑØu„ù`Ö¥Œ1*ðù\uº4>ßÎëì7ŽÐÐ,ߌ¹\©+Yå”¶>¹W¯Çuâ`Da‡ŽäôÖP¢Ou¾æsáÞ5Ï? ¬÷û`.m3BHã-0<{ M7ÂÌž8á@ÇÔj|þw’ÎËÐT,ãÐUè¿^¬œa!¸_'ÿ¶©í—Æjô@ªk¤æ >©ç>©Ï:¿ªÄÿúÉm„;YG̃©÷?&¿(×è@¡è[•s³P‚K«€#½9`æƒOì3 |7'm¡ŒpÁ>Ô§$c#ü¼â¾#ÎÃŘÇõÄ_›6m"ž†ƒdmKÄ sgTÐ1crÙ£Ö%¾w¬G‡›Ýj$ ÇŠª¶åK„sø RÂsİ0&Š!,g¢v†ò‡~1'`æºP7f˜Ï^À2B=?/ÿî2^Äòý%þ†QNc2‡ŒÕIe7 <(©AsÂàáGˆFp1Š9¼ÿUÅ1ú}LFب9’ gúe¼?a—˜§Ùÿgeea™åAX(òD¿gFð\Áœô×0"Âû)±'€%0ñ‡P¼!:‡«E>’`Å™«Õ#¾XWÿ"…WL~Uç£á„Äùé0U€À)qÖUgŒIöïzU²kHS‡—Ó Oqû:~y¶ÿýb ½=_:5Ϙ?uš†;¡_‡ _,Éz§*ôOtK}½^.MAù‹UiÆ‹Â:ihê…øvÌñ‚ag•äñžÎûBøúl2Wvóa6H÷ÖyÆ;r0÷£Š'`,ð€¹`žMýò¨–ŸñDºlºWÃÁËl‹å?(ì‡7ñõüƒpÁ¨RG K×9'㽯i[­/qƒñÒT]ÅHÛcÌ]»ê[ òBº1¿¥»†¹>Õ¯pkúDl‡žÌå( Š0:O(Æè´­‚^sÒ¬õXqÛÿÁpl¸÷«à¡€Ê6=;8Žú ­yÜzNy¶ÍQ Óà@=áBy50uÇ0tëÖ­P¦dl‹YW~–Ž–3V>Ð =X!!\fmðÉÿtØ"^“(±3>“}÷ªg“ÖLåíž·)ß-§Û?êšÞÏüæ–o/Ê5è4»ê\ ðüE'÷%xó$ ¼‘ñèæ!oÖ¨¾@'×aÒY2¿i²¨vqd·Þz«¼ûî»Æ$^3<óX ÈTÌ1±ó{ì1c©P¬â…Pð1ás&L˜`Ì@üÿøñ㕃0:€5ñ1qøÑG5ŠÀâ ·Ür‹±}Þyç™Å&ìsæÌ™Æ‹2ã] ÊI&ÁÄÞ+¿.¾F©7Õ*k4žú]F±*h›5„΄'~U£0ôø•Wÿpæy/¨#vÈž‡B£§‘Ê¿ùHŸà‚QR¼ÿäE넉¿q4ÅšûÎèà—­÷Ÿ·yny>±dé¬reƒ®i²Mp@8}S0*ð”ŽHüG_ ¹K«ƒQ_S Pï}8TÇS5DvY»Aß]WÓÁ0ÏÒó   Æ[xWZF¡ÍsbñùÖ™…•pÌk°Ê3únSàáLÛù°>û·hxŒšpA]­m67Õ—gþ¬![gÃhU¼Œ³¼h> ÿ²¢9#BxmàqÁ°)c(âP†Ÿå1¡µ|g„ìŒ]ð´C±Æ’¡èüÑñÃX½zu¡SàÝÁ’›ˆý„Wôð¡\„æà…]±ðÁ0 žh;ê‰6¢¨'ÊÏÌÌ,H“Œm1*Ç¥&€ÿLø‰$Ø£Ïê<"¥M•}ˆÕ„`^DÃjx8Œab¼'Aí Ï^;áÇ;»zŸ*툧œ¯«Yü®^º^êá11’˜?ð“ xã$<1·éZàXbK‹bÍæuú0zq*–U ®ìažËσŸúð{î¹Çp `…78Y°Ï*˜¼‹I¼˜cÏ<”w8ð¬±.1 ‡úì|Ðè³M' úm¹F_ž¿µ¬¢¶Ÿx≢•z?VJÄ =Éö°RƒÊ?A/sAvaþRE`à/YŠ:bÿ©ò_”ÀãoUþ‹J‡ýá ¾5mqǬéì܆ÑIù¦Næ€hÒÆ;MLn1(ÄP´±jŽùgVx ·â³4Eÿ¶…r ²Õ!Ìïf~76 ¬ºcN†Á€r1Ù8Ö‚¼Í'Ô Þ&ÔÓœ€Q<`Ì•‚’¹-±fSòƒÐ[ã›i `$9D=ÖõK¦=aY'RÚTÙ‡Éi˜˜‡eÒÞÑ¥ÍÐAbI´/Í,ýyš¾ü“„?ÒðÄz¥KáAð`Á’jÃ,Ã¥X±ºgëpþ{š/{PGÒœ¢¡FÀýcƒ!IXÒÃÆ(‹’z0ÏÊ\"Rë Ø[ÃrÌþiñLBlkZs<žfÞ¥ù„bï7£>©b”†-Ó’ D&àP/yÑ&]äsŠÝ ï;&½Â3EÊoyqÿÈ/ÒDßð¼áÍÁƒÁŒû ?Ïïh»é‘*ªœƒ¥-EÕŸûí!€w,B|b•OQðÆH¬æ€w˜,¬uºMϼwëÕƒ¿[ß2‰Õ0Aª4²J'Ãû¾Nxiò`Z°›ÞW`uf]ýõq5† &C‡-h6dæ» v–s£êã:|—‚)¤ã`o&®Ûuð\Åx\¯˜ûΠ|ÃŽ˜ÿX(ÿ¸<¶FùGZxyìPþQv¸G ûÂå`iKx½ù¢!€ØP,×i*ÿ8+C˜Ê?¾ÃëØP¬TZåçcõ*ÿ AI%Vå<íŠwþñ¨3ó$ˆ˜ñ«*s&  Ô%0dȸ4.^ùÆ¥²Ì”H !h$3 !  â D/Ö+õ ?ÆþÏGI Ù 8â ­Ç!ËdÇÈú‘ @r¸æškbf@ùG~‰ËJ؉*’å@… €pÆZhÄš(ó#  r€Ò^Þ°œŸHåÍm”ÿÒ¾r4§’ „X™¿ðEØîrÉ2 å®3 (‘‡ñKDÄ$2ð{ïÞ½»”vu ðÕ~ ä¸Ì€|öw\•‰lË"$#€å¯›ëÊz±±&ÊüH b±hªÅ,I€âL«÷À@€¿H/ 3ãü‘ÎNGÁãÇçÉèÅé²S—þ¥ ”ÀÊí"Ÿèû„>žå’õÿ½Q¹|¹†ÎŽù{BYs‹H€H€H ð÷DJÏ}ñxê‹·t?4Þ#¿­rʺ]"þzCo<¯ó&“&üšo>´_þwjž4‰ý;m…#&q~’ ”‹@ã ‘wÎÌ+W<™H þhÄŸ1K   À O! ;0Èê,“H€H€H€H€l"Àe@mÏbI€H€H€H€HÀ4ì Î2I€H€H€H€HÀ&4lÏbI€H€H€H€HÀ4ì Î2I€H€H€H€HÀ&Ž€ŠMe³X     ptëÖÍ6 33S²²²ÜäPq}ûö•‰'†v$xËîö³|{ï?ò'öY îuCÅñ÷Çߟ¿?ÞöÞ]ÿCOÈ Ðó€[$@$@$@$@$òh¤ü%fI€H€H€H€H D€@ˆ·H€H€H€H€H å ÐHùKÌ’ @ˆ € n‘ @Ê ò—˜ $    !Ü"    ”'@ å/1H$@$@$@$@!4B,¸E$@$@$@$@)O€@Ê_b6H€H€H€H€Bh„Xp‹H€H€H€H€Rž €”¿Äl „Ð±à ¤<)‰Ù@     bÁ-    Hy4Rþ³$@$@$@$@$"@ Ä‚[$@$@$@$@$òh¤ü%fI€H€H€H€H D€@ˆ·H€H€H€H€H å ÐHùKÌ’ @ˆ € n‘ @Ê ò—˜ $    !Ü"    ”'@ å/1H$@$@$@$@!4B,¸E$@$@$@$@)O€@Ê_b6H€H€H€H€Bh„Xp‹H€H€H€H€Rž €”¿Äl „Ð±à ¤<)‰Ù@    pœuÖYÐ׊µ•™™)YYY«Ñl- (ö¼ H€**ŠÞÿA÷uÛ©Û}X¾½ù“?ûŸ,Ûž¿üýñ÷Çßvu@ììípÝd×ÝÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.ŽÛo¿=`Wá,—H€H€H€H€H q&Nœ(ŽnݺÙfdffJVVVâZVRß¾}ì»ÛÏòí½ÿÈŸüÙÿeÙÕý üýÙùûãýgïýWÑõ?t¼ ²íñÂI€H€H€H€H ñh$ž9K$    Ûа = &    Ä xæ,‘H€H€H€H€l#@À6ô,˜H€H€H€H€O€@♳D    ° Ûг`    H<‰gÎI€H€H€H€HÀ64lCÏ‚I€H€H€H€H ñh$ž9K$    Ûа = &    Ä xæ,‘H€H€H€H€l#@À6ô,˜H€H€H€H€O€@♳D    ° Ûг`    H<‰gÎI€H€H€H€HÀ64lCÏ‚I€H€H€H€H ñh$ž9K$    Ûа = &    Ä xæ,‘H€H€H€H€l#@À6ô,˜H€H€H€H€O€@♳D    ° Ûг`    H<‰gÎI€H€H€H€HÀ64lCÏ‚I€H€H€H€H ñh$ž9K$    Ûа = &    Ä xæ,‘H€H€H€H€l#@À6ô,˜H€H€H€H€O€@♳D    °€ã¬³Î ØVºÍgffJVV–͵`ñ$@$xìÿÏœ%’ $ŠÞÿA÷uÛ©Û}X¾½ù“?ûŸ,Ûž†üýñ÷Çßvu@ììípÝd×ÝÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€H€HÀ4l€Î"I€H€H€H€HÀ.4ì"ÏrI€H€H€þ¿½;³¬¬ï„ÿTwu³#‹€ì‰¸±)ÁÄCi4Ѹfb|gKÂ8™×ÄÌd’7ëLÖÉdu2&FQã–¨(¨à÷ /ˆìˆ² ½Õûüo÷mª›ê¥šîû«îúžÏ§»º«nÝß½ßS÷ÜçwÎsN @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H LLOOϤÂÓ¹SSSm0¤†|Œ]Àöoìä X ‹}ûWcßÉä8½äg þ¶?ƒØÛ¡×Ÿ×Ÿ×Ÿ×_jdû“ÝþÔz7(õÓ/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ ˜˜žžžI…§s§¦¦Ú`0H? ù»€íߨÉ °@ûö¯Æ¾“ÉpzÈÏ þüm±·C¯?¯?¯?¯¿ÔÈö'»ý©õn Pê§_. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ %01===“ OçNMMµÁ`~ò  0vÛ¿±“ $@`,öí_}'“àô Ÿ-@üùÛþ bo‡^^^^© íOvûSëÝ ÔO¿\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J`bzzz&žÎššjƒÁ ý0ä @`ì¶c'H€ÀXìÛ¿ûN&Àé ?[€øó·ýÄÞ½þ¼þ¼þ¼þR ÛŸìö§Ö»)@©Ÿ~¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”ÀÄôôôL*<;55ÕƒAúaÈ'@€ÀØlÿÆN."°Ø·5öL€Ó+@~¶ñçoû3ˆ½zýyýyýyý¥6@¶?ÙíO­wS€R?ýr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€)‰ééé™Tx:wjjª ƒôÃO€± Øþ\  D`±oÿjì;™§W€ülâÏßög{;ôúóúóúóúKm€l²ÛŸZ殮~úå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€RÓÓÓ3©ðtîÔÔT é‡!Ÿc°ý;¹@ˆÀbßþÕØw29N¯ùÙÄŸ¿íÏ övèõçõçõçõ—ÚÙþd·?µÞMJýôË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤&¦§§gRáéÜ©©©6 ÒC>Æ.`û7vr,žý«±ïdrœ^ò³ˆ?ÛŸAìíÐëÏëÏëÏë/µ²ýÉnj½›”úé—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H Lœ{î¹3©p¹ @€ŒOࢋ.j'Ÿ|r¬LMMµÁ`0¾g¼QÒgœÑ !µ¤Ÿ¿üìÏþ¶ƒÔæ·yýyý%_~þ²?‹}üW^S€bo?‚  @€Œ_@¿¹D @€1 F/˜ @€Àø€ñ›K$@€ Pbô‚  @€Œ_@¿¹D @€1 F/˜ @€Àø€ñ›K$@€ Pbô‚  @€Œ_@¿¹D @€1 F/˜ @€Àø€ñ›K$@€ Pbô‚  @€Œ_@¿¹D @€1 F/˜ @€Àø€ñ›K$@€ Pbô‚  @€Œ_@¿¹D @€1 F/˜ @€Àø€ñ›K$@€ Pbô‚  @€Œ_@¿¹D @€1 F/˜ @€Àø€ñ›K$@€ Pbô‚  @€Œ_@¿¹D @€1 F/˜ @€Àø€ñ›K$@€ Pbô‚  @€Œ_@¿¹D @€1‰ééé™Xz8xjjª ƒð£O€ñ Øþß\" C`±oÿjì;™§W€ülâÏßög{7ôúóúóúóúKm€l²ÛŸZ殮~úå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€RÓÓÓ3©ðtîÔÔT é‡!Ÿc°ý;¹@ˆÀbßþÕØw29N¯ùÙÄŸ¿íÏ övèõçõçõçõ—ÚÙþd·?µÞMJýôË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤&¦§§gRáéÜ©©©6 ÒC>Æ.`û7vr,žý«±ïdrœ^ò³ˆ?ÛŸAìíÐëÏëÏëÏë/µ²ýÉnj½›”úé—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€r\Žý>IDAT @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H LLOOϤÂÓ¹SSSm0¤†|Œ]Àöoìä X ‹}ûWcßÉä8½äg þ¶?ƒØÛ¡×Ÿ×Ÿ×Ÿ×_jdû“ÝþÔz7(õÓ/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ ˜˜žžžI…§s§¦¦Ú`0H? ù»€íߨÉ °@ûö¯Æ¾“ÉpzÈÏ þüm±·C¯?¯?¯?¯¿ÔÈö'»ý©õn Pê§_. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ %01===“ OçNMMµÁ`~ò  0vÛ¿±“ $@`,öí_}'“àô Ÿ-@üùÛþ bo‡^^^^© íOvûSëÝ ÔO¿\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J@HÉË%@€ Pè"  @€¤€”¼\ @€ €.’ @€@J`bzzz&žÎššjƒÁ ý0ä @`ì¶c'H€ÀXìÛ¿ûN&Àé ?[€øó·ýÄÞ½þ¼þ¼þ¼þR ÛŸìö§Ö»)@©Ÿ~¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”ÀÄôôôL*<;55ÕƒAúaÈ'@€ÀØlÿÆN."°Ø·5öL€Ó+@~¶ñçoû3ˆ½zýyýyýyý¥6@¶?ÙíO­wS€R?ýr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€) %/— @€@@@ ‹$@€ PRòr  @€€ºH @€)‰ééé™Tx:wjjª ƒôÃO€± Øþ\  D`±oÿjì;™§W€ülâÏßög{;ôúóúóúóúKm€l²ÛŸZ殮~úå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€R @J^. @€€€@I€ @ % ¤äå @€(t‘ @€Rçž{îL*\. @€ã¸è¢‹ÚÄÉ'Ÿ+SSSm0Œïo”tÆg´BH-éç/?ûóÇŸ¿íß µùm^^ÉןŸ¿ìÏßbÿՆנØÛ` @€ãPÆo.‘ @€@L@ˆÑ &@€ 0~`üæ  @€Ä€½` @€ãPÆo.‘ @€@L@ˆÑ &@€ 0~`üæ  @€Ä€½` @€ãPÆo.‘ @€@L@ˆÑ &@€ 0~`üæ  @€Ä€½` @€ãPÆo.‘ @€@L@ˆÑ &@€ 0~`üæ  @€Ä€½` @€ãPÆo.‘ @€@L@ˆÑ &@€ 0~`üæ  @€Ä€½` @€ãPÆo.‘ @€@L@ˆÑ &@€ 0~`üæ  @€Ä€½` @€ãPÆo.‘ @€@L@ˆÑ &@€ 0~`üæ  @€Ä€½` @€ãPÆo.‘ @€@L`bzzz&–žššjƒÁ ü(Ä @`ü¶ã7—H€ÀÂXìÛ¿ûN&Àé ?[€øó·ýÄÞ ½þ¼þ¼þ¼þR ÛŸìö§Ö»)@©Ÿ~¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”€’—K€ @  ÐE @€H ()y¹ @€ @]$ @€”ÀÄôôôL*<;55ÕƒAúaÈ'@€ÀØlÿÆN."°Ø·5öL€Ó+@~¶ñçoû3ˆ½zýyýyýyý¥6@¶?ÙíO­wS€R?ýr  @€€ºH @€)‰cŽ9fÑžB—K€ @ %0q÷Ýw+)}¹ @€Æ,` ИÁÅ @€H (I}Ù @€Æ, Œ\ @€¤€Ô—M€ @`Ì À˜ÁÅ @€H (I}Ù @€Æ, Œ\ @€¤€Ô—M€ @`Ì À˜ÁÅ @€H (I}Ù @€Æ, Œ\ @€¤€Ô—M€ @`Ì À˜ÁÅ @€H (I}Ù @€Æ,09æ±ñûÃÆÿÝçìWôr~îy“í#WÜû^Uû5^püšö‡g­l,Â")£•òK\Öžzì=íà½GŸñ‘Q`yß’üùÙ+7xè—ܸ¤ýÓ×–¶éXÖÎ{éŠö„©™ ¾î? Wà†nh«W¯n{ØÃÚ²eËî]ìÏúàÿ5œìGJZ;û¡kÚ¾»Í´O^½¤]uëD{å»Ënî] à¡{Æ*0×ûÄèœtÈÖ þG·ŸÏÇïÿ°µg½qY›ìcÿ·þÔÊvòƒÖ´+n]Ò>ðÍ%ízi»á޾Sú¥¾ÍçþwÖÛÆ ÀA}пruk¿xÞ²ö–,>øõÆã&0—@NýéûÍ[Ó~ú„Õí1½¼½ñ+K{°7.»…ø¹þð‡m¯½öþYˆo!=¦¿þ\ÿáïËŸ>kU{Å#û›Úºå%ÿ´¬½ëÒ%í·?6Ù¬}ÚG‹V`î÷‰Ïñ¡+—´k~0ÑÎ{ÙŠöÄu;¢ŽxÀšö¤©5}ð?ÑÞúÕ%íë7M´‡´¸vRÅ À~»Ï´_îS~ö]ËÚ;ûFòyß|ûûø`¢ýÖG'ÛWnX2œ[yÖ®iÿíI«Ú²¾í½µ·»ç¼yyû7Z=ü3úqªÆ·÷òÖÞÖßhù›/,mo½diû@ß#i~æHÅG;FàøCfÚî}'èèµV¯õ?ü×Évá+V´Ú4Zþð“KÛ§¯YÒÞ>ëµ:úÚèãæ¶£Ûø¸yo~ó›í€h333í¦›njwß}wÛ}÷ÝÛá‡ÞöÝwßvÇw´ï|ç;ÃϯX±¢]vÙeë¿V÷|Ûm·µë¯¿¾Õ¡%K– BMÚm·Ý6¼‹~µ3¶o÷=ýµÜ8kúOýÿ¿±ª´W?¢ÿ»vvÕ{U}üŸŸXÚÞÖ߃®î’=ûkã´#×´_ëïe':Ó>ÿ݉öš –µ}–Ï´w½he?÷¢î©µÜÝÚOüãò¶db¦½»~Ïþ¾öÉ«&Úï~|²}ñº%í€=fÚSŽYÓ~ë©«Ú¾}ê…ÀÎ(pÞ6÷|¿÷ÚÒm÷ÔÇ ù¿ù”•íô#—¶Ýf½ÝÖ_o¿úáÉöÑA/·M´c÷ŸiÿÏ©«ÛÏõ?£å)»¼{úªáóO>µ´¾ïLûËç¬j?ìÃÍ_¿p²½ÿò%í{?œh;jMûÅÓVµÇ}oî–nSù¹Éö÷Ï]Ñ^ÝgÊ|âª%Ã÷Ëg?xuû½3W _ÿ£Çq>Þ;êþÜË6~ï OXÓžÑç|ÛÜrצï¤ö¢<ëMˇ'lüEŸfðü‡¯n¯ûüÒö⾇¥–ý÷X»J«Å–šïõÑo/iïëçÜ0kÃ\ƒÿý{ù HF·÷‘í/ðÁ~ˆõî¾A<£ïi©åæ»&Ú—¯hkîÝ?ÿ>ºä†u£ág6ükKÛ€ o훨9ý7ÞxãpðÐA ÷5ÕçŠ+®Nù™œœlûí·ßðÄßÔ׿—/ï£Í¾ÜrË-íòË/þûÈ#l‡zh«#—^zéðãð ‹ì¯ ×|-¿ÑßôÏéÓÝÞôå%í»?hí!œiüÌUíúŸü×òª^Ö~§ïȺ¾ïu¬½ë{?Ð Oÿûåíæ;[;±æËúžÈ ¾µ¤ýëÕ÷¾j0ñ©þÿÝû ¥ÿïîçÜ<ãËÛ…}Ïæƒœ‰ÿÛwn=îo–·;œ:·Ûß;À¶¾?l鉞ÙÏA«×ÍÏôοóÑ¥íâëû{к}·?  öÇôA~-õ~õ„ÿ»¼ï˜^Ú^zÒêVcÎãû¹lç¾²ýQßQ5Z¾tÝDûX/unÃê~_9b¦­êýàioXÞÞóõ%íN[Ýþè+ÛŠþ¹çüÃòáë·¾wknSŸ½f¢ó–å­×?se{æ®nõÿý~®ÑöZ¶ß=mã#úÓþÄõW»µW`Y{ÃóîÝS?º»Z¿tþ²aûúƒgÜ;…àô¾×ä¬ý‰¾äñ½YóÕí·ú¡Ö;û‘Ö½úŠ®Æôð¾Òné ¬ZÜOö=jÃø™ïL [Úèþ}$@àþ ü°¿4ëäýѲ²okÏèEýµ÷«}ïæó±nk;ºÁ<>ní6`w¹¨oºreC;þøáü‚¨þ·¾õ­vûí·ü5°¿õÖ[‡Gêßµ¬éï–×\sÍð(ÁqÇ7ü\ýµÿþû·K.¹døµ?øÁë?¿˜þñú~1‹—½kyût ¨ÜëO-'ö=ú/<~uûw^=Ü{W{ßñµ%ݽµýìŠaA¨Û½ðmËÚ¿ôC7pÎÃÖ wpÕý?õÈãŽ^ûž÷ž¯¯x¼¨O©»«¿Çýç¾W°0êGÒN?jíÀå?¾w²ýí×~ã)÷¾WV†…ÀB¨1Øá¿ߣ…¿Ð÷¿æ ÷î]ßÞµ®Èõþ—¬h¿ò¡eí·{ÿíöqbO8zM;§Ÿ·S¯«QIÿ?ýµ÷­[&ÚÇ_¹¢=ê°µ¯­ÚY]ç üEß+ÿêÇÝû8ÿ²_¬æýˆÜY^ûþöýÿ5•è+ÿþžvD/µüTíèþûeí7.šlxÙÊöº~ÿ[ºM}_…* ?ß‹D-õzqŸóá^úÿû“‡ŸºßÝûŽ}¿ïjÛî Ú×ÿxúªöþe²½àKÚÙÙp pÉíúÛÚp/G ög/ûõ=ÿïºli/«ÚtßpþÆ…m8د3É?Þ7¦µ‡ev¨"P˳û×-l?Œ\¸îõU÷ZS#êÐé} óÀ½î´-‰[» Ø–û^ŒßSS}júÎhÙ{ïµWa¨#›ZjÊO‡£Ž:jƒ›Ôƒqíž¾zoûóVµ{új9¿_¹¤¦Òýx¬Ôíë=±vp՜꺟ZžØß謁¯-ø§,¢à©î4ËúûÁ¯<ñ¾åôÔ~Å·½<ºï¡¯Â|M?:WcÁšrzþ}:x½üAß³ÁËW´Cú¦°^k5o4ø=®÷¾de[µÑÃ|ò±}GôºÁÝîü^þë<‚Á÷'úŸÑw¶öÈ~Ú§ ÕL—­¹Íè;Ÿû° ·É:tÍðñ¾~?Æ @=:qêm—,i?ÿþeíñGmxüòÊuó+_Ý/ß4×ríík7~ÇõíõçC}å @?ðûO_9œƒU+·–:¤_ ÛO Žº}æUëF0ëî¶JÁϾgYûOýÐiM“¨K‚n˲µÛ€m¹ïÅø=5hŸïrÏ=k·ËsÍõ¯ÏÕ‚:g`4]h¾÷¿³Þ¾öê×`¾ç5h8éеƒ›:àO?3Ùþ¸¿÷|¾Êÿ`ÔûÒ?\¼¤ý^Ÿ·EßÃXK}_ âg/§9Ó¦úaÿAïûD?ªPó—ïéGÂkOb½Îêw Ôriß9öÄ>Uaãå›ëî{ãÏû?´Ànýgý?>fÃAí¸Sí™ñIk†ú~öö†/-mÿ¾ï€þo}Î]vúª>xŸë½ª¦oÿñ;KúFuÓ¯½;VÎz!oôÐæ³ Øè[ýw; Œ.ZG6^êsõ‹Â¶¥Xl|_;Ûÿko{]êóˆýZûÆ/Ü»óª.m]'äÖÉ|u9Ðúå`u‚ïÏõÛ>°íÏïS_ûûÙ‘ýwüTŸt^¿ŸÙK¨sê2ºw®{mÔ4…ZÞkíû`í}üý~„`ãeÓ¯¤oéÿvͽ?lÍ3xêß-žwváÏl¸“ª¾÷å}ôÿî—ò­“ék9 ?«Ôo¼Ô¹¤W÷rpJŸ4:€Z³™½Ô{UÍÙÿÇM\Ù² ÐÖÜæ“WϾ×÷ï ·:;.g‹÷\s´~³Ï[ü‡~¹ÀôC¨£å„uWùxߣ¿Gß[2úS‡KŸÝO ®9Æ£eú¡«Û•}ïÈ›.^Úêê#urpíI©óßyépNòsú¹Æ#0º¬Úè )uu“Zêéh©+£ÔM6µÌg°©ûðùû'°çž{§ }ï{ßÛàŽêjBu¾Àèë|qü§Nü«åš~¸¿öîÏ^êB£#Ôì×ÿLŸrPËÓdõðªwõÞTËhþð?ëþ]R÷Ý}î\¥á)}À_ˉýzé½oµ/_¿¤º÷ÌðDâ:™¸æ-ÿt?!ñ¯û2,vFmyØšçyJŸ:ó…>-¯Žšm¼ÔûOí™?®ŸL_ËIýµZÓƒnê'åÏ^êþ×~xÙúÁÿì¯þ]Gï>ÿÝ%ë}ƪõ±ÎøÙ^þëu»5·Ýߎþ¸ákG§máþÿm?Yê´~BÓ×f] ä}Þä/ž¾zx¹³ÿÕçPÕFîcý’ ?×§|¿~}êºbÝu‚=²‰ÿõéÉöľ÷´<ñèÕíOúçj؃ö}ÖGv´@müjÞçw×MÕ«½'µÔ%Öjžô—û<éWô+3ŒörÎõxæ³ ˜ëû}îþ ÔÞýúÀu% :¸.ZçÔÉÃõﺌèb\Ž=`¦ý‡uSjïþ¯_>œNPñë¿ÿbeßAÿ¤~yÎ*±?Òo[ËÛû^ý_¹`²Õ¥ëê?ß¼yí ä½—/½®ÛÔ^ÄÇôÁÄ-}RÓŒ^Я|7š~pTß¡õ³§¬n·öùÄOìy¿û±¥íû4»Ÿë”šþS'5ZìŒÛòþ°5Ïó?õËuÔÏE{v¿\|ýÞŽ: ÷Ú~M P¿¨²^c£K|þçÇ®=ªV—Ý­S_íãѺ¬gÜÿšÇß÷ˆÛìüŸïG¼W÷—ùsû÷Öe«k‡ôëûy9uðtŸÏ_`kn3û>wä¿Ì z’…óWÏYÙÝ7œuY¥Ñò_ûI#Ë—Ì KÀk/X;o²þÿçÇW®ß(Žn;Ý7~õ›ÝêàÑR— ¬# çô#Æ+pL/å5ý®ö´Ôy:¿Ù§FÔõ—/^å•}0óªSVµ7÷#w›Zæ³ ØÔ}øüý8ì°Ã†—½îºë†¿  î­~‡@]ý§N,^¬Ëïöër×´œÚÉô¹>ßÿs׬ý9®ùý5Pÿ§­î5|F?YðßþØêá¤N¬åÔ¾Sêµý*Y5ÝçŸû¥=æ‘ý÷Üì¿ö½ëÅ}Ðg¾³ö-z4ýgdüûýÂõ;nê·ÿV\ÔRGºÿº¿žÑ ‡…ÀÎ(°­ï[z®‡öÍÓyý*@õ¾³ñù¤'÷Ru%Ÿ'¯{ÝTÁþP?!øßý˲öôusùk'ÖéW)zZ¿œèæ–ûœýþ›ÃËý>³_¦·æë×sú¥~å ºe-[s›ÍelϯMô½7kwKlÏ{Ý÷uu?ÔZgjÏþ¥ ;0Î] °Vô)u• š=ºüÚÖÆØl­ÔŽ»]ð[WZŒóþ7¥Z·N ¬£]õ‹¹ê—ÕI»/u½ÿú%`õ‹ƒê½¬–:o­Ž‚=´Fó‹×~eó×¥/ï{ýëýpªíÑQ‚Í—¯XØ÷çýaKÏìö~ªN]¢º.Tÿ©«xmj©_ÀwK¿&ÝnrÓû§æüöº\oK°¹ûßšÛÌyçÛé“;]ØNÏÛÝ @€X” ê€E¹S€Æg-‰ @€@\@ˆ¯€ @€Àø€ñYK"@€ Pâ«À @€ 0>`|Ö’ @€Ä€ø*ð @€ŒO@Ÿµ$ @€qÉø#ð @€À<n¹å–öÅ/~±]{íµíž{îi‡vX;ôÐCÛ 'œÐ–/_>{rÓ¤ÀUW]ÕƒÁp=Þ~ûí<”}öÙg¸^;î¸áºÝà‹þC€Àýð‹Àî7¡; @€q Txï{ß;üÏÎÝm·ÝÚÙgŸÝ<ðÀÙŸöï&Pÿý×mú7õ0« œqÆŠÀ¦€|žÀ6(Û€æ[ @ +°¹ð¼ç=¯Õ Ñ²ð>úѶo|ãÛôÀêÏé§Ÿ¾Mßë›ØP@ØÐÃÿX„¯{Ýëæ|Ö¯zÕ«æü¼O. M•€‡<ä!íIOzÒÂxÅzû3ø݉u;’ð‘ÀýpðýóóÝ6)°×ÿ·[ÛøÏ&oì lR ¦Š¬X±â>_¯©>5姦þÌ^j^¹ea lÁ=£:zð…/|aa=9†ÀN(à$àp¥yÈlMíùÝû–¾>º##‰ó±æûæ÷o|’o•€: øÛßþöúð:1زpjÎÿ¦¦ýÔº;å”Sî3¿t¢÷ìõ:zFUF'~>ç#óp`~^nM€c¨#7ß|óðÄßԞ幉c~ˆâ6#P'üεsÌ1Ã#8UêÞð†7 ÿTY¨¥ŠÝ™gžÙjÊÏ\‹£s©ø­p`ë­Ü’]XÀ^ü…¿rG% ¦ýÔ qSÓJœ¼pÖe è7uµŸÓN;mø@k°_ë³nWeáè£^ÿê¤ß¹ŽÔ%`ë(A}¯…ù (ó7óìb|ððm픟Í=}Ebs:÷ÿk£PƒüMíùŸššºÿAîa»lî|ŒÙE­ÖÙW¿úÕû”…§|Í~P—_~¹«ÍñoóPæå¦æ#p篙‡<¯äm9ävå•W&‚ìÍÔT‘Ùƒý*õgSKÍ·, ÚS¿©¥¦ñÔüÿšÖµ¹¢°©ï¿îºë6õ%Ÿ'@`  À€|™Àö¨+m¼( ‹Œ÷ÿUn¸á†ñ†JÛjG=êQëëïÖ|ÓE]4üÅQ³§’lÍ÷¹ÍöØÔôŸJª°ñ\þ*{³—K.¹dö7ø÷æJà7ôî#à$àûø‹I ¦ÿ{ì±Û¥Œ¦-&¿q<ךç]sÁ7¾Ü禲ë*@üà[M±ì\Çüú\ƒÿM@¼þFþA€À6 8°Ml¾‰]E`4ýçÆo¼ßO©î˲cŽ;î¸á¥"kPXÓEF{–øÀ¶úZ•„óÏ?¿Í¾h ¨i"~)ØŽY'Ûû^ëŠ?‡zèpÝÖ Þ››>´½³ÝÅ& ,¶5îù °Àöœþ£l@»ÝÿS'Ö‘€ú3×RŸ¯Aÿ쥮 SsÌ«lî„ÒÙßãßÚû_Gm>õ©OmPä2F*][À ]{ýzvlF`{Oÿ©©D–œ@ ¨“J7^êâúebÿoçÿÛ_`ö•~¶tïug>ƒÿ:úc!@`ÛØ67ßE`›œð»ÍtÛýMÿÙî¤ñ;¬pÇwÜçÚñuÂè[Þò–á/žríøñ­¦º"Ó\×ñŸëÔô®ÙS¸æºÍìÏÕt! Û& l››ï"°^`SWõ™ïç×ß¡ŒMÀôŸ±Q5¨¦Õ/‰Úø*15¸¬#gœqÆ¿lj¬n‘…Õõý·¶Ì÷„ß:âc!@`ÛLÚ67ßE€À."°=.ÿ9šJ´‹ìôO£æú×o žëªA£+mîò’;=Àzu)Ö­™tÖYgµú%zõqk–:²àHÎÖH¹ ¹€¹]|–E PƒWÿÙ5WôæJ@=ãÚÛ\Wš±ìxÇ>ö±[ ýΆÑÇ-}Ã\çzlé{|{€{-ü‹E&°=öþ™«ÿ,ÌœÚC¼ñƒN=õÔöœç<§Õ ´¦¦ÔI§–+PƒúºÄçæ–Ñïl}ÜÜmkðoþÿæ„|À–œ°e#· @`Ø{ÿ‹ÆÕîHͯß0ú³õ[…k©d¨çÆ%aá>›÷‘~æÎ¨Ë·n| ×¹žm {ÿç’ñ9óPæçåÖî#°©«úÌ÷ó÷¹cŸØá5çØ²ë ̾2P\GF¿Hl>WÙõ¥vì3ÜR ØRú 'œ ¬m É× l¥ÀÄÝwß=³•·u3 °S Ôï¨+ÕÀ¿ @ü×åÑÀt§|b;ჾꪫ†G_F%lKO¡N"®+7™ö³%)_'°õ ÀÖ[¹%ìÄUÎ?ÿüvíµ×ŸE]IæéOºßZ§UƒÁp}l\jÐ_맦pø‡VØ]Z@Ø¥W¯'G€ @`CWÚÐÃÿ @€ìÒ À.½z=9 @€ (zø @€]Z@Ø¥W¯'G€ @`C`Cÿ#@€ °K (»ôêõä ôßyÒ¾÷½ïµÕ«W>åcPàŽ;îh7ÝtS»óÎ;ƒB4§€ß¼8×»g½ ©?Ú­Ýtǽ_Ücykg·¦½øÄÕíÌ]sï6ó¯×qiÿžÕíà½×ÞèªïO´O^=Ñ~úÄ­ûþÍܵ/mƒ@]óýŸøDûþ÷¿ß–-[ÖÖ¬YÓŽ:ê¨ö„'<¡í¾ûîÛp¾åþüà?h^xa»ùæ›Ûääd«kó×uÞŸüä'·½÷^÷¢ÙBÀe—]ÖŽ>úè¶çž{oY׿îºë†×Œ¯O¬Zµª½þõ¯o?ù“?ÙöÛo¿-Ü›/ï7½éMí‘|d{Ä#±ÁÝûÛßn\pA{å+_Ù–,Ùü>Hëq:ÿ!°]6ÿêÛ®QîŒÀ¨_‹ýÚ'­j—þü=Ã?ÿðü•íΕ­=÷-ËÚ×ošØª'pîy“­ý£åâë'Ú¯_¸lô_Ç(pÍ5×´÷½ï}íÈ#l/}éKÛ+^ñŠö¼ç=oXÞõ®w Šc|8¢º@ý"®½öÚ«½ìe/k/ùËÛ9çœÓêhÀÇ?þñ­öùä'?9ü¾£o¨ßêûùÏ~ôßáÀòQzTÛm·ÝÖÎ?Æ+033Óê……) ,ÌõâQØ£µ£÷_ûçé}¯ÿ_?ge›èãù_éå\-ÛýÅ/~q8ø?í´ÓÚ{ìÑ×ãDÛÿýÛ3žñŒöÃþ°}ó›ßܦûõMÛ&PÓ°n½õÖá^áåË—×Ç!‡Òþð‡·ï~÷»Ã£3ÛvÏ~WíY>õÔS‡ë|ïø”€)@~lA`ÿ^j:ÏÊu3x.üö’ök™l_»q¢-éÅà‰G¯i¯ûñ•í†;û4Ÿ·/ësÌ[{É;—·é‡®nÚ{¦ýÙg'Û}ZÑI¾¼ýÑ3Wµ§»¦]{[k¯¹`Y«ûÚw·™vÎC×´ß|ʪ6¹´µ¿ùÂÒvå­íÄCÖ´?þÔd{íVµÓ\ÓÎ|Ãòö'ÏZÕ^û¡ÉvùÍíáÏ´¿<{e;þ{ÙæZ…5мþúë‡{˜kà?{ÙgŸ}†ÓEj*ÉÃö°vÅW´+¯¼rX.¿üòá‘=èAí±}ìúi)5uèË_þr«¯×´•ƒ>xøõ}÷Ý·Ýu×]í½ï}o{Üã×>ó™Ï 0pÀÃiFxàìèEýïÑᚎuØa‡­·xèCÚʱŒkð^GʱJAMÛ:æ˜cÚýØ ]?ô¡ o÷‘|¤MMM §]rÉ%Ãuð¶·½m¸NjJÑ;ÞñŽaÑ«û­ÛqÄm0´šV壎Tn-•û¹Ï}®Õô”Z·•·téÒáÏCý|Ôy 5¬¾·–>ðíñüðëÃOøk›6µ®7žTëåÝï~w;ùä“ÛÅ_<<TÓ»N9å”ᔾm~¾‘À"°Ks‘®xO{ën¹«µ?ÿìÒvÃí­½àá«Û]+Zû‰\6Ü_ýê{Úe}ªPM÷©yÿ?zÀL{׋V¶¥ýUõ?Î\Ù^ýØUíå'¯n¿ÒðíÕ†_;íˆ5mŪ֞ý¦åíÁδ¯÷ï?ï¥+Ûç¯]Òþßó×öñÊüç¯/iÛïó×út¤'M­i«zùøÖ-íO?½´ýãóW sÚs¦½fÝ÷lݳY\·ªi!5ˆ«ú\K @ë¤àüÕà¢uTà¹Ï}n{þóŸ?œŸ^Ó‡F' ד>ûÙÏn/|á ‡ƒÀô××ë>jPûÕ¯~µ=íiO~½Î/øô§?=Wô¢ý\…©yá5˜~Ï{Þ3t_uÕUÃ#5è®sÊóýï{À0t<û쳇' êSŸ~®ŽÞÔàð1yL;餓ÚCòá}Öùõµ:¢PE£ÖG­—ZêàüñíÅ/~q;ñć¡Öw-ußµnëûkÝÖ¥*uÄ¢–úÞº¯úÞ—¼ä%òRÏÁ²yn¸¡]zé¥ü©iy£esëzt›ÑÇÑ:ýÊW¾2<_¤ÖC9ª)e7Þxãèf> °• ÀVB¹Ùâøå &ÛA¿·ÛðÏѸ[û§¯-mÜ÷Üþ€¾§°ïlç W¶sO_ÝöìÓúo¹kb8࿱ïýß­ßí% õ͇ï3ÓéG èç(²×L›ì¯´úÚ^ý¤â|kI»mÅDû™“Wµï÷ñÅÒ‰™öK½,üí—– FIßÔïïí?µ²=û!kÚ~ýÄhùïg¬NOª#/=iuûÖ÷6ܳ=º­ÝsÏ=Ã=½ïýÙÔ^àÔÕ‰†µÔ€½öø× µ“u’píÙ¯KÝ®÷5p¬û«ÂP{ëßµWy´Ô´“Úã\ßÜqǵ:áÕ²¡À£ýèá ûØcúÔÜÿ7¾ñÃAv ò®¾úê¶råÊáÀ¾œË¸ú_ÿúׇë¡|k©Az9×z«u»úZ1˜kyðƒ<<êP_¯c-U jZG‚ªPÔåÑÑ:J4Z*£ ÅhšRé©“–-›¸í¶ÛZ•€ÙÊq´ln]×ÏÀ\KMç«£jµ«üUq¬’a!@`~kw9Îï{ÜšÀ.-ðÚ'®Ýs_Or>–xÀ¬ ÅìÝÏ)üê íW?¼¼­ìS}ŽzÀLxÌ£¦÷Üܯ|xæß÷60k9¤OºiÝOèÓzö•;ºÙa½XŒ–å}ºÐê™y†¾y|¬Á\íá­"0×É 5©c øj©Ác1-5À¨«ÒÔ ±¦€Ô@±N>­æì¥î´Ôý–º¯Ñ”—ÑçûÇÚ£^»²>ᄆʨJT]¦¦MÕ”ZouteöR¶õùM ðgßv®Wa-u¡ÖceWÉ«‚7*£ÛÌ.UZêg¨ö>øÃ…*%U*,›(Ÿ:ê2{©#muŦZª ln]Ï~=îcã«:ÕÿGS³F·ñ‘- ([6r‹E&°oä?èÞ<ûw]º¤ýÎÇ&Û§_µ¢½ßÚÁøËß9÷Ç ¾q֎ò—ýBŸO´n©©E÷bqÔº+î½üÞþè6>ÎO ¦þÔ¾¦rÔ<áÙK øj¯aí…-5Ð¯Ïæ×€¿þ5©Ác}þÌ3ÏltÐè[†—²¬¯Õm-[¨=è5u¦®È4r®xíÅ­x1©]™¾èE/Z‡UjJ×ìAùú/nã?Få¬Öo=†ÊÝýÔÿ?üðá½×ù$u.@M_ªÇòµ¯}mx)Óšn´qqØÆ‡³(¿­¼7·®çz]Ui­§B«×í\EaQ‚zÒæ!` Ð<°Ü”@è[ÓxöÛ}íýドvÞ7—´{fÿ–õWÕwoŸhw¯;‚½¬ïT¾³ðk¯ÿª~»³ú•…V¬™hð‰¥muŸ¢\_û¥N¶×}~rÞG¬‘M ÔžâÓO?½}éK_ž¼;šÏ]{þÏ;ï¼á ½N-µ'²æz× £þÔœÿš“^—­ÁjMé©Sëv5x¬=™øÀÖdG÷ãã¦j@]¦]tÑú_Vƒío|ãÃ=ÿe]êsuÂu}¬wÍѯi:5P¯¥ÖG•³Ñô­úý»ÖM}Ï|–:RS{ª?ûÙÏ÷H×ZÏ£Ÿ—º¯úY¨ÇP?õs5:¯dö£ùdºíZ­Y×[Õzª£DµÔô¼:¿^›æ'àÀü¼Üz‘ <¿Ÿ\sõî¿0lþê9å°5íÜÓVµßýød{NŸ¯_— }^¿ÍËÞ±¬ó°5í?±²=êÐ5mÿ=fZOðæ¬lÓýóïü©í•ïYÖ~»M¨sÔšögÏž{Îë"'¿_O¿ö,?ëYÏîu®C Þj€X¿lzzzƒ_6š~òw÷wÃÌÚËxÖYg­ŸrRskïõ›ßüæá ¶NR­ójjH R-[¨¹ôÏ|æ3‡S©Ê±þ_vµ÷©O}êú£+å^%á _øÂpZV]Õ§®º3ZêÈM]Ù§Öo}_]•§¦rÕ¹uv­ßù,5§¿¦wÕ•ƒj©BPƒÓѿΠ©)Jõ³1:w¤>W{¯-Û.P¯Ç-­ëï½®æôö·¿}ý§ëÜZWæ'0Ñ÷r˜k0?3·^ä}çïð2žun@PK]æsô›×~fëþ¾µ_„d÷^ê\ËŽ¨=»5ß»î£é'£ÄÚ»\'™Ö€jÏoíᯓçZj/pœº©¯Ïõ=>w_r®=¹5 ®²5Ú»?û–u›:bPväRWƒªRe®Ö}ý|¼õ­om5÷ö4±:ÂPGê¶£r°#×bºï-­ëzý¾á oN +ÿz-׿¹~n“›çJ`[vìVu[•ï#°€jB]hö²-ƒÿúþú–ñÔà®þli©½Ò›[jàgð¿9¡­ûZ9oÉzK_ߺ¤-ߪ¦Õ´Ž2Ôú­óCªäÕÞæÙ‹õ>[cûþ{>ëºÖÑìó¶ï#qo‡€°8Ö³gI€Àfj¢_ص ]üK5ð¯)bõûê@ý,Ôï{]!jú;ÅÓ«=ý5lã£w;Ń÷ ,@S€àJñ @€ì(WÚQ²î— @€ÀPàJñ @€ì(`Gɺ_ @€ Pàÿ @…årXH`IEND®B`‚golly-2.8-src/gui-ios/Golly/PatternView.h0000644000175100017510000000222312525071110015275 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.8-src/gui-ios/Golly/help.png0000644000175100017510000000102412525071110014310 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.8-src/gui-ios/Golly/OpenViewController.m0000644000175100017510000004447312525071110016647 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.8-src/gui-ios/Golly/StateView.m0000644000175100017510000002172012660172450014761 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 // ----------------------------------------------------------------------------- - (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; } } } // ----------------------------------------------------------------------------- - (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)dismissStatePopover { [statePopover dismissPopoverAnimated:NO]; statePopover = nil; } // ----------------------------------------------------------------------------- - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController { statePopover = nil; } // ----------------------------------------------------------------------------- @end golly-2.8-src/gui-ios/Golly/InfoViewController.xib0000644000175100017510000000671012660172450017170 00000000000000 golly-2.8-src/gui-ios/Golly/Golly-Info.plist0000644000175100017510000000333712660172450015730 00000000000000 CFBundleDevelopmentRegion en CFBundleDisplayName ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFiles Icon.png CFBundleIcons CFBundlePrimaryIcon CFBundleIconFiles Icon.png UIPrerenderedIcon CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType APPL CFBundleShortVersionString 1.2 CFBundleSignature ???? CFBundleVersion 1.2 LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads UIFileSharingEnabled UIRequiredDeviceCapabilities armv7 UIStatusBarHidden UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance golly-2.8-src/gui-ios/Golly/SaveViewController.xib0000644000175100017510000001434512660172450017176 00000000000000 golly-2.8-src/gui-ios/Golly/Default-Landscape~ipad.png0000644000175100017510000014321712660172450017714 00000000000000‰PNG  IHDRºº AiCCPICC ProfileH –wTSهϽ7½Ð" %ôz Ò;HQ‰I€P†„&vDF)VdTÀG‡"cE ƒ‚b× òPÆÁQDEåÝŒk ï­5óÞšýÇYßÙç·×Ùgï}׺Pü‚ÂtX€4¡XîëÁ\ËÄ÷XÀáffGøDÔü½=™™¨HƳöî.€d»Û,¿P&sÖÿ‘"7C$ EÕ6<~&å”S³Å2ÿÊô•)2†12¡ ¢¬"ãįlö§æ+»É˜—&ä¡Yμ4žŒ»PÞš%ᣌ¡\˜%àg£|e½TIšå÷(ÓÓøœL0™_Ìç&¡l‰2Eî‰ò”Ä9¼r‹ù9hžx¦g䊉Ib¦טiåèÈfúñ³Sùb1+”ÃMáˆxLÏô´ Ž0€¯o–E%Ym™h‘í­ííYÖæhù¿Ùß~Sý=ÈzûUñ&ìÏžAŒžYßlì¬/½ö$Z›³¾•U´m@åá¬Oï ò´Þœó†l^’Äâ ' ‹ììlsŸk.+è7ûŸ‚oÊ¿†9÷™ËîûV;¦?#I3eE妧¦KDÌÌ —Ïdý÷ÿãÀ9iÍÉÃ,œŸÀñ…èUQè” „‰h»…Ø A1ØvƒjpÔzÐN‚6p\WÀ p €G@ †ÁK0Þi‚ð¢Aª¤™BÖZyCAP8ÅC‰’@ùÐ&¨*ƒª¡CP=ô#tº]ƒú Ð 4ý}„˜Óa ض€Ù°;GÂËàDxœÀÛáJ¸>·Âáð,…_“@ÈÑFXñDBX$!k‘"¤©Eš¤¹H‘q䇡a˜Æã‡YŒábVaÖbJ0Õ˜c˜VLæ6f3ù‚¥bÕ±¦X'¬?v 6›-ÄV``[°—±Øaì;ÇÀâp~¸\2n5®·׌»€ëà á&ñx¼*Þï‚Ásðb|!¾ ߯¿' Zk‚!– $l$Tçý„Â4Q¨Ot"†yÄ\b)±ŽØA¼I&N“I†$R$)™´TIj"]&=&½!“É:dGrY@^O®$Ÿ _%’?P”(&OJEBÙN9J¹@y@yC¥R ¨nÔXª˜ºZO½D}J}/G“3—ó—ãÉ­“«‘k•ë—{%O”×—w—_.Ÿ'_!Jþ¦ü¸QÁ@ÁS£°V¡Fá´Â=…IEš¢•bˆbšb‰bƒâ5ÅQ%¼’’·O©@é°Ò%¥!BÓ¥yÒ¸´M´:ÚeÚ0G7¤ûÓ“éÅôè½ô e%e[å(ååå³ÊRÂ0`ø3R¥Œ“Œ»Œó4æ¹ÏãÏÛ6¯i^ÿ¼)•ù*n*|•"•f••ªLUoÕÕªmªOÔ0j&jajÙjûÕ.«Ï§ÏwžÏ_4ÿäü‡ê°º‰z¸újõÃê=ꓚ¾U—4Æ5šnšÉšåšç4Ç´hZ µZåZçµ^0•™îÌTf%³‹9¡­®í§-Ñ>¤Ý«=­c¨³Xg£N³Î]’.[7A·\·SwBOK/X/_¯Qï¡>QŸ­Ÿ¤¿G¿[ÊÀÐ Ú`‹A›Á¨¡Š¡¿aža£ác#ª‘«Ñ*£Z£;Æ8c¶qŠñ>ã[&°‰I’IÉMSØÔÞT`ºÏ´Ï kæh&4«5»Ç¢°ÜYY¬FÖ 9Ã<È|£y›ù+ =‹X‹Ý_,í,S-ë,Y)YXm´ê°úÃÚÄšk]c}džjãc³Î¦Ýæµ­©-ßv¿í};š]°Ý»N»Ïöö"û&û1=‡x‡½÷Øtv(»„}Õëèá¸ÎñŒã'{'±ÓI§ßYÎ)ΠΣ ðÔ-rÑqá¸r‘.d.Œ_xp¡ÔUÛ•ãZëúÌM×çvÄmÄÝØ=Ùý¸û+K‘G‹Ç”§“çÏ ^ˆ—¯W‘W¯·’÷bïjï§>:>‰>>¾v¾«}/øaýývúÝó×ðçú×ûO8¬ è ¤FV> 2 uÃÁÁ»‚/Ò_$\ÔBüCv…< 5 ]ús.,4¬&ìy¸Ux~xw-bEDCÄ»HÈÒÈG‹KwFÉGÅEÕGME{E—EK—X,Y³äFŒZŒ ¦={$vr©÷ÒÝK‡ãìâ ãî.3\–³ìÚrµå©ËÏ®_ÁYq*ßÿ‰©åL®ô_¹wåד»‡û’çÆ+çñ]øeü‘—„²„ÑD—Ä]‰cI®IIãOAµàu²_òä©””£)3©Ñ©Íi„´ø´ÓB%aа+]3='½/Ã4£0CºÊiÕîU¢@Ñ‘L(sYf»˜ŽþLõHŒ$›%ƒY ³j²ÞgGeŸÊQÌæôäšänËÉóÉû~5f5wug¾vþ†üÁ5îk­…Ö®\Û¹Nw]Áºáõ¾ëm mHÙðËFËeßnŠÞÔQ Q°¾`h³ïæÆB¹BQá½-Î[lÅllíÝf³­jÛ—"^ÑõbËâŠâO%Ü’ëßY}WùÝÌö„í½¥ö¥ûwàvwÜÝéºóX™bY^ÙЮà]­åÌò¢ò·»Wì¾Va[q`id´2¨²½J¯jGÕ§ê¤êšæ½ê{·íÚÇÛ׿ßmÓÅ>¼È÷Pk­AmÅaÜá¬ÃÏë¢êº¿g_DíHñ‘ÏG…G¥ÇÂuÕ;Ô×7¨7”6’ƱãqÇoýàõC{«éP3£¹ø8!9ñâÇøïž <ÙyŠ}ªé'ýŸö¶ÐZŠZ¡ÖÜÖ‰¶¤6i{L{ßé€ÓÎ-?›ÿ|ôŒö™š³ÊgKϑΜ›9Ÿw~òBÆ…ñ‹‰‡:Wt>º´äÒ®°®ÞË—¯^ñ¹r©Û½ûüU—«g®9];}}½í†ýÖ»ž–_ì~iéµïm½ép³ý–ã­Ž¾}çú]û/Þöº}åŽÿ‹úî.¾{ÿ^Ü=é}ÞýÑ©^?Ìz8ýhýcìã¢' O*žª?­ýÕø×f©½ôì ×`ϳˆg†¸C/ÿ•ù¯OÃÏ©Ï+F´FêG­GÏŒùŒÝz±ôÅðËŒ—Óã…¿)þ¶÷•Ñ«Ÿ~wû½gbÉÄðkÑë™?JÞ¨¾9úÖömçdèäÓwi獵ŠÞ«¾?öý¡ûcôÇ‘éìOøO•Ÿ?w| üòx&mfæß÷„óû2:Y~ pHYs  šœ@IDATxì˜SeöÆßd23t^¤ RD@,Ø{ÇÞQܵ׵¯®½¬«®»úwíØ ö‚½ ‚ ¨ˆ(½÷ÞëÔäÞîÌÉ„™”!óžçÉ$¹å+¿›¹÷;ç;ç|¾¼¼¼$" " " " " " " MÀŸÑ½SçD@D@D@D@D@D@D@2è‡ " " " " " " 5€€ 5à"«‹" " " " " " " €~" " " " " " "PÈP.²º(" " " " " " 2è7 " " " " " " 5€@ ôQ]í‚À¢uÀÕŸecüR?–¬‚¶@gˆ‹tj¡Îíâúmoô™ù×ïš×Ú5 á蟳½õBíšM`¡gì°Ô;k6õ>³h¼’øëéËËË“z‘x®*Q¶‰Àú å¹¸ù bœ³k1Ú7 Át³íZêÞ“‹wäo×}(¯ñ™Ô·¹k€ûG0d\¦]“6 Êëµ¶‹€ˆ€T'™8vˆ—o&=‡ãí³÷¸šØW¼¿€ª}–@ÕøélHã_ÏÁ ¾Å¸í€¢„”§BD ^íOW„„py ¼}Fa¼§ê84ÐØ!ðUuÊ h¼’8äÊ8–*I*M`þZn> ¸ÒçëD¨*A½ƒNøIUËÑù" " ©! ±Cj8«–êE@㕪_ªÎP%ˆ@• ,ێîrA*@*I€a'Kíw(Ø>hì°}\'µ2±4^©:OªÎP%ˆ@• 0áßöó_e* 튕8*í×@ x hì/)—i4^©Ú• jüt¶$„@HŠWB8ªªÐï°jüt¶ˆ€¤’€îÙ©¤­ºªýö«v5ÒfÈÏÏÇŒ3ân½­V€éÓ§Ç}¼(%òUB¶°ù²e˰hÑ"Wœô, bÉ’%΋Ÿ“-K×-ÄŒ“P/·!ºµè…Ü@ídW©ò“D ÀêO_åò>´©B§Bd%©²$»66ÅÅ|hm}9¾[õsÕæ[?¿ŸãÇ;%ÿÿ#‘Ýœ¼Üç´{³%ïÕ"„C;áKsÄ:ã¼r³í·’ùj†ÑJ: }µ²QƒÊŠ ÄGT|vüGü¼À‡v ChY˜»X“çCïVÑž„ñ—ï‘ÉW$cŒµ­cßûÐ'A ÿXâÃKº’mãbŽ‘»6-½FÞkè§÷Ì"RÀÆ1oÞ<ð=Y½z5,Xz $[–oX‚¿< 3ãà³ÿ ýÉý£NÝáj\Þÿ¼ýÇsxdéÕ1›qs›ç0 ÇY˜±|þúûž¨_ØŸ3o«s|Ú«³—•Ù^»¨.zdí“:]ˆƒw:|Yžòº~¡Ãðè–)#Ñ_N{3ŸNõã¹ qÖ®[·å_ðÄÏYX[b¯ÏâuÀKý8¸c9•ü…>úSþ;*€•žŸZ[KrvßaE8¹Gi_QW¢¹G–÷‹=LOx#û¶ ¢EÝ^Ÿ…¿ô᛿ [³VnNz=ïHìuˆlG"¿ß÷}žü%€]‹±©Ðg×ÊÞ-ƒøp`!ø0Zo]9Ý~ü^Ùß@eÚû¯¬2À³'$f)¼“ÞÈFw»F k•mMßV•6¤‹MÙ蛈€ˆ€—ÀYogã£Éå;Ö¾}f!¨LžóN6&_•v¶+eäšÔz4/UÀÂ{÷·¢qDâjnú*WîY„Sz1lZFÏóãõÓóLÕΊÆ±Îµ/c¬mkŒ™ïÃѯæ`Õ͉ãql<Ò®Iç-yö›œ°Ì‡3w)ÆÓÇÛï5ŒÅf{ÚwþûÙxóO?önÂ×6~Ž&üÿìø¹X»¸ïð"\½w1ÞŸäßê6Ú¹ÜV÷ž\ÜD®ê{‚;ò¸~Oå _ë ž9!Ì¿¼ò¹½’êÕ¶53ýœñ_ºti\'ÒÝþüùX»vm\Ç'â ëFž„¡…x´û—ØmÇ}0vþxnâ}x}ýƒè:}WÜé8´®×¾¤ªÿN¹ ÙÈÁÕÝþ[²­G‹¾Îç×&>ŠFͱ&g¾> w9®ä÷C×â~¸°ëíîWÌX=,ywÎ:mŒÂ¿»|€à–—Ïæ¼Žo‹ßÂ}ÞBÀ—ãœÓ¢~›’s“ýá†/²mv6Íë%»¦pù#æúÁÔ™×æ;äm­õñ1Y¸ÙŒWìUŒ¿ô-Fmû•g3äώ͹ïf£iBÐ!l¨j]ÛÚ¶Êë7\¶G1n?¨ôÆ0àÕlÜ><°]®Ù¾ÜŒ2ÿú>€_.-(ðÐÓó‰\¼k7Ú3{Qh÷Îv͘à(r¯µ‡^£çú0ЖÃK¤ãÍ(ÓÆ‘|âWDž“ŽïÛ2ÖøÄ&à^ÿ3 ŸO7OÂÄ !œn¿s1þwLéïm’öx:7ì[Œš„ðÉÙÈÙN=f+º®?Îóa¦ywn¼5Ô9•¯4­ÚêÖ»{ýì¹%§ «V­rfñ ¢[[¼µÒÅñâÅŽ¡ îþnÝùEy˜›5§Õ¿ÖQþ¹½_ÛýÐ~‡qʨ.øjîÛ8¬Ë‰hZïp÷<>µŽr±o§ÒmÜɇћ†áØÆçãÇÕŸáÝÙÏD5Ô÷ïPæÜ}q8ºÍíƒë¦ 0eu.Þó–’º~_6ʦDþíIyHB3Sú©p\ýY6ÞH·¤ÓUøðœ)ú|À>xdéÍ­Sãbìg3è»™•í™_³J U¨&e§®/ðam^ÙÕ“6À˜¾*úLô>\ûY¿.ò£¹y \درF™^{À 9xÚÎ¥;Þ SÄ})]ä¸ß3ÂfÛÿÊÉ…Îñ­ ~Üo3âK-„‚ƒ“ÇŽ)DÓºÀD{PÜnF ZFoý:€÷+rBâ²ÁúC¡;¢+­ŸžSàÌ”ÿ¹ÔΤPö|&÷.ÆJ®þ4Ü/z>Üup‘ã%ÂãÚñ4ê¼öG¦XhÁ.RðБ…Ø­uYn<6šؾ{µ â­FdZêíØDmcÛ›¿ `è„,s‘„ã)0ø¸BÇÍûn2#Ööðßl?ã=­mÏ_ˆ5ùÛÆ¦ª×*Q}U9" "PPiÅcÒí{sÿ²Ct{L2Þ+GP!úÛ'œj³öþ…‚bþyH! ƒ><02 «Í3î<›PyÀf7)sÌqÅÇü´Àï„îÝ%>¿ê„ç¨ÊíByãŠÿ…ÚöØçlû+¿gaêÕë ÞJ*WðØMVäßí¹ú‰y%p¦—mþŸkNëyì­‡ŸcE"ük¬A/ ?ÌÆ[gbgsǧKþ_ûãH ïäØ'™â¤êå„ÇL4J ÜµØ -%·ë>àóY¨›ÂÍûᱟsqøM°1÷_öä°sËmÜøO»QÊ»æéŸ´°°z™ò7v÷!áöy¹¾lÛ÷Ø1^ Wö· œtüϺõ'ë=º‘€Úè¶Ï¤}³fÍB<Ê?Ýý'L˜àR©ü³«Eù§k¹ ò–éyÓz-pS»gqðŽ'•ÙëËSßŦìµ8µûEØ¿ññø34ëóâódèÕjGõÈͪ>yÕ2EÊf0éÖöžÍÎV$te;òål´|0{™òv‡ÍRÓ€@¡‚yžÍìaû½Êc›ö}./Ër¿;¿ ßèŽ=§D —ß_Æ›ña)¼™Òˆqb÷pƒ¨d–WãÒ©€õz<mþ“븣²ÙaW¾0‹,ÛL«é)C³Ñö¿¹ØùÑ\§‰^Ký†}Š£ÅþÏ›2ü]–3SÝÊnbŒ™”v?>â•ìi7°iWçãy ßxÜnÔô~àMoÇ!|aqé”ÑóÃ9¾Üò}œ]‡›ÂVÑïfû%ÿÅ“ 1ùoùÎyg¾~²“ wÙuºº‘cX‰lG¬ïŒ¯?m— ޾¾OÿVÚû· 9Jp³Ê¾`í¦¼vj!2Åž cÌî ó˜yM>n2£•þ¹kÂ×dîZR¸ÿ°B̰ý't+ÆÑVþj³än0¯9íåþ6yƒ?ܲ;E±ÇêK<û¾œ™åç™«í±ÆËmìÁ±ÀÔ~ó ØZ1‹U.÷U4®à1œÈšm†‹ïÏ/À¨ ÀqÃ-6‰A‰õ>>§ƒÇÀ‰& û|¤9OìÄts^·O1îù.àä«âþX×<ã¿5û3lp²ˆ:‰W˜ª6|–çšÑÅ+ÞÿYw; U}@·GsÐøþ\Ð+—ÿ;‘ïq‘çU¤ƒD_™ï 7)qœ®þtùG‘§¡€îþkÖ¬©LûrNýZ Ñ3´† ÅÂÏg`ß&°û£Ðµy/ÓýŒmªãƒ¹Ï¡mqw´nÔ§îrÞý †þñ.Úó1Ë †Ìç§ÛàeáÐÎñbš tÉ~{bרÍóÀùN¬Z´¢'sî{ÙÔ»—ìQè¸Ø<4:àÌÈÒ¢é·çÚ5¦0rúz +xÎâ¬ù#ÿ«x㣵±Àþï²|~Ì7…VÏö·¿­r’)øÏ؃äèW²qñîÅ8Èr ì°Å¦rœ%ÏsåÛ­®"kÃa/ç8–èëífÖ × 6{œ$èÅø¡•¦Xþn<*¥,‡F’Eë}ø¿öÏÅÏ磱Åô%BG·g›|¼3)¬ü?:ÆïXʱ:Oòä3`]˜âØÐÚ{‡… 0¡ ·PæD º}99ö/Æö°ÿ›…I|jxÊ7vã;Îbò)|Ð_jaŒ?]ÏþaßåÚÃ9|ƒcn…OíAÀ™öÊÈKæep‘T>6Küëv#¾Á¬Ç|ð½|RyÞ D§ÂËdyC-n‹Æ ¶Ÿž û´5‚Yï_ïÇ-†Ûü·½ÌÑ>ÜžkÌ;á‰YΫ­ Rhˆ&44tJ‚Òï­ëG3´L_YÊ)7+äÌò÷ß1ˆ÷Ï :V~nhgÂJJû`2BžË~òZ¯²ßY¸FŠxØ01dU¯•·/ú," "Py4JsìÀ±N›-Ï´9«ÎXç8{¾q[2$žqÇ XÜs®=‹Ž³Y\ÇÍŒíNR\{.Sáç3Šymè*ÞÇòöpœ3߆ïÞçWyí¯h\Áó^¶±ÛQ‰5®hfÞ‹oüáǯzèŽ+9u ±žÇÞ¶|d.âåEèqX•±=9i“ ™cclN2P8²Ú&Îæ¯ +ýn‚iî£à‰~Œ¿¼­ÍSÓüœ1å™[¼49ælgãÄË÷ Ã8^á<´Å“²¢kžŽñÉ9¦£<0"ËóÒÀâ ÇÆü=µûR:fôþÏòX=öy6ÇÉ_uíÞEà“ãgN:y%Þã¼çðs<:Hä9•ù^ÚÃÊœ圹sçbÅŠQöDß4iÒ¤¸Vˆ~vâ¶>vØGxö—ðíªwðÒê»ñš»,‰ß8°Þ)¦´Þ‡Ú9v÷¨@Ön^…ɳ›†•ýæõZ¡}ñ.øzÅP\„²€?ƒ#qܧé}°É¿ÖQþÙå3ìØ¨C5¥~÷£G›;õÓ¹ææ“íÜ #[g÷¬¾ÌÆ%¦dþ÷¨RëíÞ¦¨iÊô¦ìQ9£ë90TøŽßÙ¯ÌÚÍl¤,pf¨/²ó©pÓ˜p…%‘aÙm•ÿ˜‹¨ÁæêÎ;ágÿïÄù»;‰óXfyu=c³åt#oVmμR8ó|”î6Ëæçç–Þ éRŒ'+íï1vóëgqTüÀ=Q܋¥Åÿ—7‚filkÉ‚®5c_\Ýà?£²ð3¶`¯ð¦Î‡³÷Ú£YsÖ„ÿÕéj®dfÈ¡{”)—CO-À+ãs±Æ%Ãmfâ–Â7qºŸ0WÀÒ[-§óÍ*L¯ÚvŸ«¬òÏ›"•ø}í÷°oû0;æ8÷ý\ùi6†]Ê×íÛ,kϯ6hênF¯ÔïY:Xêfר+ä@¼ÎGu±§Iî<(z€&WöOû=Qɧw÷®ð·úOûý³‚-ÌžŽÉK~G÷–}JNhl‹CšœZò}eÞ ß4O¼/´ý¾d{uùÐÆáÛ ôŠaœÖÓÆøx…D—˜G—%*û^id³ïïOÎ2@XÙ»Ì,…T6/°‡Qf‡u-²Þó*û™Ký1¶ç6sgcq<£,Û)]Ûè^Fkä¿l%Ư—'t‰§%–7¶9Ç”¾f¼xôÇ,Ç3À=—¯ÐÐÀÕ XÆ=‡x÷TîózãÓÙ2’z33É=î³Äu|yg ZÚƒøóeùóÞ¢^øÍLÃ{˜«9Ýú¸ Ì@CÌ´•æŽØ.¬|·¶Yf1eEWܺèæDKeå-›™ÉÂ=F\Pª”3Ày}‹,¬ÀF Q¤íg(ÀGãÀ² ®,4 ¯,´ßc»Ž´ð³Ñd`¯b'¯A´}ÉÞv•;è­Á‡]œxî·ð-™nc§õ¤'M±ó{ûb¸¢Àâ¿—5ø°±Øð7\•k•l*_D@2‰@¶ÝÂo6¯»HaˆWº$žqDݲ“—1›ÊYa†h2_ëUÉU£*’Xã Ž ëoC"ëªh\ÁDn”åöl¥Á‚‰ž1–ÀãœXÏãðÑ῱ž·Õu¬ámyŸ9®äÒãm‰@¯0…îñ/R¨Ô»B–_Î,ýîì_Î Áϱ®yUÇ’n*ó~®y0´³ûô¦Þ¼‘îÿÑÊfH@óöp•÷˜Kv/*cˆ÷8÷|÷=„cùªJôQqKmÞ¼9¨Ø7j´å×£¼œœì´ÓNèÒ¥ rs« UĨ£¢]#g}Ž[‡ÿµä°z¹ pT·ÓðÈïâ˜Üó1%ëg¬Ú¸¼dy¾Yõ&êÕǔͿbìúáÎ+/´ÉföýxcÊãeNkè€Ëöº½äuÛOàó˜šõ+f.Ÿ\æØêòå¯v“<Дۿ™âÂc¯0³-å:K>Çï‹ÇÒ=Þ+Œ§ò¿ƒýˆ©0'ChÅ£×­êŒ[šb±jtѺůqmÚò„}¡‹ž·üLåŸâ]?5šá‚ÛÜØôòêˆw;oL´TÒó‚J!…–Ê—ÌrYÏþ]zE¸àk.ü|½k.[”UvÎlù ³Nºr‚ÅjÝgÉýöÙWÆ5é{ΜY[î§YØÁSf0qëd\"Pï €[Þ¶¾3db’µ‘ƺRh½Ó’áÑAqÛ±q‹3-ë?/ôÃÍÃÀßCI;é Wpó/ð8~Ž·®$Àh/÷Üt¼³í½[Úr£öàeÿé~FÏ 3ÿža9h•çþäÅ(?‡+Å&\ªþŠ€ˆ€$“@® ®´ÐºÈsܤK¶uQQ;™àÏ&רÁdnœdqŸQåŸÎq3¹›ë¢Ïg.ãÿ×Ú;%Öó8|Døo¬±HUÇ ¥øŸ3¹¢A²…c ŽÁùbN.æø¢â9çøƒãþÚ„¯9Ç„^ÏPŽ99ø‘å3¢P‘v?ó{2¯9˯¬0|– ;92>à(ôñx¶2T‚Æ’H¡Ç0C]‰÷8÷x÷}[t÷œÊ¼‡§›*sf縊=göçÍ›Wa"À† -ߌÌÀ•âÉPAâÞ],ÄwÅoã—yçav–9¯Y­6€Ý Ü%ùÊìô|™°x,gÏÂõ-ÇɽÎóì.þüü´ù+£Øf,Ã?¶2lù²ŸåxÞBf¯™ŠÎͺG;$íÛž2wwº¸3“jSN]qÝľ²µ59S)^Å‘Éf˜O ŸÅ|3¦œ–WÆn%B˜Àã8KÆñ‘)ü‘Iò¿tÝ>E8Ûb—ÆY¶Òö;lѶ"*f_è"4Ô<¢ 𮕔IóÕ.Û_nk¶ÅjíümÝ6ä”BËΛNæ ÀX£µ«Åý,l‚1áðc2Áv3ƒëÍ_‡oìŒÇb¦~Wçÿw Á¸nŸpÿ™=ÿJKès§g™Á³- Œûçö´ž?vl!è]QU¡ûØ[§:Yc™,†æÅf b¼ú#jBaû˜ñ¦ãù¶.m¡“UùE‹c˜K>{×§¨L–†›ìùL®‹ÈЧ,#±»ÌKÏæ¥ž Um¢Î¿bóD±ÿZhÔᲕÿ°ÿ+&üÀBU¾5+s;ë ãÃø¼ÿ³ÐZéùŠ—Í¯ K $‰j·ÊؾT8ŽØ†îp|Dj×'s±N{—ЛŽËûžjÆêò$Ýã ÆüŸgž§LÚÌ "Žù¬¥ÄzÞ¹´OœñŽ5©ÊXcÖ ô *z;&r íz¼ô›ybÚË•m¾–a†Ì)ävñGÙØñ¡\Ç£ãÉIËÃê#ÇÕsrå© >‡ ºž‹,'™×<²Ûò/§Øo•al# ôŽG˜„›ãüHáÄÃ%\‰÷8÷x÷=Ä=¶*ïI3¸¢@ýúõ¤€Ë–-³nYeÉ=Žï~3´jÕ Mš4IiXÀ>Gó©ípÇ„A¸bÿqxדÌ2”‹3?Ã{+ž@G_/[°…·©[}:ùqÔ.ªƒã{ž³Õ¾mÏÅ¿]‚O'¿‰=nµßÝкa{çã² ÝMÕî³ÛŒMf OÏì3g¢©ŒÒ ¼O»Ò›%-™g¼•ã$‘£‚GáÒqÌÄ:Ö’±Œ°ã/û(`ÊŸßQòªÚáÝZ…ëàlj¤€e3†âs6xþÐRÿ¬å`b”¦ˆºÂØf¿gfzWÞ¶™ö›·ÄÍs­ÊL2Àbí%|à0‰"]öiQldnã Ép…7àwl1cÛÆÃ,~œ+}#k?t^¡—÷x*ÉÞï<–3ð÷[®^ëuV´7¡!“õͺ¶´>oÙñ~>ļã.+p2!¯2å–Iu¨ô{å+ËŽï•£éÌ®á~55«4^!ó'Ž-r¼È$r¿÷Øò>‡c0K¿åïö ·—Ïéœ>A›ÙÏw¬ï  pE—}Z‘ß?«ÐÙGcC;¼Æ—xÙ$âZ…[¦¿" " Û+ŠÆ=š‡°ÄV£q…Ï ÈqÁŸW–>“_µq—æøÂ}v3‹;ûKáÍä3[/—Ù}%©#pº%ÌKör~©ëj¨).´ñ•‡“-Ï΋9Ψ)ÔÏêIàÃ3Tñ‘æ¡ÂÝ—† ÐÄñ2•èæœ0U~çrÎÛƒpÙò»mb0žänhøa/° Îã-ä˜Â|f ³9áµÒIàxsËuß·Eqϩ̻////-šJAAãæÏ€ñH~~¾s<½$ÕŸ]cèræ.)“Ž3ge‚w–®3ƒ—*¡Õn[„ R˜%4rÖýuËØ~‘Œ͹>ßâãáXyc¤E¼2R÷žÜ¨®_•)«ºœ“‰}rÙfjß2µ_îuÓ»ˆ€dš|Ï®É}çoXýOÿ¸™¡¹ ƒpWH(ïÞïq‘ç—§ƒDW™ï)õð6Ðuó÷n‹õ™+HùE¨zíóÆÅ¤«et¥f;ÚYÞ‚Ê ½øŠ%ôˆÐìs,BÚ'" " " " ™C€!5|U$ñYN<:Hä9ñ~OI€x£ãD@D@D@D@D@D@D@’C@€äpU©N`_KòÂI…NÆöDtÕ§ÿÄD`TU$ ßaêtH!ݳS[UU+úíWír¤- jÍÖÙ"^\‘¯D‰ßÂXš½ID mø;”ˆ€ˆ€l4vØ>®“Z™x¯T©æ«ÆOg‹@B´¨̵µV%".s·$îLWýªWD@D`Ûhì°m¼ttfÐx¥ê×Q€ª3T "Pe»¶âÕñúw¬2HPi\¾³]ÃÄyµTº!:QD@D .;Ä…IeWª~APu†*AªLàÑ£ Ñõ‘\[¶Ð‡›(v1ùT« ˆƒ=Oh|2. Kþ‘Ç:DD@D :ÐØ¡:\µ!U4^Ii_^^ž¦|ÇS%‰@¥ l(Ž=ó×ú°t´ÿÌÿ;õZi¦:±|L Ã¥2[Ô8‹Äd›å¯=" " ÕÀzÏØa™;vV¿vªE"PY¯T–\ùçÉP>íŒ!  ãŒ¹”ꈈ€ˆ€ˆ€ˆ€ˆ€ˆ€”O@€òÙhˆ€ˆ€ˆ€ˆ€ˆ€ˆ€d 2æRª#" " " " " " "P>Êg£=" " " " " " "1dȘK©Žˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ùd(Ÿöˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ÆüøãûÓuDD@D@D@D@D@D@D :_(ô[(ú.mÈ È”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ 2Ä€£]" " " " " " ")dÈ”+©~ˆ€ˆ€T’@(ÉçU¦üXçÄÚOWÜó#ßÝsÝíüÎÏîw÷=Úqî¶hï‘çE;&žmn9|w?ÇsÙÖãã-Wlj€ˆ€ˆÀöE °}5W­Ê0%0TÛ^YV€ÂÊR̼ó|€¯ ü‚}–ˆ€ˆ€ˆ@ ƒ/®º&" "P)zå‘©yÛõ[¨y×\=šK@!5÷Ú«ç" " " " " " 5ˆ€<jÐÅVWE@D@"øèþm¯ÃªyX€ÛÖ`0¢ž¯þ-výTõÇmÜùk[ˆ/O›âùè–ãž[ò};¸.ñôOLj€ˆ€ˆ@5! @5¹j†ˆ€ˆ@* PñÏÇ܉31{Á4éÖ]Ú4D-¦¨v¶nÆ‚és1kQ!:÷ê„VMêÂôjÙvŒ3fü> ã§l@Ïýzc§6; @…:Yâ`ý¢™ùÝ/˜8o @Ë®»àȃz¡Mc˵ËPQÒ&¶; ¦ÌÁ´9ѾWtnS §ÌÆÔ9ìûNhߺQrûQÒ}Ì'àšì3¿§ê¡ˆ€ˆ€¸8ÃZQ߇›Oº ¯Ž]Œµ›M¡¶ÍÕNœ¶®Ã˜‘#pîáwã‡Ù˱±8âñÍc‚ëðÛo¿âô³¯À/ Wac0Y±rýøãÓ÷pç÷âá¿ÆŽÂGý€×?‹<†Ï_ˆ<3T(N»×cÂï?áì÷bôÜåÈ nÂä?~Â@û>jÖlEôµÂBu€ˆ€ˆ€ˆ@yôT-Œ¶‹€ˆ€d6s—϶Yêü‚å¦ÐÚL¹Ï;£îé:•T*³e^®ríÙÇã(>{´:ÇÚ»{]óK^ž²ÜsÂgn9Ƴ߿¥¶Õfó ¹¹äd™«‚Û–²—¯:¶íˆ»o¾ ›ÔC.Ÿð%uºmÚRv™zí\·,·Ýîû–êÝæ9ïþlÌùn$Þ~(¾±k[tÇå7_ˆ»¯>Ý›å`ÓÊÑðä˜:se¸~žä´ÃÛ¯-lØnÛ—e1¡Í@1ñ…¿ò»1²JÎ Ÿã\¥hŒË4R_D@D@D@¢°§±DD@D@j&Wަç:DLÙ ­žÏÞÿï}3 ›MamÞ®#Ž>ûì×­5êäͲ}£ñõØ Î¼æ(ôíØ y³~ÅÇŸÀ¯»â²söEçV!Œùø[|;݇=»æbÊŸSðã¸YhÐc\|Áè¹£¹êÓSßo3áÃGàÍ÷Æœ5yÈnÐ'üõ8ºk;ÔËe ýèëÛ€_>ÿ¼½ 3,$ ·Ë~¸ö’CнMc³_˜j\XŒâB;Ò<ríØß>ÿ_N*Âî;×ŬI“1ò—™¨ß­?.´zwmßÄ\ë휢Ö¾¯ñÊÐß°¢þN8éÐQ°f9&¯iŽ¿œ±7ºµoTêÎOÅ;o.ÆMŸ†·‡ÍǺ ¯Ä°kGïÎ;X¥ÙØeÇ&hšw?îyá≠ ºtnŠ:š0uÔh yu8&¯ÈCQaö<åœl´j†°wY%Ö‡<²|µQ»V&…qÆoE·ƒ1ð°]ѱE=,™0_}ü¦î°7þ: Ÿ…;Ô±6–cÀ §¿" " " F@ý D@D@D ΂o˜W†|ˆg‡ŽÃ†U°ª8mÌǰçá…ÑW¢½ ˜?{ yrúÿõ@ìbîê—,ÁôŸGãááE8óäÝ­ä.\„/^û#šø°xáZæÔFÃYoá²¼FxõÊýЩ 0òaxþqSj ò±b];4]Š_N›ˆüwoÅIýj!`“þõÚ×èOFcÕÒ Õ®Ó^Þxé’ý°SëB,\¼O?ü5ºœzv/`ÉâÅøüåQÑ2€¥‹Ö"/‹F³ßÁ•ù ñÒ•¢kÛ"|ÿÞxâ¡/1?T€UëçcÑô¨“µ_/èÇöFJRüÁ—…¢e˱zÑ|L.n†ÏÜ :6³iûp®6û†›{€ÜÚ¹6ÈØˆ±}gîy㲊°ré&ÔÇ’‡þ‹Ùë¯ÂͧõGçf¾è9C…ùk#+o–Nüw}ÕïÚÁ >Ìœ>¯ßþ<?´‚ìhWOÛD@D@D@¢0S¾DD@D@D`k~,[Š¥¦àÿ¸®/þ¿ÿú ^ýi޾ýfŒøú\y\WLšožãcõÚû^0q üýOÆÛ_?…·<{4ÛŒŸ^Ÿ„5ù›±nætL;ƒ¯¹Ÿ}y?nØuV.Ch-]ñ­§d÷ëV®Åš…3vfth\ i™X7ß¾ý¸ïE<ýüÛxøáwñÓœ•X9{*Æÿ<Ïý¾']{-F Ÿ<~é‘…oøSæ-±‚³àF:¸µ„ß‹QXèCç®­Ñu¿ƒà;37lBÞºX½t¾Ä^л9Z5ËÕìYpú&" " å@¹h´CD@D ¦ˆê<,@N§þ8ïÒÚhÛy>}êY<³h æ-ZmZqÀq¡+«{i•µ¯‡l}:âªc»¢yÓVÈÊ­…jÀW/ ³lX¿ëVÍBñWàÄmЪmœtÁØ÷¸SáoÔ ÍëmBqQ1¦úúâ†#wFËf­Ð¨ycthÛ> -ð»± Ö„¬- ¿1 pÅ1]вyk¬µz›Ô1cë5CÅfS¨×-Ÿ‚à™×㬽º¢S»fhºWoLÿs,>z)L%²…æj_XlSü«fÖ°½LÒ·yæÍ[]„ý{ÔÁÂQEèrÂhnîÿë–MGððSpÔ®íѲa`·žØóÀþÀ[ßcÅæXkJ= ¼ís°¨µZ´EÛö=p0†bœ­ØÐÇr¬ž;ÁÃC—fQߌ†W"" " "․CD@D@2—ÕÜ\SèýTC=Š4|ÙÈŸñÞyõc ýfæZàø=¡iq‘ÄWrjv¶ÙQ¼Ò‹¬|7Î=·^ÔjÐXdÅXÌW¾BÓb{XÌ|nŽSvýÆMQ¿q‹­·v[!îþÐF„èU`¯P±/¼Òžå0,/! *2›½£"Ÿ[§6r5·z­0§^k“%ÞËiVß’ Z£M™¯U'¹umV=ª„Фy4ëÐÕÂ#>ÀÄÕÐÃ’îШŽx#&:Ÿû 7Œ˜éxDd[y~+m!§V­p‰µk¡Žµƒ^ëíA‡¢kûÖ8â´ñшßЦIæŽù—{š´4†,…×͹vÖ)7€»yø"ÇÕ`Ëwn’ˆ€ˆ€ˆ@ #PvŠ¢†u^ÝÓ W¯]k³ák±iÝz¬]c.î«Ö˜âÄÌ)K1í§¯1²ßYøfè½xì®3phŸ–¦P¢ÐHf¬÷3W@h 6lö½ó­Á¼™k På.+î3lQXm¿)ª¡ eîË® ÿ‹?`öƶ1ˆ1kzŸŒ›ÞŒU‚ÈÎâ#;D½=¦Dî/óÝêò9Šr¸ˆ-µ›¡èIsÙŸ½ –8pæ¬ùøã—y¥íóÖ*F E+4iÑ=,Iß}|„‘¿ÎF~îhÕ¾! ׮¬?æÚ¹a HÐÂ#B¹õáíWÌ^µÎ’üç¢`yQL›nÇ4° ÿö¶¥ü2íôÔYlmlÖ¹ :î»?~>_Œ‹~<‡woŠ–YyP,[Œ ?ýŽß'/Å:.çè/²ùóðóè ˜³Äê5#JpójÌ™2cÆÎÀ²U¶Â@ô¸OÍú(" " ™G@™wMÕ#8 ˜Úœûa⛯áºsÌ->œnóâ…è×}8ps6i‹&3þÀoÀ›3gàÇ1ÓLçÌEN „ZÍ›¢^£ÆèÛª!^~h0~iÄòù˰p³e¥7Ý´Ø£®çØgú”Îz›¢j3ÓùææÞ¼[4ÙyWÔÛáO<üïWðU£<,›·C&ÏÁàfµQ§v¶Ë(´s\eٙض2Í!¿Dœcì›[O™ïM0Åö}‰}™e l’©‹n– p¿3ÛàÍdžã¦;£©]ØwŠß—‡53æcþ>v<—*4 nƼàX3a®…ÂuÆ|ù380ïcï$" " "PsزÁ¿y†<5§ãꩈ€ˆ@M#`»Í‡8CM ™m .gµ=nñΛZ÷gY¢?˨*Ü„å+×!¯ØèíP¹3rò³ ÝVذk6ÚJµê¢~€£|óá°ýtsg= )Èʦ—Õlšn‘ÅüíÈ@¶e çÕÌÛ€¥–eýÆBÔ·ÙñÆê!×´w*ÁE6Ã^\leX™,[W X.Ôû’zÊãsE;ÇÊ˶„€X³¿ü1 g`·vÃ.]ZaÞ·Ÿáù‡îÇý-/ß·ŽžLIn­(“A°h3V­X‹µëó¨×ÐøÔ‡¥0EÞq[ Ë:o ;=+yÜÚÍðåÔC“Æ Ð ~ö–ä…¦ð[»KÛY¶ÝN¾ZÈŸÿ^{ñE\ôï ûþb¾G'dÓb`4#J )¶LaÀê´ÈŒ2e² ZÂÌCÆœ×Ŷ9b}ùö¢Í&È\òÈÜk«ž‰€ˆ€Ä$`ÊwNÅA_N]4oi.ñ&ÞøùpÑTóýÈ­ßÀ2õÛg3$DS!Y·&ŸÅ¤g纆ˆpI,;«v}´jS-Miö™2ë+Éîgm¥â_RˆíRFÙc,¹ åÃä‚¡u˜2v4î{mv>š±~ÅRL³»]Ù'qû¸µpY¬œ:6_Û’ñ9]/áSZ§gýògÕBÓæ¹hҌ߹ÉËÉÊ)ÓNo»í`Ëò?ýûOñú¯á‹Éó°×õ7 m‹faQj”ð›A$Ç^^‰,“É#™{×g¨ J†5¡³ê£ˆ€ˆ€T†ÀÖŠÿÖ¥ÄsÌÖgm½ÅQŽMA¦‡BR…‰›tÇ¡GU‹ßÁ oÁÈ‚¬YžKÿó$®?s/tje^nVýrno9;=›ã=ÎsJÉÇ<[&qΰQÓ~ Þ;¾º´­gí*5”¨" " " 1 ( &íȦP— Èœž±'ASˆ mÑ?s½Ï¶ÙðhžÑz²óè>ô(úŽwÍÊ—z D;3uÛ‚ÅîPdié%a}£›â„. HO•$" "P È :_µMD@D@â$à·˜öÜ ÀWóßR.—2Ì.‰‡÷V–doU|f>†œ²þœ¡Ý" " " Ñ$Ò„­|mHmTþSÕ,Õ#" " "P=ÈP=®ƒZ!" " Τ¶´äT V" " " Õ€Bªß5Q‹D@D@’BÀ¿Åzƒ/‰x Ð2$׈>‹€ˆ€d&2óºªW" " Q TŸ¸ö¨ÍÓFH"…$®ŠêB@€êr%ÔH"’WE‹€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@u! @u¹j‡ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€$‘€ I„«¢E@D@D@D@D@D@D º º\ µCD@D@D@D@D@D@’H@€$ÂUÑ" " " " " " "P]ÈP]®„Ú!" " " " " " I$ @áªh¨.d¨.WBí$ ‰pU´ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€T2T—+¡vˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ ÈD¸*ZD@D@D@D@D@D@ª ªË•P;D@D@D@D@D@D@D ‰dH"\-" " " " " " Õ…€ ÕåJ¨" " " " " " "D2$®ŠêB 0l؈êÒµCD@D@D@D@D@D@D I|yyy¡$•­bE@D@D@D@D@D@D@ª …T“ ¡fˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@2 ÈLº*[D@D@D@D@D@D@ª ªÉ…P3D@D@D@D@D@D@D ™dH&]•-" " " " " " Õ„€ ÕäB¨" " " " " " "Ld®²E@D@D@D@D@J 4¨ôKš> 2$M5«Zt ÝW@õ‹€ˆ€ˆ€ˆ€Ô(Ó§OO[»té’”º­îø6#çø°x½ÅÅI©F…Š@Æð™o¾ß4¯´k‡ P?'ñÝ• ñLU¢ˆ€ˆ€¤ŒÀºuë0kÖ,têÔ 4HY½ªHD@\Tþwœ‹µ›Ü-™ñ¾ñŽüÌ舧uïÉ…úåR ?Î]Ü?2€–äbÚ5ùh“àG» Õð¢«I" " "Wù/**’ `:F¶3»ï¾;ÜW¿~ý¶jýرcñ믿–¼¶: EnžqʊЩ؊@ûFÀÓÇaÇ!\óY6Þ>£p«cª²A€ªÐÓ¹" " "&k׮Ŝ9s°ÓN;aÊ”)ÎûÌ™3ѱcGy¤éš¨ZH$K/½—\rIÌ"ià‹Ç <O?ýtÌ㓵ó‡yÊ+ž,¶*·æÔ;ˆWÆ'^]×kÍýM©ç" " Öq+ü@IDATÛ)Wùïܹ3êÕ³`A¾óûìÙ³AωˆÀöI€3þãÆ«Pùì<ç§Zé–“j䪯hß(„¥ßQÏT%Š€ˆ€ˆ@ÒÐÝþüùÎŒ¿«ü»•ñ;=èP¬ \.½‹ÀvCà¹çžÃ³Ï>[¥öò|–“J *á_*q«®D 8˜øÎÊx¦*QD@D@’F  G¨[·nÔ:¸}—]vAVVVÔýÚ("P= Piç_™Ö²œT*ÓN#"›@H€Ø€´WD@D@j¿?¶ý¾¢ý5‘ú(Ûºí'JùwûÍòÒàÖ¯wêI ñYªg?Õ*¨–ªêö_^§Xnß¾}ËÛ¶í=[„в^È©¿Èf8ç®ñaÞZ‚I˜íLW'¿šáG¸‡átn_®Ì] ¬Éó¡w«Òmî>ï{¼ÇyÏIÔçÉË}ø~Ž›- }/»f‡v ÂgëÔW$ùEpÎ;b§ê{A',õaÑzhD­ì²=bGÎõÛò{!ôlûú”=sûø–À´iÓŸŸ^½zEíõܹs±|ùrDzé‹çWµ”Ò\î¤mÛ¶hÑ¢EéÆ~š1cÖ¬±#„k×F«V­Ð°aȽ•ûšì¾T®U:KD@D ×}Àà_²pnßbÚÙ?ñ ŸåI´Ù½m=¾¼²Ïz;M.ëiÀGx{üÚ±÷R„¦Ñ£Ê+²Âí#çøÐ¤Ð#\v^86mÚ„ß~û «W¯F“&MЧOÔ©c?Šj$óæåå%l,ÈlÿÉ–Ÿ®ÕÊë× ûaS¼f®òÁo÷&; Øíæ¶o²ñúø²÷òʨîÛOz#Ý›…аPl:äK|èÚ4„ÁÇb×–! ›–…ѶzÂë§Å^â-ÞãÍã¾ï³ðä/ èZŒM…>üw”½[ñáÀBdWa¶rpÒëÙØxG~•šõé4?~YèÇoý|­RÁvòÿ~ 8¿µçN,ÄY»–5T¼;ÑK>ÊÆ9}Š1øøÄ×]Õ¶Wõü„ªÚˆêx>Ý'Û·o_¦i|(ñDA×®]Q¿~ý2ûõED@D æȳ1Ûfadž!¼=1 ÿ9¢õr“ÓÿhŠ~y5•wl,Ã@yeåØ(ብƒÓEë|>Û!ã³0q¹ßþµD#”WtÔí—œ;ñø€ÌpEí°6–!Àe,|ðAlÞ¼999Îä[^ýõNrKüÒK/9+^œzê©eÎöeÅŠÎñGqvÝu×h‡ló6&á|ôÑGDœ|¯ªðÿµ¢¥þªZËçÿeîU­;ÖùMɨ®ìgÿûo^ˆ›²ñåôÌ0 ÃùèñXŽVÒ?V(ýÕy[äÏÓ§OGãÆEš¡t£ªU«Ú´iƒ ì×µEÜ¥Ž6lØ€ÂÂBgÆÇD®y¼dÉçAÁ‡³ ï¸ãŽÈÍMìt CX¾7”…… ‚ë2³Í´V·lÙ²dmf¶·:ö%GmˆÀ‹ã8´s{µ a?se}á·,œ_MgsâëQüG¹S1†þaƒ&óØÃ¢\9½doÚim«e£‹}Ûñ6ûÕ~‡p¹t½Ý»?Í÷ƒ1¿t…½nï"œfÆ„¯gš‹ç·'øC›g²»Íåó0ãKah‚ã—šwž¹ iq¥·XT¡j¸fýÝ^pr¥  À3qœÕ­[7\vÙeŽ÷%'_þõ¯aÙ²eŽBOãÀwÞé„l¾üòË`8*ÏéÙ³'Î;ï<ç¸gžyÆéú|€yóæá/ù‹Sö[o½…1cÆ8ûöÜsOœ~úéÈÎ.;€Æ¬Y³fàkôèÑÑvWj[ªóTÕS)ž“~[äÇ_ÌíšÒ¬nǘ‚Æ{ÇÐØ"A†œRˆ¿¼— º†dJÿ›æ1ð¢)οš›ø^;ò~ÂÜÕ>»G£ƒ}Þ­uÈ1Veß§®ØZ¡öTôÓM ~Õf–쾯­¶øÿ…v¿¤|fý¹õ›^;µ½šñؘNy33¯.u¡g~„K†0ßr%¼sFÅnøUéPGcÇ{óQCrœk@ϬƒìÕßžw®|gJüíÖf^Ï{ô™oçàkó óÊ&ûzÌ«9¸ÍîÙ<– ý@3üdš¦uì~þJ®îÞGeœ¡Ýìùp®ýÜXüÇŽ-Bn´V–yJb¼öG–chb»‡üîÇi=‹Aøæ-Îh_š’õ§ÙxÕ~ýÛ1Ô¼ÿŽ66^‘}ìY÷›…÷ý¾Ø‡>–ÏËö½ü{¾<7Ìáï_œ\¿^’ï¼²ßoãÚÀe{&Ñ‚ã½Q>—š_¢ìLÖ¦7:7f*ÿ¼‘R©çzÅ´èºëó}òäÉ bß¼ysÇŸ7gÞà#…–]w;gé£O÷±I“&9ï‘ÇWå;•|*ü®û?HS§Nu@ÌIÀú¹ŸíY¿~½SUuíKU8è\¨É8=ׇsv ?ÀÏéÄ8› o€š ŸXì*¥ýÉëmvã??dáäA¼lÿ<´?Ù,×ECIÙhã ò˜ðê±c ñ¼Å\¶©ÂyïgãÇy>'ÑÒñ;£^N8˜Ÿ™|‰ÂÜ <2yÖ“Žpª Öž±Y³mÀ%É,x c¸é¦›pÿý÷cذaèØ±#Ž>úhG¹ç~N²pé°Ãs–º|òÉ'1kÖ, 8ƒ ÂĉñÎ;ï8ÇôïßßÔ½{÷’Dx¯¼ò ¾ÿþ{tÐA8î¸ãðÝwßaÈ!ÎqœÙ1bÄV/ºÎsòçì³Ïv^;ì°Åª•ü‰Îü_^“RUOyõÇ»}“Í–F*zç™Âôí,¿G‚Å•`÷óL9£’ÖÈbì©drVù0›a§PQåL2¼Q˜¼nØÔð}ËÙ¢?§¿•ƒ¶ÿÍE«s±×39hg÷Ì Íõ?Rž3òe{9!P4tÜz@î?¬ÐbïÃG2‡ÀZ›™f ~²ÂͼízÉîåœñï`F××MAæì7=˜”ÂP†K̓ûé™ðý‹ð§%Ö‹4´|4Õí~Îû:¿û˜}”Í®¿f¹>œâw =ô.ÛÁ”bu>°þÑ0ÐÌrÌ´´hëºö\ ÁØì{I‘A½‹ñªõÂ~ð3·y…ž)—›Â~¸ŸëÛÜòE»;†*úl߉æ™òþäp?Ì 'd.Îþ¿dª;*rr\°_·üÏMýoÑÛŸ$ØR¼Å—ÿ™3ú\§˜7T c½[O¥¹Q£FŽ€®[\ëØMþBwü 83ýnÉT¶¹žŒËw…7ç &8ûè¶¿­BÅžåºÂzض >|(´DÓØÀ¾°¶“€Å‹;†“ξ8Ò„àŒS}t·e&çÄîŸÚÜ2_°íÿk•9ñë…6X{ÏÛ®p¶ê+›­ç@{·6!ôµÙ˜¾°ÙÎÖPñw…½Ÿ²"….žëÌ•ôŠ=‹œðn#;ÎôL_>·{3„ÙìXK2uÓþáÁ—ã:ùe6.±ÁÖ*-{o@ùr~0#Ì~í­’Œ pâ‰'¢S§NŽÎ1'r8[øá‡ãÜsÏÅþûïO>ùã|ðÁNŸihÚ´):tèàŒ9fäÇi{íµÞÿ}ì¼óÎN†Pùç9Ç{¬sþªU«œ2i@ Á!‘‰¥íe=²íÛÛw*ÈóÌÛ×]žß×nv1¥ê΃ cᔈ}*“T,y?ZºÁfÕ§gáS¤y¿æŠ?[ØRªåaó‚ÚÓî•”Vfô¤²Mæ˜×ÂÀ^¥÷²€Ý:zåÊ'¦D3iâ$ËÊO€š”ë“È÷ æx@e}_»¿îÛ>|ïe€sßÏÁ•6>ììB'ãðÙ<øC©:É„Žl_K~èÊ,Kôø«È»?VÖ+»~O{~ØAœí÷ ½ R){ìN@9ÚŒÑEAê˜m™ž#oN(m¯Ï™»”5 ô´>ÎÙò[ØËÆŸp÷!Àx–}§Ì5¦BbÿçË^øÚi¶_—^±Ò>¦ävWùg…´èR\*Útãw•g§ý¡7]ý]á͜ƄvíÚ¹›œ÷@ à(â|TF¨ðÓûÀ+tKc›Y¶@†PÁç˶›í¤ëºûâ¶Iï" " U'À™'*ª'™ÒϬÕEö½¶=M˜«*Ýï?¬uÊ>ë«^išJÈ·Ù‹A3íMlVæ›éçìÔ>¦^vud3¬~77Îa6§˜ÑF6»sýçÙ˜µ*ìÚßǶ}dƒÈX2Á KìQÜÅ»Tö½Âò8ã²ß–Á©wŸ>oÊq0_y啎7%•qÎØõÕWŽòOo€HáØì¹çžÃ¢E‹¥Ÿa£åÉÒ¥KriDàË+Üwà 78û½ÛùÙóEn×÷Äh^UßY.W˜gÅ•SÍ%nÓ‡¾”ãÜlq.ó:*=€žIÿ²û/g‘GXc-†~×Ap)ºOÍ@ceª…3ßñ(ëMlfxéÆÒ{ÝÈ…‹¶x ìÝ.ää_¹ÜB!.–¯þR´q2bNÎ\¸ ôÞÎçõ-Â]߆µ×ÖÖ·«úã/¶ Ž+Töé½ÅU\icç1|À{¿_fÿ¦4¼;) Ë<ýæ9T i°ñ†¸e%ëÞ|LüWh€ÈÙÖÙÂÚÃð6¯,´…ô~ °›Š|N¸ ‡ßþ]¶Ú²Ôå4 å ç…a K7”-+¼'ub¨èÆÈÙtŠ÷8*ѱ„Ê4ëHá,»·WéŽëÏmTäùppgç#Ë+ï;—ü£÷A¤ÐÍŒËÒ`Áö±l>´MhœHw_¢µKÛD@D@*G`˜ÍĬ´DG¯Øàˆ¯Ha†äA}¶h¾‘;·³ïumÀ2ïºÒ6l\ R~³Ù,c; l,¸³ÍèÐuö–ÄJ)*ñ剻„ó9çœSâAÀÉ®ðļQLBÈ1^¤ÐÃàâ‹/ŽÜ¬ïU$ÀYî\Ó%ù_ÜÖfþoÚ¯Èqõ>óí(7;†Þ40Ò(H¡û9…†X ïËô6¢RzóW'ûOËÂ\#·Y¬zuæ`hÓ6ËÌøp攡"ùws§43Ï@=pxú>•‹§,¼.éÉ’C̈r£Å®ÓÍŸXYƘ^oN0£k»ðóí´žAgÿsíçò­ÌåÂp°±¶r€WŽêRŒ›ìzŒ2#.= Ö˜'ÇJðºå;`>îûÞ 6œù§«ÁüxQ¸Œ,ë3CÈ’-4<õ{:× 3¹÷­ Óg˜ñé_#,/ƒ… q_†®q,ðýyáÆÑN[,ùßNƒh½%¥]ód® ûìÜûìY4•øï_œp¯Ç\²ûY~Bþ¨\óJEß«œ»•Q ÞVœÇ»Þn9|ç6× ÀïnÒÖ)ÜÆöTdlˆgëg8{ÐÚ\f)_YR)†D ‡’Ì ÀœPœá§‹>C)™Š9gÿéUÉ}Žû˜,a£®')'{8.ûí·ßœÐLæiâ;þ›3gŽ–IW~†…²LŽÛ8F¤÷Ç•Ì9Àñ‘Âí’Äàx|ÑÕ|¦)~tÑßÝ”0*òÑ„ç/°ñi–ýŸŠ=®˜ ðqË+rŠ…QçO£âhK6J¡QòF3,x³Î;;ªÙŸKMÉžf! ÝÍufŠwnăGl}_lh?ÏGŽ.tò§cἯ&CX.—d¼Îú{¾  ¹%d\l÷jzS°~ÊÙ¦4O¶„æÚÏv1¾9^hØñJ sò~Ñò¾0|€÷l2ÎëSä¸Ùó¸g/Ä9æiÆÜu²CN‚W&{¥ì¹cwYýõïÍŲ›lr¸‚ç‘sR%þPaß½MÐióD ½hÞcp®åœYnž°¾öö<—hDxd´­b`ýñ sלÿå‚x(×éc_ s»ÿð²ÇxOÅçÒ'sj£"Ì›'cÞ´½Â0­ºnÒ<ï¾XŸéþOw¬ÈÙ{> ¼Â‡¬Ûµìr?ÛÃcÝýÞsªòÙõJp l'-Ь^®°ítCëܹ³ÊPûâ¶Uï" " ñàò@NæcKèà ɑ2nI1þgn›u÷Ä@F—èïéŒOf²¿63ĤU®òÏþM\¶eZÎ>nkzÿû‡>8«À(rÐÔÛr%ç7–Ü«<éÕ"ä FÚ ~Ÿv¥³]\£ú K®Å¤SJ2ƒÀUW]…^xÁIâçöˆ3ó\ ÀUÌ™Øyî¾ûng©@fñ§BÏ|&ücî€o¿ýÖÉÀøÿáÇ;+Ð;à’K.Þu×]NLÞü·¿ýÍù|Úi§¹Õ¦ì}ìØ±HE‚>ÖS„‰ýÎ{/v‹n·ÙT¯,°xê]lµ¦ -7rïýÞŒB¥Ão<þS–órÏ{È ‘|¥C6Ü^ê=­þ+÷*_zI=> [®&þcˆ“+Þã¸íønA¬¼9vÙî¹Uyç’…ã.+ÀËi¾Ê¸2œŠ¾+ô ¸ß<þyHÖYsèõå êw”¶ñh ‘›Ù5¼w7µãhp…ÏÒÓv ï‹ôëi9æz¼ÐÜsñþì e•pæ5ðÊ¿(Í;Ãþ»­Ÿwس……7Ш)l«·Ïîþ_ZÈÃYè­’,#†[_<ïeÿ³â9#Ê1´Ú2Ñݦ¨S§2Ìø|.G帼åû¢çlâL;k.È›?oü4$ÌŸ?¿Ì)´îrÉ=Æ~Ñ*L7-Z‚Y/]ó½‰ËœXÉ/46ÐbLÃ…ídßÙNö‘m`;Y‡JŽ©Ž}q§?" " q`Æ_ þDn§€^ÿ9²tðíØLÙÆXM ó"´¬Ç Ïq}Ïâ8ÍiÏ™Ùëj1üc-L€±«7›ÒÎxÊI–ÍúG›¥ëo3<®0F’ù¾0ƒAo›%áLÌÕ¶8—äÒ‚\³y‘ FÍe•™½Ýsõ¾ýàîÆot&P¸Â'Y¸Í+LÞÇ$~̱ęy*ïœâXÓ»Ä4'¤8f»í¶Ûœ1›;IÃqô\åX.²|o]å}¾÷Þ{ËÛµÍÛ¹Â@* ¬'Ä.sIûÃ,|eŠÐÀWu*êŒýoeÊy¯ò_ÞqÜ©à{µÏ{\:?ÓèMù§Mn€xŽMö1 ù‰Q!¦¢Í¬ùîËm8gàénÅ÷m*Òtÿ¢Û•k •}f‡u¿»åµnÝÚ180ë¾› ÖËdƒ‰–í†<°M´6³nz ðã®Pû’h6*OD@2™ Xœb[‹Œ&»ØŒuO{qɤ{=ñ£›)Û˜œŠ‰¹¸LÒó¶´H\éóAàÒÇ Év’1÷ÆzîmKaQ8°ä’Jƒ=î’\‹±º'›;ï‹vüé63t›yäøÍEÛŒ·|Ià’^te]’Ì#Ài3tèÐsæÌIq—K«Sý5›ÿA„ï¾û®ô‘âOúýÕìߟ®¿®:Ÿºÿé÷—Îߟîúý¥ó÷§ûŸ~éüý¥ûþGuG!)VúTˆ€ˆ€ˆ€ˆ€ˆ€ˆ€¤ƒ€ é ®:E@D@D@D@D@D@D ÅdH1pU'" " " " " " é @:¨«NH1R \Õ‰€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@:ÈêªSD@D@D@D@D@D@RL@€Wu" " " " " " "2¤ƒºê ÅÀUˆ€ˆ€ˆ€ˆ€ˆ€ˆ€¤ƒ€ é ®:E@D@D@D@D@D@D ÅdH1pU'" " " " " " é @:¨«NH1R \Õ‰€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@:ÈêªSD@D@D@D@D@D@RL@€Wu" " " " " " "2¤ƒºê ÅÀUˆ€ˆ€ˆ€ˆ€ˆ€ˆ€¤ƒ€ é ®:E@D@D@D@D@D@D ÅdH1pU'" " " " " " é @:¨«NH1R \Õ‰€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@:ÈêªSD@D@D@D@D@D@RL@€Wu" " " " " " "2¤ƒºê ÅÀUˆ€ˆ€ˆ€ˆ€ˆ€ˆ€¤ƒ€ é ®:E@D@D@D@D@D@D ÅdH1pU'" " " " " " é @:¨«NH1R \Õ‰€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@:ÈêªSD@D@D@D@D@D@RLÀwâ‰'†R\§ªjA C‡˜3gNµh‹!" ©$ û_*i«.êD@÷¿êt5Ô–T îH§”î@ÕŸ^XüÅ_÷Ÿ9©¾ï—Ô§ÿ?ýÿéÿOÿ%7„ÐýG÷ÝtÿIñm§¤ºš~ÿ!…”üôAD@D@D@D@D@D@2—€ ™{mÕ3(! @ }Ì% @æ^[õLD@D@D@D@D@D@JÈP‚BD@D@D@D@D@D@D s ȹ×V=2” ÐÈ\2dîµUÏD@D@D@D@D@D@D „€ %(ôAD@D@D@D@D@D@2—€ ™{mÕ3(! @ }øÿöîÌÒª<ÿ©îê}“½ ²(«@pÜ€PâŠû$F3óOòwŒ™$&ã̘'f³ŒN2ê¨Ä—à’°(Š`PQ\EÙ d‡f_z­šóÞî[}»¨ª®jºÏÛÝ÷wž§»îòÝû~ßï»ß¹÷¼ß9ç#°ù Hl¾ûÖ– @€ @€q €q 7 @€ @€Àæ+ °ùî[[F€ @€Æ$Æ)Ü @€ @€›¯€Àæ»om @€§pƒ @€l¾›ï¾µe @€ @`\@`œÂ  @€ °ù Hl¾ûÖ– @€ @€q €q 7 @€ @€Àæ+ °ùî[[F€ @€Æ$Æ)Ü @€ @€›¯€Àæ»om @€§pƒ @€l¾›ï¾µe @€ @`\@`œÂ  @€ °ù Hl¾ûÖ– @€ @€q €q 7 @€ @€Àæ+ °ùî[[F€ @€Æ†‡‡ÇÆï¹A †††ÊÈÈHm±M%@€ÀJõŸOý* þë×=o»C Ú>ƒ™  ìPüÜ0þꟑ´o#ÇŸãÏñçøËª€Ô?êõúGý“%PŠ!yö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yÃÃÃcyáE&'044TFFFòV@d$ ¨ÿ’à…%@ ]@ý—¾ ¬@¢@´}3@Ù ø¹ `þüÕ?#i_Ž?ÇŸãÏñ—U©Ô?êõú'K CòìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò†‡‡Çò‹L O`hh¨ŒŒŒä­€ÈHPÿ%Á K€@º€ú/}XDhû f6€²@ñsÀüù«FÒ¾Ž?ÇŸã/«Rÿ¨Ô?êõO–@)†äÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä å…™@žÀÐÐPÉ[‘  $ þK‚–tõ_ú.°‰ÑöÌle€âç6€ùóWÿŒ¤}8þŽ?Ç_V¤þQÿ¨Ô?êŸ,R ȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€ÈË /2<¡¡¡222’·" @ I@ý—/,éê¿ô]`¢í3˜ÙÊ>ÅÏmóç¯þIû pü9þŽ¿¬ Hý£þQÿ¨Ô?Y¥g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ '00<<<–^dyCCCedd$oD&@€@’€ú/ ^XÒÔé»À $ DÛg0³”}ŠŸÛæÏ_ý3’öàøsü9þYúGý£þQÿ¨²J1 Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O`àï|çX^x‘  @€ @€ -pñÅ—#Ž8"-044TFFF6ôvNùþâ÷·ÿ‰'žXâ È*>ýýù³ÿíÿÌï?õŸÏ_æçOýçó—ùùSÿùüe~þ²ë¿h÷Õú— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈÈ’— @€4hˆ- @€ÈË ..L¡¡¡222’¹ b @ E@ý—Â.(€úo#Ø V!M Ú>ƒ™  ìPüÜ0þꟑ´/ÇŸãÏñçøËª€Ô?êõúGý“%PŠ!yö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yyö" @€ @€fͨ"@€ @€yÃÃÃcyáE&'044TFFFòV@d$ ¨ÿ’à…%@ ]@ý—¾ ¬@¢@´}3@Ù ø¹ `þüÕ?#i_Ž?ÇŸãÏñ—U©Ô?êõú'K CòìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò$òìE&@€ @€Í$šQ D€ @€ò†‡‡Çò‹L O`hh¨ŒŒŒä­€ÈHPÿ%Á K€@º€ú/}XDhû f6€²@ñsÀüù«FÒ¾Ž?ÇŸã/«Rÿ¨Ô?êõO–@)†äÙ‹L€ @€x<ô­;ÜIDATš H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä HäÙ‹L€ @€š H4£ˆ @€ä å…™@žÀÐÐPÉ[‘  $ þK‚–tõ_ú.°‰ÑöÌle€âç6€ùóWÿŒ¤}8þŽ?Ç_V¤þQÿ¨Ô?êŸ,R ȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€Èȳ™ @€4hF- @€ÈË /2<¡¡¡222’·" @ I@ý—/,éê¿ô]`¢í3˜ÙÊ>ÅÏmóç¯þIû pü9þŽ¿¬ Hý£þQÿ¨Ô?Y¥g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ ' g/2 @€h& ÐŒZ  @€ '00<<<–^dyCCCedd$oD&@€@’€ú/ ^XÒÔé»À $ DÛg0³”}ŠŸÛæÏ_ý3’öàøsü9þYúGý£þQÿ¨²J1 Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O@ Ï^d @€ ÐL@ µ@ @€ @ O``xxx,/¼Èò†††ÊÈÈHÞ ˆL€$õ_¼°¤ ¨ÿÒwHˆ¶Ï`f(û?·ÌŸ¿úg$í+Àñçøsü9þ²* õúGý£þQÿd ”b@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@ž€@ž½È @€ @ ™€@3j @€ @€@žÀÀðððX^x‘ ä •‘‘‘¼™Iê¿$xa HPÿ¥ï+(mŸÁÌPö(~n˜?õÏHÚW€ãÏñçøsüeU@êõúGý£þÉ(Å€<{‘  @€ @€@3 €fÔ @€ @€<Á|0-úwÜQÄçŸõ¼ñÆ}þÿY¿¢þSÿg~ÿ©ÿ|þ2?ê?Ÿ¿ÌÏŸúÏç/óó—]ÿÅßG}4mÀ26–¾ˆÏßçÏñ—•Pÿ¨Ô?êõOŽ€úWý«þUÿæÔ>µñÜþí6 kï‹K€ @€ H4ÄŠ @€d HdÉ‹K€ @€ H4ÄŠ @€d HdÉ‹K€ @€ H4ÄŠ @€d HdÉ‹K€ @€ H4ÄŠ @€d HdÉ‹K€ @€ H4ÄŠ @€d HdÉ‹K€ @€ H4ÄŠ @€d HdÉ‹K€ @€ H4ÄŠ @€d f—Øx–/_^æÎ[6Þ•ÜHÖléòR®¿o Üýè@Ù{Û±²Ïvce®S,ÉÞ±(å®G:õô‚Á²ïv+ÊŽ[ö¯JJàµ_XPÎÿÅÜò‘Ó––×R¿5'”÷|c~ùß?,üÑcžq—6&7œ½ üÛµsŸ°J[/,å;–?|βòÂýV<áùé8æÃ[”#w[QþéÔ¥Ó-æ¹µÜ|óÍåÞ{ï-GuÔZ–\óéÇ{¬ÜrË-åÑG-O}êSË{ì±æî­!ð¿/,ýÝyeQmüwËž5 ðÞ––×:»Ï~÷õþ @`s˜êwBwû>÷š%åeûϬ®œøû`âýî{öþ½¡&gßõµùå¢WÿV‰¼ö«^Qþú¤%e‡>L¤$º;å÷/˜_ž?´¼ìò”î#þ @€À¦&0¿~“ü¯—/Ycµv÷œröÕƒåôÏ.(ç¾aqyÎ>£k<ïÎÆ+p÷Ýw—+V”ƒ:¨Ì›7oã]Ñ`Í>Tÿôõùµ§D)'¸¢l³`¬|÷—sËÍ÷”·ÿ낺†K$6‚ýdÈèý½ÊÆÆÆÆWèð]7Üïƒ/åÔÏ,,ƒµGÖY¯^RŽxêh¹áþ9å«×Í)ºl^íµµ°üÛë¯K¿ÜHKì´ÕXY>:Pþó×”O¿rÍŽý‚o;  °9̯Ÿ3žp¦sE9£öð:þ£[”Oýt°&œÍßTöõã?^¶Új«Î¿Me³Öó#—¯LüÝK—–·±ºG㛿¸ |ùš¹åÏ¿=¿&ê/P…},Ðû;ab`C²\xÓÜrëƒåÜ7..Ï]u"bÏmGËóöYQÿsÊç6·\{Ï@9hçÕ ‰ ¹>Ë{§%¶ß¢”?xÎÒò¶/Ï/_ª_’¯xúô]?¾}óœòþKæ—ŸÜ5§Ž¯-/þ•åOž·¬Ì«?<ï¯ß­§µ°ü‡g.ïüëâFÆg«ycå³5ãÓ-ÿ÷ŠÁòù«ËyõŒÔàêž Ý§ý%@€õ$pÈ®ceamuÇBG]ÿKç• ß¼¸,è9±ü·õ±ïÝ:§|®§®ž¸ Ó}L\ÖýÉ®»îº²ãŽ;–ÑÑÑÎЀŋ—… –Ýwß½l³Í6å‘G)·Þzk‰Ç—.]Z®½öÚñçâzè¡rçw–HÌ™3§“ ˆá Ä™îþ+që¦z¦?Ê==Ýÿãþ?oiÙy«y%ž]VÞÄo•øû7u¨Àêo[êÒ-ë1ð¬=W”ÿZËVÏJ]~ûœò‡uäÖóÇÊÙ¯]Rç^ˆw*åÁzrêÕŸ_Ø9ŽÎ~Íâ²åüR¾{ËœòßžW~tçܲÃcµ7åŠò¾ç/-ÛÔ¡7 65ÞßÑ[ [fòû »ìdX¼²"}hɪ µg¡¨3ÝsnYÐï¡Zßþ׋æ—¿¹&(ûm?V~óÈeåmG­Nð¾èÌ…åÿ?vY§ùߟWöØf¬|èä¥åñe¥¼ï[óËù×Í-÷=>PŽßkEùÝg-+Çコ‡ÃÊeæM¹L8üÓç•3‡—”ß«=å¿sËÜúý1VN®C$ÞÿÂ¥ú¿gÖùfê5¯=dEyIÝ wÕ^‹¦îYôSjc~¿íGËk7ÓW=cEùèóÊ›j†=J$"o_ªÝã=¾uÓœr^kà®Gº–Nãû…&çY-â6ŒÀ×Ï-‹ëâ 5ÓåÞÇÊOî˜SF'$ÚYCWÕ!S•µ}Lõ:¯)cû£{Ì °óÎ;w÷ÑÕÿÆoìtù,Ûn»mgâ¿hÔÇíùókk³–ûD!Ê^{íÕ™ ×\sM'!Ðy¢Ïþ‹ú³Wý°{ßÅóÊ+êp—ÏÔÞ.·×î4VþçK––¿©ÿ¢ñå·ÎYPþüßç•;ëDT' –ƒv-_«?_ú©…åÞGK9t—Ñrí½sÊ7n˜[.ýåêã!~L~¯Þ_PFãÿ+uΗza¹¸žÙzÚ£e‹Á±ò±zrãyߢ<²ú|ÇÊ þ'@€À& °®¿Ö¶i/ªsE½ù_YPþâ’yåÊz"¹æÀ;e÷Úp†ý¾µ‘%~¯œø‰-ê‰éÁòÆÃ–wڜ׹ŒÞõÕùåïꉊnùñsÊ%5AðÆ/.,+ê{³ÇhY^æ¼ø“ Ë¿þ|nùíc–•¿yñ’²´>vÚgvêïxíL– ‡Ü6§ ×ï“¡íFë÷Hái+:u|$×WYÝb^_ï8Ë÷ùûÚmîè:áÓ»/XP>^³KìŒß¯ãëÞ^wÐ_½¸Û…tEÍØ¬(/«Ðß©Yðø>­Ž½û³ºc­‹lUwtdLž^wÚ¢š‰,ΫëDñÅxY=Ëô¡“Ÿgb\÷  @`f×ÄxLÞÚ-ËêbœýV­{ßSÏn¾²&m×µÌô;`]ß¿ß^·lÙ²rðÁwù13ú×_}çì4øwÛm·òÀtzÄí(Ñc zl½õÖå€'Û~ûíËUW]Un»í¶ò´§=müñ~ºñÑ_[RÞòååûµ~am¸Ç¿(‡Ö3ú¯=xyù­£——8›g•¾xõÜÚs¢”‹ÞúxínZO\Tÿ×ÿË‚rNýÁóüÚA+Ê+Ÿ¾¼óCïìúôø½Wþæùן¯ü©öº:¤æ±úлëY¡ø{AíIsì^+ÉþîyóË'~4Øéaðߟ_8)؈¢ ¶÷ž8ÛÞïÔ3ä¿ÿì WgÅYΩcüßsáüòþš€[ÕóÇÏÙ{EùµÚvŒzµ›¤ýhM¤^¿¨þvùõÅå™»­¬[ãdu̓ӿó¸ÕëùOõþ¿ÔžZ/®ó(ÿXïÿ¼&pô[wzÄc¯©¯=¹&kÿôßçwæBúH}ÿXæÇÿqqÙ}ë•ï?q™x]$ "ñÛÏZÙë ~Cý´&.¾Y“¾ï=qõ:IJëZÒ‘}ùó--¿sîüzfn9ù€5(^uÏœr×Ã,w4ö{ËvõÌÿ—¯¬ €¥u'./‘Æ~Ì$yI]62ì½ €x.ÊËg8Ódo,·  @`rhŒ\4²º~Ž®Ñ·=<§ž™,õ2;O®ÇÕL¿&_3Nˆ®þÑ}¿[b¬”¸äßT%zDâ`ï½÷^c‘è1C î¹çž5ï§;ñæëµ!þÓzFèìÚ[ñ⑹åǵ—Ë•õþ•wÖ!Žõ7Ê7êóÑ5ÿþUW6Ša‹WÜ>·\]Çþ°vûòȪógº2Ý@ÿú¤:…`ýIôõ:su ¥9µþXåã7Qœàˆ1µW¬zýsk/›Hœý`‘è§O m%°iÌ«¿bèw”Þ9ŽÞ}eCxCnÅÑõ }$Lo«½³¾U«|ÿ¶¹å‚š¬X1,ñ«o|¼ìZ'¤º6†cuÿÝuúÊ‹ë¼uÝ{+ÿž¸ïŠñÆ<òõú~Ö^]# tþu—>|×åƒu˜@ôtï]æ¦:a·ô.Ó}lâÐø#kB"Öo}•ô@lHLœó/u¶èß=~yö^kN–sãªñuï®—o˜¬Ü^¿£P»ÛÅ¿ +N$¾]{üÕIK;c0bçF‰‰ "㉅Ö@ôººômk΢Ißü·å÷j×¹wð.úýÏ0ôL¿føv}¿X4Úg[b>€(ÝὯǢ‡@,3Ùó½Ënn·ã¬~Œ/]P»àÇÆøWGú—»ë°ÃÿUg—þûúÛãòÚ•3~hÆï’³®¬¿K¾3¿ÜPÏ0E‰F}4â{˳ö-Cµ;êHýíóÚ« ÞI=ág‰â8‹Ù«£\SOŽœøñ'ø¿nÕ{÷¾§ÛÈXPëºÿ‰æÞ@Ëõбú¯?lEyÃᣵÖÒòÏ?,¿]O@ÿ·:æ?.;|˃s:—/ž¸NskµÿzË!~ÓÜôÀœNݽÓ'+1ô«»ÌKÿyòysb™nÙ±Îí2±ÄÉ•õUfÿK`}Ežð>1¶ÿ˜lQþ v#ݱ§¾ûÖ+·ök5s—n˜Xæ®¶êôøbí6wK;ļhì?X¿<£wAd}"9ã2ذq’ùwj}û…:Ãî÷n[SŸa~xÕÙÏÉÖh6ß“½ÞcO^ ›4˜¬—@ô ˆsÝež|´MçΫgâR{l;V®ùíÕ'/âÒÆú‚eŠq9À»ë1Áß;ê²;Ö+ yú’ränceÏmFËuÀWëûô–èsÄe4»=¢›j”]êë£ÄÙ§¿¬'9&–žŸDŸrŸ›œÀt¿f²1'ýóÂμC¾eÍ“ñÚ7×ÐúÁÊÉTã~Ì×40îwKÌ%÷Ëšˆ³ðÝtÛÕe{KüV‰1ûŸ™âÊv‘é.sÖ«–®qÄîûÄ2ßýe÷Þ†ý;!Ÿ±aƒM÷î1F㜸´œU'Ðùf¼¯[©“âD–<ÎèoQÿvÿÅ—bÌòcL»e¸ŽŸ»±Nþ÷é+ëÍÑÎ䀑I/çOþd°3&5ºÐ) °á¢;\”î é1»y”è"×-13ú¥uüóTe6ßS½‡ÇŸœÀ–[nÙ6ö–ÃótŸï}®nÇÄOQn«“XÆÙýÞw{(>³ž¼ø~(J\Á(ºvÆo“(Ý3ú;«þë6ö¿RÇþµvé¤Áókƒ?ÊaõzÙ1ùàOîš[v{ÊX °òß ÷Í©#/,©$+ØÔÖå÷ÁL¶ñ¨Úh¿¢˺úîÕ¿;º¯‹ßqÖ}ÿ:™j”Ãk]W$º§NÊÚ[b×?þæüñÆïsÝÛÇì±¢&zçv®öÒm«ÆßÿSgôÿÍšüz{&ËtßoCÿ]ÝÒÞБfðþ﨓å<«NhsuÏlÐÛÖž1AD\îæ¾·rr†Kê%ßQ»–>X/éð‚U_ŠñöÑýn¯šHˆK2ºì‰_Ìݵ›Íw@÷5þ®_8»¿ë®»–E‹u&ü‹ËƼ7ÜpCç’qÁ~,ûí0VþÓª.­qvÿŸXØéNúƳ”ã>ºEYVOÚŸ°ïh‰$Ö¯Ôe£ÄpÇ÷|£¨¿gböÿëî]ùÙ?÷º•½c™˜‘ú˜:`Qýà ^]'€êv?Ý«žÐøõ#——ûëxÒ矹EùËúÛè?×a6ï¨?P£ûÿ©LÝÓ&Þ[!@€ÀÆ(Ðûû æQ™ÉlÇ;]VvªsZ/ÿá–këÜ+wÔß$1Àéu¦ý¨c£^æ/Ê»VMò—]K­^y×@ùu~¹˜Üõ¿¬e¢Âèa¾¢V󯬯ËÇ é×yYÞ÷­yå´ƒ–wÝeNÿÜ‚)—™É6­e£ë^fé«ò§,-ÏúÈÊË*tŸû“ç-¯—¿)å/ëØ¹?¹p帹hø¸Ž×ìP7$®ðÁïv&ì¾þÄ:àY?­ÏÕÝǺÛ<ñ~÷ñVÅßx>­öyoûßþïý<´¾½>?S½×¾5)ï–ÖK£Õ™ÏßW»FÇjL¾³£ÿFmÌÄ5v?S{nõ¾GÜîÞŸÍwÀl »ï?›×¬Ïe7tü®a7Îd{—é>ÛØ}¼»½{ì±G§›ÿwÞYîºë®ÎÃqý÷ß¿s¹Àîr³ùÛo6¯[_Ë®øïѲN·ü8ÉðÃ:Þ?þE‰ž‹ÑPÿ³.«W\(/Ý´¼ãW—w~€Æ„PQŽª'%þ¨^%#ºûÿ[½´ß[˜Sö©—;Žòú: à²[WÎ}tÆ¡kþvù«“–•§Ô§>tÙ`ù³úã2Jôtü§S–•ç™Õ«ëcû;Á×ñ?ñg¶ŸÖ‘w­/ãÏ­’õ¼@ïg®÷v„Y×ßñÚx¯‰ïGÙm›RÎ{Ã’ÎóÉ^OJÄLþ/XUoî½]¨ïÍKÊ:g~y骱üqãÝÏY^^ô+Q7¯ù™é¹SO÷¢·.®'¨çwfþñú17ÝÎá²òµ3Y¦ûž+·©³ kü×}~gy'zï <úè£+ÓÒ³|qÖâq½è·`£™½ KB\lšKëIÊ[ë¼,q6³{ù™n‰ï€™Jm¸åb¿¸’@?ŽûŸJ5º’Þ\‡¶Do—êäMûÕ³ø1ißÄro=«ÿˇæt.³NG‰y‹bXãAõÇbw|éÊg¦ÿ?.õ‹zÖ?~ ÕD[·—Àô¯ò,6^'óû`m[õp½áH¬/.¿wýýWq™ª @€ô‡€@ìg[I€ @€}. Ðç›O€ @€ý! ÐûÙV @€ @€@Ÿ HôùÀæ @€ @€@HôÇ~¶• @€ Ðç}þ°ù @€ Ðý±Ÿm% @€ô¹€@Ÿl> @€ô‡€@ìg[I€ @€}. Ðç›O€ @€ý!0xî¹çöÇ–ÚJ @€ ÐÇ‹/ëãí·é @€ @ / è‹Ýl#  @€ @ ß$úý`û  @€ @ /$úb7ÛH @€èw €~ÿØ~ @€è  €¾ØÍ6’ @€ú]@ ß?¶Ÿ @€úB@ /v³$@€ @€~ìwÛO€l:‹-*W\qE¹ýöÛË’%KÊî»ï^vÛm·r衇–ùóço:ÒçkzóÍ7—‘‘‘Î~|øá‡×ÐØzë­;ûõ€èìÛ5žt‡ž”ÀÀâŋǞÔ;x1 @ ‘@$Î9çœNã¿7ä‚ Ê)§œRvÜqÇÞ‡ÝÞÈ¢áÿÝï~·LlôOµš‘ 8ñÄ%¦ò8f) 0K0‹ @€¹Ó%N?ýôFeãøÖ·¾U~þóŸ¯ÓŠEãŽ;n^ëE °Z@`µ…[ Їþð‡'Ýê·¿ýí“>îÁC`ª$ÀXN8á„c%­Å¸À“iüwßľíJøK€u0 àºÛy%¦Øê} ÊÄS.ì ¦ˆ®âK—.}ÂóÑÕ?ºüG×ÿÞãÊ•K`}4þc‹¢÷Àå—_¾qmœµ!@€À&&`ÀMl‡Y]X?Sùï¾ûÚžï.§§@WbÃüñþÝñý'ù‹$@LxÓM7‰•G ÆüOÕí?öÝQGõ„ñý݉{÷kw‹"Ðø±û˜¿ 0s=fneI @ ±@ô¸÷Þ{;ÿMì g–'k$6^Eᦈ ÿ&+ûî»o§G$uÎ<óÌοHD‰ÄÎI'T¢ËÿdE/€ÉTwX/ÓÍÇЛ¨‰}vå•W>!Y0qÈGïJýâ¿pU€^·  0C €BYŒ³xô½Æ!ÏÆ+sÙ]wݵÜx㙫 ö4ÑU¼·±I€ø7U‰ñáÊÆ!gê§*Ñ?ÆÿǰŽéS½þŽ;î˜ê) @€À4ÓàxŠë[ ® 0±HLi{?wÝuWÛ ¢ÍXàÈ#,Ñœéä~_|q9ñÄ×èJ>ã`\¯Suÿ ‘˜8–?’=½åg?ûYïÝ5nO—ZcAw @` “®Ááô“@tÿßo¿ýÖK ;” ŸüZlkŒóޱà/÷7UìH|ík_+ÑE\Ù´9äñŽÆÿTŽ/äÌZ@€Y“yl.Ýîÿwß}÷“Þ¤x/eÃpÀKÅE£0º‹wÏ,ï´ÓN%ž‹$Á\°F/è ÝÄO8á„ ³RÞu½ ÄŒÿ»í¶[g߯Ó X¯½úL@ Ïv¸Í%@€Õë³û¿Àj× q+&‹žño²G£¿·Ä ò1Æ<’ÓM(×û·sâìôÚ¸ôÒK×Hä䬨Ø| Ø|÷­-#@€iÖw÷ÿJ ä DO€˜Tnb‰ Ï9çœN"`âsîoXÞ™þ×)zq̦ñ½?˜½€³7ó ¬³€ ÿÖ™n½¿P÷ÿõNšþ†‘xä‘Gžpíø˜0Î*§œrŠkÇ7ÜKqE†è…1“Ã;f:Ñc¼_ P @`ö³7ó Œ L5«ÿlC7š èþߌºi  °hÑ¢'\*0—ÑÀÚ펡¡¡'f;á_ôøP @`ö†ÌÞÌ+ @`3X—ÿë%ØLH6ù͈±þq¦²«t¯0Ýåå6y€höÙgŸ2“a/yÉKÊÛßþögR¢gA P @`ö³7ó Ø ¢ñoöÿÍ`GN² Ó%bñ8Û3Í+^àøã_kHDéþ]Û &›ëam¯ñ<¬ðI @€¾XgÿÎìÿçÇ'ÎO¼bÀÑG]N=õÔÒ›“Î)V õq‰¿éJÌþ¥ûwºe£ñoüÿtBž#@€Àôæ˜Þdz °™ ¬³ÿAcöÿ÷ãÄ~øárùå—wVòÈ#ìüdôˆçÄ$ÁÆ»5›îšÅe£L5!`\¾qâ%'ÛÚH$8û?™ŒÇ 0s €™[Y’O˜jVÿÙ>þ„7öÀˆ1ÇÊæ/Ð{e€˜0zDR Êlfßü¥6ì®- °¶è‡z¨dÍÚèƒl  @€ @€€€Ï @€è €>ØÉ6‘ @€Hø  @€ @€>èƒl  Ðï‹/.÷Ýw_Y±bE¿SlÛÿÈ#”{î¹§<úè£ÅúX  Ð/ƒý²¡¶“kúÀ‚rÏ#«—Ú¢^ü”FË[QNzÚèê'¦¹õ±+æÖ׬(»eË-·ì,׿ãŽ;:׌–/_^>ö±•×¼æ5e»í¶[Ë»yzC|êSŸ*Ï|æ3ËÁ¼ÆÛßtÓMåë_ÿzyÛÛÞVæÌ™þ”ý¸;XoÓ×¾ë-Œ7"@€ÀÆ/0VWñ=',/WÿΒοϼjYytY)¯8k^¹öžmÀ;Ï,Ñèï–ŸÞ9PþûEóºwým(pë­·–sÏ=·ìµ×^åMozSyë[ßZN?ýôN2àK_úR§¡Øpu„ª\pAÙj«­Ê›ßüæò–·¼¥œvÚi%z\rÉ%3öùÎw¾S¢Ñß-‹-*?üá»w; Ë#<²,X°`ü17Ú Œ•ø§ @€ÀÆ' °ñíkD€@¢À[”²Ïö+ÿ½¸žõÿ?§.+µ=áªËÄݲN¡¯¸âŠNãÿØc-[l±EÝeûí·//}éKËã?^®»îºuz_/Z7†qÿý÷wÎ ÏŸ?¿³?vÝu×òŒg<£ÜvÛmÞëöÎk¾*Î,}ôÑ}¾æ3î @€†ø  @`íkB ºó/[Õƒÿ¢›æ”÷~s°\u÷@™SÏÛg´|ø×–•»­Ýü¿0¯Ž1/å_œ_†ZQžú”±òÁËËÝuXÁáš_>ð²åå…û–Û*å¾>¯Ä{m³`¬œvÐhùÓ,/ƒsKùèåsË÷”Ãv-{é`yÏs——ãö-'9¿üÝË——÷|c°üâÞòŒ]ÆÊ?ž²¬²«³l“í¾hhÞyç3ÌÑðï-[o½u§»xt%úÓŸ^n¸á†rã7v’¿øÅ/:=žúÔ§–ã?~¼[z øñ\âùè¶¾Ë.»tžßf›mÊc=VÎ9çœòìg?»|ÿûßïô0Øa‡:à vÜqÇÞÐ}}»{F8†cì¾ûîãtP Ç0ŽÆ{ôÇH İ}÷Ý·sÌ1×o|ãå¾ùÍo–¡¡¡Î0€Ÿýìg}ðùϾ³OvÛm·röÙgw=ñ¾±ìž{îYFFFJ ‰äCôˆ¸Q"î~ðƒÝÓcßF¼¹sçv>ñùˆy bI¼6ÊN;íTžóœçtžï<à¿u˜j_OûåË_þr9âˆ#ÊOúÓNÞqÔQGu†ô¬ó x!úPÀ)­>Üé6™™ ,z¬”]6·ÜU{¿ú+ÊcKKyågçu÷·¼kI¹¦ˆîþ1îÿi;Œ•/±¬Ì­µê_ž´¬¼ëøåå-G¬(Tð;oU:Ï»çhYº¼”“?5¿ì¿ãX¹¶¾þü7-+?¼}Nù/¬ÌÇF̽vNùx}Ï÷Öá' –å5ùpý¢òß›[>ûª¥¸;o9Vþ`Õkf¶5ýµTt F\4Ô'+ÑI£ñ‹hüE¯€W¼âåU¯zUg|z èN]Ì£AzòÉ'—×½îuF`4úãùxhÔ^yå•åE/zQçù˜_à{ßûÞd¡ûö±è…ã£1ý•¯|¥Óè¾ùæ›;=¢Ñs„çyçW¶ÝvÛŽã)§œÒ™,ðÒK/í<½7¢qø¬g=«~øáåÀì¼gÌÏE‚H4Äþˆý%† DÿC)oxÃÊa‡ÖY‡ØßQâ½c߯ëc߯…H*D…(ñÚx¯xíßøÆN²"¶A™^à®»î*W_}õÿbXN·L·¯»Ëtÿv÷éO~ò“óEÄ~ˆž#1¤äî»ïî.æ/Ì@@`H!@ þðëƒeç¿XÐù·Ïÿ\Pþ媹åoë™û=¶­g ëÉö/¾nYyçq+Ê–uXÿ¢Ç: þ»ëÙÿµý¾_M”z²y­ÇÊ®µ×Àu޲]·+ƒµ¦ç¶ª“ ~õú9å¡¥å?±¼1öÿ“Ÿüd§‘¼[n¹¥,[¶¬Ó°ç0ކþµ×^ÛÙá%éáû-þÆrñ\ô˜¬ì¿ÿþ^ñ|4£Db ¡Ñ$ qF¹Û; z‰tKĈ„Bw˜BôôˆF¨2½ÀC=T" Ðû/»eº}ŸÉJ ç‰^5±#ù‰£H2( 0s•§œf¾¼%  °Y ¼çy+ÏÜÇFnQÛÛöLÿ”:§Ø•w ”?¾p~YV»úï½íXmxÌŽ#º÷ß[¯|vÒ?×l@OÙµ¸gÕÑ­Ýú·é‰Û]l÷šXè–ùu¸ÀбYᄌþFc.ÎðF"`²Éà¢! ÇhðE‰Æcôè–h`ĬôÑHŒ.àÑPŒÉ碡Ù[âý»%Þ¯[⽺]Þ»õûß8£ »°>ôÐC;ÿÂ(’(13| ›ˆ.á±ß¢wEo Ûx|ª~ﲓݎ„A·D‚Ø;’<‘àé&ºËô&"iŸ¡8û|á…v‘”ˆ¤‚2µ@øD¯‹Þ=m⊠Q"A0ݾî=žºï1ñªq¿;4£»Œ¿ 0½€Àô>ž%@ Ï¶©ü§®>ù·ÆÖéê9åýÿ>X¾÷ö¥eŸíV6ÆßòÅÉÏ8®ñž;ûÔ¤A4ä¯ùÝ:ž`U‰¡?­‰…½W]±ì)óW7ô»Ëø;;èú øèÊã„{K4øâ¬aœ…î–hèÇãݱÇÑà†4B¢ñŸtÒIeçws)»x.–UÖ.gУë|\‘¡ë ñ8‹ ðè1 º0=ãŒ3Æß0’1¤£·Q>þä:Þè&gbÿÆ:DìîûÇç îï±Çwù$b.€¾ërÕUWu.eà &&Öquúòeá=ݾžì¸Š¤Aw?Z·“% úÔF @`††ÌÊbˆ‰þ¢ÿv W6Ð/(ç_7§,éiÿÍ«µêm”Å«z°Î«'•­ ü8뿼.÷’ze¥£åo¾=·¬¨C”ã¹wm°|ø‡ƒ³îM`L-gŠ;î¸ò£ý¨3y_w÷¹cÿ{‡‰DƒèiËv“r½úé½×¶¯ãø=óÌ3;CCÂ?Žåâ3Ù禟Ül+ÖE`Ã~«®Ëy 6bè…Wè-ëÒø×o?y³÷­Ý^OѸ‹k+qVzº ?ÿé„fö\8¯ÍzmÏÏ,ÒÚ—ŠáÑ^±c~ˆHòÄÙæÞb¿÷j¬ßÛ³Ù×±zçX¿kâÝ °ù HlþûØ @€À4qF1.-¦ô§@4ücˆÈyç×韅“O>yü ý©²qmuœé¡ {ïl\kim °i°iì'kI€ @€ž”€«<)>/&@€ @€›†€À¦±Ÿ¬% @€xROŠÏ‹  @€ @€À¦!ðÿçøÅE8w@NIEND®B`‚golly-2.8-src/gui-ios/Golly/Golly-Prefix.pch0000644000175100017510000000047112525071110015674 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.8-src/gui-ios/Golly/pattern@2x.png0000644000175100017510000000031412525071110015410 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.8-src/gui-ios/Golly/GollyAppDelegate.h0000644000175100017510000000276112660172450016227 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); // show/hide tab bar void ShowTabBar(bool show); // get height of tab bar CGFloat TabBarHeight(); golly-2.8-src/gui-ios/Golly/StatePickerController.xib0000644000175100017510000002566412525071110017660 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.8-src/gui-ios/Golly/InfoViewController.h0000644000175100017510000000310512525071110016617 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.8-src/gui-ios/Golly/triangle-down.png0000644000175100017510000000032012525071110016130 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.8-src/gui-ios/Golly/PatternViewController.xib0000644000175100017510000004752112660172450017717 00000000000000 golly-2.8-src/gui-ios/Golly/PatternViewController.m0000644000175100017510000007452112660172450017371 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, drawingcells #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 user's data 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 NSString *appdir = [[NSBundle mainBundle] resourcePath]; supplieddir = [appdir cStringUsingEncoding:NSUTF8StringEncoding]; supplieddir += "/"; 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"; #if 0 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()); #endif } // ----------------------------------------------------------------------------- - (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 2016 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 { if (drawingcells) return; // 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 (drawingcells) return; // 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 presentViewController:modalInfoController animated:YES completion:nil]; modalInfoController = nil; // RestartGenTimer() will be called in viewDidAppear } // ----------------------------------------------------------------------------- - (IBAction)doSave:(id)sender { if (drawingcells) return; [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 presentViewController:modalSaveController animated:YES completion:nil]; modalSaveController = nil; } // ----------------------------------------------------------------------------- - (IBAction)doUndo:(id)sender { if (drawingcells) return; [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 { if (drawingcells) return; [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 { if (drawingcells) return; [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 { if (drawingcells) return; // this can happen on iPad if user taps Start/Stop button while another finger // is currently drawing cells 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 { if (drawingcells) return; [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 { if (drawingcells) return; [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 { if (drawingcells) return; [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 { if (drawingcells) return; [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 presentViewController:modalRuleController animated:YES completion:nil]; modalRuleController = nil; } // ----------------------------------------------------------------------------- - (IBAction)toggleFullScreen:(id)sender { if (fullscreen) { ShowTabBar(YES); 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 + TabBarHeight()); pattView.frame = CGRectMake(x, y, wd, ht); [statView setNeedsDisplay]; } else { ShowTabBar(NO); 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.8-src/gui-ios/Golly/StatePickerController.h0000644000175100017510000000220612525071110017310 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.8-src/gui-ios/Golly/StateView.h0000644000175100017510000000263112525071110014743 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.8-src/gui-ios/Golly/SaveViewController.h0000644000175100017510000000324712525071110016631 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.8-src/gui-ios/Golly/open.png0000644000175100017510000000036012525071110014323 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.8-src/gui-ios/Golly/OpenViewController.h0000644000175100017510000000267212525071110016635 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.8-src/gui-ios/Golly/SettingsViewController.m0000644000175100017510000002312312660172450017544 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 currlayer, etc #include "undo.h" // for currlayer->undoredo->... #include "view.h" // for ToggleCellColors #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) ToggleCellColors(); 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.8-src/gui-ios/Golly/RuleViewController.h0000644000175100017510000000316712525071110016643 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.8-src/gui-ios/Golly/en.lproj/0000755000175100017510000000000012751756121014501 500000000000000golly-2.8-src/gui-ios/Golly/en.lproj/InfoPlist.strings0000644000175100017510000000005512525071110017726 00000000000000/* Localized versions of Info.plist keys */ golly-2.8-src/gui-ios/Golly/InfoViewController.m0000644000175100017510000001757412660172450016654 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)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 } } // ----------------------------------------------------------------------------- - (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 dismissViewControllerAnimated:YES completion:nil]; } // ----------------------------------------------------------------------------- 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; } @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 presentViewController:modalInfoController animated:YES completion:nil]; modalInfoController = nil; // only reset textfile in viewWillDisappear } golly-2.8-src/gui-ios/Golly/beep.aiff0000644000175100017510000003105612525071110014424 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.8-src/gui-ios/Golly/RuleViewController.m0000644000175100017510000006444412660172450016666 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 dismissViewControllerAnimated:YES completion:nil]; } // ----------------------------------------------------------------------------- - (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 dismissViewControllerAnimated:YES completion:nil]; // 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 pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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 dismissViewControllerAnimated:YES completion:nil]; 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.8-src/gui-ios/Golly/StatusView.m0000644000175100017510000000717612660172450015175 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 top [[UIColor grayColor] setStroke]; CGContextSetLineWidth(context, 1.0); CGContextMoveToPoint(context, 0, 0); CGContextAddLineToPoint(context, wd, 0); 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:14]; // set position of text in each line float lineht = ht / 3.0; CGRect rect1, rect2; rect1.size = [line1 sizeWithAttributes:@{NSFontAttributeName:font}]; rect2.size = [line2 sizeWithAttributes:@{NSFontAttributeName: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 withAttributes:@{NSFontAttributeName:font}]; [line2 drawInRect:rect2 withAttributes:@{NSFontAttributeName:font}]; if (status3.length() > 0) { // display message on bottom line NSString *line3 = [NSString stringWithCString:status3.c_str() encoding:NSUTF8StringEncoding]; CGRect rect3; rect3.size = [line3 sizeWithAttributes:@{NSFontAttributeName:font}]; rect3.origin.x = 5.0; rect3.origin.y = rect2.origin.y + lineht; [line3 drawInRect:rect3 withAttributes:@{NSFontAttributeName:font}]; } } // ----------------------------------------------------------------------------- @end golly-2.8-src/gui-ios/Golly/SettingsViewController.xib0000644000175100017510000004357012660172450020102 00000000000000 golly-2.8-src/gui-ios/Golly/iTunesArtwork0000644000175100017510000011014412525071110015422 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.8-src/gui-ios/Golly/PatternView.m0000644000175100017510000004735712660172450015334 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]; } // ----------------------------------------------------------------------------- - (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]; 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 (fabs(velocity.x) > 1000.0 || fabs(velocity.y) > 1000.0) { TouchMoved(prevpt.x + delta.x * fabs(velocity.x/100.0), prevpt.y + delta.y * fabs(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 (fabs(velocity.x) > 1000.0 || fabs(velocity.y) > 1000.0) { TouchMoved(prevpt.x + delta.x * fabs(velocity.x/100.0), prevpt.y + delta.y * fabs(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) && !drawingcells) { // 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(); } } } // ----------------------------------------------------------------------------- - (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); 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; } // ----------------------------------------------------------------------------- @end golly-2.8-src/gui-ios/Golly/OpenViewController.xib0000644000175100017510000000751712660172450017204 00000000000000 golly-2.8-src/gui-ios/Golly/StatusView.h0000644000175100017510000000200212525071110015136 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.8-src/gui-ios/Golly/HelpViewController.xib0000644000175100017510000000610612660172450017164 00000000000000 golly-2.8-src/gui-ios/Golly/RuleViewController.xib0000644000175100017510000001747612660172450017217 00000000000000 golly-2.8-src/gui-ios/Golly/pattern.png0000644000175100017510000000022012525071110015032 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.8-src/gui-ios/Golly/settings.png0000644000175100017510000000105512525071110015224 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.8-src/gui-ios/Golly/SaveViewController.m0000644000175100017510000003254412660172450016651 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 dismissViewControllerAnimated:YES completion:nil]; } // ----------------------------------------------------------------------------- - (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 dismissViewControllerAnimated:YES completion:nil]; // 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 dismissViewControllerAnimated:YES completion:nil]; 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 presentViewController:modalSaveController animated:YES completion:nil]; modalSaveController = nil; // cannot reset inSaveTextFile here (it must be done in viewWillDisappear) // because doSave: is called AFTER SaveTextFile finishes } golly-2.8-src/gui-ios/Golly/Icon.png0000644000175100017510000000461312525071110014257 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.8-src/gui-ios/Golly/StatePickerView.m0000644000175100017510000001430112660172450016114 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 // ----------------------------------------------------------------------------- - (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(); } } } // ----------------------------------------------------------------------------- - (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 sizeWithAttributes:@{NSFontAttributeName:numfont}]; textrect.size = CGSizeMake(ceilf(textrect.size.width), ceilf(textrect.size.height)); textrect.origin.x = x+1; textrect.origin.y = y+1; textrect.size.height -= 2; [[UIColor whiteColor] setFill]; CGContextFillRect(context, textrect); textrect.origin.y -= 2; [[UIColor blackColor] setFill]; [num drawInRect:textrect withAttributes:@{NSFontAttributeName:numfont}]; // avoid fuzzy lines CGContextSetShouldAntialias(context, false); // draw lines around box 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; } } } // ----------------------------------------------------------------------------- @end golly-2.8-src/gui-ios/Golly/HelpViewController.m0000644000175100017510000002563312660172450016644 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"]; // we could use this instead: // NSString *str = htmlView.request.mainDocumentURL.absoluteString; pageurl = [str cStringUsingEncoding:NSUTF8StringEncoding]; // replace each %20 in pageurl with a space (for GetURL) for (size_t pos = pageurl.find("%20"); pos != std::string::npos; pos = pageurl.find("%20", pos)) { pageurl.replace(pos, 3, " "); } } // ----------------------------------------------------------------------------- - (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.8-src/gui-ios/Golly/HelpViewController.h0000644000175100017510000000260512525071110016620 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.8-src/gui-ios/Golly/GollyAppDelegate.m0000644000175100017510000001152212660172450016227 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; } // ----------------------------------------------------------------------------- void ShowTabBar(bool show) { tabBarController.tabBar.hidden = !show; } // ----------------------------------------------------------------------------- CGFloat TabBarHeight() { return tabBarController.tabBar.frame.size.height; } golly-2.8-src/gui-ios/Golly/SettingsViewController.h0000644000175100017510000000362112525071110017527 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.8-src/docs/0000755000175100017510000000000012751752464011246 500000000000000golly-2.8-src/docs/License.html0000644000175100017510000007602412525071110013424 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.8-src/docs/Build.html0000644000175100017510000004756512751752464013134 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 Python
How to build Golly
      On Windows
      On Mac OS X
      On Linux
Building Golly using configure
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, get the wxMSW source installer.
  • On Mac OS X or Linux, get the source archive for the latest stable release.

Golly should compile with wxWidgets 2.8.0 or later, but it's best to use the latest stable version (3.0.2 at time of writing). Mac users should definitely get 3.0 or later.

On Windows

If your wxWidgets version is earlier than 3.0 then you need to enable OpenGL. Edit \wxWidgets\include\wx\msw\setup.h, find the line "#define wxUSE_GLCANVAS 0" and change the value to 1. If you've previously built wxWidgets 2.x without OpenGL enabled then you might also need to edit \wxWidgets\lib\vc_lib\mswu\wx\setup.h, change wxUSE_GLCANVAS to 1, then run "nmake -f makefile.vc clean" before running "nmake -f makefile.vc".

If you only want to build one wxWidgets configuration (e.g. a 32-bit release) then it's a good idea to edit \wxWidgets\build\msw\config.vc and set all these options:

   BUILD=release
   DEBUG_INFO=0
   DEBUG_FLAG=0
   UNICODE=1             (already 1 in wxWidgets 3.0+)
   USE_OPENGL=1          (already 1 in wxWidgets 3.0+)
   TARGET_CPU=X64        (only if you want a 64-bit build)
   RUNTIME_LIBS=static

Then you can build wxWidgets very simply:

   cd \wxWidgets\build\msw
   nmake -f makefile.vc

If you don't edit config.vc then you'll need to pass all the options to nmake, like so:

For a 64-bit release 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 DEBUG_INFO=0 DEBUG_FLAG=0 TARGET_CPU=X64
                        UNICODE=1 USE_OPENGL=1

For a 32-bit release 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 DEBUG_INFO=0 DEBUG_FLAG=0
                        UNICODE=1 USE_OPENGL=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-3.0.2
   mkdir build-osx
   cd build-osx
   ../configure --with-osx_cocoa --disable-shared --enable-unicode
   make

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 a Golly script wants to update the viewport via an update() or autoupdate(True) command. Without this change, scripts like heisenburp.py will run way too fast.

On Linux

Before building the wxWidgets libraries you might need to install some packages for OpenGL development. For example, on Ubuntu:

   sudo apt-get install mesa-common-dev
   sudo apt-get install freeglut3-dev

Unpack the wxWidgets source archive wherever you like, start up a terminal session and type these commands (using the correct version number):

   cd /path/to/wxWidgets-3.0.2
   mkdir build-gtk
   cd build-gtk
   ../configure --with-gtk --disable-shared --enable-unicode --with-opengl
   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 Python

Golly uses Python for scripting, so you'll need to make sure Python is installed. Mac OS X users don't have to do anything because Python is already installed. Windows and Linux users can download a Python installer from http://www.python.org/download.

How to build Golly

Once wxWidgets 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 Python must also be included, so change the path for PYTHON_INCLUDE if necessary. Now you're ready to build Golly.

If you edited config.vc to set all the options then it's simple:

   cd \path\to\golly\gui-wx
   nmake -f makefile-win

Otherwise you'll need to specify all the same options that were used to build wxWidgets:

For a 64-bit build:

   nmake -f makefile-win BUILD=release RUNTIME_LIBS=static DEBUG_INFO=0 DEBUG_FLAG=0 TARGET_CPU=X64
                         UNICODE=1 USE_OPENGL=1

For a 32-bit build:

   nmake -f makefile-win BUILD=release RUNTIME_LIBS=static DEBUG_INFO=0 DEBUG_FLAG=0
                         UNICODE=1 USE_OPENGL=1

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 will probably 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 for GTK-2 and Python 2.7:

   sudo apt-get install libgtk2.0-dev
   sudo apt-get install python2.7-dev

Then you can build the golly executable:

   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 and automake 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

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 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-web

Contains source code and resources for a web 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).

lua

Contains the source code for Lua.

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 Lua 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::StartGenerating() starts generating a 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 routines for rendering the viewport using OpenGL.
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.

wxlua.*

Implements Lua script support.
RunLuaScript() runs a given .lua file.

wxperl.*

Implements Perl script support if ENABLE_PERL is defined.
No longer officially supported.

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/web 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::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.8-src/docs/ToDo.html0000644000175100017510000000753212675241401012715 00000000000000 To-do notes for Golly
Andrew's list:
==============

- 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).

- 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".

- 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???

- 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:
- 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:
- Allow a command line argument (-minimize?) to start up with the
  main window in minimized state.  Should be possible in OnInit.
golly-2.8-src/docs/ReadMe.html0000644000175100017510000000465312675241401013206 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 Lua 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.8-src/cmdline/0000755000175100017510000000000012751756121011723 500000000000000golly-2.8-src/cmdline/bgolly.cpp0000644000175100017510000005112212675241401013633 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 ; #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 viewport viewport(1000, 1000) ; lifealgo *imp = 0 ; /* * This is a "renderer" that is just stubs, for performance testing. */ class nullrender : public liferender { public: nullrender() {} virtual ~nullrender() {} virtual void pixblit(int, int, int, int, unsigned char*, int) {} virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b, unsigned char* dead_alpha, unsigned char* live_alpha) { static unsigned char dummy[256]; *r = *g = *b = dummy; *dead_alpha = *live_alpha = 255; } } ; nullrender renderer ; // the RuleLoader algo looks for .rule files in the user_rules directory // then in the supplied_rules directory char* user_rules = (char *)""; // can be changed by -s or --search char* supplied_rules = (char *)"Rules/"; /* * This lifeerrors is used to check rendering during a progress dialog. */ class progerrors : public lifeerrors { public: progerrors() {} virtual void fatal(const char *s) { cout << "Fatal error: " << s << endl ; exit(10) ; } virtual void warning(const char *s) { cout << "Warning: " << s << endl ; } virtual void status(const char *s) { cout << s << endl ; } 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 user_rules ; } virtual const char* getrulesdir() { return supplied_rules ; } } ; progerrors progerrors_instance ; bool progerrors::abortprogress(double, const char *) { imp->draw(viewport, renderer) ; return 0 ; } /* * This is our standard lifeerrors. */ class stderrors : public lifeerrors { public: stderrors() {} virtual void fatal(const char *s) { cout << "Fatal error: " << s << endl ; exit(10) ; } virtual void warning(const char *s) { cout << "Warning: " << s << endl ; } virtual void status(const char *s) { #ifdef TIMING cout << timestamp() << " " << s << endl ; #else cout << s << endl ; #endif } virtual void beginprogress(const char *) {} virtual bool abortprogress(double, const char *) { return 0 ; } virtual void endprogress() {} virtual const char* getuserrules() { return user_rules ; } virtual const char* getrulesdir() { return supplied_rules ; } } ; stderrors stderrors_instance ; char *filename ; 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 }, { "-s", "--search", "Search directory for .rule files", 's', &user_rules }, { "-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() { if (imp->gridwd > 0 || imp->gridht > 0) { // bounded grid, so must step by 1 imp->setIncrement(1) ; if (!imp->CreateBorderCells()) exit(10) ; imp->step() ; if (!imp->DeleteBorderCells()) exit(10) ; } else { imp->setIncrement(barg) ; imp->step() ; } if (timeline) imp->extendtimeline() ; 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 ; 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 2016 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 exponentially increasing steps") ; imp = createUniverse() ; if (progress) lifeerrors::seterrorhandler(&progerrors_instance) ; else lifeerrors::seterrorhandler(&stderrors_instance) ; if (verbose) { 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) { err = imp->setrule(liferule) ; if (err) lifefatal(err) ; } bool boundedgrid = (imp->gridwd > 0 || imp->gridht > 0) ; if (boundedgrid) { hyper = 0 ; inc = 1 ; // only step by 1 } 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) ; } if (boundedgrid && !imp->CreateBorderCells()) break ; imp->step() ; if (boundedgrid && !imp->DeleteBorderCells()) break ; if (timeline) imp->extendtimeline() ; 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.8-src/cmdline/RuleTableToTree.cpp0000644000175100017510000001347012525071110015341 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.8-src/gui-web/0000755000175100017510000000000012751756121011647 500000000000000golly-2.8-src/gui-web/shell.html0000644000175100017510000021030712525071110013552 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.8-src/gui-web/patterns.py0000644000175100017510000000110612525071110013762 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.8-src/gui-web/webcalls.cpp0000644000175100017510000005707212660172450014076 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 jsSetStatus(const char* line1, const char* line2, const char* line3); 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); } jsSetStatus(status1.c_str(), status2.c_str(), 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.8-src/gui-web/zlib/0000755000175100017510000000000012751756121012607 500000000000000golly-2.8-src/gui-web/zlib/crc32.c0000644000175100017510000003156612525071110013605 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.8-src/gui-web/zlib/gzguts.h0000644000175100017510000001463012525071110014212 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.8-src/gui-web/zlib/zlib.h0000644000175100017510000025351312525071110013634 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.8-src/gui-web/zlib/uncompr.c0000644000175100017510000000372312525071110014346 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.8-src/gui-web/zlib/README0000644000175100017510000001210112525071110013365 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.8-src/gui-web/zlib/gzwrite.c0000644000175100017510000003750712525071110014365 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.8-src/gui-web/zlib/inffixed.h0000644000175100017510000001427412525071110014467 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.8-src/gui-web/zlib/adler32.c0000644000175100017510000001155012525071110014114 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.8-src/gui-web/zlib/gzclose.c0000644000175100017510000000124612525071110014327 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.8-src/gui-web/zlib/deflate.h0000644000175100017510000003074612525071110014301 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.8-src/gui-web/zlib/infback.c0000644000175100017510000005426512525071110014267 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.8-src/gui-web/zlib/inflate.c0000644000175100017510000015041012525071110014301 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.8-src/gui-web/zlib/trees.h0000644000175100017510000002043012525071110014004 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.8-src/gui-web/zlib/zconf.h0000644000175100017510000003622412525071110014011 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.8-src/gui-web/zlib/compress.c0000644000175100017510000000474112525071110014517 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.8-src/gui-web/zlib/trees.c0000644000175100017510000012633712525071110014014 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.8-src/gui-web/zlib/gzread.c0000644000175100017510000004440612525071110014142 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.8-src/gui-web/zlib/crc32.h0000644000175100017510000007354212525071110013612 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.8-src/gui-web/zlib/inftrees.h0000644000175100017510000000556012525071110014510 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.8-src/gui-web/zlib/inftrees.c0000644000175100017510000003134412525071110014502 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.8-src/gui-web/zlib/inflate.h0000644000175100017510000001437712525071110014321 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.8-src/gui-web/zlib/deflate.c0000644000175100017510000021346412525071110014274 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.8-src/gui-web/zlib/inffast.h0000644000175100017510000000065312525071110014321 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.8-src/gui-web/zlib/inffast.c0000644000175100017510000003221712525071110014315 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.8-src/gui-web/zlib/zutil.h0000644000175100017510000001515612525071110014042 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.8-src/gui-web/zlib/gzlib.c0000644000175100017510000004003712525071110013771 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.8-src/gui-web/zlib/zutil.c0000644000175100017510000001636612525071110014041 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.8-src/gui-web/Makefile0000755000175100017510000004424412525071110013225 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.8-src/gui-web/beep.wav0000644000175100017510000001243012525071110013204 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.8-src/gui-web/Help/0000755000175100017510000000000012751756121012537 500000000000000golly-2.8-src/gui-web/Help/keyboard.html0000644000175100017510000000545412525071110015140 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.8-src/gui-web/Help/about.html0000644000175100017510000000123112751752464014462 00000000000000
This is Golly version 0.8 for the Web

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



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

http://golly.sourceforge.net/
golly-2.8-src/gui-web/Help/help.html0000644000175100017510000000300212525071110014253 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.8-src/gui-web/Help/index.html0000644000175100017510000000164512525071110014445 00000000000000

Table of Contents

golly-2.8-src/gui-web/Help/changes.html0000644000175100017510000000015312525071110014737 00000000000000

Changes

Version 1.0 released !!! 2014

golly-2.8-src/gui-web/Help/problems.html0000644000175100017510000000175112525071110015157 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.8-src/gui-web/images/0000755000175100017510000000000012751756121013114 500000000000000golly-2.8-src/gui-web/images/favicon.ico0000755000175100017510000000706612525071110015154 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.8-src/gui-web/images/about.gif0000644000175100017510000013617112525071110014631 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.8-src/gui-web/images/item_blank.png0000755000175100017510000000020412525071110015631 00000000000000‰PNG  IHDR Ðá.I!tEXtSoftwareGraphicConverter (Intel)w‡úIDATxœbhhh` “¤xTè†Õÿÿ9›€~zŽIEND®B`‚golly-2.8-src/gui-web/images/next.png0000644000175100017510000000035512525071110014506 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.8-src/gui-web/images/redo.png0000644000175100017510000000036112525071110014456 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.8-src/gui-web/images/triangle_down.png0000755000175100017510000000030112525071110016356 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.8-src/gui-web/images/fit.png0000644000175100017510000000030512525071110014305 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.8-src/gui-web/images/cursor_zoomout.png0000644000175100017510000000034612525071110016641 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.8-src/gui-web/images/step.png0000644000175100017510000000033712525071110014503 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.8-src/gui-web/images/cursor_move.png0000644000175100017510000000035112525071110016067 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.8-src/gui-web/images/zoomout.png0000644000175100017510000000042212525071110015237 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.8-src/gui-web/images/cursor_draw.png0000644000175100017510000000032712525071110016061 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.8-src/gui-web/images/step1.png0000644000175100017510000000032112525071110014555 00000000000000‰PNG  IHDRóÿa pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡úVIDATxœbøÿÿ?±øÎ³oÿà$F²æÎ•÷Á˜d`šWxAž0C¨or `ÃDƉ6€"Œ†Á`HH¤@vf‚€>ÿÿʸ”¤V2IEND®B`‚golly-2.8-src/gui-web/images/triangle_right.png0000755000175100017510000000025412525071110016533 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.8-src/gui-web/images/info.png0000755000175100017510000000134012525071110014461 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.8-src/gui-web/images/zoomin.png0000644000175100017510000000042412525071110015040 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.8-src/gui-web/images/reset.png0000644000175100017510000000040012525071110014641 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.8-src/gui-web/images/cursor_pick.png0000644000175100017510000000035012525071110016046 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.8-src/gui-web/images/menu_down.png0000755000175100017510000000024612525071110015525 00000000000000‰PNG  IHDR b û!tEXtSoftwareGraphicConverter (Intel)w‡ú@IDATxœbhhh` &¦ªaX üO Ú…ä†×ËäF0 I5Œ è†’)¸ %FÑ’‚G ÿÿBÁ€í[wêIEND®B`‚golly-2.8-src/gui-web/images/scale1to1.png0000644000175100017510000000033412525071110015321 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.8-src/gui-web/images/slower.png0000644000175100017510000000040312525071110015035 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.8-src/gui-web/images/full.png0000644000175100017510000000025712525071110014473 00000000000000‰PNG  IHDR‘h6 pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú4IDATxœb``h@Cwž}ƒ#LY25 +Â…¯b”¢h„a°’©†©ÿÿë§Ÿœ]ÅIEND®B`‚golly-2.8-src/gui-web/images/start.png0000644000175100017510000000056312525071110014666 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.8-src/gui-web/images/undo.png0000644000175100017510000000035312525071110014473 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.8-src/gui-web/main.cpp0000755000175100017510000020176412660172450013230 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); glEnable(GL_BLEND); 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); } UpdateEverything(); } // ----------------------------------------------------------------------------- static void RotatePasteOrSelection(bool direction) { if (waitingforpaste) { RotatePastePattern(direction); } else if (SelectionExists()) { RotateSelection(direction); } UpdateEverything(); } // ----------------------------------------------------------------------------- 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.9 for the web. Copyright 2016 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.8-src/gui-web/webcalls.h0000644000175100017510000000757612525071110013536 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.8-src/gui-web/jslib.js0000755000175100017510000004070212660172450013232 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 statusbar: null // status bar element }, // ----------------------------------------------------------------------------- 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); }, // ----------------------------------------------------------------------------- jsSetStatus: function(line1, line2, line3) { // check if the statusbar element lookup has already been done if (!GOLLY.statusbar) { // lookup and cache the statusbar element GOLLY.statusbar = document.getElementById('statusbar'); } // set the statusbar GOLLY.statusbar.value = Pointer_stringify(line1) + '\n' + Pointer_stringify(line2) + '\n' + Pointer_stringify(line3); }, // ----------------------------------------------------------------------------- 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.8-src/gui-common/0000755000175100017510000000000012751752464012370 500000000000000golly-2.8-src/gui-common/utils.cpp0000644000175100017510000003516512525071110014143 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.8-src/gui-common/view.cpp0000644000175100017510000015052512660172450013764 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 InitPaste #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 drawingcells = false; // currently drawing cells? 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 Layer* pastelayer = NULL; // temporary layer 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 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(); } // ----------------------------------------------------------------------------- bool OutsideLimits(bigint& t, bigint& l, bigint& b, bigint& r) { return ( t < bigint::min_coord || l < bigint::min_coord || b > bigint::max_coord || r > bigint::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 pastelayer->algo->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(Layer* templayer, 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(), *templayer->algo, 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 templayer->algo; templayer->algo = CreateNewUniverse(i); err = readclipboard(clipfile.c_str(), *templayer->algo, t, l, b, r); if (!err) { templayer->algtype = i; 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 = templayer->algo->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 layer for storing the clipboard pattern if (pastelayer) { Warning("Bug detected in PasteClipboard!"); delete pastelayer; // might as well continue } pastelayer = CreateTemporaryLayer(); if (!pastelayer) return; // read clipboard pattern into pastelayer bigint top, left, bottom, right; if ( GetClipboardPattern(pastelayer, &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 { // temporarily set currlayer to pastelayer so we can update the // paste pattern's colors and icons Layer* savelayer = currlayer; currlayer = pastelayer; UpdateLayerColors(); currlayer = savelayer; #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); InitPaste(pastelayer, pastebox); } } // waitingforpaste will only be false if an error occurred if (!waitingforpaste) { delete pastelayer; pastelayer = 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 pastelayer 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 if (err) { // allow rule change to cause algo change ChangeAlgorithm(pastelayer->algtype, newrule.c_str()); } else { // if pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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); } // use 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* pastealgo = pastelayer->algo; 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 (pastelayer) { delete pastelayer; pastelayer = NULL; } } // ----------------------------------------------------------------------------- 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 pastelayer lifealgo* savealgo = currlayer->algo; int savetype = currlayer->algtype; currlayer->algo = pastelayer->algo; currlayer->algtype = pastelayer->algtype; // 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 pastelayer->algo = currlayer->algo; currlayer->algo = savealgo; currlayer->algtype = savetype; inscript = false; if (result) { InitPaste(pastelayer, 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 pastelayer lifealgo* savealgo = currlayer->algo; int savetype = currlayer->algtype; currlayer->algo = pastelayer->algo; currlayer->algtype = pastelayer->algtype; // 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 pastelayer->algo = 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); InitPaste(pastelayer, pastebox); } return result; } // ----------------------------------------------------------------------------- void ToggleCellColors() { InvertCellColors(); if (pastelayer) { // invert colors used to draw paste pattern for (int n = 0; n <= pastelayer->numicons; n++) { pastelayer->cellr[n] = 255 - pastelayer->cellr[n]; pastelayer->cellg[n] = 255 - pastelayer->cellg[n]; pastelayer->cellb[n] = 255 - pastelayer->cellb[n]; } InvertIconColors(pastelayer->atlas7x7, 8, pastelayer->numicons); InvertIconColors(pastelayer->atlas15x15, 16, pastelayer->numicons); InvertIconColors(pastelayer->atlas31x31, 32, pastelayer->numicons); } } // ----------------------------------------------------------------------------- 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.8-src/gui-common/algos.cpp0000644000175100017510000010531512660172450014114 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() { // QuickLife must be 1st and HashLife must be 2nd qlifealgo::doInitializeAlgoInfo(AlgoData::tick()); hlifealgo::doInitializeAlgoInfo(AlgoData::tick()); // these algos can be in any order (but nicer if alphabetic) generationsalgo::doInitializeAlgoInfo(AlgoData::tick()); jvnalgo::doInitializeAlgoInfo(AlgoData::tick()); // RuleLoader must be last so we can display detailed error messages // (see LoadRule in file.cpp) 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.8-src/gui-common/MiniZip/0000755000175100017510000000000012660172450013735 500000000000000golly-2.8-src/gui-common/MiniZip/ioapi.c0000644000175100017510000000665512525071110015125 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.8-src/gui-common/MiniZip/unzip.c0000644000175100017510000013564112525071110015167 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.8-src/gui-common/MiniZip/zip.h0000644000175100017510000002121712525071110014622 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.8-src/gui-common/MiniZip/zip.c0000644000175100017510000010655512660172450014637 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.8-src/gui-common/MiniZip/unzip.h0000644000175100017510000003125012525071110015163 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.8-src/gui-common/MiniZip/ioapi.h0000644000175100017510000000474712525071110015132 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.8-src/gui-common/MiniZip/crypt.h0000644000175100017510000001105712525071110015162 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.8-src/gui-common/layer.h0000644000175100017510000002475212660172450013575 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 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 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 atlases for rendering icons unsigned char* atlas7x7; // atlas for 7x7 icons unsigned char* atlas15x15; // atlas for 15x15 icons unsigned char* atlas31x31; // atlas for 31x31 icons int numicons; // number of icons (= number of live states) bool multicoloricons; // are icons multi-colored? (grayscale if not) // used if the layer has a timeline 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 }; 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. Layer* CreateTemporaryLayer(); // Create a temporary layer with the same algo type as currlayer. // Color handling routines: void CreateColorGradient(); // Create a color gradient for the current layer using // currlayer->fromrgb and currlayer->torgb. void UpdateIconColors(); // Update the icon texture atlases for the current layer. // Must be called BEFORE calling UpdateCloneColors. 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 icons. void InvertIconColors(unsigned char* atlasptr, int iconsize, int numicons); // Invert the icon colors in the given texture atlas. void SetLayerColors(); // Open a dialog to change the current layer's colors. #endif golly-2.8-src/gui-common/algos.h0000644000175100017510000001160612525071110013547 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.8-src/gui-common/status.h0000644000175100017510000000372212525071110013765 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.8-src/gui-common/prefs.h0000644000175100017510000001415012525071110013556 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.8-src/gui-common/render.h0000644000175100017510000000314412660172450013730 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 Layer; // Routines for rendering the pattern view: #ifdef WEB_GUI bool InitOGLES2(); // Return true if we can create the shaders and program objects // 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 InitPaste(Layer* pastelayer, gRect& bbox); // Initialize some globals used to draw the pattern stored in pastelayer. // 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). #endif golly-2.8-src/gui-common/select.cpp0000644000175100017510000020673012660172450014271 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) currlayer->algo->CreateBorderCells(); currlayer->algo->step(); if (boundedgrid) currlayer->algo->DeleteBorderCells(); 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) tempalgo->CreateBorderCells(); tempalgo->step(); if (boundedgrid) tempalgo->DeleteBorderCells(); 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) currlayer->algo->CreateBorderCells(); currlayer->algo->step(); if (boundedgrid) currlayer->algo->DeleteBorderCells(); 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) currlayer->algo->CreateBorderCells(); currlayer->algo->step(); if (boundedgrid) currlayer->algo->DeleteBorderCells(); 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.8-src/gui-common/Help/0000755000175100017510000000000012751752464013260 500000000000000golly-2.8-src/gui-common/Help/about.gif0000644000175100017510000013617112525071110014767 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.8-src/gui-common/Help/changes-ios.html0000644000175100017510000000502512660172450016256 00000000000000

Changes

Changes in version 1.2 (released !!! 2015)

  • This version requires iOS 7.0 or later.
  • Rendering speed is faster in most 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 an undo/reset bug that could occur if there was a rule change at the starting generation.
  • 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.8-src/gui-common/Help/open-ios.html0000644000175100017510000000402312525071110015573 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.8-src/gui-common/Help/open-android.html0000644000175100017510000000204512525071110016423 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.8-src/gui-common/Help/Algorithms/0000755000175100017510000000000012525071110015346 500000000000000golly-2.8-src/gui-common/Help/Algorithms/HashLife.html0000644000175100017510000000120512525071110017635 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.8-src/gui-common/Help/Algorithms/Generations.html0000644000175100017510000000637212525071110020442 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.8-src/gui-common/Help/Algorithms/RuleLoader.html0000644000175100017510000003170212525071110020215 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.8-src/gui-common/Help/Algorithms/JvN.html0000644000175100017510000000472612525071110016662 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.8-src/gui-common/Help/Algorithms/QuickLife.html0000644000175100017510000001254612525071110020040 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.8-src/gui-common/Help/help-ios.html0000644000175100017510000000321112525071110015560 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.8-src/gui-common/Help/pattern-android.html0000644000175100017510000000351312525071110017140 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.8-src/gui-common/Help/about.html0000644000175100017510000000424412751752464015204 00000000000000


© 2016 The Golly Gang:
Andrew Trevorrow, Tom Rokicki, Tim Hutton, Dave Greene, Chris Rowett,
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.8-src/gui-common/Help/formats.html0000644000175100017510000010172212675241401015531 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.8-src/gui-common/Help/index.html0000644000175100017510000000400612525071110015152 00000000000000

Table of Contents

  • References
  • File Formats
  • Bounded Grids
  • Known Problems
  • Credits
golly-2.8-src/gui-common/Help/Lexicon/0000755000175100017510000000000012525071110014636 500000000000000golly-2.8-src/gui-common/Help/Lexicon/lex_m.htm0000644000175100017510000005647012525071110016410 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.8-src/gui-common/Help/Lexicon/lex_w.htm0000644000175100017510000003244712525071110016420 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.8-src/gui-common/Help/Lexicon/lex_a.htm0000644000175100017510000003660012525071110016365 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.8-src/gui-common/Help/Lexicon/lex_u.htm0000644000175100017510000002327512525071110016415 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.8-src/gui-common/Help/Lexicon/lex_f.htm0000644000175100017510000005502712525071110016376 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.8-src/gui-common/Help/Lexicon/lex_c.htm0000644000175100017510000013501312525071110016365 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.8-src/gui-common/Help/Lexicon/lex_r.htm0000644000175100017510000005011712525071110016405 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.8-src/gui-common/Help/Lexicon/lex_l.htm0000644000175100017510000005327412525071110016406 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.8-src/gui-common/Help/Lexicon/lex.htm0000644000175100017510000001721312525071110016064 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.8-src/gui-common/Help/Lexicon/lex_n.htm0000644000175100017510000002242712525071110016404 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.8-src/gui-common/Help/Lexicon/fix-lex-files.py0000644000175100017510000000402012525071110017600 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.8-src/gui-common/Help/Lexicon/lex_x.htm0000644000175100017510000000664712525071110016424 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.8-src/gui-common/Help/Lexicon/lex_t.htm0000644000175100017510000014606112525071110016413 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.8-src/gui-common/Help/Lexicon/lex_q.htm0000644000175100017510000002161712525071110016407 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.8-src/gui-common/Help/Lexicon/lex_1.htm0000644000175100017510000001177212525071110016310 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.8-src/gui-common/Help/Lexicon/lex_y.htm0000644000175100017510000000456112525071110016416 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.8-src/gui-common/Help/Lexicon/lex_b.htm0000644000175100017510000013047512525071110016373 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.8-src/gui-common/Help/Lexicon/lex_o.htm0000644000175100017510000002513512525071110016404 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.8-src/gui-common/Help/Lexicon/lex_s.htm0000644000175100017510000020255212525071110016410 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.8-src/gui-common/Help/Lexicon/lex_h.htm0000644000175100017510000012241712525071110016376 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.8-src/gui-common/Help/Lexicon/lex_v.htm0000644000175100017510000001134312525071110016407 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.8-src/gui-common/Help/Lexicon/lex_k.htm0000644000175100017510000001270012525071110016372 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.8-src/gui-common/Help/Lexicon/lex_p.htm0000644000175100017510000016062512525071110016411 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.8-src/gui-common/Help/Lexicon/lex_bib.htm0000644000175100017510000001025012525071110016672 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.8-src/gui-common/Help/Lexicon/lex_j.htm0000644000175100017510000001533312525071110016376 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.8-src/gui-common/Help/Lexicon/lex_d.htm0000644000175100017510000005210012525071110016361 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.8-src/gui-common/Help/Lexicon/lex_z.htm0000644000175100017510000000600212525071110016407 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.8-src/gui-common/Help/Lexicon/lex_e.htm0000644000175100017510000006110412525071110016366 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.8-src/gui-common/Help/Lexicon/lex_i.htm0000644000175100017510000003075212525071110016377 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.8-src/gui-common/Help/Lexicon/lex_g.htm0000644000175100017510000007763112525071110016404 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.8-src/gui-common/Help/problems.html0000644000175100017510000000144012660172450015676 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!

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.8-src/gui-common/Help/settings-android.html0000644000175100017510000000030212525071110017314 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.8-src/gui-common/Help/credits.html0000644000175100017510000000561212751752464015527 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, Chris Rowett 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.8-src/gui-common/Help/intro.html0000644000175100017510000000334012525071110015176 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.8-src/gui-common/Help/refs.html0000644000175100017510000000735612675241401015025 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.8-src/gui-common/Help/algos.html0000644000175100017510000000075212525071110015154 00000000000000

Algorithms

Golly can generate patterns using a number of different algorithms:

golly-2.8-src/gui-common/Help/help-android.html0000644000175100017510000000323412525071110016413 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.8-src/gui-common/Help/pattern-ios.html0000644000175100017510000000352312525071110016313 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.8-src/gui-common/Help/settings-ios.html0000644000175100017510000000027412525071110016476 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.8-src/gui-common/Help/changes-android.html0000644000175100017510000000235012660172450017102 00000000000000

Changes

Changes in version 1.2 (released !!!)

  • Icon rendering is faster in most cases.
  • Correct colors/icons are now displayed when pasting a pattern with a rule different to the current layer's rule.
  • Fixed crashes on some Nexus devices.
  • Fixed problem with Move button becoming enabled after a multi-finger pan/zoom.
  • Fixed an undo/reset bug that could occur if there was a rule change at the starting generation.

Changes in version 1.1 (released June 2015)

  • Fixed some bugs that could cause Golly to crash.
  • 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.
  • Fixed bug that could cause Undo button to fail due to a temporary macrocell file containing comment lines not prefixed with #C.
  • Fixed minor problem with the Fit button not centering a pattern accurately in some cases.
  • The size of text in the Open screen has been increased.

Version 1.0 released November 2013

golly-2.8-src/gui-common/Help/archives.html0000644000175100017510000000264312525071110015654 00000000000000

Online Archives

Golly can download patterns and rules from these online archives:

golly-2.8-src/gui-common/Help/bounded.html0000644000175100017510000005566512525071110015504 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.8-src/gui-common/undo.cpp0000644000175100017510000015417712660172450013766 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!"; // the following prefixes are used when creating temporary file names const char* genchange_prefix = "gg_"; const char* setgen_prefix = "gs_"; const char* dupe1_prefix = "g1_"; const char* dupe2_prefix = "g2_"; const char* dupe3_prefix = "g3_"; const char* dupe4_prefix = "g4_"; const char* dupe5_prefix = "g5_"; const char* dupe6_prefix = "g6_"; // ----------------------------------------------------------------------------- // the next two classes are needed because Golly allows multiple starting points // (by setting the generation count back to 0), so we need to ensure that a Reset // goes back to the correct starting info class VariableInfo { public: VariableInfo() {} ~VariableInfo() {} // note that we have to remember pointer to layer and not its index // (the latter can change if user adds/deletes/moves a layer) Layer* layerptr; std::string savename; bigint savex; bigint savey; int savemag; int savebase; int saveexpo; }; class StartingInfo { public: StartingInfo(StartingInfo* dupe, Layer* oldlayer, Layer* newlayer); ~StartingInfo(); void Restore(); void RemoveClone(Layer* cloneptr); // this info is the same in each clone bool savedirty; algo_type savealgo; std::string saverule; // this info can be different in each clone VariableInfo layer[MAX_LAYERS]; int count; }; // ----------------------------------------------------------------------------- StartingInfo::StartingInfo(StartingInfo* dupe, Layer* oldlayer, Layer* newlayer) { if (dupe) { // called from DuplicateHistory so duplicate given starting info savedirty = dupe->savedirty; savealgo = dupe->savealgo; saverule = dupe->saverule; // new duplicate layer is not a clone count = 0; for (int n = 0; n < dupe->count; n++) { if (dupe->layer[n].layerptr == oldlayer) { layer[0].layerptr = newlayer; layer[0].savename = dupe->layer[n].savename; layer[0].savex = dupe->layer[n].savex; layer[0].savey = dupe->layer[n].savey; layer[0].savemag = dupe->layer[n].savemag; layer[0].savebase = dupe->layer[n].savebase; layer[0].saveexpo = dupe->layer[n].saveexpo; count = 1; break; } } } else { // save current starting info (set by most recent SaveStartingPattern) savedirty = currlayer->startdirty; savealgo = currlayer->startalgo; saverule = currlayer->startrule; // save variable info for currlayer and its clones (if any) count = 0; for (int i = 0; i < numlayers; i++) { Layer* lptr = GetLayer(i); if (lptr == currlayer || (lptr->cloneid > 0 && lptr->cloneid == currlayer->cloneid)) { layer[count].layerptr = lptr; layer[count].savename = lptr->startname; layer[count].savex = lptr->startx; layer[count].savey = lptr->starty; layer[count].savemag = lptr->startmag; layer[count].savebase = lptr->startbase; layer[count].saveexpo = lptr->startexpo; count++; } } if (count == 0) Warning("Bug detected in StartingInfo ctor!"); } } // ----------------------------------------------------------------------------- StartingInfo::~StartingInfo() { // no need to do anything } // ----------------------------------------------------------------------------- void StartingInfo::Restore() { // restore starting info (for use by next ResetPattern) currlayer->startdirty = savedirty; currlayer->startalgo = savealgo; currlayer->startrule = saverule; // restore variable info for currlayer and its clones (if any); // note that currlayer might have changed since the starting info // was saved, and there might be more or fewer clones for (int i = 0; i < numlayers; i++) { Layer* lptr = GetLayer(i); for (int n = 0; n < count; n++) { if (lptr == layer[n].layerptr) { lptr->startname = layer[n].savename; lptr->startx = layer[n].savex; lptr->starty = layer[n].savey; lptr->startmag = layer[n].savemag; lptr->startbase = layer[n].savebase; lptr->startexpo = layer[n].saveexpo; break; } } } } // ----------------------------------------------------------------------------- void StartingInfo::RemoveClone(Layer* cloneptr) { for (int n = 0; n < count; n++) { if (layer[n].layerptr == cloneptr) { layer[n].layerptr = NULL; return; } } } // ----------------------------------------------------------------------------- // 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 bool scriptgen; // gen change was done by script? 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 StartingInfo* startinfo; // saves starting info for ResetPattern // 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 oldcurrfile, newcurrfile; // old and new currfile paths // also uses oldgen, newgen // and startinfo // 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; startinfo = NULL; whichlayer = NULL; // simplifies UndoRedo::DeletingClone cellinfo = NULL; cellcount = 0; oldfile.clear(); newfile.clear(); oldtempstart.clear(); newtempstart.clear(); oldcurrfile.clear(); newcurrfile.clear(); } // ----------------------------------------------------------------------------- bool delete_all_temps = false; // ok to delete all temporary files? ChangeNode::~ChangeNode() { if (startinfo) delete startinfo; if (cellinfo) free(cellinfo); // it's always ok to delete oldfile and newfile if they exist if (!oldfile.empty() && FileExists(oldfile)) { RemoveFile(oldfile); } if (!newfile.empty() && FileExists(newfile)) { RemoveFile(newfile); } if (delete_all_temps) { // we're in ClearUndoRedo so it's safe to delete oldtempstart/newtempstart/oldcurrfile/newcurrfile // if they are in tempdir and not being used to store the current layer's starting pattern // (the latter condition allows user to Reset after disabling undo/redo) if (!oldtempstart.empty() && FileExists(oldtempstart) && oldtempstart.compare(0,tempdir.length(),tempdir) == 0 && oldtempstart != currlayer->currfile) { RemoveFile(oldtempstart); } if (!newtempstart.empty() && FileExists(newtempstart) && newtempstart.compare(0,tempdir.length(),tempdir) == 0 && newtempstart != currlayer->currfile) { RemoveFile(newtempstart); } if (!oldcurrfile.empty() && FileExists(oldcurrfile) && oldcurrfile.compare(0,tempdir.length(),tempdir) == 0 && oldcurrfile != currlayer->currfile) { RemoveFile(oldcurrfile); } if (!newcurrfile.empty() && FileExists(newcurrfile) && newcurrfile.compare(0,tempdir.length(),tempdir) == 0 && newcurrfile != currlayer->currfile) { RemoveFile(newcurrfile); } } } // ----------------------------------------------------------------------------- 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: currlayer->currfile = oldcurrfile; if (undo) { currlayer->currsel = oldsel; RestorePattern(oldgen, oldfile.c_str(), oldx, oldy, oldmag, oldbase, oldexpo); } else { if (startinfo) { // restore starting info for use by ResetPattern startinfo->Restore(); } 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->currfile = oldcurrfile; if (startinfo) { // restore starting info for use by ResetPattern startinfo->Restore(); } } else { ChangeGenCount(newgen.tostring(), true); currlayer->startgen = newstartgen; currlayer->savestart = newsave; currlayer->tempstart = newtempstart; currlayer->currfile = newcurrfile; } 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) } } 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 // 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; 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(); } else { // save starting pattern in a unique temporary file prevfile = CreateTempFileName(genchange_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(genchange_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; // also remember the file containing the starting pattern // (in case it is changed by by RememberSetGen or RememberNameChange) change->oldcurrfile = currlayer->currfile; if (change->oldgen == currlayer->startgen) { // save starting info set by recent SaveStartingPattern call // (the info will be restored when redoing this genchange node) change->startinfo = new StartingInfo(NULL, NULL, NULL); } // 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 // until the scriptstart node, or until the list is empty while (!undolist.empty()) { node = undolist.begin(); change = *node; if (change->changeid == scriptstart) { undolist.erase(node); redolist.push_front(change); break; } // undo this change so Reset and Undo restore to the same pattern UndoChange(); } } 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 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(setgen_prefix); // also need to update currfile (currlayer->savestart is true) currlayer->currfile = currlayer->tempstart; } 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->oldcurrfile = oldcurrfile; change->newcurrfile = currlayer->currfile; if (oldtempstart != currlayer->tempstart) { // save starting info set by most recent SaveStartingPattern call // (the info will be restored when undoing this setgen node) change->startinfo = new StartingInfo(NULL, NULL, NULL); } 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 fix up any nodes that have pointers to that clone // (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->whichlayer == cloneptr) { change->whichlayer = NULL; } if (change->startinfo) { change->startinfo->RemoveClone(cloneptr); } node++; } node = redolist.begin(); while (node != redolist.end()) { ChangeNode* change = *node; if (change->whichlayer == cloneptr) { change->whichlayer = NULL; } if (change->startinfo) { change->startinfo->RemoveClone(cloneptr); } 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; } // set flag so ChangeNode::~ChangeNode() can delete all temporary files delete_all_temps = true; // clear the undo/redo lists (and delete each node's data) ClearUndoHistory(); ClearRedoHistory(); delete_all_temps = 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, if necessary, create new // temporary file names in the destnode and copy such files bool allcopied = true; if ( !srcnode->oldfile.empty() && FileExists(srcnode->oldfile) ) { destnode->oldfile = CreateTempFileName(dupe1_prefix); if ( !CopyFile(srcnode->oldfile, destnode->oldfile) ) allcopied = false; } if ( !srcnode->newfile.empty() && FileExists(srcnode->newfile) ) { destnode->newfile = CreateTempFileName(dupe2_prefix); if ( !CopyFile(srcnode->newfile, destnode->newfile) ) allcopied = false; } if ( !srcnode->oldcurrfile.empty() && FileExists(srcnode->oldcurrfile) ) { if (srcnode->oldcurrfile == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->oldcurrfile = tempstart1; } else if (srcnode->oldcurrfile.compare(0,tempdir.length(),tempdir) == 0) { destnode->oldcurrfile = CreateTempFileName(dupe3_prefix); if ( !CopyFile(srcnode->oldcurrfile, destnode->oldcurrfile) ) allcopied = false; } } if ( !srcnode->newcurrfile.empty() && FileExists(srcnode->newcurrfile) ) { if (srcnode->newcurrfile == srcnode->oldcurrfile) { // use destnode->oldcurrfile set above or earlier in DuplicateHistory destnode->newcurrfile = destnode->oldcurrfile; } else if (srcnode->newcurrfile == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->newcurrfile = tempstart1; } else if (srcnode->newcurrfile.compare(0,tempdir.length(),tempdir) == 0) { destnode->newcurrfile = CreateTempFileName(dupe4_prefix); if ( !CopyFile(srcnode->newcurrfile, destnode->newcurrfile) ) 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 if (srcnode->oldtempstart.compare(0,tempdir.length(),tempdir) == 0) { destnode->oldtempstart = CreateTempFileName(dupe5_prefix); if ( !CopyFile(srcnode->oldtempstart, destnode->oldtempstart) ) allcopied = false; } } if ( !srcnode->newtempstart.empty() && FileExists(srcnode->newtempstart) ) { if (srcnode->newtempstart == srcnode->oldtempstart) { // use destnode->oldtempstart set above or earlier in DuplicateHistory destnode->newtempstart = destnode->oldtempstart; } else if (srcnode->newtempstart == currlayer->tempstart) { // the file has already been copied to tempstart1 by Layer::Layer() destnode->newtempstart = tempstart1; } else if (srcnode->newtempstart.compare(0,tempdir.length(),tempdir) == 0) { destnode->newtempstart = CreateTempFileName(dupe6_prefix); if ( !CopyFile(srcnode->newtempstart, destnode->newtempstart) ) allcopied = false; } } 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; // copy existing temporary file to new name if ( !prevfile.empty() && FileExists(prevfile) ) { prevfile = CreateTempFileName(genchange_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); } if (change->startinfo) { newchange->startinfo = new StartingInfo(change->startinfo, oldlayer, newlayer); } // if node is a name change then update whichlayer if (newchange->changeid == namechange) { if (change->whichlayer == oldlayer) { newchange->whichlayer = newlayer; } else { newchange->whichlayer = NULL; } } // 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; } 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); } if (change->startinfo) { newchange->startinfo = new StartingInfo(change->startinfo, oldlayer, newlayer); } // if node is a name change then update whichlayer to point to new layer if (newchange->changeid == namechange) { if (change->whichlayer == oldlayer) { newchange->whichlayer = newlayer; } else { newchange->whichlayer = NULL; } } // 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; } redolist.push_back(newchange); node++; } } golly-2.8-src/gui-common/view.h0000644000175100017510000000710312660172450013422 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 drawingcells; // currently drawing cells? 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 ToggleCellColors(); 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.8-src/gui-common/prefs.cpp0000644000175100017510000005660412525071110014123 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.8-src/gui-common/undo.h0000644000175100017510000001376512660172450013430 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 void ClearUndoHistory(); // clear undolist void ClearRedoHistory(); // clear redolist void SaveCurrentPattern(const char* tempfile); // save current pattern to given temporary file }; #endif golly-2.8-src/gui-common/control.h0000644000175100017510000000402712660172450014132 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(); 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.8-src/gui-common/render.cpp0000644000175100017510000011763512751752464014310 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 pastelayer. ----------------------------------------------------------------------------- */ #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 #include "jnicalls.h" // for LOGI #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 int currwd, currht; // current width and height of viewport, in pixels unsigned char dead_alpha = 255; // alpha value for dead pixels unsigned char live_alpha = 255; // alpha value for live pixels GLuint rgbatexture = 0; // texture name for drawing RGBA bitmaps unsigned char* iconatlas = NULL; // pointer to texture atlas for current set of icons Layer* pastelayer; // layer containing the paste pattern gRect pastebbox; // bounding box in cell coords (not necessarily minimal) // the pxldata array is used to render icons and magnified cells; // its size is chosen so that at scale 1:2 DrawMagnifiedCells will only need to call // DrawRGBAData once (assuming golly_render::pixblit passes in 256x256 bytes of state data) const int maxrows = 256 * 2; const int maxbytes = maxrows * maxrows * 4; // 4 bytes (RGBA) per pixel unsigned char pxldata[maxbytes]; // ----------------------------------------------------------------------------- #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 // fixed texture coordinates used by glTexCoordPointer const GLshort texture_coordinates[] = { 0,0, 1,0, 0,1, 1,1 }; #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; } // ----------------------------------------------------------------------------- GLuint pointProgram; // program object for drawing lines and rects GLint positionLoc; // location of v_Position attribute GLint lineColorLoc; // location of LineColor uniform GLuint textureProgram; // program object for drawing 2D textures GLint texPosLoc; // location of a_Position attribute GLint texCoordLoc; // location of a_texCoord attribute 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" "void main() { \n" " gl_Position = v_Position;\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 glUseProgram(pointProgram); positionLoc = glGetAttribLocation(pointProgram, "v_Position"); lineColorLoc = glGetUniformLocation(pointProgram, "LineColor"); if (positionLoc == -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 (used for drawing lines and rects) GLuint vertexPosObject; glGenBuffers(1, &vertexPosObject); glBindBuffer(GL_ARRAY_BUFFER, vertexPosObject); // create buffer for index data (used for drawing textures) // where each cell = 2 triangles with 2 shared vertices (0 and 2) // // 0 *---* 3 // | \ | // 1 *---* 2 // GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW); 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 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_DYNAMIC_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 glUseProgram(pointProgram); #else if (glIsEnabled(GL_TEXTURE_2D)) { glDisable(GL_TEXTURE_2D); }; #endif } // ----------------------------------------------------------------------------- void DrawRGBAData(unsigned char* rgbadata, int x, int y, int w, int h, int scale = 1) { // called from golly_render::pixblit to draw RGBA data // create texture name once if (rgbatexture == 0) glGenTextures(1, &rgbatexture); #ifdef WEB_GUI glUseProgram(textureProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, rgbatexture); glUniform1i(samplerLoc, 0); #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, rgbatexture); glTexCoordPointer(2, GL_SHORT, 0, texture_coordinates); } #endif glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // update the texture with the new RGBA data glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbadata); if (scale > 1) { // we only do this when drawing icons beyond 1:32 w *= scale; h *= scale; } #ifdef WEB_GUI GLfloat vertices[] = { XCOORD(x), YCOORD(y), // Position 0 = left,top 0.0, 0.0, // TexCoord 0 XCOORD(x), YCOORD(y + h), // Position 1 = left,bottom 0.0, 1.0, // TexCoord 1 XCOORD(x + w), YCOORD(y + h), // Position 2 = right,bottom 1.0, 1.0, // TexCoord 2 XCOORD(x + w), YCOORD(y), // Position 3 = right,top 1.0, 0.0 // TexCoord 3 }; glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); glVertexAttribPointer(texPosLoc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GL_FLOAT), (const GLvoid*)(0)); glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GL_FLOAT), (const GLvoid*)(2 * sizeof(GL_FLOAT))); glEnableVertexAttribArray(texPosLoc); glEnableVertexAttribArray(texCoordLoc); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0); #else 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 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 -- if higher then the 31x31 icons will be scaled up) int iconsize = pmscale > 32 ? 32 : pmscale; int iconwd = (iconsize-1)*4; // allow for 1 pixel gap at right edge int atlas_rowbytes = iconsize * currlayer->numicons * 4; int rowbytes = w*iconsize*4; // probably best to bump rowbytes up to nearest power of 2 int pot = 1; while (pot < rowbytes) pot *= 2; rowbytes = pot; int stripht = h; #ifdef ANDROID_GUI // reduce chances of crashes (probably due to OpenGL ES bug, and only on some Nexus devices???) if (pmscale > 16) stripht = 1; #endif int numbytes = rowbytes*stripht*iconsize; while (numbytes > maxbytes) { // do 2 or more horizontal strips if (stripht == 1) { // LOGI("BUG in DrawIcons: rowbytes=%d pmscale=%d\n", rowbytes, pmscale); return; } stripht = (stripht+1) / 2; numbytes = rowbytes*stripht*iconsize; } int nextstrip = 0; do { memset(pxldata, 0, numbytes); // all pixels are initially transparent bool sawlivecell = false; // at least one icon needs to be displayed? for (int row = nextstrip; row < nextstrip+stripht && row < h; row++) { for (int col = 0; col < w; col++) { unsigned char state = statedata[row*stride + col]; if (state > 0) { // get position in pxldata of icon's top left pixel int pos = (row-nextstrip)*rowbytes*iconsize + col*iconsize*4; // copy pixel data for icon from appropriate place in iconatlas int ipos = (state-1)*iconsize*4; // subtract 1 from iconsize to allow for 1 pixel gap at bottom edge of icon for (int i = 0; i < iconsize-1; i ++) { memcpy(&pxldata[pos], &iconatlas[ipos], iconwd); pos += rowbytes; ipos += atlas_rowbytes; } sawlivecell = true; } } } if (sawlivecell) DrawRGBAData(pxldata, x, y, rowbytes/4, stripht*iconsize, pmscale/iconsize); y += stripht*pmscale; nextstrip += stripht; } while (nextstrip < h); } // ----------------------------------------------------------------------------- void DrawMagnifiedCells(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) int rowbytes = w*pmscale*4; // probably best to bump rowbytes up to nearest power of 2 int pot = 1; while (pot < rowbytes) pot *= 2; rowbytes = pot; // if pmscale is > 2 then there is a 1 pixel gap at right and bottom edge of each cell int cellsize = pmscale > 2 ? (pmscale-1)*4 : pmscale*4; int rowtotal = pmscale > 2 ? (pmscale-1)*rowbytes : pmscale*rowbytes; int stripht = h; #ifdef ANDROID_GUI // reduce chances of crashes (probably due to OpenGL ES bug, and only on some Nexus devices???) if (pmscale > 16) stripht = 1; #endif int numbytes = rowbytes*stripht*pmscale; while (numbytes > maxbytes) { // do 2 or more horizontal strips if (stripht == 1) { // LOGI("BUG in DrawMagCells: rowbytes=%d pmscale=%d\n", rowbytes, pmscale); return; } stripht = (stripht+1) / 2; numbytes = rowbytes*stripht*pmscale; } int nextstrip = 0; do { memset(pxldata, 0, numbytes); // all pixels are initially transparent bool sawlivecell = false; // at least one live cell needs to be displayed? for (int row = nextstrip; row < nextstrip+stripht && row < h; row++) { for (int col = 0; col < w; col++) { unsigned char state = statedata[row*stride + col]; if (state > 0) { // set cell's top left pixel int pos = (row-nextstrip)*rowbytes*pmscale + col*pmscale*4; pxldata[pos] = currlayer->cellr[state]; pxldata[pos+1] = currlayer->cellg[state]; pxldata[pos+2] = currlayer->cellb[state]; pxldata[pos+3] = live_alpha; // copy 1st pixel to remaining pixels in 1st row for (int i = 4; i < cellsize; i += 4) { memcpy(&pxldata[pos+i], &pxldata[pos], 4); } // copy 1st row of pixels to remaining rows for (int i = rowbytes; i < rowtotal; i += rowbytes) { memcpy(&pxldata[pos+i], &pxldata[pos], cellsize); } sawlivecell = true; } } } if (sawlivecell) DrawRGBAData(pxldata, x, y, rowbytes/4, stripht*pmscale); y += stripht*pmscale; nextstrip += stripht; } while (nextstrip < h); } // ----------------------------------------------------------------------------- class golly_render : public liferender { public: golly_render() {} virtual ~golly_render() {} virtual void pixblit(int x, int y, int w, int h, unsigned char* pm, int pmscale); virtual void getcolors(unsigned char** r, unsigned char** g, unsigned char** b, unsigned char* deada, unsigned char* livea); }; golly_render renderer; // create instance // ----------------------------------------------------------------------------- void golly_render::pixblit(int x, int y, int w, int h, unsigned char* pmdata, int pmscale) { 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; } if (pmscale == 1) { // draw RGBA pixel data at scale 1:1 DrawRGBAData(pmdata, x, y, w, h); } else if (showicons && pmscale > 4 && iconatlas) { // draw icons at scales 1:8 and above DrawIcons(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 DrawMagnifiedCells(pmdata, x, y, w/pmscale, h/pmscale, pmscale, stride); } } // ----------------------------------------------------------------------------- void golly_render::getcolors(unsigned char** r, unsigned char** g, unsigned char** b, unsigned char* deada, unsigned char* livea) { *r = currlayer->cellr; *g = currlayer->cellg; *b = currlayer->cellb; *deada = dead_alpha; *livea = live_alpha; } // ----------------------------------------------------------------------------- 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 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 InitPaste(Layer* player, gRect& bbox) { // set globals used in DrawPasteImage pastelayer = player; pastebbox = bbox; } // ----------------------------------------------------------------------------- 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); // set up viewport for drawing paste pattern pastelayer->view->resize(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; } pastelayer->view->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 = pastelayer->view->getwidth(); currht = pastelayer->view->getheight(); #ifdef WEB_GUI // temporarily change OpenGL viewport's origin and size to match pastelayer->view glViewport(ileft, saveht-currht-itop, currwd, currht); #else glTranslatef(ileft, itop, 0); #endif // make dead pixels 100% transparent and live pixels 100% opaque dead_alpha = 0; live_alpha = 255; // temporarily set currlayer to pastelayer so golly_render routines // will use the paste pattern's color and icons Layer* savelayer = currlayer; currlayer = pastelayer; if (showicons && pastemag > 2) { // only show icons at scales 1:8 and above if (pastemag == 3) { iconatlas = currlayer->atlas7x7; } else if (pastemag == 4) { iconatlas = currlayer->atlas15x15; } else { iconatlas = currlayer->atlas31x31; } } // draw paste pattern pastelayer->algo->draw(*pastelayer->view, renderer); #ifdef WEB_GUI // restore OpenGL viewport's origin and size glViewport(0, 0, savewd, saveht); #else glTranslatef(-ileft, -itop, 0); #endif currlayer = savelayer; 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 add/subtract 0.5 from coordinates 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) { #ifdef WEB_GUI GLfloat points[] = { XCOORD( -0.5), YCOORD(v-0.5), XCOORD(wd+0.5), 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) { #ifdef WEB_GUI GLfloat points[] = { XCOORD(h-0.5), YCOORD( -0.5), XCOORD(h-0.5), YCOORD(ht+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[] = { 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) { #ifdef WEB_GUI GLfloat points[] = { XCOORD( -0.5), YCOORD(v-0.5), XCOORD(wd+0.5), 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) { #ifdef WEB_GUI GLfloat points[] = { XCOORD(h-0.5), YCOORD( -0.5), XCOORD(h-0.5), YCOORD(ht+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[] = { h-0.5, -0.5, h-0.5, ht+0.5 }; glVertexPointer(2, GL_FLOAT, 0, points); #endif glDrawArrays(GL_LINES, 0, 2); } } } } // ----------------------------------------------------------------------------- void DrawPattern(int tileindex) { gRect r; int currmag = currlayer->view->getmag(); // 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, currmag); else if ( currlayer->view->x > currlayer->algo->gridright ) currlayer->view->setpositionmag(currlayer->algo->gridright, currlayer->view->y, currmag); } if ( currlayer->algo->gridht > 0) { if ( currlayer->view->y < currlayer->algo->gridtop ) currlayer->view->setpositionmag(currlayer->view->x, currlayer->algo->gridtop, currmag); else if ( currlayer->view->y > currlayer->algo->gridbottom ) currlayer->view->setpositionmag(currlayer->view->x, currlayer->algo->gridbottom, currmag); } if (nopattupdate) { // don't draw incomplete pattern, just draw grid lines and border currwd = currlayer->view->getwidth(); currht = currlayer->view->getheight(); if ( showgridlines && currmag >= mingridmag ) { DrawGridLines(currwd, currht); } if ( currlayer->algo->gridwd > 0 || currlayer->algo->gridht > 0 ) { DrawGridBorder(currwd, currht); } return; } if (showicons && currmag > 2) { // only show icons at scales 1:8 and above if (currmag == 3) { iconatlas = currlayer->atlas7x7; } else if (currmag == 4) { iconatlas = currlayer->atlas15x15; } else { iconatlas = currlayer->atlas31x31; } } currwd = currlayer->view->getwidth(); currht = currlayer->view->getheight(); // all pixels are initially opaque dead_alpha = 255; live_alpha = 255; // draw pattern using a sequence of pixblit calls currlayer->algo->draw(*currlayer->view, renderer); if ( showgridlines && currmag >= 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, true); } if (waitingforpaste) { DrawPasteImage(); } } golly-2.8-src/gui-common/layer.cpp0000644000175100017510000021525112660172450014124 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->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; } } } } // ----------------------------------------------------------------------------- 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* CreateIconAtlas(gBitmapPtr* srcicons, int iconsize) { 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; } // allocate enough memory for texture atlas to store RGBA pixels for a row of icons // (note that we use calloc so all alpha bytes are initially 0) int rowbytes = currlayer->numicons * iconsize * 4; unsigned char* atlasptr = (unsigned char*) calloc(rowbytes * iconsize, 1); if (atlasptr) { for (int state = 1; state <= currlayer->numicons; state++) { if (srcicons && srcicons[state]) { int wd = srcicons[state]->wd; // should be iconsize - 1 int ht = srcicons[state]->ht; // ditto unsigned char* icondata = srcicons[state]->pxldata; if (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; } // start at top left byte of icon int tpos = (state-1) * iconsize * 4; int ipos = 0; for (int row = 0; row < ht; row++) { int rowstart = tpos; 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) { atlasptr[tpos] = 255 - r; atlasptr[tpos+1] = 255 - g; atlasptr[tpos+2] = 255 - b; } else { atlasptr[tpos] = r; atlasptr[tpos+1] = g; atlasptr[tpos+2] = b; } } else { // grayscale icon (r = g = b) if (r == 255) { // replace white pixel with live cell color atlasptr[tpos] = liver; atlasptr[tpos+1] = liveg; atlasptr[tpos+2] = liveb; } else { // replace gray pixel with appropriate shade between // live and dead cell colors float frac = (float)r / 255.0; atlasptr[tpos] = (int)(deadr + frac * (liver - deadr) + 0.5); atlasptr[tpos+1] = (int)(deadg + frac * (liveg - deadg) + 0.5); atlasptr[tpos+2] = (int)(deadb + frac * (liveb - deadb) + 0.5); } } atlasptr[tpos+3] = 255; // alpha channel is opaque } // move to next pixel tpos += 4; ipos += 4; } // move to next row tpos = rowstart + rowbytes; } } } } } return atlasptr; } // ----------------------------------------------------------------------------- Layer* CreateTemporaryLayer() { Layer* templayer = new Layer(); if (templayer == NULL) Warning("Failed to create temporary layer!"); return templayer; } // ----------------------------------------------------------------------------- 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; currlayer->multicoloricons = oldlayer->multicoloricons; currlayer->numicons = oldlayer->numicons; for (int n = 0; n <= currlayer->numicons; 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 atlas currlayer->atlas7x7 = oldlayer->atlas7x7; currlayer->atlas15x15 = oldlayer->atlas15x15; currlayer->atlas31x31 = oldlayer->atlas31x31; } 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 atlases currlayer->atlas7x7 = CreateIconAtlas(oldlayer->icons7x7, 8); currlayer->atlas15x15 = CreateIconAtlas(oldlayer->icons15x15, 16); currlayer->atlas31x31 = CreateIconAtlas(oldlayer->icons31x31, 32); } } 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(); } } !!!*/ // ----------------------------------------------------------------------------- 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 texture atlases if (layer->atlas7x7) { free(layer->atlas7x7); layer->atlas7x7 = NULL; } if (layer->atlas15x15) { free(layer->atlas15x15); layer->atlas15x15 = NULL; } if (layer->atlas31x31) { free(layer->atlas31x31); layer->atlas31x31 = 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 atlases (used for rendering) currlayer->numicons = maxstate; currlayer->atlas7x7 = CreateIconAtlas(currlayer->icons7x7, 8); currlayer->atlas15x15 = CreateIconAtlas(currlayer->icons15x15, 16); currlayer->atlas31x31 = CreateIconAtlas(currlayer->icons31x31, 32); 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 UpdateCloneColors() { if (currlayer->cloneid > 0) { 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; cloneptr->multicoloricons = currlayer->multicoloricons; cloneptr->numicons = currlayer->numicons; for (int n = 0; n <= currlayer->numicons; 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 atlas cloneptr->atlas7x7 = currlayer->atlas7x7; cloneptr->atlas15x15 = currlayer->atlas15x15; cloneptr->atlas31x31 = currlayer->atlas31x31; } } } } // ----------------------------------------------------------------------------- void UpdateLayerColors() { UpdateCurrentColors(); // above has created icon texture data so don't call UpdateIconColors here // if current layer has clones then update their colors UpdateCloneColors(); } // ----------------------------------------------------------------------------- void UpdateIconColors() { // delete current icon texture atlases if (currlayer->atlas7x7) { free(currlayer->atlas7x7); } if (currlayer->atlas15x15) { free(currlayer->atlas15x15); } if (currlayer->atlas31x31) { free(currlayer->atlas31x31); } // re-create icon texture atlases currlayer->atlas7x7 = CreateIconAtlas(currlayer->icons7x7, 8); currlayer->atlas15x15 = CreateIconAtlas(currlayer->icons15x15, 16); currlayer->atlas31x31 = CreateIconAtlas(currlayer->icons31x31, 32); } // ----------------------------------------------------------------------------- void InvertIconColors(unsigned char* atlasptr, int iconsize, int numicons) { if (atlasptr) { int numbytes = numicons * iconsize * iconsize * 4; int i = 0; while (i < numbytes) { if (atlasptr[i+3] == 0) { // ignore transparent pixel } else { // invert pixel color atlasptr[i] = 255 - atlasptr[i]; atlasptr[i+1] = 255 - atlasptr[i+1]; atlasptr[i+2] = 255 - atlasptr[i+2]; } i += 4; } } } // ----------------------------------------------------------------------------- void InvertCellColors() { bool clone_inverted[MAX_LAYERS] = {false}; // swapcolors has changed so 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) int maxstate = algoinfo[layerptr->algtype]->maxstates - 1; for (int n = 0; n <= maxstate; n++) { layerptr->cellr[n] = 255 - layerptr->cellr[n]; layerptr->cellg[n] = 255 - layerptr->cellg[n]; layerptr->cellb[n] = 255 - layerptr->cellb[n]; } // clones share icon texture data so we must be careful to only invert them once if (layerptr->cloneid == 0 || !clone_inverted[layerptr->cloneid]) { // invert colors in icon texture atlases // (do NOT use maxstate here -- might be > layerptr->numicons) InvertIconColors(layerptr->atlas7x7, 8, layerptr->numicons); InvertIconColors(layerptr->atlas15x15, 16, layerptr->numicons); InvertIconColors(layerptr->atlas31x31, 32, layerptr->numicons); if (layerptr->cloneid > 0) clone_inverted[layerptr->cloneid] = true; } } } // ----------------------------------------------------------------------------- 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 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 atlas7x7 = NULL; // no texture atlas for 7x7 icons atlas15x15 = NULL; // no texture atlas for 15x15 icons atlas31x31 = NULL; // no texture atlas for 31x31 icons currframe = 0; // first frame in timeline autoplay = 0; // not playing tlspeed = 0; // default speed for autoplay // 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; // 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 currfile = currlayer->currfile; savestart = currlayer->savestart; startalgo = currlayer->startalgo; startdirty = currlayer->startdirty; startrule = currlayer->startrule; startx = currlayer->startx; starty = currlayer->starty; startbase = currlayer->startbase; startexpo = currlayer->startexpo; startmag = currlayer->startmag; startgen = currlayer->startgen; startsel = currlayer->startsel; startname = currlayer->startname; if (cloning) { // if clone is created after pattern has been generated // then we don't want a reset to change its name startname = currlayer->currname; } else { startname = currlayer->startname; } } 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->currfile == currlayer->tempstart) { 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.8-src/gui-common/utils.h0000644000175100017510000000750712751752464013632 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 Lua or Perl or Python script. // It simply checks if the file's extension is .lua or .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.8-src/gui-common/status.cpp0000644000175100017510000002102012525071110014307 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.8-src/gui-common/file.cpp0000644000175100017510000012255112660172450013727 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 "ruleloaderalgo.h" // for noTABLEorTREE #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(); // InitAlgorithms ensures the RuleLoader algo is the last algo int rule_loader_algo = NumAlgos() - 1; const char* err; if (currlayer->algtype == rule_loader_algo) { // RuleLoader is current algo so no need to switch err = currlayer->algo->setrule(rulestring.c_str()); } else { // switch to RuleLoader algo lifealgo* tempalgo = CreateNewUniverse(rule_loader_algo); err = tempalgo->setrule(rulestring.c_str()); delete tempalgo; if (!err) { // change the current algorithm and switch to the new rule ChangeAlgorithm(rule_loader_algo, rulestring.c_str()); if (rule_loader_algo != currlayer->algtype) { RestoreRule(oldrule.c_str()); Warning("Algorithm could not be changed (pattern is too big to convert)."); } return; } } if (err) { // RuleLoader algo found some sort of error if (strcmp(err, noTABLEorTREE) == 0) { // .rule file has no TABLE or TREE section but it might be used // to override a built-in rule, so try each algo std::string temprule = rulestring; std::replace(temprule.begin(), temprule.end(), '_', '/'); // eg. convert B3_S23 to B3/S23 for (int i = 0; i < NumAlgos(); i++) { lifealgo* tempalgo = CreateNewUniverse(i); err = tempalgo->setrule(temprule.c_str()); delete tempalgo; if (!err) { // change the current algorithm and switch to the new rule ChangeAlgorithm(i, temprule.c_str()); if (i != currlayer->algtype) { RestoreRule(oldrule.c_str()); Warning("Algorithm could not be changed (pattern is too big to convert)."); } return; } } } RestoreRule(oldrule.c_str()); std::string msg = "The rule file is not valid:\n"; msg += rulestring; msg += "\n\nThe error message:\n"; msg += err; Warning(msg.c_str()); return; } std::string newrule = currlayer->algo->getrule(); int newmaxstate = currlayer->algo->NumCellStates() - 1; if (oldrule != newrule || oldmaxstate != newmaxstate) { // if pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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 if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { ReduceCellStates(newmaxstate); } if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberRuleChange(oldrule.c_str()); } } // set colors for new rule UpdateLayerColors(); } // ----------------------------------------------------------------------------- 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.8-src/gui-common/file.h0000644000175100017510000000410012525071110013350 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.8-src/gui-common/control.cpp0000644000175100017510000012025012751752464014474 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 (use currlayer->currfile as the starting pattern) if (currlayer->currfile.empty()) Warning("Bug in SaveStartingPattern: currfile is empty!"); return true; } currlayer->currfile = currlayer->tempstart; // ResetPattern will load tempstart // 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; } } 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->currfile.empty()) { // 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 LoadPattern(currlayer->currfile.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); std::string msg = "Failed to reset pattern from this file:\n"; msg += currlayer->currfile; Warning(msg.c_str()); } // 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) { // best to clear the pattern and set the expected gen count CreateUniverse(); currlayer->algo->setGeneration(gen); std::string msg = "Could not restore pattern from this file:\n"; msg += filename; Warning(msg.c_str()); } // 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; } // ----------------------------------------------------------------------------- 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 (!curralgo->CreateBorderCells()) break; curralgo->step(); if (!curralgo->DeleteBorderCells()) 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) curralgo->CreateBorderCells(); curralgo->step(); if (boundedgrid) curralgo->DeleteBorderCells(); 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) { 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)."); } else { UpdateEverything(); } return; } } } // should only get here if .rule 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(); int newmaxstate = currlayer->algo->NumCellStates() - 1; if (oldrule != newrule || oldmaxstate != newmaxstate) { UpdateStatus(); // if pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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 if (newmaxstate < oldmaxstate && !currlayer->algo->isEmpty()) { ReduceCellStates(newmaxstate); } if (allowundo && !currlayer->stayclean) { currlayer->undoredo->RememberRuleChange(oldrule.c_str()); } } // set colors and icons for new rule UpdateLayerColors(); // pattern or colors or icons might have changed UpdateEverything(); } // ----------------------------------------------------------------------------- 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 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 (rulechanged) { 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.8-src/gui-common/select.h0000644000175100017510000001475012525071110013724 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.8-src/gui-android/0000755000175100017510000000000012751756120012511 500000000000000golly-2.8-src/gui-android/Golly/0000755000175100017510000000000012751756121013600 500000000000000golly-2.8-src/gui-android/Golly/gradlew0000644000175100017510000001173012660172450015066 00000000000000#!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # For Cygwin, ensure paths are in UNIX format before anything is touched. if $cygwin ; then [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` fi # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >&- APP_HOME="`pwd -P`" cd "$SAVED" >&- CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" golly-2.8-src/gui-android/Golly/build.gradle0000644000175100017510000000047212660172450015776 00000000000000// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle-experimental:0.2.0' } } allprojects { repositories { jcenter() } } golly-2.8-src/gui-android/Golly/gradlew.bat0000644000175100017510000000441212660172450015632 00000000000000@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega golly-2.8-src/gui-android/Golly/gradle/0000755000175100017510000000000012751756120015035 500000000000000golly-2.8-src/gui-android/Golly/gradle/wrapper/0000755000175100017510000000000012751756121016516 500000000000000golly-2.8-src/gui-android/Golly/gradle/wrapper/gradle-wrapper.properties0000644000175100017510000000034612660172450023467 00000000000000#Wed Apr 10 15:27:10 PDT 2013 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip golly-2.8-src/gui-android/Golly/gradle/wrapper/gradle-wrapper.jar0000644000175100017510000014135012660172450022050 00000000000000PK  ;„B META-INF/PK  ;„BÓ¸àNhMETA-INF/MANIFEST.MFóMÌËLK-.Ñ K-*ÎÌϳR0Ô3àåòÌ-ÈIÍMÍ+I, ê†d–ä¤Z)¸%¦ä¤bÈ"i5Ó520460BS##Sm àåâåPK  ;„Borg/PK  ;„B org/gradle/PK  ;„Borg/gradle/wrapper/PK  ;„Bh‚df£Õ#org/gradle/wrapper/Download$1.class}ŒM Â0…ßh5Z+v/‚ ׆žÁp!.óOí2ÄâC¢¶ÃRÝ ÄëÞQCÈ7¼áSÄ®‡Mîpééý8˜P/bXßDJíɰ+¤òDDÞñ ÚS(¯ÉU(¬WA dÍçQ$ˆó¼ʶۖ¼å ·/y—¨î‹°ø!omÎ/XaXn µGåú¡lM`^0l8Åúþ‘»Pî줊» ùιZÊ=˜ØñCaN"ƒ¹ödS¼ôôx2gPIK±Á"Õ˜#‹a±£T·ÔÕG~ iàž…\ºƒ?ÀW#;ÊîãîðÐÀ#†Ýÿ.Cî·Ê)`õÜ 0d‡DŸmwÔ‡!­ïiÔmÀ°åÔ'R”ô‚v¥øwˆáɌĤf§c$B…µ—U)9‰H8ÅÃC~F‹Ãš¾î•sމ5úË,è/Ž˜¾UzDK´sÉÒ‹ÂÂö bŸÉ‰!Kkr|‹´Z£ظB6òcr•¢ËCü8Å‚´S¤¾à ÌOSååò£rfpm\î)ÙØX ›­%7JkÑÞ ®i«Ãü¸LÖ&/".ÁÄU²È¦~PK  ;„BçìXsªÛ"org/gradle/wrapper/IDownload.classEÁ Â0 †ÿÌéæ¼ ^õbñ¼« APô^·26J;êt>›À‡;•É—üùó|Ýè{èz~¢+%5O“é&çWΔ(Ùa…_Ê4[gR„³#!XÝbQ”™Vg=Ë{}1±¨÷„A´üYÍëCÂX›”¥†'R°Êð¢†5Âðc/¹JÙö”‹¸$Œþ£æS‡@pP¹„\ËmKuíØôlïÀPK  ;„BÛHE*P 3org/gradle/wrapper/ExclusiveFileAccessManager.class•VKpU=/™Ì/†€2 „‰"“ˆ†‘@`ȇ@ I'iÒé{zâÿ‡ñ»±Ê=K¥J0‘*KKË….)7n¬r¡å‚rc•âyÝ“/›×ïÝw?çÞ{Þùþß/®x†Q‰TÑ,—–Ž„áÃÑZÃð#%mr×D‡ü“’N¹ãº8Ä©0J¥°§ÃxgÂtÕÆY¨ô‘–†½AhÒ¬/Œrôczç0€!%CÅ0a àI¥©#ÉÃÝM©ýÝíÇ›N”¥Î©ÃjÜPÍþx»cëf@IÒ2³Žj:ª‘ÓBŽ>¤Y9§9+ š–d,Ãh2ÍV )ô×ë¦îì(Š55Uu ø’V/ KSº©µä†z4»Cí14ÏJ«F§jëòœúœ^â)Ëî÷Ûj¯¡ÅGl5“Ñìøþói#—Õ‡µFÝÐÒi-›mVMµ_³ Ô¯º†˜—‡nÅ¥^wÊ9ºO[f:gÛšéÄ“ªaȈuU3²>ÒsNK;t`ʶÓà0ÇCÄdXéA OÓ¤ãô€jšš‘u#0AÚ¢_9ÃÑjG·LYEm&tVm6D™¶šeˆ ÿV (±xN–ÚªÙk y…ðDk¦ý¶Í¹“IåQO‡™—IÒ;P·|voF3SýÙ|w„õu{ij×ûMÕÉÙ4i®ïHÌ/òÞ{j“ç·Š«À²!u´GKVVkÍéšcŒïoî…×Z²ÏO–DJOÉ–/ ,n·rv:ß¡ ‹“m»4VP[ÁýØ¢ †-ÊÌldAò¬šû öåt£W£]à Fpžßn¤ŒJAžRð4ž àYÏáyÕ‹õS ÀQð^ à%/ãûÑÀ¯â5RáNì¶œ)_í4!Š;¼Wµú¢Çë|qQ[SÓZotDÕböYvtš·QïyE+ÚÇð š½áA~3€·¼w¸¨à]جï¯@ª¾Àû >*5÷ô¾Iö¹(ŒÉ—ôkÎQU’%ÿ*bUsW€*-ê/WĪr~ßì%ªØüëùù.Ê×èXžH`Ó‚|žåHÒqh°W·³.ø“³²jÍ:ÚÙ§¾ìP³nº§Ì1fÉ©'¼q*“»<âuwU`]{4厶õ‹zË·@;HÖª(khZ†Ž’™UÄšîV©R‚oèÉZFÎÑŽªÎgåBµîœB½Ø `<&cn+§'÷šÅÓ`¶fhj–NVÏ ÎŒ¬‘鉱lÞl`®îðàoîFþ˜…ˆ`6Cà>ž F™œÜ—Éaàjò½šëVžº¨SÈoiõ8DõÚ+(¨®¸‚ÂË®ñ6×ÌÇu#×J„èz ×Põ̰qÀÝÉ0ÂÝÉ@Ü×òOF Sp–@TLÀ×µu Eðw#Àmp ¡²0—1Ci©áíJŽ‹„O$Š®bÉ.¿H#ÁoÑÈC¹¿ús\P?ú»&PÚUS¶t˾ˆo e‰¢M—»Ú·ŒÐxEÄÇ…&…®bå¥ÛÒOÍÊ»òÊV1²t9†Õeî‰h͘µ“Û®¡B Šå:×!1¹> ïN€Hè³DxaðdÂñß@ùÇEü_¡|RFøÇ±a2Q<ÃEñ$kô)Æq“5¼‰ŸÝo-~À-¬çþ–ûåY”È{Qê~ Ý]d_ÀšW²òÕln ×Z®;ÙÝܥ؇xÝØ>Jñ02ØÅQ¿›cºð#70v_rVß@#¾Æ|‡ƒŒßŠŸÐFIü»_y÷ïþàÝ-Â_8Œ…h!¢V±‚º’§É–¸Î¨;˜×nLà!žƒÔ_Íè»(#¦ØÃÝnì‘ìá.:²¦ÙfXƒ?‰o/X‹ßñ(C±‚|šÒßGý¤ËØÇIxþÖäÉ}Šß—Üß ¤ú¢—àK]¦ØGÅÔ#y9]Ç)í¢ü4oN’ègÜDÊ©³„ßíÑû š$f&/CþPK  ;„Bc¯º`-org/gradle/wrapper/WrapperConfiguration.class’ÛnÓ@†g“8N7Ρ--ç@¡Ž[ê¸QU”6¤@QB[‰›ÊIŒë*Ø‘í€ÄSD„ÄÀC!f×N›,‰ ÏÌÎÎ?óyìß~þ€:×q_¨øRÇ-Éù _«øFÇ·øNÇ÷øAÅm?â'ÏþHeÿ+ÐK±äp1‹Îár‘Å©ì 9pdò vmˆJ_³ÔðÇSvV:“áXÔí W7KG«ˆt´B¿øRŸ¦tí‹-®V¤FgJ8ç’Ž½ “ËÞ jÜNg<|ž’RÍÇà‹ WBZªF…›Êrng}™zÉljªæ2¾¤‘‹tá³¼¥Žõ¡w´4ú¡¤áÄĵœ°â¢F£´ —ñÇØ7oÊ:ûŽãlÖ¬ÂÖJqI +á&½†%MÈüþOý×ó(ÎÀõlDÇk˜?“Cìã¯ò¯ŠœO¤xŠpU¸ú;W¡ü<æ"Õ £ƒk:ÑE-+÷áC¼?ÖP7³Šú±Î<|¿Àßµ²?ñ5¨3ôœèîÉ£ÿÚ2ô~ŸÜ„|–Ñ6±}f ›¨½¹iK[éb[M=«Øþ¨iÇ4Otç±ó!ZôûB¾‡Ø¥à.NÉ]ˆ,OÈŸGkÏõBèZA=9„^&Ћ½5„cèG#%„i4“îcŠíØB̶1é-Ú Ä!‚Ð…nZuÑ&B«DyºÀ¬Ëq7p”î%ÜFîàeÜ£Ö µîSK‚:ùaÔL=¼-ŠÝ´pw­Œå0?½nè#ô ¯>zêc ’8C_Ç;AÇq¼Â5ˆßè7Ê"…ð+p‚ŹÌï­A¼J¯ XÐz»“^‘‡¸;åí†ÿPK  ;„B+Nm q&org/gradle/wrapper/PathAssembler.class•Vù{W=cKeu]`'^÷XÎòv>œÈÇ龺Ôg¥d5ùÛ&øÊÎÔ0 ?UVGi -µ£Ù#Ô Ô‡“Uo¸¦§V¢ˆ#DFh${FÅõì ã;¸H–l+±ƒdê-´Ô½ì#X ³NbN¹ž{Ö¾'1,‘%_žÏÿR$‘ú[ÉT­U„òÉþ*“ÉT‘¡ÐÄE~­bϤÅ*Úh&W°7¶šÎ5쯢}(¼m{`‡ml‡­;ê¯oŠláàb²3Ü©¢c³vœ.D¨MÑQú±Ÿ=‚A:DëxÈ=Ú¸ºv´[¸Dk¤<‡墅vÝÀã4j¥½:½Ò%jÆÈ~‚(“Ÿ½ÈÓ(B–ôºóɸNOBÔOÂÖ Uqx2v$ü6Ž.¶¦fC³wѹٔº³”²s.ª¤·»†ê¸‹@pGŒ¯…,c˜rQµðûÌ{‡öñÎÁX×]<'Òº'û*8¶…ã‹!Âò¡*âíñ Nlæ·Ð»;I9:ußõ|=ôkdmˆÚóh£Óµ“xzH½eÄE¦gݘÁ,íh#fæ0OXzi¼€Ëîikèñ¤‹¾…¿ |¤O‘5 ­#{°‚ÓÃÝwNm¦Z»+HÔy‰¹§ÉP޲äù"q=îÆ{{k:pÅ ’ÅU|Ò•7}†ø±L²f?]ÄG_¾Ÿ•súÂ1 Ø¿Ù,ôtÉzÄÃt2PnÔU™òÙN,Çu=+]µ¨]XÂÓ#ŒCP\­Èt}8>g…¾qüø¯Ð>f$“Š‚þÛˆ&ßDËf*6àÎÚYî±Á»HWñÐ&§Å×|ì É;ÅZx[çÜoB:OJ] ¨—)OÒ•½Òpa35¤ü ¨îþkø°«:z±R.ÏAøPK  ;„Bà·(/ò org/gradle/wrapper/Install.classX |çuO{Ìj5t!-æX°º%n,0¶.ŒIȈà <ÒŽÄàÝõì,HÄŽÇ ¾’´4m‚Ó6©ëTuë6Á1’mÅØMZ7MÛ4mÒ#ië´qÒãצ÷6ôÿfV{H‹1F?¾ï›ïxçÿ½÷}ûÕ½|•ˆ6óÇ‚¥?‘æ[Ò|[š?-Eóg2úó ÕÑ }ÇCüÍׂ ¿µ¿”æ»Az“¾¤ïÓ_éAúkiþF¡¿ Rýlý{…~PFÿ@ÿ¨Ð?èŸú— 5Ò¿i%ý›Ìÿ{€þCúÿTè¿‚´–ÞR5ý·4ÿ#ÍeíEŠÿ ÐdæšÂ¤0¸$ÀL°7H›Ø'?È J¹”ƒ —©“Þ°Šž—ÉÆr-ò ®P¸Rá*Ù^¤]\¤¼RáÚ í vr]€CøàUÒ,Wø– õðj…שWxm€×8¯õ¥¼o…V\àé7 ·MÒ4*ܤn–¦¥Œ[¹Mšv…;‚t˜~ˆ†;eãf…·(¼5HÇdo„·ÉíЛwy'ï’Ï]A¾»äs·Œv)¼‡)Ô׿¯ûðà¡S}£‡ô>4p`øÔH÷¡ýL•ƒg´³ZGLKLvŒÚ–‘˜ÜÍ´¬×L¤l-aÑbi=À·3¢æ¹DÌÔ¢LkMk²cÒÒ¢1½ãœ¥%“ºÕ1ЗY—ãIÍ>ÝJéñ±˜n1m(v`$­Ò§Æcé”qVßgÄôîñq=•ÒÚ¤Pè(F¡ÿº@οÇHö^¦ÞÆ·÷Ʋ5aòöšQiù ‘ЇÓñ1Ý:¤aQìgŽk±#šeÈwfÒkŸ6RL«‹rËÆb18néš­÷)›é¶¢bu{¸c˜L[šm˜‰ÝM®Ë ³C{ç¯35½mRÐ( ö–1––ïÃVŒ©Ü%ŸÐíŽÃ°¥"&*öåíS†­\<ͤ$àÓ`<`Û [¿„*"SŸaeeÉ©ª:²3’ò zRŽ¥¾ƒ©jR·ó‰4Mض³±ÌRÈ/1im¾YúôÔ¸e$]½QÂj+ÜXu b/ά,„ÂtráE{÷rÛ‹³˜«2(‡IÛ´”“wÂÑÞ«YV=\x|±ôÞ˜žÀ0•”Ž“ ÍN[úRc,&_D¸º”n÷Oéãi[ôÑ­¸‘J‰Í‚ÅÔŽK,Ôeç{Òº¥GêZÔ Í”5ÓðKMë}¦×lÛÙà!Ê@'9†´ç¬Ë” ïI1—'áò¥dEÏ’‡²8Ùu‡sb –V:iëÑü-A³ûÍ8è,s?zÍx\K ÿ©8aZC`„\ã©£FéZ{›ŽAA35¬ÉÉÒ¨Ó%­"–ÂF%•vÒäÅÀÁøi(géZÕñb©Ùb¾tâ¼å×Ev¾3|z¶¦³þpl£¡~Y‘˜‚3’i,t-.0^ r o^X;,½Q]ò•"t òÚ<Êý‰t\ÏæåüBœÖ.åžêòq39=ÈãßžÓ)o~wq©\¼% œ(ÚAšÌ!öïÁ\LìÔÛ×wvv2 ¯™\}Óé£dªSšÍÒlɱÚ,¬ö¼%«¢¹;¿¸.ÐÚrcZ7Ì# ´¶ ­¶›¡u,wx›Þ}ÓöËé©í7-‡5ÓÖ¸îMÍìk—m*}‚>©Òè•~™žSé#ôQ• :£Ò‡é‚J&ß v7u³CÝ*Å)¡Ò}S¸Gå^îS¸_ú}*ßÅûUä]ܬV__‹zƒ„Ô»T~7Bì|­Ry˜žEòË!í`:aq=›¤˜î½Ë¡ίTáM ©Mᨩ§Â Óã^`kF"¬%¦±ÍÒÇmSb¶=Ü?•ć ÛfxÉ+¬Oiãvl:¼9»oºE.ÇÿÀØL«|€GDð»U>È£L'®+D†w ,ÌpüI ò!>ŒL˜n·eiÓ‚^•г*å{TŽÈèWéÅjÁ1#‘1¼ˆú$¿ëÕÝ`FÊ?7‘ç=;·oWùŸ*§T¾—5…ÇTçQ…£*}YŠLíâóYÊáQ݆V e3œÌÕÍð„iu…UžàI•OƒRÿI…Ϩ|ß \¼tâ"_$ǹk*Ç8.r&¤1 l–-­*êåIdð†TCB,BÊy•^SøQ•ã;~\å'øI•?ÂE¬_?]à ²0#q†š»åæïÕ ¾všçE\YäšÐ80 ý¦·ùr@á^tÕF(56-~:„o$'Ó©›yø¼£çDå"IëXVØ\Ñb_öe1ðŽ Z¡ Ĩ~-sËë.z]s@‡t9ž¶pñ³;zÁAÂh¡bçå_HY^XÅFª?ž´ þ 'ÒÇä’;Êñ¥ÄšŠ]0kŠœu^À)ã¼îÀ¯ L%[ŠŠè×§\˜–Ê«F4u^ MKÞ)eFªo!Ùƒ¨.â¿ (®·Þø)W@°^-a& à@ ÁTÝXTÏ•Eî×N(ÀÅ–£]þ¹ÜÓ¢bɤd!Ͱ‘g ëÉtÊÖãùWÓ0É]Mý‚)yP´3ù’©Ü³GB¯{,eÆÒ¶îê°Í…êUU„LÊW QZŽÃ÷íÚ¼H(¼;׿‰‹‘ªrK™w̰to{n ‚Kž€‹ÙV>`j  |ãÛ²ÖîW¸‘"iAž”‡G³?yå-msÐ<‡Œƒ"•ã‘¿§(ÕGŸ:0q¸p³)MEßs~÷‰ˆÚÞ˜o‹Â‡TMÑá´–2-½?¦Ç‘9IJ„>eg>C?Ÿ ìé>PýñûÜŸ3B9.y_uä£àíx=àT£%«˜)Ö­*r †ðH%:Þ#vó³ ±‹‚o©M´ž¢TGD^ ‘NÄ4‰¯:M•r§Ç¸R®äNû9úåØcRíýøŠ“<è×5Ï‘ÒÜ6KË»¼hWtù0YòÍSE¤9ä y[ç¨r–ª^£êÏ/’§ m •S+dj£UÔáȳץŸ•gMÑ4dðaý<½Ê!ùô~È] é?@C¯Uøû F>zÄ1,Ó‡°o£ŒÉ¾H f‰†›[æÈ;ÜöÕ0]¢ºyZ©¬õ¾BuOë苚£U¯bõxñÓ™åÕ‹—=/ÑšÊhäq4ZåH}í(œu6>Bít”z)âhÕìrÏj5ìÈÍÎèQ@ '÷Ócô8è=Aò¤âÌÌ“˜)‘÷^Æ¿^Aß=Ok#s´n_¢­èÖ·]ÝáõìðÕøj¼OS¸­Æ·¥ËòÏÒ†K¤¶†ü/Ñ­%tôÏ\ûNkNøµÁpíIŠé^ê$nÃø TØ=TAƒØ~¾…~Œ~çëh]¤Ÿ€z·@éc$®íÎ*ÚQ4j¢^IV=wæIÌü¤ŒŸÂ¼r]‡ñ·À¥óoãõ—È{yžª#-• s´qˆ‡çiSÄÿ 5F<•M£oeóhÄ×:K-£sÔÚå yg©­ËòÍRûS´áy꘧NØjså–YÚŠ}ÛÐÍÒöYÚ1CûæigdžvEdûmsÔ5G»»üó´nïRÄz{#]ש6¤TÞáB!¥;Î\û^H™¥îáZéríŰÌö·½N›òxï[Ìk•w¡¿ Åkèš¡§žú2qr’jÑ0ý˜+FUý$‚­H]0Svi0õYû!Äè㈕ŸE”<ƒè˜AŒïsžç²Y£Òáñ(Àó2Èã€Þ“Ž+] Þ*òÃ/9IµD~*Éðù,¤`îlq‚¡ÝðgïšÖ«OÓúf[­k¶\säÙá­ñ>E>Ïsx$P°õ@Nˆ 0û ЯùÕ@|pß ·â{ Ì—rÒ–ó ý ý*Ä.Gl|;=8³‘>O—‘wf͵.zØù 0¨è|8I\œ§‘²ÖÝ.®Jò•äe`pˆ‘‡»X?r‰jE“Vù8 ]fé`ôóÀE Öæèø½§ËßòÊÔ‰ŽN ØOÍÐ2ö§BÊ«3×>.Lï•É€3 ^½ N b :Ht. ¿ç\ÈZk2†  ²N õp+p;Üt'ìs–9‹˜°…þØà!º‚D> JW`ç¹lª§{03 Ûž@yš£´{1kÇ‹ôR&­^Øv+ÐÎ#ý{ ãô àïÍ–ˆ¬ã›I¬O`N ÒPá¥/†[PÍ´È裡¼µÍSÕÇf®ý`GŸÊÕV7ó¿Œö({•VÓ¯¡*} ¢~9 ÍŠØ€õ/9"6`Ç‹Næ_G¿N¿Ëï¯;É4+âŠý&}%ƒâ~ì‘j­4· ¬úsÕï\“WÐú­ C…¾š±‰B¿-¥$‡~7C²½¬IÙö'¨º\‚8ü5ú½Ìá®LôúªZü´þ¬8~WÐù:jY:yÿöèü}#ãÂBû”\.Jè­í#˜É7þ7é‹ ÉÅi_GHÌþ‘³ÿlId%HÌßGRf'>ðïÿPK  ;„BGÜÄ• -org/gradle/wrapper/BootstrapMainStarter.classVY[ÛV=²eT%€Y“@œÅf±Ó”Ò(MBÙ I0KÒEØ#"KT– tK—´ý }íK_›ÃW¾¦ïý}ê¿h;W²ÁùꇻÌÌ9gæÞ‘ÿüç·—ÞÀ2¸'ã¦$¼/aZFfdÌbNÆ<ø°(øŒ%,óᾸä¡+d4aUšŒulHøÀ$wóˆ›|xìLJ2>ÂÇ>ñCåË-W’à›Ð Ížà GÖˆSfš hŠk[Îg·˜µªné$ ÄÍ”ª¯«–Æ÷E¡hïh9‘¸iebKMë,öÔR÷ö˜»gšvΦ͒ª [µlf ðæøR@ox3¾«î«1]52±„miFfÜ•hflFÓÙ¸ƒGµ2¡µŽ±Ù 9gf ËÅÊÃ]í‚jú”iØìÀžÒÕ\.nªiF {Â`vlm%^¦â‡³„Ú h)‹íˆxh®_böŽI9ì,3°Ø¶ÎRvÌÕ‘eGeâ÷JÉk«v;10É=O¤Øž­™FN/Ŷf¤ãjÞHí0Ë!Ó®ÊS5sq[sª£ZV/9جÑëÌ …0/ A£…œ0óVŠÍ8§‚õ å„p]Á;¸-àÒ9© ”kl##aG†] OèÈ*0ø‚)aOÁ§°ä@w¢›®QÔ­ZT/2ŽÎ:{ŽEAû„ž§žhUeOÁSh>ßßÚ¥JH8Tð>/!+¦.¼®mq_(ø_)x†¯‰—~¸~8:ð˜È[¾Qð-¾£bŸXɶ–e§0=eæõtÈ0íNe·YÈÞa!—B¨ä3´pw%¤%qZ£lk[yî!Ôß—ë*xŽï9´ôÿϧEoä X"¯m®­P¡›Ã‘òë>?^Y©ù¢e¼Æ2N–íU¹.Õº-ÃìÄaÎfÙʇUòP}Ây•Ì~ ZÌ zGJ= éœS¼”ÕuuÇb*=» ©¼Å•öma])ŸcöTçß~E¸FÖÅ÷ß®m>5‹ÔJ-áN3›5g"¯j—ÏÓQÓÖŒ}ó ÝáÛåaÜû^¦(ŠÔŠôTµ‘:$DÐõäzÞÑš^"ée•7àÊôŸ6éæjɪ6=òØ^/µˆà¶i‘QÁ:y¬Cð4r]çë¸NßÛøÏ·4oÐ.F³@³wà Z4 ‡FŸ#ìD/Šk€>¼N3=N„ÉŠþ›ì$š7†ŽÐ°|ORübÒ3\€·_âRþ#4Ž‰Çƒb¯Å€RÀ…1oиHÖMIO+š´Œù‚>$¤gö­/´N·æ*…ë¢}7‰Í±˜%ë…Üs¡aòUô ²"È><Ä0­¸ÏD‰»HsnÒ¿/ùjÆ-¼IV#EÒ®î-Ò’D$ÉÛä…¾ÅÜQDÍ‹'hKÚÐQÀ¥¥¡—“žQ±]ìú׆ÚÅ[œj—Á:‚/èýõ¹(üòï_'¸’ \->F׺ÿ8­@…‘ aÊùMZ!Nu’†î‘ñâ"Õct®…lÞ%­‡þÝÀ{´9¼Ó”,:‰à¿ãĹûPK  ;„Bf[ÛñA µ(org/gradle/wrapper/WrapperExecutor.class•Wi`e~&Ùt7ÛiJ7I/RXJKÒM6ᦴ¥ÐÐÔ\d“ƵLv§É”ÍÎ2;ÛEµ*(ˆðz[”&@µ(Þ÷}‹÷}à<ïÌdwv»­åÇ~óïù¼Ç÷íãO=ø0€s”@·qk¯ £ ·ñÚ0jp0 ¯“Ûƒx}oâaÜ;èÅ]a,ÄÁ ÞÆb¬%å›ex‹ o•ámÂ}· ÷ÉÛCx‡|ß);ï’Ù¡Þ-ß÷ÈðÞÞ'ß÷Ëð>(ßÉp8ˆ{Cø°èüˆðÞFŽˆU32›•Ùý!< ?ÄœÐ<('wÉì£A<Æy8ÂÃò}$„…ðñ á!|2„OÉöÑ  c³}Z¾Ÿ‘áèB<ŽÏŠ”Ïñù0zðQòÅ0¾„/‹i_ ã«øZ_Ç7Bø¦‚ݽ‰‘áÞÎÑ‘ÞÁ£Ã};‡†‡z†GÆDúvk{´Ž´–™ìHØ–‘™Ü¨`Q—™ÉÙZÆÞ®¥óº‚•%:·$z|–íèÚ™î)?)eÚ2²µ2[ÙI8k™Yݲ =§`©k_Þ6ÒC…}ÚXW¤ºÜHÓÈ:—Ò0;d-^ìÕ¬ ÌÛÙ¼]帺%›Õ3)mÂ!\43»ŒIëúLk²cÒÒRi½c¯¥‘Èês¿]MÞÒlÃÌ©~—iÑ ÝzÒî6,ަµ_Á¶–R+*«<‘žž}z2OaTè2StlqŸ‘ÑòÓº5"ì43©¥·k–!koS`ó¬Q°œÖy‡ÊpZ°ÉÈöf—T´µéãx°]Ba¾ãž}I=ë¡°§ FoÍÉ9º4kéYÍÒ»Sp"/BF-CÁ)-ë\Ýîî•`å̼•,Æ»x. â[Œ¿¥k)G¤9j¥™Ž%ënJ“š­§Æ4®–€Mk¶­[§$.Ÿß¦‚ÚTQX]ÚÔRC¾Dm>)4·‘a¥éÚtAyz3ÌQw{cßfÔ'uÛÁàNI*hmy&)ÔȉÝU-W[÷•$õJH§+žuš¦Mû´l¿&i– $4k’ˆÔWÐA# W¤‚¦)TÐ0QAþqj´¢)Ì—l«9MŸ>/Œ÷Y-Ç·®’½ª×göh"e}¾“•”Òwiùô|S­Ùã~™û¦e÷¹éІN¢»EÛPV4í"_Áêÿ_^ÔëÏK-eôî2î-Û‹mUEß¡êJ‰,gß•!¥â{ø>‹«èðp>cÓz¡´y6E‹Â£»hL´ym®9š2¹Ì˜vTßÇ|og¢e NHK â*~ˆ‰Â³ÔN2åUìÀU*F0ªb;ÆT<ã*läUØ­â'ø)•¥|EÖ©åt?Ã*^†W¨ø¹¨+¡Òì)¿Š_Ê¡z‘MfÝeý•üºäÀåøüVê+tLBÔeæÓ)é,ѽ³Ìi±vÁáw*Lqâ÷"øø£Š?ÉìÏØÍÞ‘*i¤iñæÀ|"x SEVH—•'jgÞH§¤Ð‚y+=̺Rñü•ݾ£ ·”8=òoo×­œãÑRÿnWZczï2Dp Ð¨øž˜£´Ó*xô„ùÂÛÚf™ç¢©B êª"U³gts[´¹ÜØò=ÏÒæ¨–I•ž­mnŽLé9=º×H§£zÔÒ§Í=T˜3ÍL{t(­3ìÑ|Î3Mz/™öµÉ×'ƒø» ÷7 þËü…èkøÎªøþÄTüW*k?vñ”Šÿ1Š¢*UJµ‚-fÔé4ÇžŠ^£ïwÕæ²zRÌMÑ€Š™3‹ëT$öÊ}¾4¬/ÜGƒ¾Ý3ÿª™oxlûÕ-2.pª8ç,w”Ô²KJ ÷ªUpq…^ê¿3Üâ¯ÜL+õoª_œ+¿6—´”>„ª¾ìr•âe§k©¨ª>W‰¸\„”ù±´în˜´;Œ¬ËÎùî‰G–ó-b'¾hF¦,soá)VK1‰ä”.¹Hî9>¦2¶Ûï o¨â˸±@žp3'I¤Æ6‰#¤9/=ñ“º%½–AÁ!Ûœò¦gÜcÞZ •ž ÎöKíšÒ¬„~m^Ï$õ³J^÷KÊ’×y¡Hå+¹¥âûËÉ (™6%l+ÿra“$¶Ç¬“ã'û@;&L•î¹J/Ú•³®©ø®+sgð¯ãBþÁ®Å ôc€«A®ªçzÈ·^Îõ•¾õé\ûÖM\'|ëÕˆÈeËyDî[çË+×ùò&æwu>Ï%Çó¸Àr+砌ϡj<©žE`5ã³XÐ:‹àaGîNŽ ÈÄp5Ç¥.4G‡ÌD «Ù‚U<6ƒÐX>‡ÚñH8ðŽWÇ÷CÅ¢GDo¬¢º:Tsl§ºyŽOmÜsMf®ZÈ3ÈU«¬'G wî‰Í¢Ž¢Sô)G°$Öv‘XëÔÇâGÐÐJ£îÀ ­m÷£1vg±tËœid¹|f°b+gpª»×äî­röNs÷Nw÷¢ÎÞîÞjwïLgoÍ!4m8žŸåzÞ*ž¯Ì¢ù‘{iñZyåpt}îÄ)ÏGÍXŒ Ѐ à‹pÖ“fÁßÈÝMèÅ%„y3®Å¥ä滑Ëp¶ànt;8OnÂ2èØEYÄ“˜r»ÇÁNqf’(UÎLP¬æœo2޼ùäl qié#Xëà 'AîCý bÜa¸3h;ÜZŒYÄÑvµo…ŠmLÇ>_ÜÖxVÔ0¯AšVLsà7Ãs³ ûJgt#‘ø ÚbÉ:˜œñYœ=‹sÓªsËSåJªf&Ž:*UW„§Ò¯([Pô$sZ8(}s8yr~,r5ÌàÂÈEb‘õÞêbgµ¡dµÑ[mâ0ƒK(b3E\Úß¹¬ÆMrB•Dâ‰l㪡m « c‡°°ßq§{Læšó ¸ïb’¦ÑÒL"m®ömñÖLûgÝ[–}/&–7b ^R(@)‡ù²‹à…ÄWqf/"m•3»‘ÔÕä 12ct}‰?ÿ.xltJÆZ6•rø*,XPÄËPW9ýÅ$K€¥¡EXÀíñ£¨‰nãØv8Æì. wÃyÃs3ïŒW±Ý‚zÜÊÞVÈ7Š*(<ÕS(³Wr&i!ÿ€cýÍo†¼[¡ÉiŠ}5^S8ÕâÝ e.Þîs±© ±ÉÓ¨Ð:¡õÓPK  ;„B{w`~% *org/gradle/wrapper/GradleWrapperMain.classWxå~ÿXñÉç³ãÈNlgY„$–åÄ"¬Ñ€°âcÇNMhÓ‹t±’NœN]ÐAÛt·tÒ–îÒÝ­¬âBè‚–.º÷ÞtïMûþw²,ËðÓç‘þùýß÷~óÿïÁGî¾ÀvѦbN«èÄóeóÙ¼PÅ‹ðb9z‰ŠËñR9zY ×^®â¼BÁ+¼ÊWËõרÐðZ·ÊÉëT4àõ*jñ·©h’œoÁ¼IE3N+x³ŠV¹ØŒ·ÈÑ[eó69}»‚w(¸Ýwªâ]*Þ÷ÈÑ{eó>Ù¼ßøqFŸSÎ)ô.ćTä1£¢€«¸³ >¢àÛq¯Š³¸ÏÊ3óãã >!‡Ÿ”›÷ËÍ$£ûýø”dôi?Tð©òiÙ|Ö›dÿ9?>¯â xHÁýø’<üe?¾"Ä­¯Êþk5Ôþë ¾¡b§ýø¦ì¿åÇ·eÿ–žÞ}ÑñÁƒG®ö öë=²ÿÀP¯@`ð:ý¸Iêé©È˜m%ÒS»ÖWÒ=0Ò;zpòÈ@ï¤@]·™ÎÚzڞГ9ƒüÑ÷O¸¤Õ{鄽W *Ô1!àë6ã<°b0‘6†s©£†uP?š4$3¦''t+!çÅEŸ=È l4­©È”¥Ç“Fä„¥g2†¹Ê™rgCz"Mܾ{ա˵r¤ëÖù5zl ¨EÎýº%PïR$ÌȾDÒàn}Æ2¹i'Œ¬\P,Ó´{¤mÈžÊÚFj¤D@îñœHFæ×ÉfEQHïI#–³MžÞä¥Ü¡…T]ïɘ‘±4<ý“Ñ­¬1V!vŸe¦¢Ž‚›< P†iHÏgMÌLçYƒ0.)‡K&"•Ü»ÍTJOÇ¥ãºçŽ‘ÇÊØüúˆDE^+yuWÒHác‰©´nç,Ú² x÷,¦X¼²—Œõx¼6ƒI°HœKCBÈ¥ã”ÒäUý5Ñ$Vibµh¸”<ŠÉL;ÙÌfŒXâXˆésðïRD‹&Zq ‹œGþÒsÝfŽçZhÎ&Ey]RÙ5´D1hrŒº®i'Ù*¯qM¬Íb\ ¹² ])1Ê ®)±ÐÄ:±žE#Òå2×ÄiÒ2£»iˆž2ìòªÚê8וYÍ:•U ª¸Ád ¯2svyÙ!´ù²·ñ±ïVÊfäª,ônfõWÜee3Jút\¾Sxo,é o-å “Ju‡¼8öÍ•¼Ý^» ª›ÃE1ÙTã°×ýê)­¸ž{^ÅБ#ŸÇSÎM¾9ôØw¿<ÓH)æ‰ñôõiêt`î]³)Ô±”§Ãrçù#°ÃûÙPÁÁ9/ãCJñåÃL\x1}ùeìV ²8ÿÜ¡QæÉ°‡!+¯Šý”“”‰ÔȤXürió~¥”½ãœdÒ-#m»Q[SšËËѰ‡u'»+²r[F&©Ë;ÝÊ’ö²¥¨×ÓdÅüZ·¬È®2TæµèÜÓ}šoœËó,CÓJا"•4d¶áÑ)\…凄û"X·ˆëü.ùµœk7 9 –^f¥·{k îž»j‹s†žmò6[D)_q-åÖ;8m™'Üâ0±IŸëŸ±Ø´!½RmÜÓ“´×ªÐâ(ë`¥¯fuJéôÎNïö8ãåžUgáDŠ=íºktÑs²ÃëÜ9ž˜>÷5ÖòÜ—Òjç‹þ)~Õ›÷Bðüè‰XÒ”E üèA»ÐÕD`¤s ;å[`Û’Pï:ùŽ·Mw çñ›{€*´Ê’£VL°8Äñ2ôqþø²ùTŽù>f{˜+ö‚ýòð Äɵl«Å žÀVs ðDa_ƒ'A'•<üü¤°l°³€ª!6¾á–ïòµúÂTç¡l+À¿õNÔ îZÞº<<‹ÚÉYh“ºêg°b “¬œA`³hšœÁª‹fÂkœE+û5C[óXËÿºC[Ãy¬ÏcÃ}h;S‚¾š,Aÿøq°«° k°ÛtY¡úÑŠn@3n€EY‡M(üR)úë09JwtÐȳJËΛÁÆΧ­‹‹á²¥y;Ö;/'ˆ+hÅh™o;‹€‚ø¥TtI10j©×&÷7¯—=e,jCK'K,¢EºfS›ùßh„òè˜A¸’Ýþ2vÍ%vüŠ+²» é~:?Z}[]yDnG=²}²sž¥Œ‹çqÉ­h‘‹K}÷`ÇdUx¬€Ëf°ólÌ®ì>ãÈj`$\PD²2€a®]ÍÕhb­Ç(-4ÆØw®&m#êÉxŠã®]x*žæ¸_~E¬3Фë'ˆ5°'Ç „@ƒg¯ ârЃDí \™G÷ÐÖ9ŠI±u˜[½ÛÎìòɾÕwvÀÙ»Šyºÿ,¹·1Œ¢Ž‘»^z¶Ÿqe+{WŸ iO0ÙkˆªŽ+ÍÌâ6fð&æp'C/ÂàÛIKï¦çû™ Ì©c˜:©éMÔyOGñ <“ëm\}é)kig;>º¹ä#“1&mº=ÐW@ÿ@ø~h޽¥± N”/ÉÁr\1 kœ6ÙfÈúºÁ¢ ²,¹R€TÆÍNµóã9¥Zv‘ÀÚY Óº#ÄÇÕQ6yŒÝ…!™ ¢,æÎcû\GôóþPK  ;„BOÝ6Ñ "org/gradle/wrapper/Install$1.classVéwUÿ½fÒ¤é ¡lYªTIm€‚J ´ …PJW@T¦É#˜Î„ɤ¥¸ï¸ãnq_ׂ œãñ¾ù…þþ ê½™¤KâÁœ“·ÜwïïýîòÞ›?þ¾ú€5¸X:tsÓÃM/7}„±ß‡”ã àÇ~žâÑÃ~<Âý£,9ÌÆM?7±:÷CòäHðCgí£ƒÁ˃•0a±B’§Ç+a#U in†üfñ ?Fü8ÉÃÇxœwëÄlõd€8>åÃÓ><ãóÁ!ͨ5¬˜fÔ“;tC Ü=ª iÝŠð¼Y ’uâzÊiÕm¹ù™­÷§Ý2{lcÂÈ”N¤§³ŒÊ=U»Z`qÔ²‘„­Å ¶µdRÚ‘63åh†ÁzuSw6 ´…J)NçTl–ߺ®W@i±âäÉì¨nÊöô`¿´»µ~ö­*Ê®öj¶ÎóœPaªPÛLSÚ-†–JI’,-Á¨v ‘WŒœ†ê cp“õÄ9pez­ÀË”2žjµ†MÃÒââ 1s¬dTIƒr@Ì‚S`¢” æb[–#°`º‡#ɼ—5&§SÞÌ,¶ŸˆÉ$ç4åÃsD6ï—¡™‰ÈÞþ£2Æ;Uté SsÒ6¡n©0eŸ˜eÆÒ¶-M'ÒB‘b"Ŷí²ÒvLºÎ«¹ø6°¥p»3¬”n&öHgÀŠûð¼Šð¢Jço­ŠU¨WÑÀM«U4â%B˜ºŠSØ$°p’e®™Ø–Ö¸´U¼ŒWT¼Š×(K Ö1¯ó¼o¨x§U¼ÅÍÛ,{ï x’ší¨x§}x_Åø6̧ŠpklÔ‡3*>ÂÇ*>Á§>|¦âs|¡âK|¥âk|ã÷*Îâ;ΩøžwøQ:Y­ÒƒP½P$-{„à~ÄO¢ó¤žLòeºÆ±hágüâØŠó¸ âWFÙÈ®..U³T9…ùXR2aÄkÒd¢@Ý|â³¥æÈVª3 EOvŸÛ·Xæ=‘¦ƒ@¨Í3Α'ÄçyVB:Ór‹ÄGóvmP–¨›[¾UÛ¤³Sš¹<Ó"W dèw,W$°[YºtXËõ”Ës6ñÜÚŸ²Œ´#;4g€£Åb2Eãjº£·|åqc2Våq®9-Ç]#)G1+M™˜?aÒAIm°¹ J¹c\*Js‹ÀPV’<3¨6æ‹zï¤÷kØû%½¯+º˜?iÍ7©óÉKÓŸ. M!¦Çyù©´¨œº-9Yç|æi¯ýoÚÆ3¯éÛ¦Kho=÷ Ðݪ+þ_ÂôP¯„ òíPßëé Èöô4К‡þXGÚëiÔŠ2x©_^y "¼êÊÂõ—à W+— „/Ã{žVËp/µådB»Z5;^„ûÑ þD ;–´±l7á•“häÊ„/¢,ß5ø\F…; dPY¥R“Á¬Ëô…DRO³G±deÁQ, `¡»0gUc®eð |ÊY(žM‹Gq¤$þÜ üöú æõ]ÀüœRÕZ"M%ƒ…¤‘Áí¼ß8ªYV‹<¨wîèË3ÇâvZZ"ФT+W°T`x´Làw”7y§à×~µ—ˆ»rT{ÇqgßÙ®OѼËeRæêV-w§žBSVqYÔN ñ¿›BÓ¤dÑ•qÜCá[ÑW­Œe“Ì ëÅüìyˆ¿’%é!JÙašB=êÍ8G©»JÉ»Ž-¸­ø ÛD-bZÅBlÛ±Ctc§@›8Ž]bˆP¸:éüÙo¦"óÕ <@#/þ$œ-„£p äÊ#$öa­ KÐ’-ºôÂ6<„<Òª‚¹Âr×ÚwI’ìn%žQ·Ä¨E¶ü¼á Bc%êÓ›#0C힬~;öfûìË®u¢‹H«Ùß¿PK  ;„Bˆ€ü²V8org/gradle/wrapper/PathAssembler$LocalDistribution.class•R[KAþÎfÝÕt«qkµjÕxyˆÛÚ­â›EE‚-(>ø Ì&C»î†É¦ý[-4úÐÐ%žƒ4*væÜ¾ËößÍŸ¿6±:†Ì•áaÞDoͱàcÉG•à7U§8WmÂxýJ|±ÊãC•Ê~ë@i‚W\ªÎÚGÂJ=×­¸¥E3•ñw-Úm©ã/¢¸Üëtäu’JÍ8ï“ÊT±KØ« ÌÖÏî~Þ”„‰ºÊäq÷:‘úT0Öó†HÏ„V&ï]c”0i{l_«¤[¨<#GY&õ~*XšG¶‡Z[{DÂo [²ø¿d×S©­?Ü]™çx«&ãä$ïꆼK‘ Œ,Ãh£>V[Ï÷Èn¬•Td­øsr%¡T3«¬cÃ2ÿÿ3%„ÆG¡1T*Æ¢íð&ñ’ÏqÎ.àÀå{*z×E¿áDï{(E=¸?¹î`Âr˜™„™Œjâ$*\©2c1Éld´u£õÓ}­˜oâ{$ú…Ò{rÏ¿ZÂàn OH˜yì>ë'ÀÞØs–Ý‚ßNÜYä—Ð-PK  ;„BI}È#8z !org/gradle/wrapper/Download.class…Vi{×~G–4£ñ Û²qÅqË{!m rBŠ ÇP+v*hKÇÒµ-f”™K7Ò%M›¦KÚ¤YJ“ît/¤ Sì$}úý/ý mß;–%Ùè¡–Ÿ;÷žsÏ2ï{î™û¯ÿÜýÀ~üCÇDCX”Ã’ÎaYC^Çy\PQС¢¨Ã‚­£„äàÈ=®eU\ÒцË:¢¸¢ã‹ø’TYÃWt|Wå𢎯áë!ø3½ºþ††oêx ßÒñ2¾­aT.¾#÷½"%¯hø®†W5|OÃ÷5ü@Ã5¼¦âG:~Œ×U¼¡â'*ÞTFʲ„3Y0]W¸ úÒW\OO;vI8^^¸œ]¾r¤ì- ËËgMÏvDOÏžzfv*>7y|næ¤%¥`Û¤m¹žiyóf¡,Zdª Z'掛š=—N™¢¨¿]A›Y*¤§¼m͘E¡ 6}Þ¼hŽLki,í9ykiœÂ†móÂqùP~2oå½Ã ú÷ÛÜ/˜Wœ´sŒÑ6·ÄL¹¸ œçÌ…‚ÕΚ…yÓÉËuUô–óDa×´í,-9f® Æ.9LE8cGíKVÁ6sLîá¬m-æ—ÊŽØ ŸfKBFÖrU»«éZ››MUSÍÛcÇòá§©š¹œ#\ÆŽnÞJ sÂõòVÕwt³­}êrV”¤ÒUñ–‚ö°)ËŽe˜OÙ)lqŒÆ*aáËtM‡{Ö×íǰޅÂÅ ¹¼ãú½ï̆ƒjSòlþÃzêHÜß ã‰æM¥žZÕžç Zõ®¢`ç–›:Nws » ±™/”Ùië¼DùÚ MIÁC ï½¹[u6³:~û %ÎN ¤[ÝiÚĸAL«’\ѪYuˆ®fÑì’“÷ȑʠ©”ÿiñø–¡lÁvÅæŠô’¿EÛ)š ÷D“pg§·¨fõ‰Gxsà•bAìäåèçñÎÀ'¸þdÃúqÄdãä<&{'Ÿ!ê’çø$W&÷ðº€ÎÁ(ƒC·¾®‚7}Oq솼íf°^D<Š>º{‡)í]7ÇÓø”mêôÃ)þL ðÇ~] wŒ»¥®+ºƒð=DW¡f”hw©Ç‹ú>÷AC?½ øqŒu»j“8ÊÝÒçwËýmÃè´>?84¼c«»aºá|´!í¶ZÚm˜brŠ?{Çi™âvÆz*x؉ƒúH\kÙ©`×õÿÞ“ºU°;º-ª wäF*xä:ú’FSµ*Õq㣛|—®âßã¿r×jHYèáxÀ¯£k§•döÄ>R™`ÕìgÝ"OÃ Ž§‰ÞgHo–« ¤Ä%ŠW‰ÞËDïU"÷¦ñže„ãüf¦ø­;”Ý¢l•Ö’‰£´òŽ>MY˜QžÇ c¨>3§¸G£æ1|šYEå)Ì" ]2Pãn­ÆÝZ•»îò[) £w‚yú ò}V˜k†ÏFfùá­–æ¿©Ñ䉼…–éXëóÙØ£gb{8&ƒ±½òŠí“p¬_>ÔX¢]û™ZÒ™àP:Š‡Ò™p<œÎ¨q5цәöðÖBúoÔàîó¦xŽÌ£ƒ‰î`’»™æ>¦6Âä$D³ë‰U_8„Ïò'Ϙ´ùœÆ:Ôç9k¡} ç8 Ò˾ÀYˆ¾Æi}ˆðŽØÞI“yä0æ7‡uC@»FÝ>ýPK  ;„BU HPQO#gradle-wrapper-classpath.propertiesSÎÍO)ÍIUHIMËÌË,ÉÌÏãRÉ(Up,(R00Q00·22±22Vpv Q0204æ*(ÊÏJM.)¶M/JLÉIÕMÎÉä**Í+ÉÌMµåPK õ:„Bˆ$xÊbuild-receipt.propertiesmO»nÃ0 Üõ+Yrd{Ð’-@¥Eׂ’GA$zýü*I³•œîÈ»#uuwûé<æ~Uœõ‚ ­÷œï‡kELôÞ•£U(ùÈ$L\ ÚLz¶vÓØ$Ó|i¤†Qö‚\c.<*ýpÏtI`ïHcZˆËÖ|E•T‘Ü`ƒ/LÙÅ z:RöÍ8‰ùüPŸ\¨? ¼çœJ*¦®—]Æ´a"kŠ74E½üI2çê5&Ej[xP , 'ÛËã[Ž|ã?Acº^ÿPK õ:„Borg/gradle/cli/PK õ:„Bˆîò`ç1org/gradle/cli/AbstractCommandLineConverter.class•UmOA~–^_8Ë‹X¡¢B‘öÚR@E¤µ !I*iHüx½žç‘öJ®W”?áoÁ/%ÑÄà2ÎîµôN(º3;73Ï3³³Û_¿¿ÿ°Ž² «QdŒ`UÆ(Ö¸¶Îµ ¾<áËÓ(žE±Ås†HÉ´L§ÌJgޤÝV]g˜¨˜–¾ßiÖt»ªÖd™ª´4µq¤Ú&ß{FÉùd¶ò•–m [­7ô‚Ö0 ;µ¶c«š³Ûj6U«Î“í¶¬SÝvt»È0}9×ÙÉß|7ITªV‹eÊÕ\ C:]9VOÕBCµŒÂ¹ð¬ÅLŸñ]íX× ’TÛ æ‰ jʉj·u›aqP‘áCÞA¨¥>Û¡c›–!¸Ê¯¾hú‰c¶¬v[ £‡¦a©NǦâóCçÉPå ›éAr‚Q½bpí¾¢üq +Ãd<¶»îäqè t‡ÏWÀ×Xº1äîrºeéŸ÷¬¶£Zu6‘ħ]ç÷¥ê¶ÿ{Ùoºb|S)¶:¶¦¿6ù\/\5Ç«'Ž8ÆR×[/°G¥8î"G®½dÈÞàî0LVǰ4Dy~˜>¯Ûè4uËé 9 8]Φ!|Ù7RþÛÄß °¸} [ÿ¹ÎCLï›!¦w¨ •è½”AEïk˜$­ã´Û!ɸU¹ûFJ´F„q “´Æ]ܦ=pç’%A’ÑÉMSOwF2DræF>\ ôVÉu!)¹lá."ç=€qá–@Œ‚Ç(œ¥ÜPˆk3HRúEÜÃ,ýpði’®W¢çuŸ¼.‘|ˆ9ÒF0/ˆ¥ó?fÞëýxȇCD„èln¶àm­˜°ÈMÛJ]îkÍ'iÛu#ï’0ßèBWëêÀÝÕ”!f„¥±•¨¬,‹BÕâçy•@ˆwZ³Í•tŽ!é‘BI]‰ã¥á¢#¤ÿHIê9|gèߌ|{Ÿúü õ-™|PK õ:„B ‚»ª¡÷<org/gradle/cli/CommandLineParser$MissingOptionArgState.class•kOÓ`ÇÿÏ6º­ëd  ^™ed ÐDç%Ɖ&3˜à«g¬Öj÷”´ñò•|!‰ŽÄ~?”ñ£Òp«Õ¬ëÎ+^·èd¼jïrk›;¦ÔÃØ÷Τt'ž›®k #@ÞwŒ°ªµÁYôõ¤R2Mþ¹®“æxÁ;Š’«¾çyÉâÂ(Õ<‡Ü6ò; Qî2¿ž— i[AìôAô×ý”-¶lq*ud¾úå>8ÌÑ[t™< ª=—ߎã6Þ 5ôÁ>e1"Ÿå­Ì0{µf·œ]ý±)e²ÇfAöCÃ(2ò¶¢AÅ «˜Ò°†;.ᲆuLÇA¬•áöˆaþ4-fX:}f·ƒaîà 0ÝÃRýïYº ³˜;õ¨~+ZM]x ÙAÎÈÒ, ¹Jãr$)ˆÈ ÑÉiOH‹Ð3U`ˆŠ?Ý'5Bæ ó(yêao¡2gél20Ç9’àKËè:©ºB•B±Ø·O\ê]¥ÃQp}mIÈyFñ)¤ ?mc¤8߆òýnÏÇeÃ.⤤’!ù ¦CðÝ0Á¤SŽñãÐVWŽÉ4ÙÉ1‹k!jÕ×CåøúûTéξ Á¾ú8-0 pÐfCÈC²Œ ;Û?–L½«Âî†]÷/¥˜ó+Êùžyª˜AŒ†S†“?±2& ae\%}†žÈ$þPK õ:„Bƒ —“ƒ=org/gradle/cli/CommandLineParser$OptionStringComparator.classTAOAþf;eam¡"TE+( ­,¥’"ibBlÄC¢·¡LÊ’e—ìn‰NÞ<Ø‹H41žýIFÑ7Ûµ ­©ñÐyoÞûæ½o¿yÓ/ç>(â‘Ì0Ô¢cVGÁÇœZLó*M¶¨cAG‰¡oÕr¬`!–›ÙfàwW2 U-G>kìHï…Ø±)2\ukÂÞž¥öQ{–ÏÞ< ,×Ù <Ë©W܃Cá‰ÀõŽ#½Š-|_n¥êzu³î‰][š5Û2 { œ]Õì¹ð|ée»W*3èµpGM§sÕ}q$L[8u³…,wFf6èŒV+*ö€vzDð÷\/ {õk³p©ÑæÎ¾¬åΈj¤½ž¿Ø#Ê© )½È€°\ÏÏ/–Õ%dÿÈ0°eÕ4”(«£Ú,Ûü­äj§kTÊØr^M>±Ô­¦;ÚÍ©C $Là!–t,3<îɱ"|¹áøÒñ­À:’ã1Þ¡:N&0Š4Cê2o†åÿœ¦ ÅZb1ŒtS‹á^ï› ‰±¥SöÂ7DÓ0Ñë æé4WèÉrhJXÚ ÒÎ$KÓ‚øì´÷äh¢µOÙW¤ÈO´¸Š¨¹"y¢Ãï£8°ž?EŒ¿Îß‚ÇÖ î–xæÆ(?A\kfN”{Œ8o~ÉÎϺ¯Ùn|‡þCÀ¾a}G†cŠý@Nc(jJ -¶šF„”w7B’ë¸IžFäJÃ-¢—A·Éã©u"ž‰ˆ?¥LŒlr6ÿz~§èovýú‰°Ý,IÇÃfIÊCK)…&£Â+dµHNÖ]Ît Ð.§‚YÊÇp?ÄOa:´9\#;Fñä1LÞ]²HõÓ æñc?PK õ:„B—›ÈËFK1org/gradle/cli/CommandLineArgumentException.class•‘ÍJ1…Oú3£µ¶ZmÅ‚bwÚªƒëJADA\ØÒ}: ÓÈL"™õµ\\ø>”˜¤¥ŠÁ,nrOîýî yÿx}p† Ø2aÛEÝEƒÀ9ç‚§=‚ú¡O©QzýTqv†…K9fUŸ v›Å#¦ti¥æË€FCª¸Éçb!ð„àÄ—*ôBEÇó‚ˆ{—2Ž©È… ³˜‰ôê9`)—¢KàÆ,Ihh©¿\´—xû¦ &J>™ùÖp1 Y¢Iõ¥¥¾ÌTÀ®¹ñÛúËØ©”Q„cB… óW4¿æße"å1[\¢…¼þ³r f‚Ž®Îz:ÏéÝiw¦ /ö~EÇ’Uwue«úÔ˜Ui}ÍR”±®†U™³nôŒ¼ÞÝvçxŠÜOØžnÚ·°ƒYÙæÎaæTņµ¸i»kŸPK õ:„BlZ5¶„û=org/gradle/cli/CommandLineParser$KnownOptionParserState.classÝX[|WÿŸd“Y&M h;¶$›Ë†­FCJ%mHÐ@bŠ¿¶“Ýéf`3³Į̂·ÔK[µ÷bÛ´Øz¡E-*ÔfCH)h5j½?øì«?|é»ú}3³›MvÃ&}ôåÌwÎùnç»ï¾÷ŸËïØŽ¿É´Œ­¡ÅщcŽË!Å'㼘¼X¼¤yù<ãÛœ0\ ·á„  ãT Âé‹2¾„/óö+–± _ ãë2vâ2Á£|ó˜Œoâ[Œøí0ç“'jð$žâåi Ïðõ³|ýœŒIœ–ðH…ñ<_àåÅ0¦øû’Œ—q†q¿+ããxE«¾' Xi×°ÌA×6̤„ÐÉ@Á m{MS·{RšãèŽ@¬Ï²“±¤­%Rz,ž2b=Öø¸f&ú S?¤ÙŽn7Òï¨ö%ÜzRŸ†°kâ ‡%H<‰B"©r\ÍÕ%ü¨}ù@ ½¼®ø¬ê -•áWÖöÓNh±Œk¤b}†ãÒÝšA#ijnÆ&Æ K®÷úû”f&cÁ»»˜;f8 ×¹¯cï5LÃí˜o*¾J/”·|yC¯Î˜ÍC¡+AÖºQú3㣺}XMÑI¤ÏŠk©!Í6x†ØZï1­ Ó×j‘7w—W 4)ÙV¶Ìn;™×MW`_S±»šW*a-Ï/RÌN`Û^³Ý~ý¤K¢:šV-c]Rwh΂æ•MÍ÷z!ÊtJg«Ty!+Pa4l(ˆË^W·5×âÈRÒž3‚<, ¯"_1!á¬þõÿå±·{A[q²ƒ—í¼tò²ƒ—¼ìâÌ_rÑ •±ãú]öÆ"œvv“‚»ð)wb?C¯ ¬_p^·mk§¸²ðÕë >‰n;p‡‚b·‚a‚½ø„‚Ã8"в¼N¹ØÙ2®îß\·¥è^õ‹³Ú¸ÕiT–媮v\W5SÍÅx;UÄ…=¦ÇI³sø«÷c?Á{»MUO»§òdê„æ¨iÛ:a$ô„ú e«ñeD·K8¯à§ø™‚! Jø¹‚ 8¢à"ŽHxSàö²V?h8–<ôê hÔ•¯Ë ŠP¥¦µšü<®QáÞ]¢åí[šRÔ…Jt’ºR튙§t3éŽy²z©Y,IèXK$–PçÄPQË`êkÔ~ºS)k"ߨ=K†³Ÿ“üº|S]½ŠÛõJm\£Åãºã4lßÙA%»gŲò-¿„±—>ª¨ëÐ Hv͙达)ßÚŠå0å®cDãfö€Bgs/¿9ç[J{`–Þ‰ƒ­³ø‹­#àVk¸­¿¥-‹†sÿý§Ïfë<: ª¸„msh¤plŠ4genY´DZ}˜ Ê‚hÛý}l‚ä`—EÇÞ.˜üv¬%S\Äzñ&Åè4y:‹ûÉ5b§ÅeL‰9œoãuqWñq ÿïz¦’ùNSt“ÿ+ñ0¶à³ñ¢ãýÀÜ]˜Æ½8 Q ʲûÇÙä ‰]mim«ÕWͰ‹÷˜'ဗ5÷SÖ z ÈZ7 Fƒ¼Q÷ò†¡t/Ëô$$éÅ:Õ”‰“ØþÓg]!þëi}„ñ9ú¢6ŒMôý*øß­I|?$ÿPK õ:„Bÿ|ÓÛ7org/gradle/cli/CommandLineParser$OptionComparator.class•UmOÓP~îÖÑQ:oSðDÌ6ÞÊA("8Å,.`2CâÇ2šYÒµ¤íˆ?ÿ€‘ÄðÙ_bÔß`<·mæ`“â‡öž{Îsžsïyi¿ýþò@ÛR˜•ÐË_=˜1/AÀ‚„E,‰x,bYB’ï“x"b•Ã×D¨"ÖEÐúʆ¥ï4êûºóVÛ7I3P¶«š¹§9߇JÁ{o¸ éÝ#ϰ­¢]?Òͳ¹dYºS45×Õ ±X¶šRs´SWª¦¡¶®Y<ÌÍqugò*‡Ê Výz•»† ðT£ùqÚ¾\`˜ˆvhÂè®uƒ{ ”µcM15«¦T<ǰjj`#H6×bÜÝ?Ô«žÚ®á§ˆ}˜¿LÚ¸¥ ‚ÊŸ.2k•Wmò&@†îŠQ³4¯Á3Zþ×Qža*˰¥ ¢–*véêÛo‹L[ø9N-#~ϰ)b‹aå†-d¹µ¹2 œ?+⹌"^PW^-ÃfdÈ¢æê%ËÕ-×ðŒc½=öXBÆ^2ŒGeãF ÿ=—.TŽa¨Sé¨Å£Û‚JWÓ½  j.ßÒ·ä5w X†[ã›&) ‹Ó`PÚsåNöÎ §æ;Å¥Ñ ç®]“/až¾o½4<}ôuã-G»Ú)´Ò\!1u†Ø'b¤wW²ï"YÆm𠤅Ή,Aëòô)âçÞ±3$>£ëâÎL›jM8G’ï»gG„SH'Íh½ˆñ ²ŸÈ²_~Ô¥€9ŒÊ¥;¸ëŸd÷Hâžqc䛥‹“$¤·ètÂÓ½& ñ"55}žzN!Ÿt¼âxlKa‚È™/M’KƒQH¼Jk,Ì뜳Lh&ˆ0Gö8ò>~ Óþ:ƒ[´NPSTŠ eö­H'I£Ðl”~P V0úPK õ:„Bသyßn?org/gradle/cli/CommandLineParser$UnknownOptionParserState.class½UKOQþî´Ó–é¥@Å"¢´C¡”‡Š ŠD£ A”»K;G§3d:Uþ‚ÿÅ…$<nMŒ¯…7nôwÏNJ…’¶.Üœsï¹çûî¹ß9~øýö€I´&¶Ÿv%Ú…É÷kì’6¶‡–ÝCX߃¼CRdSiÆ?BfŸ °Ïèf_ÐǾâiU à à¯Ä…Ì_‰+%%Š Qô,ÎWgÉ‹,)üºvODDØ7ŸW­ž¼ ç1 sRÖöysü½,×ÀH™*x޼tø‡NUj/’qÑãÐ,Rޏ"¡í’Z»í#JN>dT û‰8ûUWR¢ÊJéÅå€kƒ$}ÓÆ²ã`;Gªzïãgª9µªb¸èÃh s i_g±Êø‘0æ³eÑI~˜"qÌB ‹ÌYœ¦*/‘GBŒÍ,®‡•?PK õ:„BIü‹Åú“ &org/gradle/cli/CommandLineOption.classV[WWÝ1’bTÀKT0$bl­— Õ*Š¢\¬¡P¥V‡ä4Œ2éd⥗â‹o­/}¨]u­®>ùеú'úCÚî3Â$3i}HÎ9ßùÎ>{ß>+ùãï_ð.¾‹c?fUÌÅÑÙ.ìÃ|nác9»@ |‚Eùµ¤âÓîஊe¹ý™Š{qôÔO}.g÷åìœéòk%†B E1|!C%«* ªUq «\UÐ;óP¤çjŽaæòÂWЕ7JeÝ©ÙBÁ‘æÝ‰úÒÔË¥\Þ±riüOhº]ª­‰²³ð´ÂC;}Y“¦^­2ewkl"#O&Š¢Z° —Œ‚T^A¼Z[)Xkkz¹ÈŒ¢¨Ø¢ Ëü%Ý.3…F¹P[aL.”» ¢FÙp.(èOû§aë+¦]T™´ŠBª7Êb®¶¶"ì¹'9XÝ\ÔmC®½`ÔòvGZÜ¢¸ Že“hÄY5XÐÃ3–]Ê•l½hŠ\Á4r“uòò¦y¦¥ ^ úš/g5=a:Ú4#ûÖ¹²ñ’pæ·¼°3=pÃpk¬Íµ‰U½zɳ‚£<õeÐ|‡x7Éä}ÝÞ½uw³#’kz¥º`ù3Ϥƒ‰oÅ@m@ôðò+~7FmQ­™³7€}¹f˜E!›ÞCM§R„¹dšÖc¿°Îô(m¹¯±5K\£b _J|ËÙ‚\ö¸\Bœž·jvALÒ}='$O £xÈ^n7íº^]eã4À;*¾Ô`bHà †T¬i(ÃRQÑð®i°A*ÉV¹*x¸†G”»:cTD›úh8‚£㉆9{Нåò-oë份§áÒôÄòösfì[ðþ_'›Hϯ<Ç­úâewcÑ2XÜÈÂ[WÙ¨à+Q3¼÷Ìò6ß÷ÎSÁ(}D̉'¼5Rv‡fïÖ)ñpwÓ["G½(ûæJÇDõJEHsŽ…ú»½-£¦(—œU·Ó ¤'ÿ+;æXõ†øc±Ÿ¿LQ¤¤[ à W8Ä ÓX懽uçÃÞ8âì"ÇnæŽ"Ãu–«—èD„ãÅÌ+(™×è¸ó ëˆd~ÆŽuD³›PÌßDLÁ3ìç¤KÁïˆÏe~Adl‰,½øç¯—„èÄq~„ê~GÐ^  O’â8I^ ½1îf¸{ œ ±NŠBŽëIƒ?½ïîìN‘êûœkë‘Ó ¡g8;‹sžŒW2g‡¤õ“›pÜ­– »—ÖAvxÔA>`ì<©).ÈYFdNWfâŸÙŠ»ìF©-ãëòÀL„‚ha '’ ùRrº[åœ ‘£°:y‡/2[^¤f²ëèÜ–‡Î¹}õ´FÉU\bCäÍ—LþôÀÄkôн3d”|-+Ç ì\â˜zƒtv»ž#žMn`÷R6µGîɤ”;Iõy¹ýÏ0К;à¦l`ï6ÕóüOV5Æ¢ô’ÌÕ"½Rúâ*w¦8»Ž›˜ÆmÜà?°<ÀœOšð¤Åp“̕Ү†×)¨ÓmÖ)ߦNG¼:MášvÞk{’£|;ßC¼@¤óÇ–æ-ùš—l4ïz8ôCœåPœépq©€¸û÷ ¸Oܱ†§O{¤ÔLdý°"Á„Úàs#ÔÑ©VG¡Ž¾éfÍü PK õ:„BúÖÐ>¦¦8org/gradle/cli/CommandLineParser$OptionParserState.class•R]KA=³Y³vMM´šâwŒ)F)n_$"h@‚ ‘<ø6I†íÈfVf'%OýO}*ôÁÐU¼³ ˆXH³ópîÜ=÷\î¹óçïïg‡øâ#ƒM.6=”æŠ'¯ªdæCÚˆ*Ÿ"a„‡0ìV'kÖí&œa¡ò?ljÔŠº+.¥]JñçÀN˜Ã ²* GÓ¯‚¡ðêÒmçQtiȯӸÄPž< CiÉ-Ñva¿,;¹êÑ- $‹1³ÿ ÎO ̦$ëû| 87"ÀÇGÀ¥µa!ÅE|Jq Ë)m¾`™+cñBg,Îþ-^Fâi´Šµ´l=åoP{P.Cg s®mº4¹³Yp td^pcÌ)T莎Ö7l›°*ÂSß Õ*®b#VÉrGlÊ4vMÇ8S4‡N*ˆ°ó¦–h¦ª gLç„XS˜°çŒâIñÄÜW¶yóaÐr¦‚Õ§ »!:y˜k;\ÓË’> ™µ²K¶¿gÛÊ=AÖwÞªضø§­j×®«;ˆ!ÉfË5*öØÜ:3穬Ԡ¬½\º ¦{pEIÔR¥±ìhQ®`‘ÏK'bÕ\…kæfô¼·ÞFûáØÞ:׿\mÚ®:sæ!K”e²Ån·8]ǼBf–ÑŽ•yv}YìlY`wÖ±ƒ 6,/Œ9ޱ(HÒù@Þ£âU¿Æk*^×ñ~£ã·ø‚ô­‘õµ!Óñ{\Tñ&€•ü©øƒŽ?âO ¶úýk(½½’K7¿B×´ùØ™sL<GpTÇŸñß…UJš<—Öñ6ÞaE÷ëÇaûð=ïâ’Š¿è8ïêø+þÆ>ÛPÀÌì‚Q¬EpðœécÞìaJ÷o¯ô§K¶›Î›g‰4¿[\Œ¡bIÇßqIÇ?0ÓÊa A ‘n‰ÖÞÁþhùO“¡)¿ž¢D«–MŒbŠJï¬ÂHINš›¬Ç¡È:Y½Mt5ä½öëšMsæ‘]uo¦Õy«&0‚ØYÛY0èã¾€ ;ýÕN–;¾Q.›¥ürjî9«·üøœ]r K ß€AØÔô¼ èØ´)fGs‡â~6x>?V,âþ2Lò7k QÊPã,„]œ³‚ëó»8gÙÖç÷¢ã|ƒò7¥—TjžÎ^ƒ’½Ðì5„¯ B1J1v*Å8Ŷ+Ðv^G»‚ÉÜuè .â(…u >FÇÔ tÒfýPd×Ut]GBÁP4õíÒB’††bÙIÅR‘ëècféægK7?x_"ù¿»ÑÎo lä/é$z° Ûù݇ÛXŽ·ÃÂ<^<‰­x iì¥õ8XüÉ}†Ã4ú1Œþf'îû1J_û¨Ù‡xFß‘«!cØHé$G)ë=Í¡:kߦÄfÀ/9c#‰I›tbcô?HΆ³Ä¤^æéÙˆ5!þ ›ß“{*ϾOFëùOûg‡D[òî_pŒq<~)’Ù3õŠº$•{„äSÝò&´\â¶«¸}&—Ø"‡T´a]ºùIî*zß[Áo†ÿÄ @cæd˜;9þÝË•!æÍ3fœs„ÜMR+"eTlÃ-¢Ì§aÉ`DDZgð8­ƒqîœÂ1"Ñèç!²n`UX¯³:M‰ Õgõ05âVº²;¯b댠”èÓ!\®Ó¨IƒûΨ ,ém¨ÑÅK¢;'1ã“ú:GêÝÑ»=µÜÝ0•eÎn»ˆhäòÒÍÏ×ë\%‰VdWcÛF\}d ŸÄÑY:ía@â@QAézV ÔÃÀØmÊ*¡9UÇš_…^ÂÂFƒ½3Äà:'sÿÃæè›MlÈ\Û)2ëv|”[N¯„D8Ãx˜ò,ƒ<-ƒL{òøé`1‰ÂQ~úL J怨HᕹûXCîF}‡ŠÇøý> Ńþ-ê Qô‡0óþŠ œcæ.P¯¨ãŒ PØä}%ÿ{›x™ù‘“½&Ã#v-ÇÛ!A8ÎË~Q»-z¨ŸÓ+{…"%ÑB´^/) SkJ_g¿PK õ:„B‹A5l| :org/gradle/cli/ProjectPropertiesCommandLineConverter.class’KOÂ@…ÏD|?PâìÀuã#QŒ+¢$÷C;–1m‡  ÿJW&.üþ(ãª1ØDã,îéœ9ßôv¦oï/¯ö±[@yl汕G)‡ívÙ }FHWkw„LSºœ°Ü!¿]®nY×7ÎZK:Ì¿cJDóØÌ螎ZRy¶§˜ësÛñ…ÝVò;ÚHŸ+-ø )ƒ€…n´kS†#cruLXõøgh|Ó×B†„j­õÀFÌöYèÙ­Dè™èÎè%×LøÜ%”ÖŽñŽ…Ž*‡_‰¨å½?õÖˆ:("‡<Ú„bJÕö ®­ØŠtòfë^*K÷¸Õ ßµ¦ XUÞðV½Œ£Üi01Èk ÂÁp8ƒwZ±ß8T0gî?Pôa¦Î›™m”ŒÎí=ƒžÌC S³s ¦§£‹| Ë1\áôZêq-}CÓ_èJšžEˉèjš™E+ ¨ùw'©õPK õ:„B1 ©«PForg/gradle/cli/CommandLineParser$CaseInsensitiveStringComparator.class¥S]oA=³|l‹‹EÚâg+Z¾ì–ê‹•Ä„”¨ MßÖi–Ýfwiü+þ^|©‰ÆgQã£ñβÁ´`01„¹wîœ{îÜsg¿üúø @ SÐñ …µ$°£–¢Ž’ —uTu<Ô±ËlHGM†X±tÄo¹Á°Ö‘Žx9õ„wÈ{6E²·Ïí#îIµ‚ñàôî´¸/ÚŽ/_òTtO:VËp®Ç`´Gx-›û¾ „ç׳LËã[˜}[š„qg ª¾æž/¼ÂÊ:ƒÞwtb瘟rÓæŽeN‘õùH©M9îI ]§¦ú™ÌŽ÷©³Xûû«Þ±èõùˆb×Þî'ŽÎÔIM‡É€ni󵺚Eá_€ «]i9<+%»ê8¶ùG¾Æ|÷M¢Juݱ×/¤nn®Ü®J2Â%{¨Ø)™¹He`:1<ýß1ŸcŸ6ݱ¨#†íåj1¬GæÐm[Žë UŸasÁR]¡òËèI>7Ê¢0MéD;ƒv&Y>åÐÞ“£!MkRÙW\&ߘ°†,Ô3! £ä!¡ãd³•êbÍ­wHlM”ŸÌ˜² Á¾!ɾ#Å~À`?CÖò43bUÞ&ra¥,®’§Ñ \ÃuÄ2Ï¨æ¨æbôÒåÊg$ªô?Cr²ðâù)pV"›¸–Hc‹<-R"?!«EJ°ÅJ䦀a‚ïÒy Û!þ ¡½+aÉ^A†î~›,2+¿PK õ:„B¢V˜"—Ü&&org/gradle/cli/CommandLineParser.classZ{`TÕ™ÿ}ÉÌÜ™› „@A(¡$!!€!„G¨( jD àã&s&3qîˆõÙªU´Õ>¤Ûú†¶«»ÕJbŒÏ®U·k×ÝÕ­Ýînëö±«¶k·»Ý¶»²¿sïÌd÷œsî9ßù^çû~ç;ßýàéç,“£!DñKÕü«jþM5ïhx7„÷ð+~üZçÌ¿ëØ†÷5üF‡®úÿÐa¨Éßâ?Õòiø†ÿ.ÃïñÓñGåø ÿ«£”á„ LDJTSª‰OÇâJ@ÇÑ4 ê˜'¡ èê»L5†¢˜¢cŸL Ê45S®šéj¦"(3¨¥Ì J¥&³tÔã}J–S4™­£ï%Ì^æ¨æTµã4ÕÌU æ)¾óUS¥Éé:VÉš,ФZG‹,Ô±Z>V&‹¤F“ZëÉ—ФN“Å:6*Š6©×¤Aǹjq‰4e)= ËÔÊò bJ“3Us–.+¤IÎÖde.–UAiÖdµ¶(Ñk‚²Vé¸.(ëÕw«&tìRŒÛ„~Þ%éveÂ.9U“MA9GÙp®Žn9O6å|Ê¥§å]¶H»&ŒÍñ¸•l‹™¶mÙ‚Y[RÑD¼3•ŒÆûÚýfÒL%’šlÌo3mksܶâv4Ýg ÊÝݹû.ÌÞßO컋šIÛJv¦Ì”¥ÉE”xÁIÖ.L÷˜îT¶Gm›¢ÝÕÖdŸ³D[Z{SVÒµ5¹D0Ó™9'š´SƒÝԫߌGÈ`ƒÕ›HZóšlË: u¿™´òä^ÊÀÌ›ØN¹ÞLK¸¢7 eg¶ì1÷™ƒ©h¬±ÝX-uFûâfj0I}7寶¸Ÿ13Þ×è2X½%‘ìkìKš‘˜ÕØ‹6¦5Ý[®èÕkÉsº‹%ö·GX‘´ñÙ!˜áÌçyŸ+k iõ˜Žg)…¢G\ÙÑD£3µ=å4YϨV‘t¶nŒÚfwÌ¢ÿ-Ñx4µVPZSK¿øÚKKµ:û»­ä%Š¢¶$zÌØ¥f2ª¾Ó“¾Ôî(Õ8ãClsý¬Ä×dõJ«¤ä•N üj‹àìšÅ^¬-åðä$‡²žñO ö`ÃDÛt ÇÊ„×e‚•59T›©‰²prâ Gáôy ΚÐÕE¹@.+aüó¸73´™hTž÷P_¢D(—h÷&Ò²KMÅ¡$ZÍ|ɉHÇæðêìt¾™Œ»BÃ<ŽÕËxÝÙ˜ÎÚ%›žoô¬ü¨ÈD–×ix$•J™-“¦ÔiÎÏ@âI:’ìÖøx>V×1ò x}@¥ß6Ûì£=á\%[xØn€1ŒDôÌL$#V2Oî¬?VЦ1÷{=34å94[¢¶"*Ýk 1§ö™±A¯#-F![ñTRmÚäö•ùØVíL+Ö‰Á”:BOÃÃÄå~3•‹I‹s2Ó¤™šg+-ðǨ ûÒ~ó€`A¾Í' €ê«OB¶ÚË / öÜ}f¡*“‚ó_ žÒ|{Q¦sKMÎþ¶D,fõ8¬½pÑ$ü„gQ¹²µ{™(¼qíìÊàÚV¶tööª“œ]$hƒ³¢ÄõªK˜±îɰ¥N¶ÎÛ"µ8I£&w-xŵÏL& Œ¾˜¯Î¢' ›==–mW¯XºT°°fâÜ®å…\r`éøÎ•j癓ÙYTDdX¬R,ÊÒËUVMžaÑel!½{±ë‰Ád+$…«³ŠX,Q Ü; ÄínÆ-nÃí‚9Þ[Sƒ)úÚ2û]štxQvøŒìdƒ{Ts/’qÏ3íÝ4’7°‡Žšì2är¹ÂÀñAÕDÈ\Ä™I¨É•†\%¦R¢[5=‚¦ o Ï‚QífÕhÒ+}šì6xÁî1d¯Äˆª…áfH¿0;K I l˜Phn9«d]ÍlhØyŚ˒”¸!¶¤ ”}†ìBŸž^]³¤Î!¹F|Ükå:®³¤VðiuN¿._RÇìÌÁâL±·)™L$ ¹^)zJqòFc•×B[n ¹I>aÈ'•ñ7ËCn‘[ ù”\gÈmêxgxà¸:ùãyçsIÒ²x>‚e“,…ÆŸÊ9·«æ &wr§|:£ußã{­H6² æ(퉓T¡ð dÈg$ßàÖdÒRŒ&wòYåÏ’ú*ßÃ_ò9å¶ÏË ¹GîÒäW䋆|©€Göâ1ä°Š-ßB{a²õå)0Í />9½GŒçBø²ú‹žÉîå¶z¼R/¸öÜ×j°x˜¶‚U8ì,.³j‹ ò)y`@NiNN³kjOV‰…OR*Nñ~¸reï$ꇉ_D?é–9Ò*еàMM¿< Vyæå¼H+Šg‰t»M»Ã:r~—`¹å‹;3kj½jÙò~s¨[=B“© ìWÖxT‰;Ô3ûêA3fdŽ‹›‹¼öÿ÷‰Æ ²g·:Ü=Øm§C·²f³ge;EEwŽ ;ªì²žDËVg´pÛ|Ž#Ã%ÇçñÀauOšÕ.²R´§Õ Dvz×ÊŽ£”C£kñ¦‡Œó­ 5°Žm¹­Ç©huøÏry¤ù«Ñ8D 7ñ•ù%®¹J—8T¡ºÅOaê0¦}3Ë6਷%‡U(Ë*„Ã8Âõ{9VV™|º¢T1-=D_–‘o å]c˜ÞU÷$JGQ!ÁŒÌlCeW]½Œ`VÇâQœÂ*Úöb¶à°¼¦FaÁ ˜Óìoû‡qêay,ì¯8ms£| óºÔÖùÇä+œ®Æé‡1‡”a?‰ÏÆ‚æ@80Œj\K‚…Á’°¿|Í0>Öp)+I±HÑja-Ì/ßUÎÞn:—›jM§;´>š”lÃþ@–nþ¨;‚JR/&õ”¡žÕð<·¨9 ÌF±¤„xÒíðfšw³æPjiÊ›ÆÐHFK+– c¹"^>Œ3U¿ 9ã¬Ã¨3æRTÓ+:üM¡ÊrYÓƒXI«ø¥ìZÔ¬ç³ÔÓ,õ,Ë7‡ä؉—Žau)ÉU7½~ 'ÒKéΑÝq샥 ÃXY¯â©Ô‰§'PÏö2ÌF`ƒt'Îg¨_‚Ëaâ ìÅ•ÂU¸_w¢›ÉЃGÁ“°ð"zñ×èÃ?b7~Ì|ýöàöÊÄäôË\Ä¥ ©ÅÕr6’Ò [v"%{°O°_®Ã9ˆ!9ŠkäQ~Çõò n”—q“¼Ž[äÜ*ïã üwÊùºûw—¨,P±?Ìb6|÷±½óq?àè&›šÓ¨™á®R—N£´3ð ‚.6SóaîQ«ng5H¹¡ô¨¯’ÓCÜñNzo–ýG9@«ŠŽRE¿´´É¯`q«²YiP°âh7OÒÚi•~•MOáÂ&ÿ±?R[.*Þ2Ýr±òÂ(:íŽðSë+.ñ=‹m]ñRíÆv´ª>cÏe4¥’)ÞU±Ã5ÊŸGÞåKst7ž¸³~;Ï‚À5˜Çöa†ÿ#3ÈkÞËØ2´M†rœa¼Ÿ|ˆA|Ãø9î¤ÿÄù9ƒä=¦ãx|€§EÇà)dzrž“õx^Úð‚ôáEÙoË]xI¾ƒ—åU¼"¯1Í2É|Ù35q#¡G%Uˆ²¿N®O1$÷3(Gñ4Óðç¨ÆéÔÿ™‹gœrå(že6ÃMH?eNªk2 ¹u¸‚º¿À¹‹ÈÑ™SAI\Ž^Ä·ò!y Ž—˜ayß¡¥X.÷âe">e^!tød>‹½«ç«Y=ÿ‚âÊú.ç\™åñÓ]W?É¥oûŸ°§8 »x˜—·ûÖ.~Šö-u£¸"÷ÆÂô5ÜìŸ{¡zÞpWn¯WÐ~••®=vâ-ž¬9ïKTÚRvRuJœŠ×1KÐKñ&k“ï³6y ðlÂß;§±–ÚÔ³¸xêg<Ôg ŽÃßp/œÑô-K_î|G ÔKù> °ˆsèßbïÛX㥠R¤…žQVYÜ^ÿÜÚÒ&_¥oîƒè¬¯ô-oö;7¯?}ó†ÇÐÝUÑ“NçSˆŒÀâ}®’¼7³ÞW¸~³WçcchëREÔv·×;À´ëhÈäiC6M}ŽL_}&»\?”®߯Lü /Ÿa%~A»Ékómžò;¼öÞeQúÑøW¬á~íxq#t&cú¨sQ”ðû‡„ÚŽ»ðŒžRúîRzözö6LqbÕ‡£[y»ÔæLaw„W¬*ìöðÌTœ—”™{?Jã{#{åmå5ߣ•âŠd÷ó–&Cnþ ~ê±¹´°ÌôÞüÏž’K&'ùmº°x³LB2ýõ³lY_笰ʞè0öŸ}Çà+ýêw®®\N%Ä Åýèw°n‹š¨£ÌFöqÌA‚ýûöW³O²·Ñ)öƒÜ¹ý~ŸŽì‡8?ý5ì?ÎþZ®W²¿Žýõìoð•Á¢¸‰ôŸ`ÿIÒ]Œßãù@èÿPK õ:„B`÷Å¥)3org/gradle/cli/CommandLineParser$AfterOptions.class­•OÓ@Ç¿×utƒ Äß ‚@ ”¡¢ˆ1QüÌ“é¢$š[Õîjº¢ø|/þ!‰J¢‰/Àe|®«£²‘‚1MzÏóÜsŸçyîžkþúö@KTLjHcª—$]Å´†$f5˜˜SQT1Ï©ºµ’-,†Ñ’ëÕͺÇkŽeVÛ|Ƚ¦U[ÞóYbHݰ…íßdŸŒwŸª0$—ÝÁsÒ°¶ÕØ´¼G|Ó!Ë`É­r§Â=[ê¡1é¿´› Ù[/|Ë[ãۮꊖ·ìðfÓ"ÕÜ93H‹®§¬ó þ~Ó*ûÜó[F†¡ÉÒ+þ–›u³ì{¶¨/Mm0$¸W—ÉuL2ô¹"‚Pq‰a %·¢Ò¤O5lt!w‰_D[î¿æŸqÅš+þT“ù+ƒÛÝj‹¤â2VqÌñäbÐ Êöœ|Ƴ„A+»[^ÕºgËÖîð™•Ef‘AV¾®dÑ MÅÃb,ý±x-Üw¢Ëé4%c\Uq-‹E\g˜9R2LeûæÞtƒãw•a¢ãD:¯BœÇn½þ&ÚŠÿšnG\ºÁ¼V»»í{¼Â-ë€@úb¦!ÛPöI=PdŸ‘¥´û¤)4ft¶ E7¾ ±Cª‚~z÷#A+WÑÃÖ ±uäÈ6ÜrGÇ€@’XFÏq …Ð¥—’øØf¥ /a9ÂPÚ …,'ÆN‡ŒUZAÑ‘ûŽäSCÿŒ„̰çÓ>à“Xh¹¶¹(¥3$)$ŸÅù};¬Y“Tã+RúU“3ìÒìy$U­MÖZä¼,|4äÝ!?¥»`;û2|É0Õæ¤p!Ø6)a<Èèb°r‚N ÐéœT ¯“4žJÊ s4hD>Mÿ@3Ð~PK õ:„BQÆbŒ—œ3org/gradle/cli/CommandLineParser$OptionString.class•SíNA=Ó¶,+]Ë—(š‚UÚ-e)â'ˆÆ# ÿ íZ–lw›ÝÅè£øþ•D ÑÄðqøáGbŒw¦+BÛøsçÞ;sî=çÎÌ·?Ÿ¿(ãa/Ρ ’1Tô£(©J*¦a*˜Q¡ (LY˜Ùnˆ³s n)¸Íç~!³´ÅßpÓánÝ\ }Û­Ï3ôxÍÐö\rl×&óç:3…5†DÅ«Y é%Ûµ–·–ÿ‚o8–èäU¹³Æ}[ÄQ2nÚƒ¶"¶ÊPøÔu-¿âð °h×\òüºY÷yͱ̪c›¯ÑànM´xÎýÀòsGñ$ ¿n…í éðw˼A}ó…nBS¡×òÜaóSé<™OYÎ"övF˜²0³ ¹ÓàúxµjA®<7CðJþŒê» UW½m¿j=±ÅЇ;*L ˆ†óÐ5d0 Ì] ièļTRpOÃ<FÚK?Ú¶šåk¸E —1ÆÀJ.aLÁ†Ò™¨3èÿë¯llYÕaâä™Ñ[΋qëíìHwr? ^Úá&ÃP—Ë-¼¢WΛMË­Ýn:R‘fšjö$nÈÒë§ß£‰Ò8Éˈ)Óš”¹zsƒ­S§5mì#nw‘0¦vÁv$tHÂd¿“ý^ü¤¢¿0L™l †\¤'Ú0é‰F1òé6¢6¯e ,ŸÈ$÷Ðóc_ ¬ï#%Â^Ê3Zö ~À迾c9õÈZ¿%­U7âÁÄSˆzš´Š½¤±­ ÌØp²Ö…Øl^!yB¸b§öÛië} áFëÈá ŒG3P0!g ¼«È!®§p ×;˜‘¸vYǘËÒ1LJ›Ç¨¼’ÝîM\€Š+´BOýPK õ:„Bý¹E#±! ;org/gradle/cli/AbstractPropertiesCommandLineConverter.class­VÝWEÿM²aòå#6 -¥”HI[j¡h TbǦ‚´»$KXvãêÇ»ïžã»¯ú’Š=}öïðïPïl–4ÉÆ6嘜3wæÎ;¿û»3wöÏ¿ýÀ|+á "ޕЋۼIJXÆŠ„U¬ñá{¼÷¾ˆ”„V$$ÜÁֱц±Ù†»¸Ç›ûA|$Á‡­ >nCð›mî$-"Ã¥*bGD–¡eVÓ5{ŽÁ]gæŒÊБÔtu¥°¿­šw”íiBI#­äÖSãcW)Ø»šÅ04Ìl,k*™œKç´X|Û²M%m¯™F^5mMµæý}EÏp·ó†~@JÕœaèʪÇF‡«y[3t†Ó‘Ñäžr ÄrŠž¥lSÓ³dÚë1]PmEË©†¾sVÚÔ\­iCßѲ“ GêÁVA[SL‹pq"ZòNŸaðÅödm¸[=ϺŒŒ¬ÛtõQB·lEO¢®ãx ¶–‹-+y²hMiY]±ÄÓõó³^z¼š9ò"¦ËT3ÜôDí@ÏT¡›©áåÏ”l– ÃðP=\Wru±˜7UËrB5ÊšO¢ŒV¹JPâÛउeÒ¬¬yÑ1HùÊiâ´]wí=ÌÒɲ'-Ój¡ˆ]†ï^šÃ&·:izk/Êêöžš¶I½Ô4Îêu ]ùŠ—ys¥6¹•éÌÝûF·}öDQ:‰H3­ÞÒx6Ç›«-Ü—Œ³ècè¬÷+ce á¢MÆöD<”‘þŒa>£Ã {ù ï’bífyný‰S†[DAƉ(Ê8ħ2>CœnÈ Ÿã Èøe|…¯yóŒ(.1œª!BÆeÁ“'*¡ÄÇK¤Àk]e7³…}U·+§žaàE•§{Þ´6SŸãüø%wëÝù¡HSŽÛiUMùŸŠüO=÷ˆa¶ßžu•Fš³¤^8§â¡š!©Yü.¶×j‚š[i©4Ö,¨ªÀ!¯–Ê2ñ·¢mç“à.=òº35=£WwÂbNð÷¡@v×"ÞRÑd¹iµ üô’?Ž9‘høŽ4Ò è£æ ø¯Œß{jÏÑ(F’n"cOÀ~¦ŽýÔ¶8Ênœ¿¥Žp^9äÊa.Éf¯¹Nódí'92ø¾MÿX þÔ¦@BH•XŽ–Ð²¥¡XBpãÙ®!ÔöÑgÙ9jûÉóyÁ@Ù[Ó‹`”öêAÕ›qZ-ðÒA’ï~•$Gü ­›O ýTÕ`UTA×ç„cÃÉ jC»q?Q-$·Æ9þÚJpŠaåÒÚ¾Ç"u:žÂw]èB%tMÂÐ¥aè¯ø±ñ#ÎÒÈ”pºW„%„Ý©~‰rt~]?D'¶aâq‚"|bŒSt›Ù}ÒpÔs„h‚tWi6@–oÐ’¢ïÂmLaÚái«ÂÓ®áM'Î-\Ç E8[‰œknfŽúiÞr9x»s¸Œ{ŽG ÝõD68q"𦛈%‚ÃIcãѧè)áÕÆÊé•*°%Ì»°%,`±¤Ï…y ï8ré_PK õ:„B“¼¼ ,org/gradle/cli/ParsedCommandLineOption.classS[OAþ¶·-í"¥\A(¡-ÊŠ¼P«1!iĤƒoC;Y†lw›Ý- Ï&¾ø ‰JD}öGÏì.¥I|™9ûï|ß93¿ÿ|ÿ`+)dPPQL!‚Bú0Ÿ¢å†Š›I,¤€žÆ-,&q[~器+¿÷䲤⾊ {ÌlqWA¦²Ëö˜Þò„©W„ë-+è© Ãb^Ëá fº~—‚³É,C¯zްŒå2¥$JÂ^YA4_ØT[µë”ÜWÑjlsçÛ6)’­Ø5fn2GÈsŒy;‚”ä+¶cè†Ãê&×k¦Ð_2ÇåõU»Ñ`V]Rm4=a[T.ipoSP0˜/œ—DNDœ=tšœ=¼ÀZšÕë+ŽÑjpËS0”?’Ž“¬ ÉþKOr‡¹¡bjÑ©ªÝrjü¹»Àê‚dÒ0„a§jW‡íKÉú‘Õp³ &N«®›&7˜Yõ˜Ç×ÞÖ¸ÏEˆ€4W·¹›³l/·ÃöxŽYû9ÿ2,ÈBS*jx’<ÂIy®Ñ2=Ñ4y€t ZÂcº<ÝN5”ñDÃS)höÿÆy†ec{—ר‡—ÎŽ†îˆ+Þ½[§•†+G±Þ9ú •tGi`]ƒ ÿɾ«Â]k4½}LÒ›ÉЃ¢É.Òw€N "N{j9­—)RF”v@¦x¥xŒÈÖ!¢_û죯Ð*ß!(#F9#´Ó<®bÔçõ«r-¿!~€Þc$¶²ê!’?‹_;B}†S'áèÒü‚ö©]q˜4‚j©T£ŸøÇ©BÕ—ÚÕÇ)ñ«ët’ÿâ’õ”,á§;’ãarÐÅ&1ZxFiW“$óGèàuw+æ&9#¾PòÉÝ4f|tgCÆR(+ôà’‚¨±düc—ÆùÙ¶Á9•ÿ PK õ:„B7ÉŠ¯™ª=org/gradle/cli/CommandLineParser$OptionAwareParserState.class­U]OQ=·]ºív±¡€ˆb)BËG¡‘$bH4©i‚o·íZ·»æîÖŸâ/ðÅMD$þ”qnYjIk‰/™3çLïÌÝýùëûKØŒ!ŽI :2òiJ£Ÿ¦1£!‹œŠY *æU,hˆaQÅ’ŠC¼ê4Ü®MÛ`HQÏׯYF¾j™ùÇ\¸Fmûf!â=7ÝÌbt®U($zôMï.ÃÙ`x°|¶Ì l;5j6!{ÍFÅOxÅ¢È@Ñ©r«Ì…)}?¨ÈvR^z¦co½æÂW+yÜ£¼¾kۆض¸ë„[ ì2Ó›‰þk²ÁßV ò„wŒaš)ðWݦVrš¢jì˜òxR]è© #¤Ž‹XÖÑ :naLÅŠŽÛXU±¦c ËÊ[Ï40½Ó•´k+çœ!ÃÜ¿œ¥Š{ `˜^íÌRku£¦{2؉ ]gèçµÚƒ7žàen5¿,S¹›ªKfΫUÃu3Ë‹tq§Îpå’¾ø/Wö¬g³Û¥v~®t0N™ 7¤NïÎåŠɤ\zŠ„¡Ð Ðd/‘W$D˜l27{–c_ÊÍ"üɯÕRž Cc#H°Q Q,E9ª!; ´ž¤Fˆ8/cÌg^#_¢"¹Ù/P>´ù"k5ÞÁióDpã”g¸Š Ÿç}-T!÷a¢ê#˾!ò©#¨ûÒ“ê<ú‰#Äö}WûØÖÔ$K#Ê&;t mÝ‚¯ÂõVM#ds¤§ï˰¢³Ìâš"¿2YÌ"F6O¼7É"ý PK õ:„B$¸Rü<Y)org/gradle/cli/CommandLineConverter.class’]KÃ0†Of·ºù5¿ñZÄVÑêëÈP -Þgm m*Y:üm^øüQb–B).ƒö¦Éyó¾O'?¿_ßp Ç6ØpˆÀŽs>'B"pœ`ŠçØK1§Þ³$OR⻵âËdJbé#è=|ÆäC²œÏl8BÐ åX‚ ¸2Å kµP Æ©?òÝ(RY#v™j¼ÈMc˜b•¼;'Èõ¨ÀIJ¼8eÞ+3’Œó,Ã< _Ñôy£F<58Ù°Á‹QUk]5ËwFõΖŒ5‹Î¾û¦¦>ŒËà‘qêa^ˆ˜<²TåŸÔâÆå"âzáBpºš\EÐÿ@p¹Úx/h‘.«—×A€ ‹¯m!XKíÚjg©zlµjÁºVº¥§• ƒ²©•-ƒ²­”èëuYÙ…=ýßÿPK õ:„B@ͤ1é| <org/gradle/cli/CommandLineParser$BeforeFirstSubCommand.classÅVërÓFþÖV²AVÀqqJÚ†šàøÅ!%SÚ$åÓÒ:ô&;ÂØ#Ë…Wè#ô-èL;¡Íú¯3ýÓ÷èC0œ•Œã`'rfúg/g¿=çÛOgöŸ<Å='±xŒš%Q,rädH¸(c‡p Ÿp|*&+«ö™ —9® á*Ç5×qCÆ0Ö9ò2"Øà(pÜbt~0ñY†‰¼eWÕª­m×tµR3Ô5«^×Ìí¼aê·4»¡Û9B_4LùÄpuÚþ:Â5owàr‰MiÍÚÖNÃF³^ÖíÛZ¹F–HÞªhµMÍ6ļe”]†èª~ϲõ+†ÝpŠÍrË'ƒrÝ4u{­¦5:Á}IÆ{:¢“†*{ÐâtŸ…aØ2‹Žf;…‡Ža™_0Œxc/-:äkk:_ûQSkšYU‹Žm˜Õ\·%áO½Ë7qjvUH×å¾åâI$oà-д°oªö¸íx¤CªB+ÆaÙäarE0Ex#Ïw)‰™1éò'mº§Á‰î QU1Îf1Á²H³9äØ<½\úó±6}S˜&Úb” Q!l!‰4}œäÉ`R$Y¶u¸­HÔsW-¶§Ö pæÜ0IÒÃ1Gê3wtÞÕKŒæñ‘û=.¸>ð!õ«¤ÝIzŸ&KœúII<——‘¢W±J=ÂCÏå5ˆÇð2n.JýçRßPÿ­$¿PK õ:„B“;™|ü9org/gradle/cli/SystemPropertiesCommandLineConverter.class’ËJÃ@†ÏØ«mµ¶ÖjÕEÜ5BDÄ…R/Pé~šÓ‘$&ÓBÞJW‚ À‡'i©AÄYœ3óÏÿÍœ¹¼¼¾Àl— "l¡Y„Íl E Ê<&Ï dÚú@¶ËÇH ÚgÞLÝŠ{:r”Rïs‹:C*X4NĬœ°€ÀQŸ Û´;hZ3a ѽÜG!]îºÔG‹v¹7S"Š5eb o}ɸG ÑÖûtFM‡z¶9‚y¶²¶~X{()spL`7e.°KV, øTXxÉ¢Šõ¿”fDT E¤G ÄPÇWãJm®h~²­Æ49Aíjx­µÑ° ­ÓsÃhöÌ gÔ™¢n8üÇ5©Û] .FÔ’¿s°9õàQˉ΢ⲙ*•sû/@žUg J*æc±e+sƒÊ+1¾ Õî$p¦¾ô´€6¿¡™/t-Í,¢;©h-Í.¢Z ª>kìZÿPK õ:„Bœ³I·2org/gradle/cli/CommandLineParser$ParserState.class•SÁnÓ@}ãØqê¤4 ´@AÚÐ$MSn(ˆHHQ‹”ª‡Þ6‰åºrÖÕÆEðO\¸€ÄࣳvZÒ&Rˆ%{fvgÞ¼·³þýçç/pXØvÅvUϱc£n£AȾd¿!dê‚Ù‰†a­HïðrÔ÷Ա臼RîFžèx²hÆgÁ˜ÿ(ÔØS½XļXø ¥§:¡=Þlu#廾ÃÐsaàv¢ÑHÈ¡îÖU§ÊÛ„âH|é{©øè""IX¯wÏÅ'á†Bún/VôÛSB._¥d„ò5Ë™<Âj$§ÐlìJ©ƒ÷éœ&sÚ.–3ƒÍò‘<ŒäÙ·óô,}N‘œJy'‡6šjõÅPm=mãó Bõ² N/ºTï} ¿1“ÓÒ‚ °‘ãYì·š6ö ØGÉF‹°·Œ4VöïpŽúçÞ &¼\þÔ [‹…Ýh–N‚`D<8Ó—·²Á¬ðŸ•…~lZ>`…#—-OÖîߨ1àð7«ÉBžýBšÀv 0™ J P™m Òæ*CC7Ë™ï0¿Þ‚YI`6Ò”&ñîâˆ×ñ ~ˆMè‹ñèš]3‰ù½Í¬4ÅŒRÈ¢†|2)|Å֘Ț)¶¦øX×|,„qö®@±”Bâ—Ù™ÙßÎÌÍÌí¯?ß¾ˆâ¹ˆVÈÍ´DD´AI6ìÅðkÆE˜ðHÀ¤/¦Eˆx,à‰€8C£õF+" ½)ÃÌËySÉT9[Ð䄱µ¥è¹”¦«+ŠYTÍYOjºfM3Ìõ×6ÿ×ÂçÊìbk ž„‘SÚ¸`yg+£š/”L$þ”‘U kŠ©ñ}Ièáî2tÄ_[ª™ÔÌ¢µº“)A2H º®š‰‚R,ªd5VÓÇÀi8§7{lyJj*#ah1ôUK1­ô¶¥º€C»Ã;W‘Ò"¬Wý© å­"=/¯Z¦¦çc•’ÚžW`“nÅÌóÄUàÑ—3l{rª,´tIvÖ·wlbfÀ°y)¾vxQ»8\ï"|‰òe˜!PÏ9qÕØ1³jRãÓUa3ÄÓ#Á+|hðTBsæ%,àCO­l0LÔt䥾©»ú)%Ð]M%ánrÇ–¨vk^°X¾«šb°Îšrj†º©|ËÝZæKšaôBmUOLÎñ]ÅTOÆTM1|þ>¡r¯]EgcDu¦d³j±P•ŽÔÑNgîXZA^R¶ùÔ8! ΫC_ùHg6Ô¬ux¶\$`…FÕ‰ÐÞŸ6^.¡ËçL½Í»Xר«í÷ÏÙ~–yiêý¯Ô…σŠúË·Ñ{€ù|| 熋Ï7š×´›§½›¨ }†+ ïÃý‘ö.tÒÚÊul l ^6.’u‘Žìq×›£ÉD2†[t›ƒúMð?ÁõžðW4¸ð˃?á?€°"MSí£yïâ:·;€w=&‘4x¨lÙ;rÅÏÙ ÚYl–´Ý :¹Ç]ô’œ»Gœ‹‚Ž €ûpû8JÉÅ4…ÆO vÌì8æF~˜ÅÊÀ…#pÇl.hG͹ÂvVmŒ!\#:Ch¥W7In½ãÑG¾&:ÅøS+Šé½D§ÀiQÌx\X$šòˆPK õ:„Bö„ŽÂGEgradle-cli-classpath.propertiesSÎÍO)ÍIUHIMËÌË,ÉÌÏãRÉ(Up,(R00Q00·22¶21Vpv Q0204æ*(ÊÏJM.)¶å**Í+ÉÌMµåPK  ;„B íAMETA-INF/PK  ;„BÓ¸àNh¤)META-INF/MANIFEST.MFPK  ;„BíA©org/PK  ;„B íAÍorg/gradle/PK  ;„BíAøorg/gradle/wrapper/PK  ;„Bh‚df£Õ#¤+org/gradle/wrapper/Download$1.classPK  ;„B ¼Î€pD¤org/gradle/wrapper/Download$SystemPropertiesProxyAuthenticator.classPK  ;„BçìXsªÛ"¤‡org/gradle/wrapper/IDownload.classPK  ;„BÛHE*P 3¤qorg/gradle/wrapper/ExclusiveFileAccessManager.classPK  ;„Bc¯º`-¤Ç org/gradle/wrapper/WrapperConfiguration.classPK  ;„B!¦¬æ 0¤rorg/gradle/wrapper/SystemPropertiesHandler.classPK  ;„B+Nm q&¤¦org/gradle/wrapper/PathAssembler.classPK  ;„Bà·(/ò ¤org/gradle/wrapper/Install.classPK  ;„BGÜÄ• -¤4*org/gradle/wrapper/BootstrapMainStarter.classPK  ;„Bf[ÛñA µ(¤A/org/gradle/wrapper/WrapperExecutor.classPK  ;„B{w`~% *¤È9org/gradle/wrapper/GradleWrapperMain.classPK  ;„BOÝ6Ñ "¤5Dorg/gradle/wrapper/Install$1.classPK  ;„Bˆ€ü²V8¤‹Jorg/gradle/wrapper/PathAssembler$LocalDistribution.classPK  ;„BI}È#8z !¤“Lorg/gradle/wrapper/Download.classPK  ;„BU HPQO#¤ Tgradle-wrapper-classpath.propertiesPK õ:„Bˆ$xʤœTbuild-receipt.propertiesPK õ:„BíAœUorg/gradle/cli/PK õ:„Bˆîò`ç1¤ËUorg/gradle/cli/AbstractCommandLineConverter.classPK õ:„B2_e¦è(¤Yorg/gradle/cli/CommandLineParser$1.classPK õ:„B ‚»ª¡÷<¤íYorg/gradle/cli/CommandLineParser$MissingOptionArgState.classPK õ:„Bƒ —“ƒ=¤è\org/gradle/cli/CommandLineParser$OptionStringComparator.classPK õ:„B—›ÈËFK1¤Ö_org/gradle/cli/CommandLineArgumentException.classPK õ:„BlZ5¶„û=¤kaorg/gradle/cli/CommandLineParser$KnownOptionParserState.classPK õ:„Bÿ|ÓÛ7¤Jiorg/gradle/cli/CommandLineParser$OptionComparator.classPK õ:„Bသyßn?¤rlorg/gradle/cli/CommandLineParser$UnknownOptionParserState.classPK õ:„BIü‹Åú“ &¤®oorg/gradle/cli/CommandLineOption.classPK õ:„BúÖÐ>¦¦8¤ìtorg/gradle/cli/CommandLineParser$OptionParserState.classPK õ:„Bƒ”†µô&¤èvorg/gradle/cli/ParsedCommandLine.classPK õ:„B‹A5l| :¤ ~org/gradle/cli/ProjectPropertiesCommandLineConverter.classPK õ:„B1 ©«PF¤ôorg/gradle/cli/CommandLineParser$CaseInsensitiveStringComparator.classPK õ:„B¢V˜"—Ü&&¤¨‚org/gradle/cli/CommandLineParser.classPK õ:„B`÷Å¥)3¤ƒ“org/gradle/cli/CommandLineParser$AfterOptions.classPK õ:„BQÆbŒ—œ3¤y–org/gradle/cli/CommandLineParser$OptionString.classPK õ:„Bý¹E#±! ;¤a™org/gradle/cli/AbstractPropertiesCommandLineConverter.classPK õ:„B“¼¼ ,¤kžorg/gradle/cli/ParsedCommandLineOption.classPK õ:„B7ÉŠ¯™ª=¤q¡org/gradle/cli/CommandLineParser$OptionAwareParserState.classPK õ:„B$¸Rü<Y)¤e¤org/gradle/cli/CommandLineConverter.classPK õ:„B@ͤ1é| <¤è¥org/gradle/cli/CommandLineParser$BeforeFirstSubCommand.classPK õ:„B“;™|ü9¤+ªorg/gradle/cli/SystemPropertiesCommandLineConverter.classPK õ:„Bœ³I·2¤þ«org/gradle/cli/CommandLineParser$ParserState.classPK õ:„B6œ7<Ê ;¤Q®org/gradle/cli/CommandLineParser$AfterFirstSubCommand.classPK õ:„Bö„ŽÂGE¤æ±gradle-cli-classpath.propertiesPK//hj²golly-2.8-src/gui-android/Golly/.gitignore0000644000175100017510000000051512660172450015505 00000000000000 local.properties build/ app/build/ .idea/ .gradle/ # It is better not to add iml files to source control. # https://code.google.com/p/android/issues/detail?id=77983#c7 Golly.iml app/app.iml # prevent these from being added accidentally app/src/main/assets/Help.zip app/src/main/assets/Patterns.zip app/src/main/assets/Rules.zip golly-2.8-src/gui-android/Golly/app/0000755000175100017510000000000012751756121014360 500000000000000golly-2.8-src/gui-android/Golly/app/src/0000755000175100017510000000000012751756120015146 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/0000755000175100017510000000000012751756121016073 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/assets/0000755000175100017510000000000012751756121017375 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/assets/readme.txt0000644000175100017510000000077612660172450021321 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.8-src/gui-android/Golly/app/src/main/assets/triangle-right.png0000644000175100017510000000024712660172450022742 00000000000000‰PNG  IHDR &2Ù !tEXtSoftwareGraphicConverter (Intel)w‡úAIDATxœbøO`€P'Nœ _sjŠfRÀ¢™x#pj&Æš!€¾6“ég2C›Ìx¦(…‘ÿÿœ¸7€Ðú{IEND®B`‚golly-2.8-src/gui-android/Golly/app/src/main/assets/triangle-down.png0000644000175100017510000000027512660172450022575 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.8-src/gui-android/Golly/app/src/main/java/0000755000175100017510000000000012751756120017013 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/java/net/0000755000175100017510000000000012751756120017601 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/java/net/sf/0000755000175100017510000000000012751756120020211 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/0000755000175100017510000000000012751756121021340 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/MainActivity.java0000644000175100017510000015160012660172450024523 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/BaseApp.java0000644000175100017510000002604712660172450023443 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/EditActivity.java0000644000175100017510000002415312660172450024526 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/SettingsActivity.java0000644000175100017510000001663112660172450025443 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/OpenActivity.java0000644000175100017510000004000012660172450024527 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(32); } // 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/StateActivity.java0000644000175100017510000000730512660172450024721 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/HelpActivity.java0000644000175100017510000004422112660172450024527 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/RuleActivity.java0000644000175100017510000004411612660172450024551 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/PatternGLSurfaceView.java0000644000175100017510000002402312660172450026124 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 unused, EGLConfig config) { nativeInit(); } // ----------------------------------------------------------------------------- public void onSurfaceChanged(GL10 unused, int w, int h) { nativeResize(w, h); } // ----------------------------------------------------------------------------- public void onDrawFrame(GL10 unused) { nativeRender(); } } // PatternRenderer class golly-2.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/StateGLSurfaceView.java0000644000175100017510000001334112660172450025570 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 unused, EGLConfig config) { nativeInit(); } // ----------------------------------------------------------------------------- public void onSurfaceChanged(GL10 unused, int w, int h) { nativeResize(w, h); } // ----------------------------------------------------------------------------- public void onDrawFrame(GL10 unused) { nativeRender(); } } // StateRenderer class golly-2.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/BaseActivity.java0000644000175100017510000000407512660172450024514 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.8-src/gui-android/Golly/app/src/main/java/net/sf/golly/InfoActivity.java0000644000175100017510000000755212660172450024540 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.8-src/gui-android/Golly/app/src/main/jni/0000755000175100017510000000000012751756121016653 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/jni/jnicalls.h0000644000175100017510000000672412660172450020550 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.8-src/gui-android/Golly/app/src/main/jni/jnicalls.cpp0000644000175100017510000024417012660172450021102 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? static bool temporary_mode = false; // is user doing a multi-finger pan/zoom? static TouchModes oldmode; // touch mode at start of multi-finger pan/zoom // ----------------------------------------------------------------------------- // 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.2 for Android. Copyright 2016 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) { // avoid mode button changing to Move during a multi-finger pan/zoom if (temporary_mode) return oldmode; 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 } // ----------------------------------------------------------------------------- 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; temporary_mode = true; } // ----------------------------------------------------------------------------- extern "C" JNIEXPORT void JNICALL Java_net_sf_golly_PatternGLSurfaceView_nativeRestoreMode(JNIEnv* env) { // restore touch mode saved in nativeMoveMode currlayer->touchmode = oldmode; temporary_mode = false; // ensure correct touch mode is displayed (might not be if user tapped a mode button // with another finger while doing a two-finger pan/zoom) UpdateEditBar(); } // ----------------------------------------------------------------------------- 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); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(1.0, 1.0, 1.0, 1.0); } // ----------------------------------------------------------------------------- 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) ToggleCellColors(); 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; } // ----------------------------------------------------------------------------- static void SetColor(int r, int g, int b, int a) { glColor4ub(r, g, b, a); } // ----------------------------------------------------------------------------- static void FillRect(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 }; glVertexPointer(2, GL_FLOAT, 0, rect); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } // ----------------------------------------------------------------------------- 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_MULTISAMPLE); glDisable(GL_STENCIL_TEST); glDisable(GL_FOG); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClearColor(1.0, 1.0, 1.0, 1.0); } // ----------------------------------------------------------------------------- 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; if (glIsEnabled(GL_TEXTURE_2D)) glDisable(GL_TEXTURE_2D); // set the stroke color to white SetColor(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) { if (glIsEnabled(GL_TEXTURE_2D)) glDisable(GL_TEXTURE_2D); SetColor(currlayer->cellr[state], currlayer->cellg[state], currlayer->cellb[state], 255); FillRect(x, y, wd, ht); } // ----------------------------------------------------------------------------- // texture name for drawing RGBA bitmaps static GLuint rgbatexture = 0; // fixed texture coordinates used by glTexCoordPointer static const GLshort texture_coordinates[] = { 0,0, 1,0, 0,1, 1,1 }; static void DrawRGBAData(unsigned char* rgbadata, int x, int y, int w, int h) { // only need to create texture name once if (rgbatexture == 0) glGenTextures(1, &rgbatexture); 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, rgbatexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexCoordPointer(2, GL_SHORT, 0, texture_coordinates); } // update the texture with the new RGBA data glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgbadata); if (highdensity) { w = w*2; h = h*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); } // ----------------------------------------------------------------------------- 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; int rowbytes = 32*4; unsigned char rgbadata[32*4*32] = {0}; // all pixels are initially transparent 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 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; } int byte = 0; int rpos = 0; for (int i = 0; i < cellsize; i++) { int rowstart = rpos; 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) { // non-black pixel if (multicolor) { // use non-black pixel in multi-colored icon if (swapcolors) { rgbadata[rpos] = 255 - r; rgbadata[rpos+1] = 255 - g; rgbadata[rpos+2] = 255 - b; } else { rgbadata[rpos] = r; rgbadata[rpos+1] = g; rgbadata[rpos+2] = b; } } else { // grayscale icon (r = g = b) if (r == 255) { // replace white pixel with live cell color rgbadata[rpos] = liver; rgbadata[rpos+1] = liveg; rgbadata[rpos+2] = liveb; } else { // replace gray pixel with appropriate shade between // live and dead cell colors float frac = (float)r / 255.0; rgbadata[rpos] = (int)(deadr + frac * (liver - deadr) + 0.5); rgbadata[rpos+1] = (int)(deadg + frac * (liveg - deadg) + 0.5); rgbadata[rpos+2] = (int)(deadb + frac * (liveb - deadb) + 0.5); } } rgbadata[rpos+3] = 255; // pixel is opaque } // move to next pixel in rgbadata rpos += 4; } // move to next row in rgbadata rpos = rowstart + rowbytes; } // draw the icon data DrawRGBAData(rgbadata, x, y, 32, 32); } // ----------------------------------------------------------------------------- static void DrawDigit(int digit, int x, int y) { unsigned char* pxldata = digits10x10[digit+1]->pxldata; int cellsize = 10; int rowbytes = 16*4; unsigned char rgbadata[16*4*16] = {0}; // all pixels are initially transparent int byte = 0; int rpos = 0; for (int i = 0; i < cellsize; i++) { int rowstart = rpos; 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) { // non-black pixel rgbadata[rpos] = r; rgbadata[rpos+1] = g; rgbadata[rpos+2] = b; rgbadata[rpos+3] = 255; // pixel is opaque } // move to next pixel in rgbadata rpos += 4; } // move to next row in rgbadata rpos = rowstart + rowbytes; } // draw the digit data DrawRGBAData(rgbadata, x, y, 16, 16); } // ----------------------------------------------------------------------------- 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 pattern exists and is at starting gen then ensure savestart is true // so that SaveStartingPattern will save pattern to suitable file // (and thus undo/reset will work correctly) if (currlayer->algo->getGeneration() == currlayer->startgen && !currlayer->algo->isEmpty()) { currlayer->savestart = true; } // 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 implemented 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.8-src/gui-android/Golly/app/src/main/res/0000755000175100017510000000000012751756120016663 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/res/values-sw600dp/0000755000175100017510000000000012751756121021364 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/res/values-sw600dp/dimens.xml0000644000175100017510000000030412660172450023276 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/menu/0000755000175100017510000000000012751756121017630 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/res/menu/edit_menu.xml0000644000175100017510000000046212660172450022241 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/menu/pastemode_menu.xml0000644000175100017510000000110512660172450023270 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/menu/paste_menu.xml0000644000175100017510000000154512660172450022433 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/menu/mode_menu.xml0000644000175100017510000000075112660172450022241 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/menu/control_menu.xml0000644000175100017510000000100012660172450022761 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/menu/view_menu.xml0000644000175100017510000000077712660172450022277 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/menu/main.xml0000644000175100017510000000066212660172450021216 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/menu/selection_menu.xml0000644000175100017510000000356512660172450023310 00000000000000 golly-2.8-src/gui-android/Golly/app/src/main/res/drawable-xxhdpi/0000755000175100017510000000000012751756121021747 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/res/drawable-xxhdpi/ic_launcher.png0000644000175100017510000003303112660172450024645 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.8-src/gui-android/Golly/app/src/main/res/values-sw720dp-land/0000755000175100017510000000000012751756121022303 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/res/values-sw720dp-land/dimens.xml0000644000175100017510000000041512660172450024220 00000000000000 128dp golly-2.8-src/gui-android/Golly/app/src/main/res/drawable-xhdpi/0000755000175100017510000000000012751756121021557 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/res/drawable-xhdpi/ic_launcher.png0000644000175100017510000001524012660172450024457 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.8-src/gui-android/Golly/app/src/main/res/layout/0000755000175100017510000000000012751756121020201 500000000000000golly-2.8-src/gui-android/Golly/app/src/main/res/layout/help_layout.xml0000644000175100017510000000637312660172450023175 00000000000000